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 "mozilla/dom/Permissions.h"
9 #include "mozilla/dom/Document.h"
10 #include "mozilla/dom/MidiPermissionStatus.h"
11 #include "mozilla/dom/PermissionSetParametersBinding.h"
12 #include "mozilla/dom/PermissionStatus.h"
13 #include "mozilla/dom/PermissionsBinding.h"
14 #include "mozilla/dom/Promise.h"
15 #include "mozilla/dom/RootedDictionary.h"
16 #include "mozilla/dom/StorageAccessPermissionStatus.h"
17 #include "PermissionUtils.h"
19 namespace mozilla::dom
{
21 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Permissions
)
22 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
23 NS_INTERFACE_MAP_ENTRY(nsISupports
)
26 NS_IMPL_CYCLE_COLLECTING_ADDREF(Permissions
)
27 NS_IMPL_CYCLE_COLLECTING_RELEASE(Permissions
)
29 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Permissions
, mWindow
)
31 Permissions::Permissions(nsPIDOMWindowInner
* aWindow
) : mWindow(aWindow
) {}
33 Permissions::~Permissions() = default;
35 JSObject
* Permissions::WrapObject(JSContext
* aCx
,
36 JS::Handle
<JSObject
*> aGivenProto
) {
37 return Permissions_Binding::Wrap(aCx
, this, aGivenProto
);
42 // Steps to parse PermissionDescriptor in
43 // https://w3c.github.io/permissions/#query-method and relevant WebDriver
45 RefPtr
<PermissionStatus
> CreatePermissionStatus(
46 JSContext
* aCx
, JS::Handle
<JSObject
*> aPermissionDesc
,
47 nsPIDOMWindowInner
* aWindow
, ErrorResult
& aRv
) {
48 // Step 2: Let rootDesc be the object permissionDesc refers to, converted to
49 // an IDL value of type PermissionDescriptor.
50 PermissionDescriptor rootDesc
;
51 JS::Rooted
<JS::Value
> permissionDescValue(
52 aCx
, JS::ObjectOrNullValue(aPermissionDesc
));
53 if (NS_WARN_IF(!rootDesc
.Init(aCx
, permissionDescValue
))) {
54 // Step 3: If the conversion throws an exception, return a promise rejected
55 // with that exception.
56 // Step 4: If rootDesc["name"] is not supported, return a promise rejected
57 // with a TypeError. (This is done by `enum PermissionName`, as the spec
58 // note says: "implementers are encouraged to use their own custom enum
60 aRv
.NoteJSContextException(aCx
);
64 // Step 5: Let typedDescriptor be the object permissionDesc refers to,
65 // converted to an IDL value of rootDesc's name's permission descriptor type.
66 // Step 6: If the conversion throws an exception, return a promise rejected
67 // with that exception.
68 // Step 8.1: Let status be create a PermissionStatus with typedDescriptor.
69 // (The rest is done by the caller)
70 switch (rootDesc
.mName
) {
71 case PermissionName::Midi
: {
72 MidiPermissionDescriptor midiPerm
;
73 if (NS_WARN_IF(!midiPerm
.Init(aCx
, permissionDescValue
))) {
74 aRv
.NoteJSContextException(aCx
);
78 return new MidiPermissionStatus(aWindow
, midiPerm
.mSysex
);
80 case PermissionName::Storage_access
:
81 return new StorageAccessPermissionStatus(aWindow
);
82 case PermissionName::Geolocation
:
83 case PermissionName::Notifications
:
84 case PermissionName::Push
:
85 case PermissionName::Persistent_storage
:
86 case PermissionName::Screen_wake_lock
:
87 return new PermissionStatus(aWindow
, rootDesc
.mName
);
89 MOZ_ASSERT_UNREACHABLE("Unhandled type");
90 aRv
.Throw(NS_ERROR_NOT_IMPLEMENTED
);
97 // https://w3c.github.io/permissions/#query-method
98 already_AddRefed
<Promise
> Permissions::Query(JSContext
* aCx
,
99 JS::Handle
<JSObject
*> aPermission
,
101 // Step 1: If this's relevant global object is a Window object, then:
102 // Step 1.1: If the current settings object's associated Document is not fully
103 // active, return a promise rejected with an "InvalidStateError" DOMException.
105 // TODO(krosylight): The spec allows worker global while we don't, see bug
107 if (!mWindow
|| !mWindow
->IsFullyActive()) {
108 aRv
.ThrowInvalidStateError("The document is not fully active.");
112 // Step 2 - 6 and 8.1:
113 RefPtr
<PermissionStatus
> status
=
114 CreatePermissionStatus(aCx
, aPermission
, mWindow
, aRv
);
119 // Step 7: Let promise be a new promise.
120 RefPtr
<Promise
> promise
= Promise::Create(mWindow
->AsGlobal(), aRv
);
121 if (NS_WARN_IF(aRv
.Failed())) {
125 // Step 8.2 - 8.3: (Done by the Init method)
126 // Step 8.4: Queue a global task on the permissions task source with this's
127 // relevant global object to resolve promise with status.
128 status
->Init()->Then(
129 GetMainThreadSerialEventTarget(), __func__
,
130 [status
, promise
]() {
131 promise
->MaybeResolve(status
);
134 [promise
](nsresult aError
) {
135 MOZ_ASSERT(NS_FAILED(aError
));
136 NS_WARNING("Failed PermissionStatus creation");
137 promise
->MaybeReject(aError
);
141 return promise
.forget();
144 already_AddRefed
<PermissionStatus
> Permissions::ParseSetParameters(
145 JSContext
* aCx
, const PermissionSetParameters
& aParameters
,
147 // Step 1: Let parametersDict be the parameters argument, converted to an IDL
148 // value of type PermissionSetParameters. If this throws an exception,
149 // return an invalid argument error.
150 // (Done by IDL layer, and the error type should be handled by the caller)
152 // Step 2: If parametersDict.state is an inappropriate permission state for
153 // any implementation-defined reason, return a invalid argument error.
154 // (We don't do this)
156 // Step 3: Let rootDesc be parametersDict.descriptor.
157 JS::Rooted
<JSObject
*> rootDesc(aCx
, aParameters
.mDescriptor
);
159 // Step 4: Let typedDescriptor be the object rootDesc refers to, converted
160 // to an IDL value of rootDesc.name's permission descriptor type. If this
161 // throws an exception, return a invalid argument error.
163 // We use PermissionStatus as the typed object.
164 RefPtr
<PermissionStatus
> status
=
165 CreatePermissionStatus(aCx
, rootDesc
, nullptr, aRv
);
170 // Set the state too so that the caller can use it for step 5.
171 status
->SetState(aParameters
.mState
);
173 return status
.forget();
176 } // namespace mozilla::dom