Skip to content

Commit fb03970

Browse files
author
Luca Sonntag
committed
Move JS binding settings to CefBrowserWrapper and optimize origin validation
1 parent ae50a6f commit fb03970

3 files changed

Lines changed: 92 additions & 89 deletions

File tree

CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp

Lines changed: 81 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,15 @@ namespace CefSharp
100100
}
101101
}
102102

103-
_jsBindingApiEnabled = extraInfo->GetBool("JavascriptBindingApiEnabled");
104-
_jsBindingApiHasAllowOrigins = extraInfo->GetBool("JavascriptBindingApiHasAllowOrigins");
103+
wrapper->JavascriptBindingApiEnabled = extraInfo->GetBool("JavascriptBindingApiEnabled");
104+
wrapper->JavascriptBindingApiHasAllowOrigins = extraInfo->GetBool("JavascriptBindingApiHasAllowOrigins");
105105

106-
if (_jsBindingApiHasAllowOrigins)
106+
if (wrapper->JavascriptBindingApiHasAllowOrigins)
107107
{
108108
auto allowOrigins = extraInfo->GetList("JavascriptBindingApiAllowOrigins");
109109
if (allowOrigins.get() && allowOrigins->IsValid())
110110
{
111-
_jsBindingApiAllowOrigins = allowOrigins->Copy();
111+
wrapper->JavascriptBindingApiAllowOrigins = allowOrigins->Copy();
112112
}
113113
}
114114

@@ -158,90 +158,53 @@ namespace CefSharp
158158
}
159159
}
160160

161-
if (_jsBindingApiEnabled)
162-
{
163-
auto createObjects = true;
161+
auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
164162

165-
if (_jsBindingApiHasAllowOrigins)
163+
if (browserWrapper != nullptr && browserWrapper->JavascriptBindingApiEnabled && IsJavascriptBindingApiAllowed(frame))
164+
{
165+
//TODO: Look at adding some sort of javascript mapping layer to reduce the code duplication
166+
auto global = context->GetGlobal();
167+
auto processId = System::Diagnostics::Process::GetCurrentProcess()->Id;
168+
169+
//TODO: JSB: Split functions into their own classes
170+
//Browser wrapper is only used for BindObjectAsync
171+
auto bindObjAsyncFunction = CefV8Value::CreateFunction(kBindObjectAsync, new BindObjectAsyncHandler(_registerBoundObjectRegistry, _javascriptObjects, rootObject));
172+
auto unBindObjFunction = CefV8Value::CreateFunction(kDeleteBoundObject, new RegisterBoundObjectHandler(_javascriptObjects));
173+
auto removeObjectFromCacheFunction = CefV8Value::CreateFunction(kRemoveObjectFromCache, new RegisterBoundObjectHandler(_javascriptObjects));
174+
auto isObjectCachedFunction = CefV8Value::CreateFunction(kIsObjectCached, new RegisterBoundObjectHandler(_javascriptObjects));
175+
auto postMessageFunction = CefV8Value::CreateFunction(kPostMessage, new JavascriptPostMessageHandler(rootObject == nullptr ? nullptr : rootObject->CallbackRegistry));
176+
auto promiseHandlerFunction = CefV8Value::CreateFunction(kSendEvalScriptResponse, new JavascriptPromiseHandler());
177+
178+
//By default We'll support both CefSharp and cefSharp, for those who prefer the JS style
179+
auto createCefSharpObj = !_jsBindingPropertyName.empty();
180+
auto createCefSharpObjCamelCase = !_jsBindingPropertyNameCamelCase.empty();
181+
182+
if (createCefSharpObj)
166183
{
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-
auto clrframeUrlOrigin = StringUtils::ToClr(frameUrlOrigin);
177-
178-
auto size = static_cast<int>(_jsBindingApiAllowOrigins->GetSize());
179-
180-
for (int i = 0; i < size; i++)
181-
{
182-
auto origin = _jsBindingApiAllowOrigins->GetString(i);
183-
184-
auto clrOrigin = StringUtils::ToClr(origin);
185-
186-
auto originEqual = String::Compare(clrframeUrlOrigin, clrOrigin, StringComparison::InvariantCultureIgnoreCase);
187-
188-
if (originEqual == 0)
189-
{
190-
createObjects = true;
191-
192-
break;
193-
}
194-
}
195-
}
184+
auto cefSharpObj = CefV8Value::CreateObject(nullptr, nullptr);
185+
cefSharpObj->SetValue(kBindObjectAsync, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
186+
cefSharpObj->SetValue(kDeleteBoundObject, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
187+
cefSharpObj->SetValue(kRemoveObjectFromCache, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
188+
cefSharpObj->SetValue(kIsObjectCached, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
189+
cefSharpObj->SetValue(kPostMessage, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
190+
cefSharpObj->SetValue(kSendEvalScriptResponse, promiseHandlerFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
191+
cefSharpObj->SetValue(kRenderProcessId, CefV8Value::CreateInt(processId), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
192+
193+
global->SetValue(_jsBindingPropertyName, cefSharpObj, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
196194
}
197195

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

@@ -377,6 +340,41 @@ namespace CefSharp
377340
return rootObject;
378341
}
379342

343+
bool CefAppUnmanagedWrapper::IsJavascriptBindingApiAllowed(CefRefPtr<CefFrame> frame)
344+
{
345+
auto browserWrapper = FindBrowserWrapper(frame->GetBrowser()->GetIdentifier());
346+
347+
if (browserWrapper == nullptr || !browserWrapper->JavascriptBindingApiHasAllowOrigins)
348+
{
349+
return true;
350+
}
351+
352+
auto frameUrl = frame->GetURL();
353+
354+
CefURLParts frameUrlParts;
355+
356+
if (CefParseURL(frameUrl, frameUrlParts))
357+
{
358+
auto frameUrlOrigin = CefString(frameUrlParts.origin.str, frameUrlParts.origin.length);
359+
360+
auto size = static_cast<int>(browserWrapper->JavascriptBindingApiAllowOrigins->GetSize());
361+
362+
for (int i = 0; i < size; i++)
363+
{
364+
auto origin = browserWrapper->JavascriptBindingApiAllowOrigins->GetString(i);
365+
366+
if (_wcsicmp(
367+
reinterpret_cast<const wchar_t*>(frameUrlOrigin.c_str()),
368+
reinterpret_cast<const wchar_t*>(origin.c_str())) == 0)
369+
{
370+
return true;
371+
}
372+
}
373+
}
374+
375+
return false;
376+
}
377+
380378
CefBrowserWrapper^ CefAppUnmanagedWrapper::FindBrowserWrapper(int browserId)
381379
{
382380
CefBrowserWrapper^ wrapper = nullptr;

CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,6 @@ namespace CefSharp
2929
gcroot<ConcurrentDictionary<String^, JavascriptRootObjectWrapper^>^> _jsRootObjectWrappersByFrameId;
3030
bool _focusedNodeChangedEnabled;
3131
bool _legacyBindingEnabled;
32-
bool _jsBindingApiEnabled = true;
33-
bool _jsBindingApiHasAllowOrigins = false;
34-
CefRefPtr<CefListValue> _jsBindingApiAllowOrigins;
3532

3633
// The property names used to call bound objects
3734
CefString _jsBindingPropertyName;
@@ -41,6 +38,7 @@ namespace CefSharp
4138
gcroot<Dictionary<String^, JavascriptObject^>^> _javascriptObjects;
4239

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

4543
public:
4644
static const CefString kPromiseCreatorScript;
@@ -84,8 +82,6 @@ namespace CefSharp
8482

8583
delete _onBrowserCreated;
8684
delete _onBrowserDestroyed;
87-
88-
_jsBindingApiAllowOrigins = nullptr;
8985
}
9086

9187
CefBrowserWrapper^ FindBrowserWrapper(int browserId);

CefSharp.BrowserSubprocess.Core/CefBrowserWrapper.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ 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
{
@@ -35,11 +35,17 @@ namespace CefSharp
3535
_cefBrowser = cefBrowser.get();
3636
BrowserId = cefBrowser->GetIdentifier();
3737
IsPopup = cefBrowser->IsPopup();
38+
39+
JavascriptBindingApiEnabled = true;
40+
JavascriptBindingApiHasAllowOrigins = false;
41+
JavascriptBindingApiAllowOrigins = nullptr;
3842
}
3943

4044
!CefBrowserWrapper()
4145
{
4246
_cefBrowser = nullptr;
47+
48+
JavascriptBindingApiAllowOrigins = nullptr;
4349
}
4450

4551
~CefBrowserWrapper()
@@ -49,6 +55,9 @@ namespace CefSharp
4955

5056
property int BrowserId;
5157
property bool IsPopup;
58+
property bool JavascriptBindingApiEnabled;
59+
property bool JavascriptBindingApiHasAllowOrigins;
60+
property CefRefPtr<CefListValue> JavascriptBindingApiAllowOrigins;
5261

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

0 commit comments

Comments
 (0)