1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "FilteringWrapper.h"
8 #include "AccessCheck.h"
9 #include "ChromeObjectWrapper.h"
10 #include "XrayWrapper.h"
11 #include "nsJSUtils.h"
12 #include "mozilla/ErrorResult.h"
13 #include "xpcpublic.h"
14 #include "xpcprivate.h"
17 #include "js/Symbol.h"
24 static JS::SymbolCode sCrossOriginWhitelistedSymbolCodes
[] = {
25 JS::SymbolCode::toStringTag
, JS::SymbolCode::hasInstance
,
26 JS::SymbolCode::isConcatSpreadable
};
28 static bool IsCrossOriginWhitelistedSymbol(JSContext
* cx
, JS::HandleId id
) {
33 JS::Symbol
* symbol
= id
.toSymbol();
34 for (auto code
: sCrossOriginWhitelistedSymbolCodes
) {
35 if (symbol
== JS::GetWellKnownSymbol(cx
, code
)) {
43 bool IsCrossOriginWhitelistedProp(JSContext
* cx
, JS::HandleId id
) {
44 return id
== GetJSIDByIndex(cx
, XPCJSContext::IDX_THEN
) ||
45 IsCrossOriginWhitelistedSymbol(cx
, id
);
48 bool AppendCrossOriginWhitelistedPropNames(JSContext
* cx
,
49 JS::MutableHandleIdVector props
) {
50 // Add "then" if it's not already in the list.
51 RootedIdVector
thenProp(cx
);
52 if (!thenProp
.append(GetJSIDByIndex(cx
, XPCJSContext::IDX_THEN
))) {
56 if (!AppendUnique(cx
, props
, thenProp
)) {
60 // Now add the three symbol-named props cross-origin objects have.
62 for (size_t n
= 0; n
< props
.length(); ++n
) {
63 MOZ_ASSERT(!props
[n
].isSymbol(), "Unexpected existing symbol-name prop");
66 if (!props
.reserve(props
.length() +
67 std::size(sCrossOriginWhitelistedSymbolCodes
))) {
71 for (auto code
: sCrossOriginWhitelistedSymbolCodes
) {
72 props
.infallibleAppend(JS::GetWellKnownSymbolKey(cx
, code
));
78 // Note: Previously, FilteringWrapper supported complex access policies where
79 // certain properties on an object were accessible and others weren't. Today,
80 // the only supported policies are Opaque and OpaqueWithCall, none of which need
81 // that. So we just stub out the unreachable paths.
82 template <typename Base
, typename Policy
>
83 bool FilteringWrapper
<Base
, Policy
>::getOwnPropertyDescriptor(
84 JSContext
* cx
, HandleObject wrapper
, HandleId id
,
85 MutableHandle
<mozilla::Maybe
<PropertyDescriptor
>> desc
) const {
86 MOZ_CRASH("FilteringWrappers are now always opaque");
89 template <typename Base
, typename Policy
>
90 bool FilteringWrapper
<Base
, Policy
>::ownPropertyKeys(
91 JSContext
* cx
, HandleObject wrapper
, MutableHandleIdVector props
) const {
92 MOZ_CRASH("FilteringWrappers are now always opaque");
95 template <typename Base
, typename Policy
>
96 bool FilteringWrapper
<Base
, Policy
>::getOwnEnumerablePropertyKeys(
97 JSContext
* cx
, HandleObject wrapper
, MutableHandleIdVector props
) const {
98 MOZ_CRASH("FilteringWrappers are now always opaque");
101 template <typename Base
, typename Policy
>
102 bool FilteringWrapper
<Base
, Policy
>::enumerate(
103 JSContext
* cx
, HandleObject wrapper
,
104 JS::MutableHandleIdVector props
) const {
105 MOZ_CRASH("FilteringWrappers are now always opaque");
108 template <typename Base
, typename Policy
>
109 bool FilteringWrapper
<Base
, Policy
>::call(JSContext
* cx
,
110 JS::Handle
<JSObject
*> wrapper
,
111 const JS::CallArgs
& args
) const {
112 if (!Policy::checkCall(cx
, wrapper
, args
)) {
115 return Base::call(cx
, wrapper
, args
);
118 template <typename Base
, typename Policy
>
119 bool FilteringWrapper
<Base
, Policy
>::construct(JSContext
* cx
,
120 JS::Handle
<JSObject
*> wrapper
,
121 const JS::CallArgs
& args
) const {
122 if (!Policy::checkCall(cx
, wrapper
, args
)) {
125 return Base::construct(cx
, wrapper
, args
);
128 template <typename Base
, typename Policy
>
129 bool FilteringWrapper
<Base
, Policy
>::nativeCall(
130 JSContext
* cx
, JS::IsAcceptableThis test
, JS::NativeImpl impl
,
131 const JS::CallArgs
& args
) const {
132 if (Policy::allowNativeCall(cx
, test
, impl
)) {
133 return Base::Permissive::nativeCall(cx
, test
, impl
, args
);
135 return Base::Restrictive::nativeCall(cx
, test
, impl
, args
);
138 template <typename Base
, typename Policy
>
139 bool FilteringWrapper
<Base
, Policy
>::getPrototype(
140 JSContext
* cx
, JS::HandleObject wrapper
,
141 JS::MutableHandleObject protop
) const {
142 // Filtering wrappers do not allow access to the prototype.
147 template <typename Base
, typename Policy
>
148 bool FilteringWrapper
<Base
, Policy
>::enter(JSContext
* cx
, HandleObject wrapper
,
149 HandleId id
, Wrapper::Action act
,
150 bool mayThrow
, bool* bp
) const {
151 if (!Policy::check(cx
, wrapper
, id
, act
)) {
153 JS_IsExceptionPending(cx
) ? false : Policy::deny(cx
, act
, id
, mayThrow
);
160 #define NNXOW FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>
161 #define NNXOWC FilteringWrapper<CrossCompartmentSecurityWrapper, OpaqueWithCall>
164 const NNXOW
NNXOW::singleton(0);
166 const NNXOWC
NNXOWC::singleton(0);
168 template class NNXOW
;
169 template class NNXOWC
;
170 template class ChromeObjectWrapperBase
;