|
@@ -148,6 +148,7 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
|
|
v8::Local<v8::Value> value,
|
|
|
context_bridge::RenderFrameFunctionStore* store,
|
|
|
context_bridge::ObjectCache* object_cache,
|
|
|
+ bool support_dynamic_properties,
|
|
|
int recursion_depth) {
|
|
|
if (recursion_depth >= kMaxRecursion) {
|
|
|
v8::Context::Scope source_scope(source_context);
|
|
@@ -181,7 +182,8 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
|
|
{
|
|
|
v8::Local<v8::Value> proxy_func = BindRepeatingFunctionToV8(
|
|
|
destination_context->GetIsolate(),
|
|
|
- base::BindRepeating(&ProxyFunctionWrapper, store, func_id));
|
|
|
+ base::BindRepeating(&ProxyFunctionWrapper, store, func_id,
|
|
|
+ support_dynamic_properties));
|
|
|
FunctionLifeMonitor::BindTo(destination_context->GetIsolate(),
|
|
|
v8::Local<v8::Object>::Cast(proxy_func),
|
|
|
store->GetWeakPtr(), func_id);
|
|
@@ -211,7 +213,7 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
|
|
auto val =
|
|
|
PassValueToOtherContext(global_source_context.Get(isolate),
|
|
|
global_destination_context.Get(isolate),
|
|
|
- result, store, &object_cache, 0);
|
|
|
+ result, store, &object_cache, false, 0);
|
|
|
if (!val.IsEmpty())
|
|
|
proxied_promise->Resolve(val.ToLocalChecked());
|
|
|
delete proxied_promise;
|
|
@@ -232,7 +234,7 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
|
|
auto val =
|
|
|
PassValueToOtherContext(global_source_context.Get(isolate),
|
|
|
global_destination_context.Get(isolate),
|
|
|
- result, store, &object_cache, 0);
|
|
|
+ result, store, &object_cache, false, 0);
|
|
|
if (!val.IsEmpty())
|
|
|
proxied_promise->Reject(val.ToLocalChecked());
|
|
|
delete proxied_promise;
|
|
@@ -278,7 +280,7 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
|
|
auto value_for_array = PassValueToOtherContext(
|
|
|
source_context, destination_context,
|
|
|
arr->Get(source_context, i).ToLocalChecked(), store, object_cache,
|
|
|
- recursion_depth + 1);
|
|
|
+ support_dynamic_properties, recursion_depth + 1);
|
|
|
if (value_for_array.IsEmpty())
|
|
|
return v8::MaybeLocal<v8::Value>();
|
|
|
|
|
@@ -296,9 +298,9 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
|
|
// Proxy all objects
|
|
|
if (IsPlainObject(value)) {
|
|
|
auto object_value = v8::Local<v8::Object>::Cast(value);
|
|
|
- auto passed_value =
|
|
|
- CreateProxyForAPI(object_value, source_context, destination_context,
|
|
|
- store, object_cache, recursion_depth + 1);
|
|
|
+ auto passed_value = CreateProxyForAPI(
|
|
|
+ object_value, source_context, destination_context, store, object_cache,
|
|
|
+ support_dynamic_properties, recursion_depth + 1);
|
|
|
if (passed_value.IsEmpty())
|
|
|
return v8::MaybeLocal<v8::Value>();
|
|
|
return v8::MaybeLocal<v8::Value>(passed_value.ToLocalChecked());
|
|
@@ -327,6 +329,7 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
|
|
v8::Local<v8::Value> ProxyFunctionWrapper(
|
|
|
context_bridge::RenderFrameFunctionStore* store,
|
|
|
size_t func_id,
|
|
|
+ bool support_dynamic_properties,
|
|
|
mate::Arguments* args) {
|
|
|
// Context the proxy function was called from
|
|
|
v8::Local<v8::Context> calling_context = args->isolate()->GetCurrentContext();
|
|
@@ -346,7 +349,8 @@ v8::Local<v8::Value> ProxyFunctionWrapper(
|
|
|
|
|
|
for (auto value : original_args) {
|
|
|
auto arg = PassValueToOtherContext(calling_context, func_owning_context,
|
|
|
- value, store, &object_cache, 0);
|
|
|
+ value, store, &object_cache,
|
|
|
+ support_dynamic_properties, 0);
|
|
|
if (arg.IsEmpty())
|
|
|
return v8::Undefined(args->isolate());
|
|
|
proxied_args.push_back(arg.ToLocalChecked());
|
|
@@ -384,9 +388,10 @@ v8::Local<v8::Value> ProxyFunctionWrapper(
|
|
|
if (maybe_return_value.IsEmpty())
|
|
|
return v8::Undefined(args->isolate());
|
|
|
|
|
|
- auto ret = PassValueToOtherContext(func_owning_context, calling_context,
|
|
|
- maybe_return_value.ToLocalChecked(),
|
|
|
- store, &object_cache, 0);
|
|
|
+ auto ret =
|
|
|
+ PassValueToOtherContext(func_owning_context, calling_context,
|
|
|
+ maybe_return_value.ToLocalChecked(), store,
|
|
|
+ &object_cache, support_dynamic_properties, 0);
|
|
|
if (ret.IsEmpty())
|
|
|
return v8::Undefined(args->isolate());
|
|
|
return ret.ToLocalChecked();
|
|
@@ -399,6 +404,7 @@ v8::MaybeLocal<v8::Object> CreateProxyForAPI(
|
|
|
const v8::Local<v8::Context>& destination_context,
|
|
|
context_bridge::RenderFrameFunctionStore* store,
|
|
|
context_bridge::ObjectCache* object_cache,
|
|
|
+ bool support_dynamic_properties,
|
|
|
int recursion_depth) {
|
|
|
mate::Dictionary api(source_context->GetIsolate(), api_object);
|
|
|
v8::Context::Scope destination_context_scope(destination_context);
|
|
@@ -423,13 +429,54 @@ v8::MaybeLocal<v8::Object> CreateProxyForAPI(
|
|
|
if (!mate::ConvertFromV8(api.isolate(), key, &key_str)) {
|
|
|
continue;
|
|
|
}
|
|
|
+ if (support_dynamic_properties) {
|
|
|
+ v8::Context::Scope source_context_scope(source_context);
|
|
|
+ auto maybe_desc = api.GetHandle()->GetOwnPropertyDescriptor(
|
|
|
+ source_context, v8::Local<v8::Name>::Cast(key));
|
|
|
+ v8::Local<v8::Value> desc_value;
|
|
|
+ if (!maybe_desc.ToLocal(&desc_value) || !desc_value->IsObject())
|
|
|
+ continue;
|
|
|
+ mate::Dictionary desc(api.isolate(), desc_value.As<v8::Object>());
|
|
|
+ if (desc.Has("get") || desc.Has("set")) {
|
|
|
+ v8::Local<v8::Value> getter;
|
|
|
+ v8::Local<v8::Value> setter;
|
|
|
+ desc.Get("get", &getter);
|
|
|
+ desc.Get("set", &setter);
|
|
|
+
|
|
|
+ {
|
|
|
+ v8::Context::Scope destination_context_scope(destination_context);
|
|
|
+ v8::Local<v8::Value> getter_proxy;
|
|
|
+ v8::Local<v8::Value> setter_proxy;
|
|
|
+ if (!getter.IsEmpty()) {
|
|
|
+ if (!PassValueToOtherContext(source_context, destination_context,
|
|
|
+ getter, store, object_cache, false,
|
|
|
+ 1)
|
|
|
+ .ToLocal(&getter_proxy))
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (!setter.IsEmpty()) {
|
|
|
+ if (!PassValueToOtherContext(source_context, destination_context,
|
|
|
+ setter, store, object_cache, false,
|
|
|
+ 1)
|
|
|
+ .ToLocal(&setter_proxy))
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ v8::PropertyDescriptor desc(getter_proxy, setter_proxy);
|
|
|
+ ignore_result(proxy.GetHandle()->DefineProperty(
|
|
|
+ destination_context, gin::StringToV8(api.isolate(), key_str),
|
|
|
+ desc));
|
|
|
+ }
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
v8::Local<v8::Value> value;
|
|
|
if (!api.Get(key_str, &value))
|
|
|
continue;
|
|
|
|
|
|
- auto passed_value =
|
|
|
- PassValueToOtherContext(source_context, destination_context, value,
|
|
|
- store, object_cache, recursion_depth + 1);
|
|
|
+ auto passed_value = PassValueToOtherContext(
|
|
|
+ source_context, destination_context, value, store, object_cache,
|
|
|
+ support_dynamic_properties, recursion_depth + 1);
|
|
|
if (passed_value.IsEmpty())
|
|
|
return v8::MaybeLocal<v8::Object>();
|
|
|
proxy.Set(key_str, passed_value.ToLocalChecked());
|
|
@@ -474,8 +521,9 @@ void ExposeAPIInMainWorld(const std::string& key,
|
|
|
context_bridge::ObjectCache object_cache;
|
|
|
v8::Context::Scope main_context_scope(main_context);
|
|
|
{
|
|
|
- v8::MaybeLocal<v8::Object> maybe_proxy = CreateProxyForAPI(
|
|
|
- api_object, isolated_context, main_context, store, &object_cache, 0);
|
|
|
+ v8::MaybeLocal<v8::Object> maybe_proxy =
|
|
|
+ CreateProxyForAPI(api_object, isolated_context, main_context, store,
|
|
|
+ &object_cache, false, 0);
|
|
|
if (maybe_proxy.IsEmpty())
|
|
|
return;
|
|
|
auto proxy = maybe_proxy.ToLocalChecked();
|
|
@@ -486,6 +534,115 @@ void ExposeAPIInMainWorld(const std::string& key,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+mate::Dictionary TraceKeyPath(const mate::Dictionary& start,
|
|
|
+ const std::vector<std::string>& key_path) {
|
|
|
+ mate::Dictionary current = start;
|
|
|
+ for (size_t i = 0; i < key_path.size() - 1; i++) {
|
|
|
+ CHECK(current.Get(key_path[i], ¤t));
|
|
|
+ }
|
|
|
+ return current;
|
|
|
+}
|
|
|
+
|
|
|
+void OverrideGlobalValueFromIsolatedWorld(
|
|
|
+ const std::vector<std::string>& key_path,
|
|
|
+ v8::Local<v8::Object> value,
|
|
|
+ bool support_dynamic_properties) {
|
|
|
+ if (key_path.size() == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ auto* render_frame = GetRenderFrame(value);
|
|
|
+ CHECK(render_frame);
|
|
|
+ context_bridge::RenderFrameFunctionStore* store =
|
|
|
+ GetOrCreateStore(render_frame);
|
|
|
+ auto* frame = render_frame->GetWebFrame();
|
|
|
+ CHECK(frame);
|
|
|
+ v8::Local<v8::Context> main_context = frame->MainWorldScriptContext();
|
|
|
+ mate::Dictionary global(main_context->GetIsolate(), main_context->Global());
|
|
|
+
|
|
|
+ const std::string final_key = key_path[key_path.size() - 1];
|
|
|
+ mate::Dictionary target_object = TraceKeyPath(global, key_path);
|
|
|
+
|
|
|
+ {
|
|
|
+ v8::Context::Scope main_context_scope(main_context);
|
|
|
+ context_bridge::ObjectCache object_cache;
|
|
|
+ v8::MaybeLocal<v8::Value> maybe_proxy = PassValueToOtherContext(
|
|
|
+ value->CreationContext(), main_context, value, store, &object_cache,
|
|
|
+ support_dynamic_properties, 1);
|
|
|
+ DCHECK(!maybe_proxy.IsEmpty());
|
|
|
+ auto proxy = maybe_proxy.ToLocalChecked();
|
|
|
+
|
|
|
+ target_object.Set(final_key, proxy);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+bool OverrideGlobalPropertyFromIsolatedWorld(
|
|
|
+ const std::vector<std::string>& key_path,
|
|
|
+ v8::Local<v8::Object> getter,
|
|
|
+ v8::Local<v8::Value> setter,
|
|
|
+ mate::Arguments* args) {
|
|
|
+ if (key_path.size() == 0)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ auto* render_frame = GetRenderFrame(getter);
|
|
|
+ CHECK(render_frame);
|
|
|
+ context_bridge::RenderFrameFunctionStore* store =
|
|
|
+ GetOrCreateStore(render_frame);
|
|
|
+ auto* frame = render_frame->GetWebFrame();
|
|
|
+ CHECK(frame);
|
|
|
+ v8::Local<v8::Context> main_context = frame->MainWorldScriptContext();
|
|
|
+ mate::Dictionary global(main_context->GetIsolate(), main_context->Global());
|
|
|
+
|
|
|
+ const std::string final_key = key_path[key_path.size() - 1];
|
|
|
+ v8::Local<v8::Object> target_object =
|
|
|
+ TraceKeyPath(global, key_path).GetHandle();
|
|
|
+
|
|
|
+ {
|
|
|
+ v8::Context::Scope main_context_scope(main_context);
|
|
|
+ context_bridge::ObjectCache object_cache;
|
|
|
+ v8::Local<v8::Value> getter_proxy;
|
|
|
+ v8::Local<v8::Value> setter_proxy;
|
|
|
+ if (!getter->IsNullOrUndefined()) {
|
|
|
+ v8::MaybeLocal<v8::Value> maybe_getter_proxy =
|
|
|
+ PassValueToOtherContext(getter->CreationContext(), main_context,
|
|
|
+ getter, store, &object_cache, false, 1);
|
|
|
+ DCHECK(!maybe_getter_proxy.IsEmpty());
|
|
|
+ getter_proxy = maybe_getter_proxy.ToLocalChecked();
|
|
|
+ }
|
|
|
+ if (!setter->IsNullOrUndefined() && setter->IsObject()) {
|
|
|
+ v8::MaybeLocal<v8::Value> maybe_setter_proxy =
|
|
|
+ PassValueToOtherContext(getter->CreationContext(), main_context,
|
|
|
+ setter, store, &object_cache, false, 1);
|
|
|
+ DCHECK(!maybe_setter_proxy.IsEmpty());
|
|
|
+ setter_proxy = maybe_setter_proxy.ToLocalChecked();
|
|
|
+ }
|
|
|
+
|
|
|
+ v8::PropertyDescriptor desc(getter_proxy, setter_proxy);
|
|
|
+ bool success = mate::internal::IsTrue(target_object->DefineProperty(
|
|
|
+ main_context, gin::StringToV8(args->isolate(), final_key), desc));
|
|
|
+ DCHECK(success);
|
|
|
+ return success;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+bool IsCalledFromMainWorld(v8::Isolate* isolate) {
|
|
|
+ auto* render_frame = GetRenderFrame(isolate->GetCurrentContext()->Global());
|
|
|
+ CHECK(render_frame);
|
|
|
+ auto* frame = render_frame->GetWebFrame();
|
|
|
+ CHECK(frame);
|
|
|
+ v8::Local<v8::Context> main_context = frame->MainWorldScriptContext();
|
|
|
+ return isolate->GetCurrentContext() == main_context;
|
|
|
+}
|
|
|
+
|
|
|
+bool IsCalledFromIsolatedWorld(v8::Isolate* isolate) {
|
|
|
+ auto* render_frame = GetRenderFrame(isolate->GetCurrentContext()->Global());
|
|
|
+ CHECK(render_frame);
|
|
|
+ auto* frame = render_frame->GetWebFrame();
|
|
|
+ CHECK(frame);
|
|
|
+ v8::Local<v8::Context> isolated_context =
|
|
|
+ frame->WorldScriptContext(isolate, World::ISOLATED_WORLD);
|
|
|
+ return isolate->GetCurrentContext() == isolated_context;
|
|
|
+}
|
|
|
+
|
|
|
} // namespace api
|
|
|
|
|
|
} // namespace electron
|
|
@@ -499,6 +656,14 @@ void Initialize(v8::Local<v8::Object> exports,
|
|
|
v8::Isolate* isolate = context->GetIsolate();
|
|
|
mate::Dictionary dict(isolate, exports);
|
|
|
dict.SetMethod("exposeAPIInMainWorld", &electron::api::ExposeAPIInMainWorld);
|
|
|
+ dict.SetMethod("_overrideGlobalValueFromIsolatedWorld",
|
|
|
+ &electron::api::OverrideGlobalValueFromIsolatedWorld);
|
|
|
+ dict.SetMethod("_overrideGlobalPropertyFromIsolatedWorld",
|
|
|
+ &electron::api::OverrideGlobalPropertyFromIsolatedWorld);
|
|
|
+ dict.SetMethod("_isCalledFromMainWorld",
|
|
|
+ &electron::api::IsCalledFromMainWorld);
|
|
|
+ dict.SetMethod("_isCalledFromIsolatedWorld",
|
|
|
+ &electron::api::IsCalledFromIsolatedWorld);
|
|
|
#ifdef DCHECK_IS_ON
|
|
|
dict.SetMethod("_debugGCMaps", &electron::api::DebugGC);
|
|
|
#endif
|