Skip to content

Commit ab5e716

Browse files
authored
Merge 6cefcea into 6de821c
2 parents 6de821c + 6cefcea commit ab5e716

File tree

6 files changed

+264
-10
lines changed

6 files changed

+264
-10
lines changed

CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp

Lines changed: 79 additions & 8 deletions
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;
@@ -87,7 +88,7 @@ namespace CefSharp
8788
//Using LegacyBinding with multiple ChromiumWebBrowser instances that share the same
8889
//render process and using LegacyBinding will cause problems for the limited caching implementation
8990
//that exists at the moment, for now we'll remove an object if already exists, same behaviour
90-
//as the new binding method.
91+
//as the new binding method.
9192
//TODO: This should be removed when https://github.com/cefsharp/CefSharp/issues/2306
9293
//Is complete as objects will be stored at the browser level
9394
if (_javascriptObjects->ContainsKey(obj->JavascriptName))
@@ -98,16 +99,33 @@ namespace CefSharp
9899
}
99100
}
100101
}
102+
}
101103

102-
_jsBindingApiEnabled = extraInfo->GetBool("JavascriptBindingApiEnabled");
104+
if (extraInfo->HasKey("JavascriptBindingApiEnabled"))
105+
{
106+
wrapper->JavascriptBindingApiEnabled = extraInfo->GetBool("JavascriptBindingApiEnabled");
107+
}
108+
109+
if (extraInfo->HasKey("JavascriptBindingApiHasAllowOrigins"))
110+
{
111+
wrapper->JavascriptBindingApiHasAllowOrigins = extraInfo->GetBool("JavascriptBindingApiHasAllowOrigins");
103112

104-
if (extraInfo->HasKey("JsBindingPropertyName") || extraInfo->HasKey("JsBindingPropertyNameCamelCase"))
113+
if (wrapper->JavascriptBindingApiHasAllowOrigins)
105114
{
106-
//TODO: Create constant for these and legacy binding strings above
107-
_jsBindingPropertyName = extraInfo->GetString("JsBindingPropertyName");
108-
_jsBindingPropertyNameCamelCase = extraInfo->GetString("JsBindingPropertyNameCamelCase");
115+
auto allowOrigins = extraInfo->GetList("JavascriptBindingApiAllowOrigins");
116+
if (allowOrigins.get() && allowOrigins->IsValid())
117+
{
118+
wrapper->JavascriptBindingApiAllowOrigins = allowOrigins->Copy();
119+
}
109120
}
110121
}
122+
123+
if (extraInfo->HasKey("JsBindingPropertyName") || extraInfo->HasKey("JsBindingPropertyNameCamelCase"))
124+
{
125+
//TODO: Create constant for these and legacy binding strings above
126+
_jsBindingPropertyName = extraInfo->GetString("JsBindingPropertyName");
127+
_jsBindingPropertyNameCamelCase = extraInfo->GetString("JsBindingPropertyNameCamelCase");
128+
}
111129
}
112130

113131
void CefAppUnmanagedWrapper::OnBrowserDestroyed(CefRefPtr<CefBrowser> browser)
@@ -147,11 +165,12 @@ namespace CefSharp
147165
}
148166
}
149167

150-
if (_jsBindingApiEnabled)
168+
auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
169+
170+
if (browserWrapper != nullptr && browserWrapper->JavascriptBindingApiEnabled && IsJavascriptBindingApiAllowed(frame))
151171
{
152172
//TODO: Look at adding some sort of javascript mapping layer to reduce the code duplication
153173
auto global = context->GetGlobal();
154-
auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
155174
auto processId = System::Diagnostics::Process::GetCurrentProcess()->Id;
156175

157176
//TODO: JSB: Split functions into their own classes
@@ -328,6 +347,58 @@ namespace CefSharp
328347
return rootObject;
329348
}
330349

350+
bool CefAppUnmanagedWrapper::IsJavascriptBindingApiAllowed(CefRefPtr<CefFrame> frame)
351+
{
352+
auto browserWrapper = FindBrowserWrapper(frame->GetBrowser()->GetIdentifier());
353+
354+
if (browserWrapper == nullptr || !browserWrapper->JavascriptBindingApiHasAllowOrigins)
355+
{
356+
return true;
357+
}
358+
359+
auto allowOrigins = browserWrapper->JavascriptBindingApiAllowOrigins;
360+
if (!allowOrigins.get())
361+
{
362+
return false;
363+
}
364+
365+
auto frameUrl = frame->GetURL();
366+
367+
CefURLParts frameUrlParts;
368+
369+
if (CefParseURL(frameUrl, frameUrlParts))
370+
{
371+
auto originStr = frameUrlParts.origin.str;
372+
auto originLen = frameUrlParts.origin.length;
373+
374+
if (originLen > 0 && originStr[originLen - 1] == L'/')
375+
{
376+
originLen--;
377+
}
378+
379+
auto frameUrlOrigin = CefString(originStr, originLen);
380+
381+
auto size = static_cast<int>(allowOrigins->GetSize());
382+
383+
for (int i = 0; i < size; i++)
384+
{
385+
auto origin = allowOrigins->GetString(i);
386+
auto frameOriginPtr = reinterpret_cast<const wchar_t*>(frameUrlOrigin.c_str());
387+
auto allowedOriginPtr = reinterpret_cast<const wchar_t*>(origin.c_str());
388+
389+
if (frameOriginPtr != nullptr && allowedOriginPtr != nullptr)
390+
{
391+
if (_wcsicmp(frameOriginPtr, allowedOriginPtr) == 0)
392+
{
393+
return true;
394+
}
395+
}
396+
}
397+
}
398+
399+
return false;
400+
}
401+
331402
CefBrowserWrapper^ CefAppUnmanagedWrapper::FindBrowserWrapper(int browserId)
332403
{
333404
CefBrowserWrapper^ wrapper = nullptr;

CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ namespace CefSharp
2929
gcroot<ConcurrentDictionary<String^, JavascriptRootObjectWrapper^>^> _jsRootObjectWrappersByFrameId;
3030
bool _focusedNodeChangedEnabled;
3131
bool _legacyBindingEnabled;
32-
bool _jsBindingApiEnabled = true;
3332

3433
// The property names used to call bound objects
3534
CefString _jsBindingPropertyName;
@@ -39,6 +38,7 @@ namespace CefSharp
3938
gcroot<Dictionary<String^, JavascriptObject^>^> _javascriptObjects;
4039

4140
gcroot<RegisterBoundObjectRegistry^> _registerBoundObjectRegistry;
41+
bool IsJavascriptBindingApiAllowed(CefRefPtr<CefFrame> frame);
4242

4343
public:
4444
static const CefString kPromiseCreatorScript;

CefSharp.BrowserSubprocess.Core/CefBrowserWrapper.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,31 @@ namespace CefSharp
2222
{
2323
namespace BrowserSubprocess
2424
{
25-
// "Master class" for wrapping everything that the Cef Subprocess needs
25+
// "Master class" for wrapping everything that the Cef Subprocess needs
2626
// for ONE CefBrowser.
2727
public ref class CefBrowserWrapper
2828
{
2929
private:
3030
MCefRefPtr<CefBrowser> _cefBrowser;
31+
MCefRefPtr<CefListValue> _javascriptBindingApiAllowOrigins;
3132

3233
public:
3334
CefBrowserWrapper(const CefRefPtr<CefBrowser> &cefBrowser)
3435
{
3536
_cefBrowser = cefBrowser.get();
3637
BrowserId = cefBrowser->GetIdentifier();
3738
IsPopup = cefBrowser->IsPopup();
39+
40+
JavascriptBindingApiEnabled = true;
41+
JavascriptBindingApiHasAllowOrigins = false;
42+
JavascriptBindingApiAllowOrigins = nullptr;
3843
}
3944

4045
!CefBrowserWrapper()
4146
{
4247
_cefBrowser = nullptr;
48+
49+
_javascriptBindingApiAllowOrigins = nullptr;
4350
}
4451

4552
~CefBrowserWrapper()
@@ -49,6 +56,13 @@ namespace CefSharp
4956

5057
property int BrowserId;
5158
property bool IsPopup;
59+
property bool JavascriptBindingApiEnabled;
60+
property bool JavascriptBindingApiHasAllowOrigins;
61+
property CefRefPtr<CefListValue> JavascriptBindingApiAllowOrigins
62+
{
63+
CefRefPtr<CefListValue> get() { return _javascriptBindingApiAllowOrigins.get(); }
64+
void set(CefRefPtr<CefListValue> value) { _javascriptBindingApiAllowOrigins = value.get(); }
65+
}
5266

5367
#ifndef NETCOREAPP
5468
// This allows us to create the WCF proxies back to our parent process.

CefSharp.Core.Runtime/ManagedCefBrowserAdapter.cpp

Lines changed: 16 additions & 0 deletions
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/JavascriptBinding/JavascriptBindingTests.cs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,117 @@ public async Task ShouldDisableJsBindingApi()
130130
}
131131
}
132132

133+
[Theory]
134+
[InlineData("notallowed")]
135+
[InlineData("notallowed", "alsonotallowed")]
136+
[InlineData("notallowed", "alsonotallowed", "stillnotallowed")]
137+
public async Task ShouldDisableJsBindingApiForOrigin(params string[] origins)
138+
{
139+
using (var browser = new ChromiumWebBrowser(CefExample.BindingApiCustomObjectNameTestUrl, automaticallyCreateBrowser: false))
140+
{
141+
var settings = browser.JavascriptObjectRepository.Settings;
142+
settings.JavascriptBindingApiEnabled = true;
143+
settings.JavascriptBindingApiAllowOrigins = origins;
144+
145+
//To modify the settings we need to defer browser creation slightly
146+
browser.CreateBrowser();
147+
148+
var loadResponse = await browser.WaitForInitialLoadAsync();
149+
150+
Assert.True(loadResponse.Success);
151+
152+
var response1 = await browser.EvaluateScriptAsync("typeof window.cefSharp === 'undefined'");
153+
var response2 = await browser.EvaluateScriptAsync("typeof window.CefSharp === 'undefined'");
154+
155+
Assert.True(response1.Success);
156+
Assert.True((bool)response1.Result);
157+
158+
Assert.True(response2.Success);
159+
Assert.True((bool)response2.Result);
160+
}
161+
}
162+
163+
[Fact]
164+
public async Task ShouldEnableJsBindingApiWhenOriginsListIsEmpty()
165+
{
166+
using (var browser = new ChromiumWebBrowser(CefExample.BindingApiCustomObjectNameTestUrl, automaticallyCreateBrowser: false))
167+
{
168+
var settings = browser.JavascriptObjectRepository.Settings;
169+
settings.JavascriptBindingApiEnabled = true;
170+
settings.JavascriptBindingApiAllowOrigins = new string[0];
171+
172+
//To modify the settings we need to defer browser creation slightly
173+
browser.CreateBrowser();
174+
175+
await browser.WaitForInitialLoadAsync();
176+
177+
var response1 = await browser.EvaluateScriptAsync("typeof window.cefSharp === 'undefined'");
178+
var response2 = await browser.EvaluateScriptAsync("typeof window.CefSharp === 'undefined'");
179+
180+
Assert.True(response1.Success);
181+
Assert.False((bool)response1.Result);
182+
183+
Assert.True(response2.Success);
184+
Assert.False((bool)response2.Result);
185+
}
186+
}
187+
188+
[Theory]
189+
[InlineData(CefExample.BaseUrl)]
190+
[InlineData(CefExample.BaseUrl + "/")]
191+
public async Task ShouldEnableJsBindingApiForOriginWithOrWithoutTrailingSlash(string configuredOrigin)
192+
{
193+
using (var browser = new ChromiumWebBrowser(CefExample.BindingApiCustomObjectNameTestUrl, automaticallyCreateBrowser: false))
194+
{
195+
var settings = browser.JavascriptObjectRepository.Settings;
196+
settings.JavascriptBindingApiEnabled = true;
197+
settings.JavascriptBindingApiAllowOrigins = new string[] { configuredOrigin };
198+
199+
//To modify the settings we need to defer browser creation slightly
200+
browser.CreateBrowser();
201+
202+
await browser.WaitForInitialLoadAsync();
203+
204+
var response1 = await browser.EvaluateScriptAsync("typeof window.cefSharp === 'undefined'");
205+
var response2 = await browser.EvaluateScriptAsync("typeof window.CefSharp === 'undefined'");
206+
207+
Assert.True(response1.Success);
208+
Assert.False((bool)response1.Result);
209+
210+
Assert.True(response2.Success);
211+
Assert.False((bool)response2.Result);
212+
}
213+
}
214+
[Theory]
215+
[InlineData(CefExample.BaseUrl + "/")]
216+
[InlineData("someorigin", CefExample.BaseUrl + "/")]
217+
[InlineData(CefExample.BaseUrl + "/", "someorigin")]
218+
[InlineData("firstorigin", "secondorigin", CefExample.BaseUrl + "/")]
219+
[InlineData("firstorigin", CefExample.BaseUrl + "/", "secondorigin")]
220+
public async Task ShouldEnableJsBindingApiForOrigin(params string[] origins)
221+
{
222+
using (var browser = new ChromiumWebBrowser(CefExample.BindingApiCustomObjectNameTestUrl, automaticallyCreateBrowser: false))
223+
{
224+
var settings = browser.JavascriptObjectRepository.Settings;
225+
settings.JavascriptBindingApiEnabled = true;
226+
settings.JavascriptBindingApiAllowOrigins = origins;
227+
228+
//To modify the settings we need to defer browser creation slightly
229+
browser.CreateBrowser();
230+
231+
await browser.WaitForInitialLoadAsync();
232+
233+
var response1 = await browser.EvaluateScriptAsync("typeof window.cefSharp === 'undefined'");
234+
var response2 = await browser.EvaluateScriptAsync("typeof window.CefSharp === 'undefined'");
235+
236+
Assert.True(response1.Success);
237+
Assert.False((bool)response1.Result);
238+
239+
Assert.True(response2.Success);
240+
Assert.False((bool)response2.Result);
241+
}
242+
}
243+
133244
[Fact]
134245
public async Task ShouldEnableJsBindingApi()
135246
{

0 commit comments

Comments
 (0)