Skip to content

Commit 8a395df

Browse files
authored
Merge b98cfbe into 3b10523
2 parents 3b10523 + b98cfbe commit 8a395df

File tree

6 files changed

+191
-40
lines changed

6 files changed

+191
-40
lines changed

CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp

+84-40
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "Wrapper\Browser.h"
2424
#include "..\CefSharp.Core.Runtime\Internals\Messaging\Messages.h"
2525
#include "..\CefSharp.Core.Runtime\Internals\Serialization\Primitives.h"
26+
#include <include/cef_parser.h>
2627

2728
using namespace System;
2829
using namespace System::Diagnostics;
@@ -100,6 +101,16 @@ namespace CefSharp
100101
}
101102

102103
_jsBindingApiEnabled = extraInfo->GetBool("JavascriptBindingApiEnabled");
104+
_jsBindingApiHasAllowOrigins = extraInfo->GetBool("JavascriptBindingApiHasAllowOrigins");
105+
106+
if (_jsBindingApiHasAllowOrigins)
107+
{
108+
auto allowOrigins = extraInfo->GetList("JavascriptBindingApiAllowOrigins");
109+
if (allowOrigins.get() && allowOrigins->IsValid())
110+
{
111+
_jsBindingApiAllowOrigins = allowOrigins->Copy();
112+
}
113+
}
103114

104115
if (extraInfo->HasKey("JsBindingPropertyName") || extraInfo->HasKey("JsBindingPropertyNameCamelCase"))
105116
{
@@ -149,50 +160,83 @@ namespace CefSharp
149160

150161
if (_jsBindingApiEnabled)
151162
{
152-
//TODO: Look at adding some sort of javascript mapping layer to reduce the code duplication
153-
auto global = context->GetGlobal();
154-
auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
155-
auto processId = System::Diagnostics::Process::GetCurrentProcess()->Id;
156-
157-
//TODO: JSB: Split functions into their own classes
158-
//Browser wrapper is only used for BindObjectAsync
159-
auto bindObjAsyncFunction = CefV8Value::CreateFunction(kBindObjectAsync, new BindObjectAsyncHandler(_registerBoundObjectRegistry, _javascriptObjects, browserWrapper));
160-
auto unBindObjFunction = CefV8Value::CreateFunction(kDeleteBoundObject, new RegisterBoundObjectHandler(_javascriptObjects));
161-
auto removeObjectFromCacheFunction = CefV8Value::CreateFunction(kRemoveObjectFromCache, new RegisterBoundObjectHandler(_javascriptObjects));
162-
auto isObjectCachedFunction = CefV8Value::CreateFunction(kIsObjectCached, new RegisterBoundObjectHandler(_javascriptObjects));
163-
auto postMessageFunction = CefV8Value::CreateFunction(kPostMessage, new JavascriptPostMessageHandler(rootObject == nullptr ? nullptr : rootObject->CallbackRegistry));
164-
auto promiseHandlerFunction = CefV8Value::CreateFunction(kSendEvalScriptResponse, new JavascriptPromiseHandler());
165-
166-
//By default We'll support both CefSharp and cefSharp, for those who prefer the JS style
167-
auto createCefSharpObj = !_jsBindingPropertyName.empty();
168-
auto createCefSharpObjCamelCase = !_jsBindingPropertyNameCamelCase.empty();
169-
170-
if (createCefSharpObj)
163+
auto createObjects = true;
164+
165+
if (_jsBindingApiHasAllowOrigins)
171166
{
172-
auto cefSharpObj = CefV8Value::CreateObject(nullptr, nullptr);
173-
cefSharpObj->SetValue(kBindObjectAsync, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
174-
cefSharpObj->SetValue(kDeleteBoundObject, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
175-
cefSharpObj->SetValue(kRemoveObjectFromCache, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
176-
cefSharpObj->SetValue(kIsObjectCached, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
177-
cefSharpObj->SetValue(kPostMessage, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
178-
cefSharpObj->SetValue(kSendEvalScriptResponse, promiseHandlerFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
179-
cefSharpObj->SetValue(kRenderProcessId, CefV8Value::CreateInt(processId), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
180-
181-
global->SetValue(_jsBindingPropertyName, cefSharpObj, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
167+
createObjects = false;
168+
169+
auto frameUrl = frame->GetURL();
170+
171+
CefURLParts frameUrlParts;
172+
173+
if (CefParseURL(frameUrl, frameUrlParts))
174+
{
175+
auto frameUrlOrigin = CefString(frameUrlParts.origin.str, frameUrlParts.origin.length);
176+
177+
auto size = static_cast<int>(_jsBindingApiAllowOrigins->GetSize());
178+
179+
for (int i = 0; i < size; i++)
180+
{
181+
auto origin = _jsBindingApiAllowOrigins->GetString(i);
182+
183+
if (origin.compare(frameUrlOrigin) == 0)
184+
{
185+
createObjects = true;
186+
187+
break;
188+
}
189+
}
190+
}
182191
}
183192

184-
if (createCefSharpObjCamelCase)
193+
if (createObjects)
185194
{
186-
auto cefSharpObjCamelCase = CefV8Value::CreateObject(nullptr, nullptr);
187-
cefSharpObjCamelCase->SetValue(kBindObjectAsyncCamelCase, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
188-
cefSharpObjCamelCase->SetValue(kDeleteBoundObjectCamelCase, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
189-
cefSharpObjCamelCase->SetValue(kRemoveObjectFromCacheCamelCase, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
190-
cefSharpObjCamelCase->SetValue(kIsObjectCachedCamelCase, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
191-
cefSharpObjCamelCase->SetValue(kPostMessageCamelCase, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
192-
cefSharpObjCamelCase->SetValue(kSendEvalScriptResponseCamelCase, promiseHandlerFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
193-
cefSharpObjCamelCase->SetValue(kRenderProcessIdCamelCase, CefV8Value::CreateInt(processId), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
194-
195-
global->SetValue(_jsBindingPropertyNameCamelCase, cefSharpObjCamelCase, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
195+
//TODO: Look at adding some sort of javascript mapping layer to reduce the code duplication
196+
auto global = context->GetGlobal();
197+
auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
198+
auto processId = System::Diagnostics::Process::GetCurrentProcess()->Id;
199+
200+
//TODO: JSB: Split functions into their own classes
201+
//Browser wrapper is only used for BindObjectAsync
202+
auto bindObjAsyncFunction = CefV8Value::CreateFunction(kBindObjectAsync, new BindObjectAsyncHandler(_registerBoundObjectRegistry, _javascriptObjects, browserWrapper));
203+
auto unBindObjFunction = CefV8Value::CreateFunction(kDeleteBoundObject, new RegisterBoundObjectHandler(_javascriptObjects));
204+
auto removeObjectFromCacheFunction = CefV8Value::CreateFunction(kRemoveObjectFromCache, new RegisterBoundObjectHandler(_javascriptObjects));
205+
auto isObjectCachedFunction = CefV8Value::CreateFunction(kIsObjectCached, new RegisterBoundObjectHandler(_javascriptObjects));
206+
auto postMessageFunction = CefV8Value::CreateFunction(kPostMessage, new JavascriptPostMessageHandler(rootObject == nullptr ? nullptr : rootObject->CallbackRegistry));
207+
auto promiseHandlerFunction = CefV8Value::CreateFunction(kSendEvalScriptResponse, new JavascriptPromiseHandler());
208+
209+
//By default We'll support both CefSharp and cefSharp, for those who prefer the JS style
210+
auto createCefSharpObj = !_jsBindingPropertyName.empty();
211+
auto createCefSharpObjCamelCase = !_jsBindingPropertyNameCamelCase.empty();
212+
213+
if (createCefSharpObj)
214+
{
215+
auto cefSharpObj = CefV8Value::CreateObject(nullptr, nullptr);
216+
cefSharpObj->SetValue(kBindObjectAsync, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
217+
cefSharpObj->SetValue(kDeleteBoundObject, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
218+
cefSharpObj->SetValue(kRemoveObjectFromCache, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
219+
cefSharpObj->SetValue(kIsObjectCached, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
220+
cefSharpObj->SetValue(kPostMessage, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
221+
cefSharpObj->SetValue(kSendEvalScriptResponse, promiseHandlerFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
222+
cefSharpObj->SetValue(kRenderProcessId, CefV8Value::CreateInt(processId), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
223+
224+
global->SetValue(_jsBindingPropertyName, cefSharpObj, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
225+
}
226+
227+
if (createCefSharpObjCamelCase)
228+
{
229+
auto cefSharpObjCamelCase = CefV8Value::CreateObject(nullptr, nullptr);
230+
cefSharpObjCamelCase->SetValue(kBindObjectAsyncCamelCase, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
231+
cefSharpObjCamelCase->SetValue(kDeleteBoundObjectCamelCase, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
232+
cefSharpObjCamelCase->SetValue(kRemoveObjectFromCacheCamelCase, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
233+
cefSharpObjCamelCase->SetValue(kIsObjectCachedCamelCase, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
234+
cefSharpObjCamelCase->SetValue(kPostMessageCamelCase, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
235+
cefSharpObjCamelCase->SetValue(kSendEvalScriptResponseCamelCase, promiseHandlerFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
236+
cefSharpObjCamelCase->SetValue(kRenderProcessIdCamelCase, CefV8Value::CreateInt(processId), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
237+
238+
global->SetValue(_jsBindingPropertyNameCamelCase, cefSharpObjCamelCase, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
239+
}
196240
}
197241
}
198242

CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h

+4
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ namespace CefSharp
2929
bool _focusedNodeChangedEnabled;
3030
bool _legacyBindingEnabled;
3131
bool _jsBindingApiEnabled = true;
32+
bool _jsBindingApiHasAllowOrigins = false;
33+
CefRefPtr<CefListValue> _jsBindingApiAllowOrigins;
3234

3335
// The property names used to call bound objects
3436
CefString _jsBindingPropertyName;
@@ -69,6 +71,8 @@ namespace CefSharp
6971
}
7072
delete _onBrowserCreated;
7173
delete _onBrowserDestroyed;
74+
75+
_jsBindingApiAllowOrigins = nullptr;
7276
}
7377

7478
CefBrowserWrapper^ FindBrowserWrapper(int browserId);

CefSharp.Core.Runtime/ManagedCefBrowserAdapter.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,22 @@ namespace CefSharp
8484

8585
extraInfo->SetBool("JavascriptBindingApiEnabled", objectRepositorySettings->JavascriptBindingApiEnabled);
8686

87+
auto hasJavascriptBindingApiAllowOrigins = objectRepositorySettings->HasJavascriptBindingApiAllowOrigins();
88+
89+
extraInfo->SetBool("JavascriptBindingApiHasAllowOrigins", hasJavascriptBindingApiAllowOrigins);
90+
91+
if (hasJavascriptBindingApiAllowOrigins)
92+
{
93+
auto allowOriginList = CefListValue::Create();
94+
95+
for (int i = 0; i < objectRepositorySettings->JavascriptBindingApiAllowOrigins->Length; i++)
96+
{
97+
allowOriginList->SetString(i, StringUtils::ToNative(objectRepositorySettings->JavascriptBindingApiAllowOrigins[i]));
98+
}
99+
100+
extraInfo->SetList("JavascriptBindingApiAllowOrigins", allowOriginList);
101+
}
102+
87103
CefRefPtr<CefRequestContext> requestCtx;
88104

89105
if (requestContext != nullptr)

CefSharp.Test/CefSharpFixture.cs

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ private void CefInitialize()
6464
settings.CachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefSharp\\Tests\\Cache");
6565
settings.RootCachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefSharp\\Tests");
6666
//settings.CefCommandLineArgs.Add("renderer-startup-dialog");
67+
//settings.CefCommandLineArgs.Add("disable-features=SpareRendererForSitePerProcess");
6768
//settings.CefCommandLineArgs.Add("disable-site-isolation-trials");
6869
settings.SetOffScreenRenderingBestPerformanceArgs();
6970

CefSharp.Test/JavascriptBinding/JavascriptBindingTests.cs

+54
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,60 @@ public async Task ShouldDisableJsBindingApi()
130130
}
131131
}
132132

133+
[Fact]
134+
public async Task ShouldDisableJsBindingApiForOrigin()
135+
{
136+
using (var browser = new ChromiumWebBrowser(CefExample.BindingApiCustomObjectNameTestUrl, automaticallyCreateBrowser: false))
137+
{
138+
var settings = browser.JavascriptObjectRepository.Settings;
139+
settings.JavascriptBindingApiEnabled = true;
140+
settings.JavascriptBindingApiAllowOrigins = new string[] { "notallowed" };
141+
142+
//To modify the settings we need to defer browser creation slightly
143+
browser.CreateBrowser();
144+
145+
var loadResponse = await browser.WaitForInitialLoadAsync();
146+
147+
Assert.True(loadResponse.Success);
148+
149+
var response1 = await browser.EvaluateScriptAsync("typeof window.cefSharp === 'undefined'");
150+
var response2 = await browser.EvaluateScriptAsync("typeof window.CefSharp === 'undefined'");
151+
152+
Assert.True(response1.Success);
153+
Assert.True((bool)response1.Result);
154+
155+
Assert.True(response2.Success);
156+
Assert.True((bool)response2.Result);
157+
}
158+
}
159+
160+
[Theory]
161+
[InlineData(CefExample.ExampleDomain)]
162+
[InlineData("someorigin", CefExample.ExampleDomain)]
163+
public async Task ShouldEnableJsBindingApiForOrigin(params string[] origins)
164+
{
165+
using (var browser = new ChromiumWebBrowser(CefExample.BindingApiCustomObjectNameTestUrl, automaticallyCreateBrowser: false))
166+
{
167+
var settings = browser.JavascriptObjectRepository.Settings;
168+
settings.JavascriptBindingApiEnabled = true;
169+
settings.JavascriptBindingApiAllowOrigins = origins;
170+
171+
//To modify the settings we need to defer browser creation slightly
172+
browser.CreateBrowser();
173+
174+
await browser.WaitForInitialLoadAsync();
175+
176+
var response1 = await browser.EvaluateScriptAsync("typeof window.cefSharp === 'undefined'");
177+
var response2 = await browser.EvaluateScriptAsync("typeof window.CefSharp === 'undefined'");
178+
179+
Assert.True(response1.Success);
180+
Assert.False((bool)response1.Result);
181+
182+
Assert.True(response2.Success);
183+
Assert.False((bool)response2.Result);
184+
}
185+
}
186+
133187
[Fact]
134188
public async Task ShouldEnableJsBindingApi()
135189
{

CefSharp/JavascriptBinding/JavascriptBindingSettings.cs

+32
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//
33
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
44

5+
using System.Collections.Generic;
56
using CefSharp.Internals;
67

78
namespace CefSharp.JavascriptBinding
@@ -15,6 +16,7 @@ public class JavascriptBindingSettings : FreezableBase
1516
private bool legacyBindingEnabled;
1617
private string jsBindingGlobalObjectName;
1718
private bool jsBindingApiEnabled = true;
19+
private string[] javascriptBindingApiAllowOrigins;
1820

1921
/// <summary>
2022
/// The Javascript methods that CefSharp provides in relation to JavaScript Binding are
@@ -33,6 +35,24 @@ public bool JavascriptBindingApiEnabled
3335
}
3436
}
3537

38+
/// <summary>
39+
/// When <see cref="JavascriptBindingApiEnabled"/> is set to true, set a collection
40+
/// of origins to limit which origins CefSharp will create it's global (window) object.
41+
/// </summary>
42+
/// <remarks>
43+
/// If you wish to create the CefSharp object for a limited set of origins then set this property
44+
/// </remarks>
45+
public string[] JavascriptBindingApiAllowOrigins
46+
{
47+
get { return javascriptBindingApiAllowOrigins; }
48+
set
49+
{
50+
ThrowIfFrozen();
51+
52+
javascriptBindingApiAllowOrigins = value;
53+
}
54+
}
55+
3656
/// <summary>
3757
/// The Javascript methods that CefSharp provides in relation to JavaScript Binding are
3858
/// created using a Global (window) Object. Settings this property allows you to customise
@@ -95,5 +115,17 @@ public bool AlwaysInterceptAsynchronously
95115
alwaysInterceptAsynchronously = value;
96116
}
97117
}
118+
119+
/// <summary>
120+
/// HasJavascriptBindingApiAllowOrigins
121+
/// </summary>
122+
/// <returns>bool true if <see cref="JavascriptBindingApiAllowOrigins"/> is non empty collection.</returns>
123+
public bool HasJavascriptBindingApiAllowOrigins()
124+
{
125+
if (javascriptBindingApiAllowOrigins == null)
126+
return false;
127+
128+
return javascriptBindingApiAllowOrigins.Length > 0;
129+
}
98130
}
99131
}

0 commit comments

Comments
 (0)