Bug 1943761 - Add class alignment to the mozsearch analysis file. r=asuth
[gecko.git] / js / xpconnect / wrappers / FilteringWrapper.cpp
blob390725fc4339bd81b582ceb2ee4372f161a17922
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"
16 #include "jsapi.h"
17 #include "js/Symbol.h"
19 using namespace JS;
20 using namespace js;
22 namespace xpc {
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) {
29 if (!id.isSymbol()) {
30 return false;
33 JS::Symbol* symbol = id.toSymbol();
34 for (auto code : sCrossOriginWhitelistedSymbolCodes) {
35 if (symbol == JS::GetWellKnownSymbol(cx, code)) {
36 return true;
40 return false;
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))) {
53 return false;
56 if (!AppendUnique(cx, props, thenProp)) {
57 return false;
60 // Now add the three symbol-named props cross-origin objects have.
61 #ifdef DEBUG
62 for (size_t n = 0; n < props.length(); ++n) {
63 MOZ_ASSERT(!props[n].isSymbol(), "Unexpected existing symbol-name prop");
65 #endif
66 if (!props.reserve(props.length() +
67 std::size(sCrossOriginWhitelistedSymbolCodes))) {
68 return false;
71 for (auto code : sCrossOriginWhitelistedSymbolCodes) {
72 props.infallibleAppend(JS::GetWellKnownSymbolKey(cx, code));
75 return true;
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)) {
113 return false;
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)) {
123 return false;
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.
143 protop.set(nullptr);
144 return true;
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)) {
152 *bp =
153 JS_IsExceptionPending(cx) ? false : Policy::deny(cx, act, id, mayThrow);
154 return false;
156 *bp = true;
157 return true;
160 #define NNXOW FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>
161 #define NNXOWC FilteringWrapper<CrossCompartmentSecurityWrapper, OpaqueWithCall>
163 template <>
164 const NNXOW NNXOW::singleton(0);
165 template <>
166 const NNXOWC NNXOWC::singleton(0);
168 template class NNXOW;
169 template class NNXOWC;
170 template class ChromeObjectWrapperBase;
171 } // namespace xpc