| /* |
| * Copyright (C) 2009 Google Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "bindings/core/v8/V8DOMWrapper.h" |
| |
| #include "bindings/core/v8/V8Binding.h" |
| #include "bindings/core/v8/V8Location.h" |
| #include "bindings/core/v8/V8ObjectConstructor.h" |
| #include "bindings/core/v8/V8PerContextData.h" |
| #include "bindings/core/v8/V8PerIsolateData.h" |
| #include "bindings/core/v8/V8ScriptRunner.h" |
| #include "bindings/core/v8/V8Window.h" |
| #include "core/dom/Document.h" |
| #include "core/frame/LocalDOMWindow.h" |
| |
| namespace blink { |
| |
| v8::Local<v8::Object> V8DOMWrapper::createWrapper( |
| v8::Isolate* isolate, |
| v8::Local<v8::Object> creationContext, |
| const WrapperTypeInfo* type) { |
| ASSERT(!type->equals(&V8Window::wrapperTypeInfo)); |
| // According to |
| // https://html.spec.whatwg.org/multipage/browsers.html#security-location, |
| // cross-origin script access to a few properties of Location is allowed. |
| // Location already implements the necessary security checks. |
| bool withSecurityCheck = !type->equals(&V8Location::wrapperTypeInfo); |
| V8WrapperInstantiationScope scope(creationContext, isolate, |
| withSecurityCheck); |
| |
| V8PerContextData* perContextData = V8PerContextData::from(scope.context()); |
| v8::Local<v8::Object> wrapper; |
| if (perContextData) { |
| wrapper = perContextData->createWrapperFromCache(type); |
| } else { |
| // The context is detached, but still accessible. |
| // TODO(yukishiino): This code does not create a wrapper with |
| // the correct settings. Should follow the same way as |
| // V8PerContextData::createWrapperFromCache, though there is no need to |
| // cache resulting objects or their constructors. |
| const DOMWrapperWorld& world = DOMWrapperWorld::world(scope.context()); |
| wrapper = type->domTemplate(isolate, world) |
| ->InstanceTemplate() |
| ->NewInstance(scope.context()) |
| .ToLocalChecked(); |
| } |
| return wrapper; |
| } |
| |
| bool V8DOMWrapper::isWrapper(v8::Isolate* isolate, v8::Local<v8::Value> value) { |
| if (value.IsEmpty() || !value->IsObject()) |
| return false; |
| v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(value); |
| |
| if (object->InternalFieldCount() < v8DefaultWrapperInternalFieldCount) |
| return false; |
| |
| const WrapperTypeInfo* untrustedWrapperTypeInfo = toWrapperTypeInfo(object); |
| V8PerIsolateData* perIsolateData = V8PerIsolateData::from(isolate); |
| if (!(untrustedWrapperTypeInfo && perIsolateData)) |
| return false; |
| return perIsolateData->hasInstance(untrustedWrapperTypeInfo, object); |
| } |
| |
| bool V8DOMWrapper::hasInternalFieldsSet(v8::Local<v8::Value> value) { |
| if (value.IsEmpty() || !value->IsObject()) |
| return false; |
| v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(value); |
| |
| if (object->InternalFieldCount() < v8DefaultWrapperInternalFieldCount) |
| return false; |
| |
| const ScriptWrappable* untrustedScriptWrappable = toScriptWrappable(object); |
| const WrapperTypeInfo* untrustedWrapperTypeInfo = toWrapperTypeInfo(object); |
| return untrustedScriptWrappable && untrustedWrapperTypeInfo && |
| untrustedWrapperTypeInfo->ginEmbedder == gin::kEmbedderBlink; |
| } |
| |
| void V8WrapperInstantiationScope::securityCheck( |
| v8::Isolate* isolate, |
| v8::Local<v8::Context> contextForWrapper) { |
| if (m_context.IsEmpty()) |
| return; |
| // If the context is different, we need to make sure that the current |
| // context has access to the creation context. |
| Frame* frame = toFrameIfNotDetached(contextForWrapper); |
| if (!frame) { |
| // Sandbox detached frames - they can't create cross origin objects. |
| LocalDOMWindow* callingWindow = currentDOMWindow(isolate); |
| DOMWindow* targetWindow = toDOMWindow(contextForWrapper); |
| // TODO(jochen): Currently, Location is the only object for which we can |
| // reach this code path. Should be generalized. |
| ExceptionState exceptionState(ExceptionState::ConstructionContext, |
| "Location", contextForWrapper->Global(), |
| isolate); |
| if (BindingSecurity::shouldAllowAccessToDetachedWindow( |
| callingWindow, targetWindow, exceptionState)) |
| return; |
| |
| CHECK_EQ(SecurityError, exceptionState.code()); |
| return; |
| } |
| const DOMWrapperWorld& currentWorld = DOMWrapperWorld::world(m_context); |
| RELEASE_ASSERT(currentWorld.worldId() == |
| DOMWrapperWorld::world(contextForWrapper).worldId()); |
| // TODO(jochen): Add the interface name here once this is generalized. |
| ExceptionState exceptionState(ExceptionState::ConstructionContext, nullptr, |
| contextForWrapper->Global(), isolate); |
| if (currentWorld.isMainWorld() && |
| !BindingSecurity::shouldAllowAccessToFrame(currentDOMWindow(isolate), |
| frame, exceptionState)) { |
| CHECK_EQ(SecurityError, exceptionState.code()); |
| return; |
| } |
| } |
| |
| void V8WrapperInstantiationScope::convertException() { |
| v8::Isolate* isolate = m_context->GetIsolate(); |
| // TODO(jochen): Currently, Location is the only object for which we can reach |
| // this code path. Should be generalized. |
| ExceptionState exceptionState(ExceptionState::ConstructionContext, "Location", |
| isolate->GetCurrentContext()->Global(), |
| isolate); |
| LocalDOMWindow* callingWindow = currentDOMWindow(isolate); |
| DOMWindow* targetWindow = toDOMWindow(m_context); |
| exceptionState.throwSecurityError( |
| targetWindow->sanitizedCrossDomainAccessErrorMessage(callingWindow), |
| targetWindow->crossDomainAccessErrorMessage(callingWindow)); |
| } |
| |
| } // namespace blink |