no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / dom / permission / Permissions.cpp
bloba74f65b80cbc8f1fe93e174fe5ded12937d4e72b
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)
24 NS_INTERFACE_MAP_END
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);
40 namespace {
42 // Steps to parse PermissionDescriptor in
43 // https://w3c.github.io/permissions/#query-method and relevant WebDriver
44 // commands
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
59 // here")
60 aRv.NoteJSContextException(aCx);
61 return nullptr;
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);
75 return nullptr;
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);
88 default:
89 MOZ_ASSERT_UNREACHABLE("Unhandled type");
90 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
91 return nullptr;
95 } // namespace
97 // https://w3c.github.io/permissions/#query-method
98 already_AddRefed<Promise> Permissions::Query(JSContext* aCx,
99 JS::Handle<JSObject*> aPermission,
100 ErrorResult& aRv) {
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
106 // 1193373.
107 if (!mWindow || !mWindow->IsFullyActive()) {
108 aRv.ThrowInvalidStateError("The document is not fully active.");
109 return nullptr;
112 // Step 2 - 6 and 8.1:
113 RefPtr<PermissionStatus> status =
114 CreatePermissionStatus(aCx, aPermission, mWindow, aRv);
115 if (!status) {
116 return nullptr;
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())) {
122 return nullptr;
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);
132 return;
134 [promise](nsresult aError) {
135 MOZ_ASSERT(NS_FAILED(aError));
136 NS_WARNING("Failed PermissionStatus creation");
137 promise->MaybeReject(aError);
138 return;
141 return promise.forget();
144 already_AddRefed<PermissionStatus> Permissions::ParseSetParameters(
145 JSContext* aCx, const PermissionSetParameters& aParameters,
146 ErrorResult& aRv) {
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);
166 if (aRv.Failed()) {
167 return nullptr;
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