* chore: bump chromium in DEPS to 97.0.4678.0 * chore: bump chromium in DEPS to 97.0.4679.0 * chore: bump chromium in DEPS to 97.0.4680.0 * chore: bump chromium in DEPS to 97.0.4681.0 * chore: bump chromium in DEPS to 97.0.4682.0 * chore: update patches * 3234737: Disable -Wunused-but-set-variable Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3234737 * 3216953: Reland "Move task-related files from base/ to base/task/" Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3216953 * 3202710: TimeDelta factory function migration. Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3202710 * 3226841: Rename WCO::RenderProcessGone to PrimaryMainFrameRenderProcessGone Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3226841 * 3212165: blink/gin: changes blink to load snapshot based on runtime information Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3212165 * 3220292: Deprecate returning a GURL from GURL::GetOrigin() Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3220292 * 3231995: build: Enable -Wbitwise-instead-of-logical everywhere except iOS and Windows Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3231995 * 3205121: Remove base::DictionaryValue::GetDouble Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3205121 * 3208413: [flags] Make --js-flags settings have priority over V8 features Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3208413 * chore: bump chromium in DEPS to 97.0.4683.0 * chore: update patches * 3188834: Combine RWHVBase GetCurrentDeviceScaleFactor/GetDeviceScaleFactor Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3188834 * chore: update process_singleton patches * chore: bump chromium in DEPS to 97.0.4684.0 * chore: update patches * chore: bump chromium in DEPS to 97.0.4685.0 * chore: update patches * chore: bump chromium in DEPS to 97.0.4686.0 * chore: update patches * chore: bump chromium in DEPS to 97.0.4687.0 * chore: update patches * chore: bump chromium in DEPS to 97.0.4688.0 * chore: update patches * 3247722: Use correct source_site_instance if navigating via context menu Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3247722 Update signature of HandleContextMenu() * 3247722: Use correct source_site_instance if navigating via context menu Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3247722 Update signature of HandleContextMenu() * 3223422: Remove PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE enum option Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3223422 sync pepper_plugin_support.patch with upstream * chore: bump chromium in DEPS to 97.0.4689.0 * 3247791: ax_mac_merge: Merge AX Math attribute implementations Xref: ax_mac_merge: Merge AX Math attribute implementations chore: fix minor patch shear in #includes * 3243425: Add VisibleTimeRequestTrigger helper class Xref: https://chromium-review.googlesource.com/c/chromium/src/+/3243425 chore: fix minor patch shear in #includes * chore: regen chromium patches * fixup! 3247722: Use correct source_site_instance if navigating via context menu * chore: bump chromium in DEPS to 97.0.4690.0 * 3188659: Window Placement: make GetScreenInfo(s) const Xref: https://chromium-review.googlesource.com/c/chromium/src/+/3188659 simple sync GetScreenInfo with upstream refactor * chore: update patches * chore: bump chromium in DEPS to 97.0.4690.4 * chore: bump chromium in DEPS to 97.0.4692.0 * 3198073: ozone: //content: clean up from USE_X11 Xref: https://chromium-review.googlesource.com/c/chromium/src/+/3198073 Fixing patch shear. Nothing to see here. * 3252338: Remove label images checkbox from chrome://accessibility page Xref: https://chromium-review.googlesource.com/c/chromium/src/+/3252338 Part of our a11y patch is no longer needed due to upstream label removal * 3258183: Remove DISALLOW_IMPLICIT_CONSTRUCTORS() definition Xref: https://chromium-review.googlesource.com/c/chromium/src/+/3258183 Replace our use of the macro with explicitly-deleted class methods. See https://chromium-review.googlesource.com/c/chromium/src/+/3256952 for upstream examples of this same replacement. * chore: update patches * 3247295: Unwind SecurityStyleExplanations Xref: https://chromium-review.googlesource.com/c/chromium/src/+/3247295 update GetSecurityStyle() signature and impl to match upstream changes * 3259578: media: grabs lock to ensure video output when occluded Xref: https://chromium-review.googlesource.com/c/chromium/src/+/3259578 Add stub for new upstream virtual method OnCapturerCountChanged() * fixup! 3247295: Unwind SecurityStyleExplanations * 3238504: Fix up drag image is not shown from bookmark bar Xref: https://chromium-review.googlesource.com/c/chromium/src/+/3238504 SetDragImage() no longer takes a widget argument * 3217452: [devtools] Add getSyncInformation host binding Xref: https://chromium-review.googlesource.com/c/chromium/src/+/3217452 Add stub for new upstream method GetSyncInformation(). Stub sends info back to caller saying that syncing is disabled. * chore: bump chromium in DEPS to 98.0.4693.0 * chore: bump chromium in DEPS to 98.0.4694.0 * chore: bump chromium in DEPS to 98.0.4695.0 * chore: bump chromium in DEPS to 98.0.4696.0 * chore: bump chromium in DEPS to 98.0.4697.0 * chore: bump chromium in DEPS to 98.0.4699.0 * chore: bump chromium in DEPS to 98.0.4701.0 * chore: bump chromium in DEPS to 98.0.4703.0 * chore: bump chromium in DEPS to 98.0.4705.0 * chore: bump chromium in DEPS to 98.0.4706.0 * chore: update patches * 3279210: Rename "base/macros.h" => "base/ignore_result.h" https://chromium-review.googlesource.com/c/chromium/src/+/3279210 * 3259964: Remove all DISALLOW_COPY_AND_ASSIGNs https://chromium-review.googlesource.com/c/chromium/src/+/3259964 * 3269029: blink/gin: sets histogram callbacks during isolate creation https://chromium-review.googlesource.com/c/chromium/src/+/3269029 * fixup after rebase * [content] Make ContentMainParams and MainFunctionParams move-only https://chromium-review.googlesource.com/c/chromium/src/+/3244976 * 3255305: Stop sending the securityStateChanged event and unwind https://chromium-review.googlesource.com/c/chromium/src/+/3255305 * [Blink] Add promise support to WebLocalFrame::RequestExecuteScript() https://chromium-review.googlesource.com/c/chromium/src/+/3230010 * 3256162: Simplify RWHV Show and ShowWithVisibility handling https://chromium-review.googlesource.com/c/chromium/src/+/3256162 * 3263824: ozone: //ui/base: clean up from USE_X11 1/* https://chromium-review.googlesource.com/c/chromium/src/+/3263824 * Request or cancel RecordContentToPresentationTimeRequest during capture https://chromium-review.googlesource.com/c/chromium/src/+/3256802 * appcache: remove BrowsingData/quota references https://chromium-review.googlesource.com/c/chromium/src/+/3255725 * [Autofill] Don't show Autofill dropdown if overlaps with permissions https://chromium-review.googlesource.com/c/chromium/src/+/3236729 * Rename to_different_document to should_show_loading_ui in LoadingStateChanged() callbacks https://chromium-review.googlesource.com/c/chromium/src/+/3268574 * cleanup patch * fixup [content] Make ContentMainParams and MainFunctionParams move-only * 3279210: Rename "base/macros.h" => "base/ignore_result.h" https://chromium-review.googlesource.com/c/chromium/src/+/3279210 * ozone: //chrome/browser clean up from USE_X11 https://chromium-review.googlesource.com/c/chromium/src/+/3186490 Refs: https://github.com/electron/electron/issues/31382 * chore: update support_mixed_sandbox_with_zygote.patch * Enable -Wunused-but-set-variable. Refs https://chromium-review.googlesource.com/c/chromium/src/+/3234737 * fixup! ozone: //ui/base: clean up from USE_X11 1/* * fixup! ozone: //chrome/browser clean up from USE_X11 * chore: fix deprecation warning in libuv * chore: fixup for lint * 3251161: Reland "Make the Clang update.py script require Python 3" https://chromium-review.googlesource.com/c/chromium/src/+/3251161 * fixup: Enable -Wunused-but-set-variable. * [base][win] Rename DIR_APP_DATA to DIR_ROAMING_APP_DATA https://chromium-review.googlesource.com/c/chromium/src/+/3262369 * Replace sandbox::policy::SandboxType with mojom Sandbox enum https://chromium-review.googlesource.com/c/chromium/src/+/3213677 * fixup: [content] Make ContentMainParams and MainFunctionParams move-only * build: ensure angle has a full git checkout available to it * fixup: [base][win] Rename DIR_APP_DATA to DIR_ROAMING_APP_DATA * fixup lint * [unseasoned-pdf] Dispatch 'afterprint' event in PDF plugin frame https://chromium-review.googlesource.com/c/chromium/src/+/3223434 * fixup: [Autofill] Don't show Autofill dropdown if overlaps with permissions * 3217591: Move browser UI CSS color parsing to own file part 2/2 https://chromium-review.googlesource.com/c/chromium/src/+/3217591 * Make kNoSandboxAndElevatedPrivileges only available to utilities https://chromium-review.googlesource.com/c/chromium/src/+/3276784 * 3211575: [modules] Change ScriptOrModule to custom Struct https://chromium-review.googlesource.com/c/v8/v8/+/3211575 * Address review feedback * chore: update patches * 3211575: [modules] Change ScriptOrModule to custom Struct https://chromium-review.googlesource.com/c/v8/v8/+/3211575 * fix: unused variable compat * chore: remove redundant patch * fixup for 3262517: Re-enable WindowCaptureMacV2 https://chromium-review.googlesource.com/c/chromium/src/+/3262517 * chore: cleanup todo The functions added in https://chromium-review.googlesource.com/c/chromium/src/+/3256802 are not used by offscreen rendering. * fixup: update mas_no_private_api.patch * 3216879: [PA] Make features::kPartitionAllocLazyCommit to be PartitionOptions::LazyCommit Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3216879 Fixes up commit b2f1aca95604ec61649808c846657454097e6935 * chore: cleanup support_mixed_sandbox_with_zygote.patch * test: use window focus event instead of delay to wait for webContents focus Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com> Co-authored-by: VerteDinde <khammond@slack-corp.com> Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com> Co-authored-by: Charles Kerr <charles@charleskerr.com> Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org> Co-authored-by: deepak1556 <hop2deep@gmail.com> Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com> Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
		
			
				
	
	
		
			733 lines
		
	
	
	
		
			28 KiB
			
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			733 lines
		
	
	
	
		
			28 KiB
			
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright (c) 2019 Slack Technologies, Inc.
 | 
						|
// Use of this source code is governed by the MIT license that can be
 | 
						|
// found in the LICENSE file.
 | 
						|
 | 
						|
#include "shell/renderer/api/electron_api_context_bridge.h"
 | 
						|
 | 
						|
#include <memory>
 | 
						|
#include <set>
 | 
						|
#include <string>
 | 
						|
#include <utility>
 | 
						|
#include <vector>
 | 
						|
 | 
						|
#include "base/feature_list.h"
 | 
						|
#include "base/ignore_result.h"
 | 
						|
#include "base/no_destructor.h"
 | 
						|
#include "base/strings/string_number_conversions.h"
 | 
						|
#include "base/trace_event/trace_event.h"
 | 
						|
#include "content/public/renderer/render_frame.h"
 | 
						|
#include "content/public/renderer/render_frame_observer.h"
 | 
						|
#include "shell/common/api/object_life_monitor.h"
 | 
						|
#include "shell/common/gin_converters/blink_converter.h"
 | 
						|
#include "shell/common/gin_converters/callback_converter.h"
 | 
						|
#include "shell/common/gin_helper/dictionary.h"
 | 
						|
#include "shell/common/gin_helper/promise.h"
 | 
						|
#include "shell/common/node_includes.h"
 | 
						|
#include "shell/common/world_ids.h"
 | 
						|
#include "third_party/blink/public/web/web_blob.h"
 | 
						|
#include "third_party/blink/public/web/web_element.h"
 | 
						|
#include "third_party/blink/public/web/web_local_frame.h"
 | 
						|
 | 
						|
namespace features {
 | 
						|
 | 
						|
const base::Feature kContextBridgeMutability{"ContextBridgeMutability",
 | 
						|
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 | 
						|
}
 | 
						|
 | 
						|
namespace electron {
 | 
						|
 | 
						|
content::RenderFrame* GetRenderFrame(v8::Local<v8::Object> value);
 | 
						|
 | 
						|
namespace api {
 | 
						|
 | 
						|
namespace context_bridge {
 | 
						|
 | 
						|
const char kProxyFunctionPrivateKey[] = "electron_contextBridge_proxy_fn";
 | 
						|
const char kSupportsDynamicPropertiesPrivateKey[] =
 | 
						|
    "electron_contextBridge_supportsDynamicProperties";
 | 
						|
const char kOriginalFunctionPrivateKey[] = "electron_contextBridge_original_fn";
 | 
						|
 | 
						|
}  // namespace context_bridge
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
static int kMaxRecursion = 1000;
 | 
						|
 | 
						|
// Returns true if |maybe| is both a value, and that value is true.
 | 
						|
inline bool IsTrue(v8::Maybe<bool> maybe) {
 | 
						|
  return maybe.IsJust() && maybe.FromJust();
 | 
						|
}
 | 
						|
 | 
						|
// Sourced from "extensions/renderer/v8_schema_registry.cc"
 | 
						|
// Recursively freezes every v8 object on |object|.
 | 
						|
bool DeepFreeze(const v8::Local<v8::Object>& object,
 | 
						|
                const v8::Local<v8::Context>& context,
 | 
						|
                std::set<int> frozen = std::set<int>()) {
 | 
						|
  int hash = object->GetIdentityHash();
 | 
						|
  if (frozen.find(hash) != frozen.end())
 | 
						|
    return true;
 | 
						|
  frozen.insert(hash);
 | 
						|
 | 
						|
  v8::Local<v8::Array> property_names =
 | 
						|
      object->GetOwnPropertyNames(context).ToLocalChecked();
 | 
						|
  for (uint32_t i = 0; i < property_names->Length(); ++i) {
 | 
						|
    v8::Local<v8::Value> child =
 | 
						|
        object->Get(context, property_names->Get(context, i).ToLocalChecked())
 | 
						|
            .ToLocalChecked();
 | 
						|
    if (child->IsObject() && !child->IsTypedArray()) {
 | 
						|
      if (!DeepFreeze(child.As<v8::Object>(), context, frozen))
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return IsTrue(
 | 
						|
      object->SetIntegrityLevel(context, v8::IntegrityLevel::kFrozen));
 | 
						|
}
 | 
						|
 | 
						|
bool IsPlainObject(const v8::Local<v8::Value>& object) {
 | 
						|
  if (!object->IsObject())
 | 
						|
    return false;
 | 
						|
 | 
						|
  return !(object->IsNullOrUndefined() || object->IsDate() ||
 | 
						|
           object->IsArgumentsObject() || object->IsBigIntObject() ||
 | 
						|
           object->IsBooleanObject() || object->IsNumberObject() ||
 | 
						|
           object->IsStringObject() || object->IsSymbolObject() ||
 | 
						|
           object->IsNativeError() || object->IsRegExp() ||
 | 
						|
           object->IsPromise() || object->IsMap() || object->IsSet() ||
 | 
						|
           object->IsMapIterator() || object->IsSetIterator() ||
 | 
						|
           object->IsWeakMap() || object->IsWeakSet() ||
 | 
						|
           object->IsArrayBuffer() || object->IsArrayBufferView() ||
 | 
						|
           object->IsArray() || object->IsDataView() ||
 | 
						|
           object->IsSharedArrayBuffer() || object->IsProxy() ||
 | 
						|
           object->IsWasmModuleObject() || object->IsWasmMemoryObject() ||
 | 
						|
           object->IsModuleNamespaceObject());
 | 
						|
}
 | 
						|
 | 
						|
bool IsPlainArray(const v8::Local<v8::Value>& arr) {
 | 
						|
  if (!arr->IsArray())
 | 
						|
    return false;
 | 
						|
 | 
						|
  return !arr->IsTypedArray();
 | 
						|
}
 | 
						|
 | 
						|
void SetPrivate(v8::Local<v8::Context> context,
 | 
						|
                v8::Local<v8::Object> target,
 | 
						|
                const std::string& key,
 | 
						|
                v8::Local<v8::Value> value) {
 | 
						|
  target
 | 
						|
      ->SetPrivate(
 | 
						|
          context,
 | 
						|
          v8::Private::ForApi(context->GetIsolate(),
 | 
						|
                              gin::StringToV8(context->GetIsolate(), key)),
 | 
						|
          value)
 | 
						|
      .Check();
 | 
						|
}
 | 
						|
 | 
						|
v8::MaybeLocal<v8::Value> GetPrivate(v8::Local<v8::Context> context,
 | 
						|
                                     v8::Local<v8::Object> target,
 | 
						|
                                     const std::string& key) {
 | 
						|
  return target->GetPrivate(
 | 
						|
      context,
 | 
						|
      v8::Private::ForApi(context->GetIsolate(),
 | 
						|
                          gin::StringToV8(context->GetIsolate(), key)));
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace
 | 
						|
 | 
						|
v8::MaybeLocal<v8::Value> PassValueToOtherContext(
 | 
						|
    v8::Local<v8::Context> source_context,
 | 
						|
    v8::Local<v8::Context> destination_context,
 | 
						|
    v8::Local<v8::Value> value,
 | 
						|
    context_bridge::ObjectCache* object_cache,
 | 
						|
    bool support_dynamic_properties,
 | 
						|
    int recursion_depth,
 | 
						|
    BridgeErrorTarget error_target) {
 | 
						|
  TRACE_EVENT0("electron", "ContextBridge::PassValueToOtherContext");
 | 
						|
  if (recursion_depth >= kMaxRecursion) {
 | 
						|
    v8::Context::Scope error_scope(error_target == BridgeErrorTarget::kSource
 | 
						|
                                       ? source_context
 | 
						|
                                       : destination_context);
 | 
						|
    source_context->GetIsolate()->ThrowException(v8::Exception::TypeError(
 | 
						|
        gin::StringToV8(source_context->GetIsolate(),
 | 
						|
                        "Electron contextBridge recursion depth exceeded.  "
 | 
						|
                        "Nested objects "
 | 
						|
                        "deeper than 1000 are not supported.")));
 | 
						|
    return v8::MaybeLocal<v8::Value>();
 | 
						|
  }
 | 
						|
 | 
						|
  // Certain primitives always use the current contexts prototype and we can
 | 
						|
  // pass these through directly which is significantly more performant than
 | 
						|
  // copying them. This list of primitives is based on the classification of
 | 
						|
  // "primitive value" as defined in the ECMA262 spec
 | 
						|
  // https://tc39.es/ecma262/#sec-primitive-value
 | 
						|
  if (value->IsString() || value->IsNumber() || value->IsNullOrUndefined() ||
 | 
						|
      value->IsBoolean() || value->IsSymbol() || value->IsBigInt()) {
 | 
						|
    return v8::MaybeLocal<v8::Value>(value);
 | 
						|
  }
 | 
						|
 | 
						|
  // Check Cache
 | 
						|
  auto cached_value = object_cache->GetCachedProxiedObject(value);
 | 
						|
  if (!cached_value.IsEmpty()) {
 | 
						|
    return cached_value;
 | 
						|
  }
 | 
						|
 | 
						|
  // Proxy functions and monitor the lifetime in the new context to release
 | 
						|
  // the global handle at the right time.
 | 
						|
  if (value->IsFunction()) {
 | 
						|
    auto func = value.As<v8::Function>();
 | 
						|
    v8::MaybeLocal<v8::Value> maybe_original_fn = GetPrivate(
 | 
						|
        source_context, func, context_bridge::kOriginalFunctionPrivateKey);
 | 
						|
 | 
						|
    {
 | 
						|
      v8::Context::Scope destination_scope(destination_context);
 | 
						|
      v8::Local<v8::Value> proxy_func;
 | 
						|
 | 
						|
      // If this function has already been sent over the bridge,
 | 
						|
      // then it is being sent _back_ over the bridge and we can
 | 
						|
      // simply return the original method here for performance reasons
 | 
						|
 | 
						|
      // For safety reasons we check if the destination context is the
 | 
						|
      // creation context of the original method.  If it's not we proceed
 | 
						|
      // with the proxy logic
 | 
						|
      if (maybe_original_fn.ToLocal(&proxy_func) && proxy_func->IsFunction() &&
 | 
						|
          proxy_func.As<v8::Object>()->CreationContext() ==
 | 
						|
              destination_context) {
 | 
						|
        return v8::MaybeLocal<v8::Value>(proxy_func);
 | 
						|
      }
 | 
						|
 | 
						|
      v8::Local<v8::Object> state =
 | 
						|
          v8::Object::New(destination_context->GetIsolate());
 | 
						|
      SetPrivate(destination_context, state,
 | 
						|
                 context_bridge::kProxyFunctionPrivateKey, func);
 | 
						|
      SetPrivate(destination_context, state,
 | 
						|
                 context_bridge::kSupportsDynamicPropertiesPrivateKey,
 | 
						|
                 gin::ConvertToV8(destination_context->GetIsolate(),
 | 
						|
                                  support_dynamic_properties));
 | 
						|
 | 
						|
      if (!v8::Function::New(destination_context, ProxyFunctionWrapper, state)
 | 
						|
               .ToLocal(&proxy_func))
 | 
						|
        return v8::MaybeLocal<v8::Value>();
 | 
						|
      SetPrivate(destination_context, proxy_func.As<v8::Object>(),
 | 
						|
                 context_bridge::kOriginalFunctionPrivateKey, func);
 | 
						|
      object_cache->CacheProxiedObject(value, proxy_func);
 | 
						|
      return v8::MaybeLocal<v8::Value>(proxy_func);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Proxy promises as they have a safe and guaranteed memory lifecycle
 | 
						|
  if (value->IsPromise()) {
 | 
						|
    v8::Context::Scope destination_scope(destination_context);
 | 
						|
    auto source_promise = value.As<v8::Promise>();
 | 
						|
    // Make the promise a shared_ptr so that when the original promise is
 | 
						|
    // freed the proxy promise is correctly freed as well instead of being
 | 
						|
    // left dangling
 | 
						|
    auto proxied_promise =
 | 
						|
        std::make_shared<gin_helper::Promise<v8::Local<v8::Value>>>(
 | 
						|
            destination_context->GetIsolate());
 | 
						|
    v8::Local<v8::Promise> proxied_promise_handle =
 | 
						|
        proxied_promise->GetHandle();
 | 
						|
 | 
						|
    v8::Global<v8::Context> global_then_source_context(
 | 
						|
        source_context->GetIsolate(), source_context);
 | 
						|
    v8::Global<v8::Context> global_then_destination_context(
 | 
						|
        destination_context->GetIsolate(), destination_context);
 | 
						|
    global_then_source_context.SetWeak();
 | 
						|
    global_then_destination_context.SetWeak();
 | 
						|
    auto then_cb = base::BindOnce(
 | 
						|
        [](std::shared_ptr<gin_helper::Promise<v8::Local<v8::Value>>>
 | 
						|
               proxied_promise,
 | 
						|
           v8::Isolate* isolate, v8::Global<v8::Context> global_source_context,
 | 
						|
           v8::Global<v8::Context> global_destination_context,
 | 
						|
           v8::Local<v8::Value> result) {
 | 
						|
          if (global_source_context.IsEmpty() ||
 | 
						|
              global_destination_context.IsEmpty())
 | 
						|
            return;
 | 
						|
          context_bridge::ObjectCache object_cache;
 | 
						|
          auto val =
 | 
						|
              PassValueToOtherContext(global_source_context.Get(isolate),
 | 
						|
                                      global_destination_context.Get(isolate),
 | 
						|
                                      result, &object_cache, false, 0);
 | 
						|
          if (!val.IsEmpty())
 | 
						|
            proxied_promise->Resolve(val.ToLocalChecked());
 | 
						|
        },
 | 
						|
        proxied_promise, destination_context->GetIsolate(),
 | 
						|
        std::move(global_then_source_context),
 | 
						|
        std::move(global_then_destination_context));
 | 
						|
 | 
						|
    v8::Global<v8::Context> global_catch_source_context(
 | 
						|
        source_context->GetIsolate(), source_context);
 | 
						|
    v8::Global<v8::Context> global_catch_destination_context(
 | 
						|
        destination_context->GetIsolate(), destination_context);
 | 
						|
    global_catch_source_context.SetWeak();
 | 
						|
    global_catch_destination_context.SetWeak();
 | 
						|
    auto catch_cb = base::BindOnce(
 | 
						|
        [](std::shared_ptr<gin_helper::Promise<v8::Local<v8::Value>>>
 | 
						|
               proxied_promise,
 | 
						|
           v8::Isolate* isolate, v8::Global<v8::Context> global_source_context,
 | 
						|
           v8::Global<v8::Context> global_destination_context,
 | 
						|
           v8::Local<v8::Value> result) {
 | 
						|
          if (global_source_context.IsEmpty() ||
 | 
						|
              global_destination_context.IsEmpty())
 | 
						|
            return;
 | 
						|
          context_bridge::ObjectCache object_cache;
 | 
						|
          auto val =
 | 
						|
              PassValueToOtherContext(global_source_context.Get(isolate),
 | 
						|
                                      global_destination_context.Get(isolate),
 | 
						|
                                      result, &object_cache, false, 0);
 | 
						|
          if (!val.IsEmpty())
 | 
						|
            proxied_promise->Reject(val.ToLocalChecked());
 | 
						|
        },
 | 
						|
        proxied_promise, destination_context->GetIsolate(),
 | 
						|
        std::move(global_catch_source_context),
 | 
						|
        std::move(global_catch_destination_context));
 | 
						|
 | 
						|
    ignore_result(source_promise->Then(
 | 
						|
        source_context,
 | 
						|
        gin::ConvertToV8(destination_context->GetIsolate(), std::move(then_cb))
 | 
						|
            .As<v8::Function>(),
 | 
						|
        gin::ConvertToV8(destination_context->GetIsolate(), std::move(catch_cb))
 | 
						|
            .As<v8::Function>()));
 | 
						|
 | 
						|
    object_cache->CacheProxiedObject(value, proxied_promise_handle);
 | 
						|
    return v8::MaybeLocal<v8::Value>(proxied_promise_handle);
 | 
						|
  }
 | 
						|
 | 
						|
  // Errors aren't serializable currently, we need to pull the message out and
 | 
						|
  // re-construct in the destination context
 | 
						|
  if (value->IsNativeError()) {
 | 
						|
    v8::Context::Scope destination_context_scope(destination_context);
 | 
						|
    // We should try to pull "message" straight off of the error as a
 | 
						|
    // v8::Message includes some pretext that can get duplicated each time it
 | 
						|
    // crosses the bridge we fallback to the v8::Message approach if we can't
 | 
						|
    // pull "message" for some reason
 | 
						|
    v8::MaybeLocal<v8::Value> maybe_message = value.As<v8::Object>()->Get(
 | 
						|
        source_context,
 | 
						|
        gin::ConvertToV8(source_context->GetIsolate(), "message"));
 | 
						|
    v8::Local<v8::Value> message;
 | 
						|
    if (maybe_message.ToLocal(&message) && message->IsString()) {
 | 
						|
      return v8::MaybeLocal<v8::Value>(
 | 
						|
          v8::Exception::Error(message.As<v8::String>()));
 | 
						|
    }
 | 
						|
    return v8::MaybeLocal<v8::Value>(v8::Exception::Error(
 | 
						|
        v8::Exception::CreateMessage(destination_context->GetIsolate(), value)
 | 
						|
            ->Get()));
 | 
						|
  }
 | 
						|
 | 
						|
  // Manually go through the array and pass each value individually into a new
 | 
						|
  // array so that functions deep inside arrays get proxied or arrays of
 | 
						|
  // promises are proxied correctly.
 | 
						|
  if (IsPlainArray(value)) {
 | 
						|
    v8::Context::Scope destination_context_scope(destination_context);
 | 
						|
    v8::Local<v8::Array> arr = value.As<v8::Array>();
 | 
						|
    size_t length = arr->Length();
 | 
						|
    v8::Local<v8::Array> cloned_arr =
 | 
						|
        v8::Array::New(destination_context->GetIsolate(), length);
 | 
						|
    for (size_t i = 0; i < length; i++) {
 | 
						|
      auto value_for_array = PassValueToOtherContext(
 | 
						|
          source_context, destination_context,
 | 
						|
          arr->Get(source_context, i).ToLocalChecked(), object_cache,
 | 
						|
          support_dynamic_properties, recursion_depth + 1);
 | 
						|
      if (value_for_array.IsEmpty())
 | 
						|
        return v8::MaybeLocal<v8::Value>();
 | 
						|
 | 
						|
      if (!IsTrue(cloned_arr->Set(destination_context, static_cast<int>(i),
 | 
						|
                                  value_for_array.ToLocalChecked()))) {
 | 
						|
        return v8::MaybeLocal<v8::Value>();
 | 
						|
      }
 | 
						|
    }
 | 
						|
    object_cache->CacheProxiedObject(value, cloned_arr);
 | 
						|
    return v8::MaybeLocal<v8::Value>(cloned_arr);
 | 
						|
  }
 | 
						|
 | 
						|
  // Custom logic to "clone" Element references
 | 
						|
  blink::WebElement elem = blink::WebElement::FromV8Value(value);
 | 
						|
  if (!elem.IsNull()) {
 | 
						|
    v8::Context::Scope destination_context_scope(destination_context);
 | 
						|
    return v8::MaybeLocal<v8::Value>(elem.ToV8Value(
 | 
						|
        destination_context->Global(), destination_context->GetIsolate()));
 | 
						|
  }
 | 
						|
 | 
						|
  // Custom logic to "clone" Blob references
 | 
						|
  blink::WebBlob blob = blink::WebBlob::FromV8Value(value);
 | 
						|
  if (!blob.IsNull()) {
 | 
						|
    v8::Context::Scope destination_context_scope(destination_context);
 | 
						|
    return v8::MaybeLocal<v8::Value>(blob.ToV8Value(
 | 
						|
        destination_context->Global(), destination_context->GetIsolate()));
 | 
						|
  }
 | 
						|
 | 
						|
  // Proxy all objects
 | 
						|
  if (IsPlainObject(value)) {
 | 
						|
    auto object_value = value.As<v8::Object>();
 | 
						|
    auto passed_value = CreateProxyForAPI(
 | 
						|
        object_value, source_context, destination_context, 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());
 | 
						|
  }
 | 
						|
 | 
						|
  // Serializable objects
 | 
						|
  blink::CloneableMessage ret;
 | 
						|
  {
 | 
						|
    v8::Local<v8::Context> error_context =
 | 
						|
        error_target == BridgeErrorTarget::kSource ? source_context
 | 
						|
                                                   : destination_context;
 | 
						|
    v8::Context::Scope error_scope(error_context);
 | 
						|
    // V8 serializer will throw an error if required
 | 
						|
    if (!gin::ConvertFromV8(error_context->GetIsolate(), value, &ret))
 | 
						|
      return v8::MaybeLocal<v8::Value>();
 | 
						|
  }
 | 
						|
 | 
						|
  {
 | 
						|
    v8::Context::Scope destination_context_scope(destination_context);
 | 
						|
    v8::Local<v8::Value> cloned_value =
 | 
						|
        gin::ConvertToV8(destination_context->GetIsolate(), ret);
 | 
						|
    object_cache->CacheProxiedObject(value, cloned_value);
 | 
						|
    return v8::MaybeLocal<v8::Value>(cloned_value);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ProxyFunctionWrapper(const v8::FunctionCallbackInfo<v8::Value>& info) {
 | 
						|
  TRACE_EVENT0("electron", "ContextBridge::ProxyFunctionWrapper");
 | 
						|
  CHECK(info.Data()->IsObject());
 | 
						|
  v8::Local<v8::Object> data = info.Data().As<v8::Object>();
 | 
						|
  bool support_dynamic_properties = false;
 | 
						|
  gin::Arguments args(info);
 | 
						|
  // Context the proxy function was called from
 | 
						|
  v8::Local<v8::Context> calling_context = args.isolate()->GetCurrentContext();
 | 
						|
 | 
						|
  // Pull the original function and its context off of the data private key
 | 
						|
  v8::MaybeLocal<v8::Value> sdp_value =
 | 
						|
      GetPrivate(calling_context, data,
 | 
						|
                 context_bridge::kSupportsDynamicPropertiesPrivateKey);
 | 
						|
  v8::MaybeLocal<v8::Value> maybe_func = GetPrivate(
 | 
						|
      calling_context, data, context_bridge::kProxyFunctionPrivateKey);
 | 
						|
  v8::Local<v8::Value> func_value;
 | 
						|
  if (sdp_value.IsEmpty() || maybe_func.IsEmpty() ||
 | 
						|
      !gin::ConvertFromV8(args.isolate(), sdp_value.ToLocalChecked(),
 | 
						|
                          &support_dynamic_properties) ||
 | 
						|
      !maybe_func.ToLocal(&func_value))
 | 
						|
    return;
 | 
						|
 | 
						|
  v8::Local<v8::Function> func = func_value.As<v8::Function>();
 | 
						|
  v8::Local<v8::Context> func_owning_context = func->CreationContext();
 | 
						|
 | 
						|
  {
 | 
						|
    v8::Context::Scope func_owning_context_scope(func_owning_context);
 | 
						|
    context_bridge::ObjectCache object_cache;
 | 
						|
 | 
						|
    std::vector<v8::Local<v8::Value>> original_args;
 | 
						|
    std::vector<v8::Local<v8::Value>> proxied_args;
 | 
						|
    args.GetRemaining(&original_args);
 | 
						|
 | 
						|
    for (auto value : original_args) {
 | 
						|
      auto arg =
 | 
						|
          PassValueToOtherContext(calling_context, func_owning_context, value,
 | 
						|
                                  &object_cache, support_dynamic_properties, 0);
 | 
						|
      if (arg.IsEmpty())
 | 
						|
        return;
 | 
						|
      proxied_args.push_back(arg.ToLocalChecked());
 | 
						|
    }
 | 
						|
 | 
						|
    v8::MaybeLocal<v8::Value> maybe_return_value;
 | 
						|
    bool did_error = false;
 | 
						|
    v8::Local<v8::Value> error_message;
 | 
						|
    {
 | 
						|
      v8::TryCatch try_catch(args.isolate());
 | 
						|
      maybe_return_value = func->Call(func_owning_context, func,
 | 
						|
                                      proxied_args.size(), proxied_args.data());
 | 
						|
      if (try_catch.HasCaught()) {
 | 
						|
        did_error = true;
 | 
						|
        v8::Local<v8::Value> exception = try_catch.Exception();
 | 
						|
 | 
						|
        const char err_msg[] =
 | 
						|
            "An unknown exception occurred in the isolated context, an error "
 | 
						|
            "occurred but a valid exception was not thrown.";
 | 
						|
 | 
						|
        if (!exception->IsNull() && exception->IsObject()) {
 | 
						|
          v8::MaybeLocal<v8::Value> maybe_message =
 | 
						|
              exception.As<v8::Object>()->Get(
 | 
						|
                  func_owning_context,
 | 
						|
                  gin::ConvertToV8(args.isolate(), "message"));
 | 
						|
 | 
						|
          if (!maybe_message.ToLocal(&error_message) ||
 | 
						|
              !error_message->IsString()) {
 | 
						|
            error_message = gin::StringToV8(args.isolate(), err_msg);
 | 
						|
          }
 | 
						|
        } else {
 | 
						|
          error_message = gin::StringToV8(args.isolate(), err_msg);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (did_error) {
 | 
						|
      v8::Context::Scope calling_context_scope(calling_context);
 | 
						|
      args.isolate()->ThrowException(
 | 
						|
          v8::Exception::Error(error_message.As<v8::String>()));
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (maybe_return_value.IsEmpty())
 | 
						|
      return;
 | 
						|
 | 
						|
    auto ret = PassValueToOtherContext(
 | 
						|
        func_owning_context, calling_context,
 | 
						|
        maybe_return_value.ToLocalChecked(), &object_cache,
 | 
						|
        support_dynamic_properties, 0, BridgeErrorTarget::kDestination);
 | 
						|
    if (ret.IsEmpty())
 | 
						|
      return;
 | 
						|
    info.GetReturnValue().Set(ret.ToLocalChecked());
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
v8::MaybeLocal<v8::Object> CreateProxyForAPI(
 | 
						|
    const v8::Local<v8::Object>& api_object,
 | 
						|
    const v8::Local<v8::Context>& source_context,
 | 
						|
    const v8::Local<v8::Context>& destination_context,
 | 
						|
    context_bridge::ObjectCache* object_cache,
 | 
						|
    bool support_dynamic_properties,
 | 
						|
    int recursion_depth) {
 | 
						|
  gin_helper::Dictionary api(source_context->GetIsolate(), api_object);
 | 
						|
 | 
						|
  {
 | 
						|
    v8::Context::Scope destination_context_scope(destination_context);
 | 
						|
    gin_helper::Dictionary proxy =
 | 
						|
        gin::Dictionary::CreateEmpty(destination_context->GetIsolate());
 | 
						|
    object_cache->CacheProxiedObject(api.GetHandle(), proxy.GetHandle());
 | 
						|
    auto maybe_keys = api.GetHandle()->GetOwnPropertyNames(
 | 
						|
        source_context, static_cast<v8::PropertyFilter>(v8::ONLY_ENUMERABLE));
 | 
						|
    if (maybe_keys.IsEmpty())
 | 
						|
      return v8::MaybeLocal<v8::Object>(proxy.GetHandle());
 | 
						|
    auto keys = maybe_keys.ToLocalChecked();
 | 
						|
 | 
						|
    uint32_t length = keys->Length();
 | 
						|
    for (uint32_t i = 0; i < length; i++) {
 | 
						|
      v8::Local<v8::Value> key =
 | 
						|
          keys->Get(destination_context, i).ToLocalChecked();
 | 
						|
 | 
						|
      if (support_dynamic_properties) {
 | 
						|
        v8::Context::Scope source_context_scope(source_context);
 | 
						|
        auto maybe_desc = api.GetHandle()->GetOwnPropertyDescriptor(
 | 
						|
            source_context, key.As<v8::Name>());
 | 
						|
        v8::Local<v8::Value> desc_value;
 | 
						|
        if (!maybe_desc.ToLocal(&desc_value) || !desc_value->IsObject())
 | 
						|
          continue;
 | 
						|
        gin_helper::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, object_cache,
 | 
						|
                                           support_dynamic_properties, 1)
 | 
						|
                       .ToLocal(&getter_proxy))
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            if (!setter.IsEmpty()) {
 | 
						|
              if (!PassValueToOtherContext(source_context, destination_context,
 | 
						|
                                           setter, object_cache,
 | 
						|
                                           support_dynamic_properties, 1)
 | 
						|
                       .ToLocal(&setter_proxy))
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
 | 
						|
            v8::PropertyDescriptor desc(getter_proxy, setter_proxy);
 | 
						|
            ignore_result(proxy.GetHandle()->DefineProperty(
 | 
						|
                destination_context, key.As<v8::Name>(), desc));
 | 
						|
          }
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      v8::Local<v8::Value> value;
 | 
						|
      if (!api.Get(key, &value))
 | 
						|
        continue;
 | 
						|
 | 
						|
      auto passed_value = PassValueToOtherContext(
 | 
						|
          source_context, destination_context, value, object_cache,
 | 
						|
          support_dynamic_properties, recursion_depth + 1);
 | 
						|
      if (passed_value.IsEmpty())
 | 
						|
        return v8::MaybeLocal<v8::Object>();
 | 
						|
      proxy.Set(key, passed_value.ToLocalChecked());
 | 
						|
    }
 | 
						|
 | 
						|
    return proxy.GetHandle();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ExposeAPIInMainWorld(v8::Isolate* isolate,
 | 
						|
                          const std::string& key,
 | 
						|
                          v8::Local<v8::Value> api,
 | 
						|
                          gin_helper::Arguments* args) {
 | 
						|
  TRACE_EVENT1("electron", "ContextBridge::ExposeAPIInMainWorld", "key", key);
 | 
						|
 | 
						|
  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();
 | 
						|
  gin_helper::Dictionary global(main_context->GetIsolate(),
 | 
						|
                                main_context->Global());
 | 
						|
 | 
						|
  if (global.Has(key)) {
 | 
						|
    args->ThrowError(
 | 
						|
        "Cannot bind an API on top of an existing property on the window "
 | 
						|
        "object");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  v8::Local<v8::Context> isolated_context = frame->GetScriptContextFromWorldId(
 | 
						|
      args->isolate(), WorldIDs::ISOLATED_WORLD_ID);
 | 
						|
 | 
						|
  {
 | 
						|
    context_bridge::ObjectCache object_cache;
 | 
						|
    v8::Context::Scope main_context_scope(main_context);
 | 
						|
 | 
						|
    v8::MaybeLocal<v8::Value> maybe_proxy = PassValueToOtherContext(
 | 
						|
        isolated_context, main_context, api, &object_cache, false, 0);
 | 
						|
    if (maybe_proxy.IsEmpty())
 | 
						|
      return;
 | 
						|
    auto proxy = maybe_proxy.ToLocalChecked();
 | 
						|
 | 
						|
    if (base::FeatureList::IsEnabled(features::kContextBridgeMutability)) {
 | 
						|
      global.Set(key, proxy);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (proxy->IsObject() && !proxy->IsTypedArray() &&
 | 
						|
        !DeepFreeze(proxy.As<v8::Object>(), main_context))
 | 
						|
      return;
 | 
						|
 | 
						|
    global.SetReadOnlyNonConfigurable(key, proxy);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
gin_helper::Dictionary TraceKeyPath(const gin_helper::Dictionary& start,
 | 
						|
                                    const std::vector<std::string>& key_path) {
 | 
						|
  gin_helper::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.empty())
 | 
						|
    return;
 | 
						|
 | 
						|
  auto* render_frame = GetRenderFrame(value);
 | 
						|
  CHECK(render_frame);
 | 
						|
  auto* frame = render_frame->GetWebFrame();
 | 
						|
  CHECK(frame);
 | 
						|
  v8::Local<v8::Context> main_context = frame->MainWorldScriptContext();
 | 
						|
  gin_helper::Dictionary global(main_context->GetIsolate(),
 | 
						|
                                main_context->Global());
 | 
						|
 | 
						|
  const std::string final_key = key_path[key_path.size() - 1];
 | 
						|
  gin_helper::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,
 | 
						|
                                &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,
 | 
						|
    gin_helper::Arguments* args) {
 | 
						|
  if (key_path.empty())
 | 
						|
    return false;
 | 
						|
 | 
						|
  auto* render_frame = GetRenderFrame(getter);
 | 
						|
  CHECK(render_frame);
 | 
						|
  auto* frame = render_frame->GetWebFrame();
 | 
						|
  CHECK(frame);
 | 
						|
  v8::Local<v8::Context> main_context = frame->MainWorldScriptContext();
 | 
						|
  gin_helper::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, &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, &object_cache, false, 1);
 | 
						|
      DCHECK(!maybe_setter_proxy.IsEmpty());
 | 
						|
      setter_proxy = maybe_setter_proxy.ToLocalChecked();
 | 
						|
    }
 | 
						|
 | 
						|
    v8::PropertyDescriptor desc(getter_proxy, setter_proxy);
 | 
						|
    bool success = 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;
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace api
 | 
						|
 | 
						|
}  // namespace electron
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
void Initialize(v8::Local<v8::Object> exports,
 | 
						|
                v8::Local<v8::Value> unused,
 | 
						|
                v8::Local<v8::Context> context,
 | 
						|
                void* priv) {
 | 
						|
  v8::Isolate* isolate = context->GetIsolate();
 | 
						|
  gin_helper::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);
 | 
						|
#if DCHECK_IS_ON()
 | 
						|
  dict.Set("_isDebug", true);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace
 | 
						|
 | 
						|
NODE_LINKED_MODULE_CONTEXT_AWARE(electron_renderer_context_bridge, Initialize)
 |