├── .pr-preview.json ├── tidyconfig.txt ├── docs └── assets │ └── images │ ├── sample-prompts.png │ └── permission-settings.png ├── w3c.json ├── LICENSE.md ├── .github ├── CODE_OF_CONDUCT.md ├── PULL_REQUEST_TEMPLATE.md ├── workflows │ ├── tidy.yml │ └── auto-publish.yml └── CONTRIBUTING.md ├── README.md ├── extensibility.md └── index.html /.pr-preview.json: -------------------------------------------------------------------------------- 1 | { 2 | "src_file": "index.html", 3 | "type": "respec" 4 | } 5 | -------------------------------------------------------------------------------- /tidyconfig.txt: -------------------------------------------------------------------------------- 1 | char-encoding: utf8 2 | indent: yes 3 | wrap: 100 4 | tidy-mark: no 5 | newline: LF 6 | custom-tags: yes 7 | -------------------------------------------------------------------------------- /docs/assets/images/sample-prompts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c/permissions/HEAD/docs/assets/images/sample-prompts.png -------------------------------------------------------------------------------- /docs/assets/images/permission-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c/permissions/HEAD/docs/assets/images/permission-settings.png -------------------------------------------------------------------------------- /w3c.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": [ 3 | "49309" 4 | ], 5 | "contacts": [ 6 | "samuelweiler", "wseltzer", "sideshowbarker" 7 | ], 8 | "repo-type": "rec-track" 9 | } 10 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | All documents in this Repository are licensed by contributors 2 | under the 3 | [W3C Software and Document License](https://www.w3.org/Consortium/Legal/copyright-software). 4 | 5 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | All documentation, code and communication under this repository are covered by the [W3C Code of Ethics and Professional Conduct](https://www.w3.org/Consortium/cepc/). 4 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | closes #??? 2 | 3 | The following tasks have been completed: 4 | 5 | * [ ] Modified Web platform tests (link) 6 | 7 | Implementation commitment: 8 | 9 | * [ ] WebKit (link to issue) 10 | * [ ] Blink (link to issue) 11 | * [ ] Gecko (link to issue) 12 | 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About 2 | This repo holds some of the sources for the Permissions API, an interface for Web applications to be able to manage permissions. 3 | 4 | The latest editor’s draft is at https://w3c.github.io/permissions/ 5 | 6 | # Contributing 7 | We welcome contributions to this repo. For more info, please see [CONTRIBUTING](https://github.com/w3c/permissions/blob/main/.github/CONTRIBUTING.md). 8 | 9 | # License 10 | Please refer to [W3C Software and Document License](https://www.w3.org/Consortium/Legal/copyright-software). 11 | -------------------------------------------------------------------------------- /.github/workflows/tidy.yml: -------------------------------------------------------------------------------- 1 | name: Tidy document 2 | on: 3 | workflow_dispatch: {} 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | tidy: 10 | name: Tidy up 11 | runs-on: macos-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - run: brew install tidy-html5 15 | - run: tidy -config tidyconfig.txt -o index.html index.html 16 | - uses: peter-evans/create-pull-request@v3 17 | with: 18 | title: "Tidied up document using tidy-html5" 19 | commit-message: "chore(tidy): tidy up document" 20 | branch: html-tidy 21 | -------------------------------------------------------------------------------- /.github/workflows/auto-publish.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: {} 4 | push: 5 | branches: [main] 6 | jobs: 7 | main: 8 | name: Build, Validate, Deploy 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: w3c/spec-prod@v2 13 | with: 14 | GH_PAGES_BRANCH: gh-pages 15 | TOOLCHAIN: respec 16 | W3C_NOTIFICATIONS_CC: ${{ secrets.CC }} 17 | W3C_ECHIDNA_TOKEN: ${{ secrets.ECHIDNA_TOKEN }} 18 | W3C_WG_DECISION_URL: https://lists.w3.org/Archives/Public/public-webappsec/2015Mar/0170.html 19 | W3C_BUILD_OVERRIDE: | 20 | specStatus: WD 21 | -------------------------------------------------------------------------------- /extensibility.md: -------------------------------------------------------------------------------- 1 | # Extensibility 2 | 3 | This document describes how the Permissions API can be used to express more complex permissions than the one currently 4 | specified and how it should be used by other specifications. 5 | 6 | ## Permission description 7 | 8 | ```js 9 | dictionary PermissionDescriptor { 10 | required PermissionName name; 11 | }; 12 | ``` 13 | ```PermissionDescriptor``` is a dictionary that describes a permission. Its minimal content is a permission name but complex permissions can be described by more than a name. Such permissions should inherit from it and extend it. 14 | 15 | ## Simple permissions 16 | 17 | ```geolocation``` and ```notifications``` do not require more options for now. So their usage only require passing a ```PermissionDescriptor``` with a ```name```. 18 | 19 | ## Quota API 20 | 21 | Quota API will need options because it is more granular than accepted/denied: 22 | ```js 23 | dictionary QuotaPermissionDescriptor : PermissionDescriptor { 24 | required unsigned long long quota; 25 | StorageType type; 26 | }; 27 | ``` 28 | 29 | Checking ```quota``` permission would look like: 30 | ```js 31 | navigator.permissions.query({name: 'quota', quota: '1024', type: 'persistent' }).then(function(status) { 32 | if (status.status == 'denied') { 33 | navigator.permissions.query({name:'quotar', quota: '512', type: 'persistent' }).then(ellipsis); 34 | } 35 | }); 36 | ``` 37 | 38 | ## GetUserMedia 39 | 40 | Capture has basically two permissions: audio and video. There are a couple of ways to design this. 41 | 42 | ### Have one permission with two booleans 43 | 44 | ```js 45 | dictionary CapturePermissionDescriptor : PermissionDescriptor { 46 | required boolean audio; 47 | required boolean video; 48 | }; 49 | ``` 50 | But it might be odd if ```audio``` and ```video``` are both set to ```false```. Though, technically, the permission 51 | should definitely be granted. 52 | 53 | ### Have an enum for the tri-state 54 | 55 | ```js 56 | enum CapturePermissionType { 57 | "audio", 58 | "video", 59 | "audio-video" 60 | } 61 | dictionary CapturePermissionDescriptor : PermissionDescriptor { 62 | required CapturePermissionType type; 63 | }; 64 | ``` 65 | 66 | ### Have two permissions 67 | 68 | Simply ```capture-video``` and ```capture-audio```. 69 | 70 | ## Geolocation extended 71 | 72 | The Geolocation specification defines a boolean called ```enableHighAccuracy```. Some user agents could have a 73 | permissions behaviour depending on that value. We could imagine that the ```geolocation``` permission could be 74 | extended to include this boolean in the future: 75 | ```js 76 | dictionary GeolocationPermissionDescriptor : PermissionDescriptor { 77 | boolean enableHighAccurary = true; 78 | }; 79 | ``` 80 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Everyone is welcome to contribute to this specification. 4 | 5 | Any simple editorial contribution can simply be done with a GitHub Pull Request. 6 | You can even do an inline edit of the file on GitHub. 7 | 8 | Note: Contributions to this repository are intended to become part of Recommendation-track documents governed by the 9 | [W3C Patent Policy](https://www.w3.org/Consortium/Patent-Policy-20040205/) and 10 | [Software and Document License](https://www.w3.org/Consortium/Legal/copyright-software). To make substantive contributions to specifications, you must either participate 11 | in the relevant W3C Working Group or make a non-member patent licensing commitment. 12 | 13 | ## Style guide to contributors 14 | 15 | - the spec uses [ReSpec](https://www.w3.org/respec/) 16 | - the spec is tidied using [HTML5 Tidy](https://github.com/w3c/tidy-html5). For 17 | instructions on running HTML5 tidy, see below. 18 | - Running tidy is optional. We run tidy on the server after every commit. 19 | - Put comments in front of sections, for better readability with 20 | syntax coloring editors. 21 | 22 | ## Commit message guidelines 23 | 24 | - When relevant, include `closes #` and the issue number. 25 | - The commit message should be short and concise. 26 | - Prefix the commit message with one of the following: 27 | - `Editorial:` -for editorial/non-normative change to the specification. 28 | - `Chore:` - when fixing ReSpec stuff or other non-spec related stuff (e.g., CI). 29 | - Normative changes should not be prefixed with anything. These go into the changelog. 30 | 31 | ## Optional - Running HTML5 Tidy 32 | 33 | We run HTML5 tidy on the server after every commit. 34 | 35 | But, if you are planning to make a lot of edits, please make sure you 36 | have [HTML5 Tidy](https://github.com/w3c/tidy-html5) installed. 37 | 38 | On MacOS: 39 | 40 | ``` 41 | brew install tidy-html5 42 | ``` 43 | 44 | Don't use the the one that ships with \*nix systems. 45 | 46 | You can confirm check the version by running the following. 47 | 48 | ```bash 49 | tidy --version 50 | ``` 51 | 52 | It should say "HTML Tidy for Apple macOS version 5.8.0" or something similar for your OS. 53 | 54 | Once you have confirmed (make sure you have committed your changes before 55 | running tidy, as the changes are destructive ... in a good way:)): 56 | 57 | ```bash 58 | tidy -config tidyconfig.txt -o index.html index.html 59 | ``` 60 | 61 | If you are not the sole contributor to a contribution (pull request), please identify all 62 | contributors in the pull request comment. 63 | 64 | ## Contributing for other people 65 | 66 | To add a contributor (other than yourself, that's automatic), mark them one per line as follows: 67 | 68 | ```text 69 | +@github_username 70 | ``` 71 | 72 | If you added a contributor by mistake, you can remove them in a comment with: 73 | 74 | ```text 75 | -@github_username 76 | ``` 77 | 78 | If you are making a pull request on behalf of someone else but you had no part in designing the 79 | feature, you can remove yourself with the above syntax. 80 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Permissions 7 | 8 | 9 | 61 | 62 | 63 |

64 | Interacting with Permissions for Powerful Features 65 |

66 |
67 |

68 | This specification defines common infrastructure that other specifications can use to 69 | interact with browser permissions. These permissions represent a user's choice to allow or 70 | deny access to "powerful features" of the platform. For developers, the specification 71 | standardizes an API to query the permission state of a powerful feature, and be notified if 72 | a permission to use a powerful feature changes state. 73 |

74 |
75 |
76 |

77 | This is a work in progress. 78 |

79 |
80 |
81 |

82 | Introduction 83 |

84 |

85 | Specifications can define features that are explicitly identified as a [=powerful 86 | feature=]. These features are said to be "powerful" in that they can have significant 87 | privacy, security, and performance implications. As such, users rely on user agents to deny 88 | sites the ability to use these features until they have given express permission, and 89 | usually only granting this ability for a limited amount of time. Express permission to 90 | allow a site to use a powerful feature is generally given and controlled through browser 91 | UI, as illustrated below. 92 |

93 |
94 | 95 96 |
97 | Sketches of possible permission prompt types 98 |
99 |
100 |

101 | In this sense, a permission represents the current state of user consent for certain types 102 | of features, and particularly "powerful features". Ultimately the user retains control of 103 | these permissions and have the ability to manually grant or deny permissions through user 104 | preferences. Further, user agents assist users in managing permissions by, for example, 105 | hiding and automatically denying certain permission prompts that would otherwise be a 106 | nuisance, and automatically expiring granted permissions if a user doesn't visit a website 107 | for some time. 108 |

109 |
110 |
111 | 112 113 |
114 | A sketch of a possible site-specific permissions controls UI 115 |
116 |
117 |
118 |

119 | Examples of usage 120 |

121 |

122 | This example uses the Permissions API to decide whether local news should be shown using 123 | the Geolocation API or with a button offering to add the feature. 124 |

125 |
 126 |         const { state } = await navigator.permissions.query({
 127 |           name: "geolocation"
 128 |         });
 129 |         switch (state) {
 130 |           case "granted":
 131 |             showLocalNewsWithGeolocation();
 132 |             break;
 133 |           case "prompt":
 134 |             showButtonToEnableLocalNews();
 135 |             break;
 136 |           case "denied":
 137 |             showNationalNews();
 138 |             break;
 139 |         }
 140 |       
141 |

142 | This example simultaneously checks the state of the `"geolocation"` and `"notifications"` 143 | [=powerful features=]: 144 |

145 |
 146 |         const queryPromises = ["geolocation", "notifications"].map(
 147 |           name => navigator.permissions.query({ name })
 148 |         );
 149 |         for await (const status of queryPromises) {
 150 |           console.log(`${status.name}: ${status.state}`);
 151 |         }
 152 |       
153 |

154 | This example is checking the permission state of the available cameras. 155 |

156 |
 157 |         const devices = await navigator.mediaDevices.enumerateDevices();
 158 | 
 159 |         // filter on video inputs, and map to query object
 160 |         const queries = devices
 161 |           .filter(({ kind }) => kind === "videoinput")
 162 |           .map(({ deviceId }) => ({ name: "camera", deviceId }));
 163 | 
 164 |         const promises = queries.map((queryObj) =>
 165 |           navigator.permissions.query(queryObj)
 166 |         );
 167 | 
 168 |         try {
 169 |           const results = await Promise.all(promises);
 170 |           // log the state of each camera
 171 |           results.forEach(({ state }, i) => console.log("Camera", i, state));
 172 |         } catch (error) {
 173 |           console.error(error);
 174 |         }
 175 |       
176 |
177 |
178 |

179 | Model 180 |

181 |

182 | This section specifies a model for [=permissions=] to use [=powerful features=] on the Web 183 | platform. 184 |

185 |
186 |

187 | Permissions 188 |

189 |

190 | A permission represents a user's decision to allow a web 191 | application to use a [=powerful feature=]. This decision is represented as a permission 192 | [=permission/state=]. 193 |

194 |

195 | Express permission refers to the user 196 | [=permission/grants|granting=] the web application the ability to use a [=powerful 197 | feature=]. 198 |

199 | 215 |

216 | Conceptually, a [=permission=] for a [=powerful feature=] can be in one of the following 217 | states: 218 |

219 |
220 |
221 | "prompt": 222 |
223 |
224 | The user has not given [=express permission=] to use the feature (i.e., it's the same 225 | as [=permission/"denied"=]). It also means that if a caller attempts to use the 226 | feature, the [=user agent=] will either be prompting the user for permission or access 227 | to the feature will be [=permission/"denied"=]. 228 |
229 |
230 | "granted": 232 |
233 |
234 | The user, or the user agent on the user's behalf, has given [=express permission=] to 235 | use a [=powerful feature=]. The caller will be able to use the feature possibly without 236 | having the [=user agent=] asking the user's permission. 237 |
238 |
239 | "denied": 240 |
241 |
242 | The user, or the user agent on the user's behalf, has denied access to this [=powerful 243 | feature=]. The caller won't be able to use the feature. 244 |
245 |
246 |

247 | To ascertain new information about the user's intent, a user 248 | agent MAY collect and interpret information about a user's intentions. This information 249 | can come from explicit user action, aggregate behavior of both the relevant user and 250 | other users, or implicit signals this specification hasn't anticipated. 251 |

252 | 261 |

262 | Every [=permission=] has a lifetime, 263 | which is the duration for which a particular permission remains [=permission/"granted"=] 264 | before it reverts back to its [=permission/default state=]. A [=permission/lifetime=] 265 | could be until a particular [=ECMAScript/Realm=] is destroyed, until a particular 266 | [=top-level browsing context=] is destroyed, a particular amount of time, or be infinite. 267 | The lifetime is negotiated between the end-user and the [=user agent=] when the user 268 | gives [=express permission=] to use a [=feature=]—usually via some permission UI or 269 | user-agent defined policy. 270 |

271 |

272 | Every permission has a default state (usually 273 | [=permission/"prompt"=]), which is the [=permission/state=] that the permission is in 274 | when the user has not yet given [=express permission=] to use the [=feature=] or it has 275 | been reset because its [=permission/lifetime=] has expired. 276 |

277 |
278 |
279 |

280 | Permission Store 281 |

282 |

283 | The user agent maintains a single permission store which is a 284 | [=/list=] of [=permission store entries=]. Each particular [=entry=] denoted by its 285 | [=permission store entry/descriptor=] and [=permission store entry/key=] can only appear 286 | at most once in this list. 287 |

288 |

289 | The user agent MAY remove [=entries=] from the [=permission store=] when their respective 290 | [=permission=]'s [=permission/lifetime=] has expired. 291 |

292 |

293 | A permission store entry is a [=tuple=] 294 | of {{PermissionDescriptor}} descriptor, [=permission key=] key, and [=permission/state=] state. 298 |

299 |
300 |

301 | To get a permission store entry given a 302 | {{PermissionDescriptor}} |descriptor:PermissionDescriptor| and [=permission key=] 303 | |key|: 304 |

305 |
    306 |
  1. 307 | 308 | If the user agent's [=permission store=] [=list/contains=] an [=entry=] whose 309 | [=permission store entry/descriptor=] is |descriptor|, and whose [=permission store 310 | entry/key=] [=permission key/is equal to=] |key| given |descriptor|, return that 311 | entry. 312 |
  2. 313 |
  3. Return null. 314 |
  4. 315 |
316 |
317 |
318 |

319 | To set a permission store entry given a 320 | {{PermissionDescriptor}} |descriptor:PermissionDescriptor|, a [=permission key=] |key|, 321 | and a [=permission/state=] |state|, run these steps: 322 |

323 |
    324 |
  1. Let |newEntry| be a new [=permission store entry=] whose [=permission store 325 | entry/descriptor=] is |descriptor|, and whose [=permission store entry/key=] is |key|, 326 | and whose [=permission store entry/state=] is |state|. 327 |
  2. 328 |
  3. If the user agent's [=permission store=] [=list/contains=] an [=entry=] whose 329 | [=permission store entry/descriptor=] is |descriptor|, and whose [=permission store 330 | entry/key=] [=permission key/is equal to=] |key| given |descriptor|, [=list/replace=] 331 | that entry with |newEntry| and abort these steps. 332 |
  4. 333 |
  5. [=list/Append=] |newEntry| to the user agent's [=permission store=]. 334 |
  6. 335 |
336 |
337 |
338 |

339 | To remove a permission store entry given a 340 | {{PermissionDescriptor}} |descriptor:PermissionDescriptor| and [=permission key=] 341 | |key|, run these steps: 342 |

343 |
    344 |
  1. [=list/Remove=] the [=entry=] whose [=permission store entry/descriptor=] is 345 | |descriptor|, and whose [=permission store entry/key=] [=permission key/is equal to=] 346 | |key| given |descriptor|, from the user agent's [=permission store=]. 347 |
  2. 348 |
349 |
350 |

351 | A permission key has its type defined by a feature's [=powerful 352 | feature/permission key type=]. 353 |

354 | 361 |
362 |

363 | To determine whether a [=permission key=] |key1| is equal to a [=permission key=] |key2|, given a 365 | {{PermissionDescriptor}} |descriptor|, run the following steps: 366 |

367 |
    368 |
  1. If |key1| is not of |descriptor|'s [=powerful feature/permission key type=] or 369 | |key2| is not of |descriptor|'s [=powerful feature/permission key type=], return false. 370 |
  2. 371 |
  3. Return the result of running the [=powerful feature/permission key comparison 372 | algorithm=] for the feature named by |descriptor|'s {{PermissionDescriptor/name}}, 373 | passing |key1| and |key2|. 374 |
  4. 375 |
376 |
377 |
378 |
379 |

380 | Powerful features 381 |

382 |

383 | A powerful feature is a web platform 384 | feature (usually an API) for which a user gives [=express permission=] before the feature 385 | can be used. Except for a few notable exceptions (e.g., the [[[Notifications]]]), most 386 | powerful features are also [=policy-controlled features=]. For powerful features that are 387 | also [=policy-controlled features=], [[Permissions-Policy]] controls whether a 388 | [=document=] is [=allowed to use=] a given feature. That is, a powerful feature can only 389 | request [=express permission=] from a user if the [=document=] has permission delegated 390 | to it via the corresponding [=policy-controlled feature=] (see example below). Subsequent 391 | access to the feature is determined by the user having [=permission/"granted"=] 392 | permission, or by satisfying some criteria that is equivalent to a permission 393 | [=permission/grant=]. 394 |

395 | 413 |

414 | A [=powerful feature=] is identified by its name, which is a string literal (e.g., "geolocation"). 416 |

417 |

418 | The user agent tracks which [=powerful features=] the user has [=permission=] to use via 419 | the [=environment settings object=]. 420 |

421 |
422 |

423 | Aspects 424 |

425 |

426 | Each [=powerful feature=] can define zero or more additional aspects. An aspect is defined as WebIDL [=dictionary=] that 428 | [=dictionary/inherits=] from {{PermissionDescriptor}} and serves as a WebIDL 429 | interface's [=powerful feature/permission descriptor type=]. 430 |

431 | 460 |
461 |
462 |
463 |

464 | Permissions task source 465 |

466 |

467 | The permissions task source is a [=task source=] used to perform 468 | permissions-related [=tasks=] in this specification. 469 |

470 |
471 |
472 |
473 |

474 | Specifying a powerful feature 475 |

476 |

477 | When a conforming [=specification=] specifies a powerful feature 478 | it: 479 |

480 |
    481 |
  1. MUST give the [=powerful feature=] a [=powerful feature/name=] in the form of a [=ascii 482 | lowercase=] string. 483 |
  2. 484 |
  3. MAY define a [=powerful feature/permission descriptor type=] that inherits from 485 | {{PermissionDescriptor}}. 486 |
  4. 487 |
  5. MAY define zero or more [=powerful feature/aspects=]. 488 |
  6. 489 |
  7. MAY override the algorithms and types given below if the defaults are not suitable for 490 | a particular [=powerful feature=]. 491 |
  8. 492 |
  9. MUST register the [=powerful feature=] in the [[[permissions-registry]]]. 493 |
  10. 494 |
495 |

496 | Registering the newly specified [=powerful features=] in the [[[permissions-registry]]] 497 | gives this Working Group an opportunity to provide feedback and check that integration with 498 | this specification is done effectively. 499 |

500 |
501 |
502 | A permission descriptor type: 503 |
504 |
505 |

506 | {{PermissionDescriptor}} or one of its subtypes. If unspecified, this defaults to 507 | {{PermissionDescriptor}}. 508 |

509 |

510 | The feature can define a partial order on descriptor 512 | instances. If |descriptorA| is stronger than |descriptorB|, then if |descriptorA|'s 514 | [=permission state=] is {{PermissionState/"granted"}}, |descriptorB|'s [=permission 515 | state=] must also be {{PermissionState/"granted"}}, and if |descriptorB|'s [=permission 516 | state=] is {{PermissionState/"denied"}}, |descriptorA|'s [=permission state=] must also 517 | be {{PermissionState/"denied"}}. 518 |

519 | 529 |
530 |
531 | permission state constraints: 532 |
533 |
534 | Constraints on the values that the user agent can return as a descriptor's [=permission 535 | state=]. Defaults to no constraints beyond the user's intent. 536 |
537 |
538 | extra permission data type: 539 |
540 |
541 |

542 | Some [=powerful features=] have more information associated with them than just a 543 | {{PermissionState}}. Each of these features defines an [=powerful feature/extra 544 | permission data type=]. 545 |

546 |

547 | For example, {{MediaDevices/getUserMedia()}} needs to determine which cameras 548 | the user has granted permission to access. 549 |

550 |
551 |

552 | If a {{DOMString}} |name| names one of these features, then |name|'s 553 | extra permission data for 554 | an optional environment settings object |settings| is the result of the 555 | following algorithm: 556 |

557 |
    558 |
  1. If |settings| wasn't passed, set it to the [=current settings object=]. 559 |
  2. 560 |
  3. If there was a previous invocation of this algorithm with the same |name| and 561 | |settings|, returning |previousResult|, and the user agent has not received new 562 | information about the user's intent since that invocation, return 563 | |previousResult|. 564 |
  4. 565 |
  5. Return the instance of |name|'s [=powerful feature/extra permission data type=] 566 | that matches the UA's impression of the user's intent, taking into account any 567 | [=powerful feature/extra permission data constraints=] for |name|. 568 |
  6. 569 |
570 |
571 |

572 | If specified, the [=powerful feature/extra permission data=] algorithm is usable for 573 | this feature. 574 |

575 |
576 |
577 | Optional extra permission data 578 | constraints: 579 |
580 |
581 | Constraints on the values that the user agent can return as a [=powerful feature=]'s 582 | [=powerful feature/extra permission data=]. Defaults to no constraints beyond the user's 583 | intent. 584 |
585 |
586 | A permission result type: 587 |
588 |
589 | {{PermissionStatus}} or one of its subtypes. If unspecified, this defaults to 590 | {{PermissionStatus}}. 591 |
592 |
593 | A permission query algorithm: 594 |
595 |
596 |

597 | Takes an instance of the [=powerful feature/permission descriptor type=] and a new or 598 | existing instance of the [=powerful feature/permission result type=], and updates the 599 | [=powerful feature/permission result type=] instance with the query result. Used by 600 | {{Permissions}}' {{Permissions/query(permissionDesc)}} method and the 601 | [=`PermissionStatus` update steps=]. If unspecified, this defaults to the [=default 602 | permission query algorithm=]. 603 |

604 |
605 |

606 | The default permission query algorithm, given a 607 | {{PermissionDescriptor}} permissionDesc and a {{PermissionStatus}} 608 | |status|, runs the following steps: 609 |

610 |
    611 |
  1. Set |status|'s {{PermissionStatus/state}} to |permissionDesc|'s 612 | permission state. 613 |
  2. 614 |
615 |
616 |
617 |
618 | A permission key type: 619 |
620 |
621 |

622 | The type of [=permission key=] used by the feature. Defaults to [=origin=]. A feature 623 | that specifies a custom [=powerful feature/permission key type=] MUST also specify a 624 | [=powerful feature/permission key generation algorithm=]. 625 |

626 |
627 |
628 | A permission key generation 629 | algorithm: 630 |
631 |
632 |

633 | Takes an [=origin=] |origin| and an [=origin=] |embedded origin|, and returns a new 634 | [=permission key=]. If unspecified, this defaults to the [=default permission key 635 | generation algorithm=]. A feature that specifies a custom [=powerful feature/permission 636 | key generation algorithm=] MUST also specify a [=powerful feature/permission key 637 | comparison algorithm=]. 638 |

639 |
640 |

641 | The default permission key generation algorithm, given an 642 | [=origin=] |origin| and an [=origin=] |embedded origin|, runs the following steps: 643 |

644 |
    645 |
  1. Return |origin|. 646 |
  2. 647 |
648 |
649 | 654 |
655 |
656 | A permission key comparison 657 | algorithm: 658 |
659 |
660 |

661 | Takes two [=permission keys=] and returns a [=boolean=] that shows whether the two keys 662 | are equal. If unspecified, this defaults to the [=default permission key comparison 663 | algorithm=]. 664 |

665 |
666 |

667 | The default permission key comparison algorithm, given 668 | [=permission keys=] |key1| and |key2|, runs the following steps: 669 |

670 |
    671 |
  1. Return |key1| is [=same origin=] with |key2|. 672 |
  2. 673 |
674 |
675 |
676 |
677 | A permission revocation 678 | algorithm: 679 |
680 |
681 |

682 | Takes no arguments. Updates any other parts of the implementation that need to be kept 683 | in sync with changes in the results of [=permission states=] or [=powerful 684 | feature/extra permission data=]. 685 |

686 |

687 | If unspecified, this defaults to running [=react to the user revoking permission=]. 688 |

689 |
690 |
691 | A permission [=permission/lifetime=]: 692 |
693 |
694 |

695 | Specifications that define one or more [=powerful features=] SHOULD suggest a 696 | [=permission=] [=permission/lifetime=] that is best suited for the particular feature. 697 | Some guidance on determining the lifetime of a permission is noted below, with a strong 698 | emphasis on user privacy. If no [=permission/lifetime=] is specified, the user agent 699 | provides one. 700 |

701 |

702 | When the permission [=permission/lifetime=] expires for an origin: 703 |

704 |
    705 |
  1. Set the permission back to its default [=permission state=] (e.g., by setting it 706 | back to [=permission/"prompt"=]). 707 |
  2. 708 |
  3. For each |browsing context| associated with the origin (if any), [=queue a global 709 | task=] on the [=permissions task source=] with the |browsing context|'s [=global 710 | object=] to run the [=powerful feature/permission revocation algorithm=]. 711 |
  4. 712 |
713 | 739 |
740 |
741 | Default permission state: 742 |
743 |
744 |

745 | An {{PermissionState}} value that serves as a [=permission=]'s [=permission/default 746 | state=] of a [=powerful feature=]. 747 |

748 |

749 | If not specified, the [=permission=]'s [=permission/default state=] is 750 | {{PermissionState/"prompt"}}. 751 |

752 |
753 |
754 |

755 | A default powerful feature is a [=powerful feature=] with all of 756 | the above types and algorithms defaulted. 757 |

758 |
759 |
760 |

761 | Algorithms to interface with permissions 762 |

763 |
764 |

765 | Reading the current permission state 766 |

767 |
768 |

769 | To get the current 770 | permission state, given a [=powerful feature/name=] |name| and an optional 771 | [=environment settings object=] |settings|, run the following steps. This algorithm 772 | returns a {{PermissionState}} enum value. 773 |

774 |
    775 |
  1. Let |descriptor:PermissionDescriptor| be a newly-created {{PermissionDescriptor}} 776 | with {{PermissionDescriptor/name}} initialized to |name|. 777 |
  2. 778 |
  3. Return the [=permission state=] of |descriptor| with |settings|. 779 |
  4. 780 |
781 |
782 |
783 |

784 | A |descriptor|'s permission state, given an optional 785 | environment settings object |settings| is the result of the following algorithm. 786 | It returns a {{PermissionState}} enum value: 787 |

788 |
    789 |
  1. If |settings| wasn't passed, set it to the [=current settings object=]. 790 |
  2. 791 |
  3. If |settings| is a [=non-secure context=], return {{PermissionState/"denied"}}. 792 |
  4. 793 |
  5. Let |feature| be |descriptor|'s {{PermissionDescriptor/name}}. 794 |
  6. 795 |
  7. If there exists a [=policy-controlled feature=] for |feature| and 796 | |settings|' [=relevant global object=] has an [=associated `Document`=] run the 797 | following step: 798 |
      799 |
    1. Let document be |settings|' [=relevant global object=]'s 800 | [=associated `Document`=]. 801 |
    2. 802 |
    3. If document is not allowed to use |feature|, return 803 | {{PermissionState/"denied"}}. 804 |
    4. 805 |
    806 |
  8. 807 |
  9. Let |key| be the result of [=powerful feature/permission key generation 808 | algorithm|generating a permission key=] for |descriptor| with |settings|'s 809 | [=environment/top-level origin=] and |settings|'s [=environment settings 810 | object/origin=]. 811 |
  10. 812 |
  11. Let |entry| be the result of [=get a permission store entry|getting a permission 813 | store entry=] with |descriptor| and |key|. 814 |
  12. 815 |
  13. If |entry| is not null, return a {{PermissionState}} enum value from |entry|'s 816 | [=permission store entry/state=]. 817 |
  14. 818 |
  15. Return the {{PermissionState}} enum value that represents the permission state of 819 | |feature|, taking into account any [=powerful feature/permission state constraints=] 820 | for |descriptor|'s {{PermissionDescriptor/name}}. 821 |
  16. 822 |
823 |
824 |

825 | As a shorthand, a {{DOMString}} |name|'s [=permission state=] is the [=permission state=] 826 | of a {{PermissionDescriptor}} with its {{PermissionDescriptor/name}} member set to 827 | |name|. 828 |

829 |
830 |
831 |

832 | Requesting permission to use a powerful feature 833 |

834 |
835 |

836 | To request permission to use a |descriptor:PermissionDescriptor|, the user 838 | agent must perform the following steps. This algorithm returns either 839 | {{PermissionState/"granted"}} or {{PermissionState/"denied"}}. 840 |

841 |
    842 |
  1. Let current state be the |descriptor|'s permission state. 843 |
  2. 844 |
  3. If current state is not {{PermissionState/"prompt"}}, return 845 | current state and abort these steps. 846 |
  4. 847 |
  5. Ask the user for express permission for the calling algorithm to use the 848 | powerful feature described by |descriptor|. 849 |
  6. 850 |
  7. If the user gives [=express permission=] to use the powerful feature, set |current 851 | state| to {{PermissionState/"granted"}}; otherwise to {{PermissionState/"denied"}}. The 852 | user's interaction may provide new information about the user's intent for the 853 | [=origin=]. 854 |

    855 | This is intentionally vague about the details of the permission UI and how the user 856 | agent infers user intent. User agents should be able to explore lots of UI within 857 | this framework. 858 |

    859 |
  8. 860 |
  9. Let |settings| be the [=current settings object=]. 861 |
  10. 862 |
  11. Let |key| be the result of [=powerful feature/permission key generation 863 | algorithm|generating a permission key=] for |descriptor| with |settings|'s 864 | [=environment/top-level origin=] and |settings|'s [=environment settings 865 | object/origin=]. 866 |
  12. 867 |
  13. [=Queue a task=] on the [=current settings object=]'s [=environment settings 868 | object/responsible event loop=] to [=set a permission store entry=] with |descriptor|, 869 | |key|, and |current state|. 870 |
  14. 871 |
  15. Return |current state|. 872 |
  16. 873 |
874 |
875 |

876 | As a shorthand, [=requesting permission to use=] a {{DOMString}} |name|, is the same as 877 | [=requesting permission to use=] a {{PermissionDescriptor}} with its 878 | {{PermissionDescriptor/name}} member set to |name|. 879 |

880 |
881 |
882 |

883 | Prompt the user to choose 884 |

885 |
886 |

887 | To prompt the user to choose one or more |options| associated with a given 889 | |descriptor:PermissionDescriptor| and an optional boolean 890 | |allowMultiple:boolean| (default false), the user agent must perform the following 891 | steps. This algorithm returns either {{PermissionState/"denied"}} or the user's 892 | selection. 893 |

894 |
    895 |
  1. If |descriptor|'s permission state is {{PermissionState/"denied"}}, return 896 | {{PermissionState/"denied"}} and abort these steps. 897 |
  2. 898 |
  3. If |descriptor|'s permission state is {{PermissionState/"granted"}}, the 899 | user agent may return one (or more if |allowMultiple| is true) of |options| chosen by 900 | the user and abort these steps. If the user agent returns without prompting, then 901 | subsequent prompts for the user to choose 902 | from the same set of options with the same |descriptor| must return the same option(s), 903 | unless the user agent receives new information about the user's intent. 904 |
  4. 905 |
  5. Ask the user to choose one or more |options| or deny permission, and wait for them 906 | to choose: 907 |
      908 |
    1. If the calling algorithm specified extra information to include in the prompt, 909 | include it. 910 |
    2. 911 |
    3. If |allowMultiple| is false, restrict selection to a single item from 912 | |options|; otherwise, any number may be selected by the user. 913 |
    4. 914 |
    915 |
  6. 916 |
  7. If the user chose one or more options, return them; otherwise return 917 | {{PermissionState/"denied"}}. 918 |

    919 | This is intentionally vague about the details of the permission UI and how the user 920 | agent infers user intent. User agents should be able to explore lots of UI within 921 | this framework (e.g., a permission prompt could time out and automatically return 922 | "denied" without the user making an explicit selection). 923 |

    924 |
  8. 925 |
926 |
927 |

928 | As a shorthand, [=prompting the user to choose=] from options associated with a 929 | {{DOMString}} |name|, is the same as [=prompting the user to choose=] from those options 930 | associated with a {{PermissionDescriptor}} with its {{PermissionDescriptor/name}} member 931 | set to |name|. 932 |

933 |
934 |
935 |

936 | Reacting to users revoking permission 937 |

938 |
939 |

940 | When the user agent learns that the user no longer intends to grant permission to use a 941 | feature described by the {{PermissionDescriptor}} |descriptor| in the context described 942 | by the [=permission key=] |key|, react to the user revoking permission by 943 | running these steps: 944 |

945 |
    946 |
  1. Run |descriptor|'s {{PermissionDescriptor/name}}'s [=powerful feature/permission 947 | revocation algorithm=]. 948 |
  2. 949 |
  3. [=Remove a permission store entry=] with |descriptor| and |key|. 950 |
  4. 951 |
952 |
953 |
954 |
955 |
956 |

957 | Permissions API 958 |

959 |
960 | 963 |
 964 |           [Exposed=(Window)]
 965 |           partial interface Navigator {
 966 |             [SameObject] readonly attribute Permissions permissions;
 967 |           };
 968 | 
 969 |           [Exposed=(Worker)]
 970 |           partial interface WorkerNavigator {
 971 |             [SameObject] readonly attribute Permissions permissions;
 972 |           };
 973 |         
974 |
975 |
976 |

977 | `Permissions` interface 978 |

979 |
 980 |           [Exposed=(Window,Worker)]
 981 |           interface Permissions {
 982 |             Promise<PermissionStatus> query(object permissionDesc);
 983 |           };
 984 | 
 985 |           dictionary PermissionDescriptor {
 986 |             required DOMString name;
 987 |           };
 988 |         
989 |
990 |

991 | `query()` method 992 |

993 |
994 |

995 | When the query() method is invoked, the user agent MUST run the 996 | following query a permission algorithm, passing the 997 | parameter permissionDesc: 998 |

999 |
    1000 |
  1. If [=this=]'s [=relevant global object=] is a {{Window}} object, then: 1001 |
      1002 |
    1. If the [=current settings object=]'s associated `Document` is not 1003 | [=Document/fully active=], return [=a promise rejected with=] an 1004 | {{"InvalidStateError"}} {{DOMException}}. 1005 |
    2. 1006 |
    1007 |
  2. 1008 |
  3. Let |rootDesc| be the object |permissionDesc| refers to, converted to an IDL 1009 | value of type {{PermissionDescriptor}}. 1010 |
  4. 1011 |
  5. If the conversion [=exception/throws=] an [=exception=], return a promise 1012 | rejected with that exception. 1013 |
  6. 1014 |
  7. If |rootDesc|["{{PermissionDescriptor/name}}"] is not supported, return [=a 1015 | promise rejected with=] a {{TypeError}}. 1016 | 1027 |
  8. 1028 |
  9. Let |typedDescriptor| be the object |permissionDesc| refers to, converted to 1029 | an IDL value of |rootDesc|'s {{PermissionDescriptor/name}}'s [=powerful 1030 | feature/permission descriptor type=]. 1031 |
  10. 1032 |
  11. If the conversion [=exception/throws=] an [=exception=], return a promise 1033 | rejected with that exception. 1034 |
  12. 1035 |
  13. Let |promise:Promise| be [=a new promise=]. 1036 |
  14. 1037 |
  15. Return |promise| and continue [=in parallel=]: 1038 |
      1039 |
    1. Let |status| be create a `PermissionStatus` with |typedDescriptor|. 1040 |
    2. 1041 |
    3. Let |query| be |status|'s {{PermissionStatus/[[query]]}} internal slot. 1042 |
    4. 1043 |
    5. Run |query|'s {{PermissionDescriptor/name}}'s [=powerful feature/permission 1044 | query algorithm=], passing |query| and |status|. 1045 |
    6. 1046 |
    7. [=Queue a global task=] on the [=permissions task source=] with [=this=]'s 1047 | [=relevant global object=] to [=resolve=] |promise| with |status|. 1048 |
    8. 1049 |
    1050 |
  16. 1051 |
1052 |
1053 |
1054 |
1055 |
1056 |

1057 | `PermissionStatus` interface 1058 |

1059 |
1060 |           [Exposed=(Window,Worker)]
1061 |           interface PermissionStatus : EventTarget {
1062 |             readonly attribute PermissionState state;
1063 |             readonly attribute DOMString name;
1064 |             attribute EventHandler onchange;
1065 |           };
1066 | 
1067 |           enum PermissionState {
1068 |             "granted",
1069 |             "denied",
1070 |             "prompt",
1071 |           };
1072 |         
1073 |

1074 | {{PermissionStatus}} instances are created with a [[\query]] internal slot, 1075 | which is an instance of a feature's [=powerful feature/permission descriptor type=]. 1076 |

1077 |

1078 | The "granted", "denied", and "prompt" enum values 1079 | represent the concepts of [=permission/"granted"=], [=permission/"denied"=], and 1080 | [=permission/"prompt"=] respectively. 1081 |

1082 |
1083 |

1084 | Creating instances 1085 |

1086 |
1087 |

1088 | To create a `PermissionStatus` for a given 1089 | {{PermissionDescriptor}} |permissionDesc:PermissionDescriptor|: 1090 |

1091 |
    1092 |
  1. Let |name:DOMString| be |permissionDesc|'s {{PermissionDescriptor/name}}. 1093 |
  2. 1094 |
  3. Assert: The [=feature=] identified by |name| is supported by the user agent. 1095 |
  4. 1096 |
  5. Let |status:PermissionStatus| be a new instance of the [=powerful 1097 | feature/permission result type=] identified by |name|: 1098 |
      1099 |
    1. Initialize |status|'s {{PermissionStatus/[[query]]}} internal slot to 1100 | |permissionDesc|. 1101 |
    2. 1102 |
    3. Initialize |status|'s {{PermissionStatus/name}} to |name|. 1103 |
    4. 1104 |
    1105 |
  6. 1106 |
  7. Return |status|. 1107 |
  8. 1108 |
1109 |
1110 |
1111 |
1112 |

1113 | `name` attribute 1114 |

1115 |

1116 | The name attribute returns the value it was initialized to. 1117 |

1118 |
1119 |
1120 |

1121 | `state` attribute 1122 |

1123 |

1124 | The state attribute returns the latest value that was set on the current 1125 | instance. 1126 |

1127 |
1128 |
1129 |

1130 | `onchange` attribute 1131 |

1132 |

1133 | The onchange attribute is an [=event handler=] whose corresponding [=event 1134 | handler event type=] is change. 1135 |

1136 |
1137 |

1138 | Whenever the [=user agent=] is aware that the state of a {{PermissionStatus}} 1139 | instance |status| has changed, it asynchronously runs the `PermissionStatus` 1140 | update steps: 1141 |

1142 |
    1143 |
  1. If [=this=]'s [=relevant global object=] is a {{Window}} object, then: 1144 |
      1145 |
    1. Let |document| be |status|'s [=relevant global object=]'s [=associated 1146 | Document=]. 1147 |
    2. 1148 |
    3. If |document| is null or |document| is not [=Document/fully active=], 1149 | terminate this algorithm. 1150 |
    4. 1151 |
    1152 |
  2. 1153 |
  3. Let |query| be |status|'s {{PermissionStatus/[[query]]}} internal slot. 1154 |
  4. 1155 |
  5. Run |query|'s {{PermissionDescriptor/name}}'s [=powerful feature/permission query 1156 | algorithm=], passing |query| and |status|. 1157 |
  6. 1158 |
  7. 1159 | Queue a task on the [=permissions task source=] to fire an event 1160 | named change at |status|. 1161 |
  8. 1162 |
1163 |
1164 |
1165 |
1166 |

1167 | Garbage collection 1168 |

1169 |

1170 | A {{PermissionStatus}} object MUST NOT be garbage collected if it has an [=event 1171 | listener=] whose type is `change`. 1172 |

1173 |
1174 |
1175 |
1176 |
1177 |

1178 | Two classes of product can claim conformance to this specification: [=user agents=] and 1179 | other specifications (i.e., a technical report that [=specifies a powerful 1180 | feature=] in a manner that conforms to the requirements of this specification). 1181 |

1182 |
1183 |
1184 |

1185 | Relationship to the Permissions Policy specification 1186 |

1187 |

1188 | Although both this specification and the [[[Permissions-Policy]]] specification deal with 1189 | "permissions", each specification serves a distinct purpose in the platform. Nevertheless, 1190 | the two specifications do explicitly overlap. 1191 |

1192 |

1193 | On the one hand, this specification exclusively concerns itself with [=powerful features=] 1194 | whose access is managed through a user-agent mediated permissions UI (i.e., permissions 1195 | where the user gives express consent before that feature can be used, and where the user 1196 | retains the ability to deny that permission at any time for any reason). These powerful 1197 | features are registered in the [[[permissions-registry]]]. 1198 |

1199 |

1200 | On the other hand, the [[[Permissions-Policy]]] specification allows developers to 1201 | selectively enable and disable policy-controlled features through a "[=Document/permissions 1202 | policy=]" (be it a HTTP header or the [^iframe/allow^] attribute). In that sense, the 1203 | Permissions Policy subsumes this specification in that [[[Permissions-Policy]]] governs 1204 | whether a feature is available at all, independently of this specification. These 1205 | policy-controlled features are also registered in the [[[permissions-registry]]]. 1206 |

1207 |

1208 | A powerful feature that has been disabled by the [[[Permissions-Policy]]] specification 1209 | always has its [=permission state=] reflected as "denied" by this specification. This 1210 | occurs because [=getting the current permission state|reading the current permission=] 1211 | relies on [[HTML]]'s "[=allowed to use=]" check, which itself calls into the 1212 | [[[Permissions-Policy]]] specification. Important to note here is the sharing of permission 1213 | names across both specifications. Both this specification and the [[[Permissions-Policy]]] 1214 | specification rely on other specifications defining the names of the permission and 1215 | [=powerful feature/name=], and they are usually named the same thing (e.g., "geolocation" 1216 | of the [[[Geolocation]]], and so on). 1217 |

1218 |

1219 | Finally, it's not possible for a powerful feature to ever become "granted" through any 1220 | means provided by the [[[Permissions-Policy]]] specification. The only way that a 1221 | [=powerful feature=] can be [=permission/"granted"=] is by the user giving [=express 1222 | permission=] or by some user agent policy. 1223 |

1224 |
1225 |
1226 |

1227 | Automated testing 1228 |

1229 |

1230 | For the purposes of user-agent automation and application testing, this document defines 1231 | extensions to the [[WebDriver]] and [[WebDriver-BiDi]] specifications. It is OPTIONAL for a 1232 | user agent to support them. 1233 |

1234 |
1235 |         dictionary PermissionSetParameters {
1236 |           required object descriptor;
1237 |           required PermissionState state;
1238 |         };
1239 |       
1240 |
1241 |

1242 | To set a permission given a {{PermissionDescriptor}} 1243 | |descriptor:PermissionDescriptor|, a {{PermissionState}} |state:PermissionState|, an 1244 | optional [=permission key=] |key|, and an optional |user agent|: 1245 |

1246 |
    1247 |
  1. Let |target key| be the result of [=powerful feature/permission key generation 1248 | algorithm|generating a permission key=] for |descriptor| with [=current settings 1249 | object=]'s [=environment/top-level origin=] and [=current settings object=]'s 1250 | [=environment settings object/origin=] if |key| is null, or |key| otherwise. 1251 |
  2. 1252 |
  3. Let |settings list| be a list containing all [=environment settings objects=] 1253 | which belong to the |user agent| if provided, or all user agents otherwise. 1254 |
  4. 1255 |
  5. Let |targets| be an empty list. 1256 |
  6. 1257 |
  7. [=list/For each=] [=environment settings object=] |settings| in |settings list|: 1258 |
      1259 |
    1. Let |settings key| be be the result of [=powerful feature/permission key 1260 | generation algorithm|generating a permission key=] for |descriptor| with |settings|'s 1261 | [=environment/top-level origin=] and |settings|'s [=environment settings 1262 | object/origin=]. 1263 |
    2. 1264 |
    3. Let |matches| be the result of running the [=powerful feature/permission key 1265 | comparison algorithm=] for |descriptor|, given |settings key| and |key|. 1266 |
    4. 1267 |
    5. If |matches|, then [=list/append=] |settings| to |targets|. 1268 |
    6. 1269 |
    1270 |
  8. 1271 |
  9. Let |tasks| be an empty list. 1272 |
  10. 1273 |
  11. [=list/For each=] [=environment settings object=] |target| in |targets|: 1274 |
      1275 |
    1. [=Queue a task=] |task| on the [=permissions task source=] of |target|'s 1276 | [=relevant settings object=]'s [=environment settings object/global object=]'s 1277 | [=Window/browsing context=] to perform the following step: 1278 |
        1279 |
      1. Interpret |state| as if it were the result of an invocation of [=permission 1280 | state=] for |descriptor| with the argument |target| made at this moment. 1281 |
      2. 1282 |
      1283 |
    2. 1284 |
    3. [=list/Append=] |task| to |tasks|. 1285 |
    4. 1286 |
    1287 |
  12. 1288 |
  13. Wait for all tasks in |tasks| to have executed and return. 1289 |
  14. 1290 |
1291 |
1292 |
1293 |

1294 | Automated testing with [[WebDriver]] 1295 |

1296 |

1297 | This document defines the following extension commands for the [[WebDriver]] 1298 | specification. 1299 |

1300 |
1301 |

1302 | Set Permission 1303 |

1304 | 1305 | 1306 | 1307 | 1310 | 1313 | 1314 | 1315 | 1318 | 1321 | 1322 | 1323 |
1308 | HTTP Method 1309 | 1311 | [=extension command URI template|URI Template=] 1312 |
1316 | POST 1317 | 1319 | /session/{session id}/permissions 1320 |
1324 |

1325 | The Set Permission 1326 | extension command simulates user modification of a {{PermissionDescriptor}}'s 1327 | [=permission state=]. 1328 |

1329 |

1330 | The remote end steps are: 1331 |

1332 |
    1333 |
  1. Let |parametersDict| be the |parameters| argument, [=converted to an IDL value=] of 1334 | type {{PermissionSetParameters}}. If this throws an exception, return an [=invalid 1335 | argument=] [=error=]. 1336 |
  2. 1337 |
  3. If |parametersDict|.{{PermissionSetParameters/state}} is an inappropriate 1338 | [=permission state=] for any implementation-defined reason, return an [=invalid 1339 | argument=] [=error=]. 1340 |

    1341 | For example, user agents that define the "midi" powerful feature as 1342 | "always on" can choose to reject a command to set the [=permission state=] to 1343 | {{PermissionState/"denied"}} at this step. 1344 |

    1345 |
  4. 1346 |
  5. Let |rootDesc| be |parametersDict|.{{PermissionSetParameters/descriptor}}. 1347 |
  6. 1348 |
  7. Let |typedDescriptor| be the object |rootDesc| refers to, [=converted to an IDL 1349 | value=] of [=powerful feature/permission descriptor type=] matching the result of 1350 | Get(|rootDesc|, "`name`"). If this throws an 1351 | exception, return a [=invalid argument=] [=error=]. 1352 |
  8. 1353 |
  9. [=Set a permission=] with |typedDescriptor| and 1354 | |parametersDict|.{{PermissionSetParameters/state}}. 1355 |
  10. 1356 |
  11. Return success with data `null`. 1357 |
  12. 1358 |
1359 | 1376 |
1377 |
1378 |
1379 |

1380 | Automated testing with [[WebDriver-BiDi]] 1381 |

1382 |

1383 | This document defines the following [=extension modules=] for the [[WebDriver-BiDi]] 1384 | specification. 1385 |

1386 |
1387 |

1388 | The permissions Module 1389 |

1390 |

1391 | The permissions module contains commands for managing the remote end browser 1392 | permissions. 1393 |

1394 |
1395 |
1396 | Definition 1397 |
1398 |

1399 | {^remote end definition^} 1400 |

1401 |
1402 |               PermissionsCommand = (
1403 |                 permissions.setPermission
1404 |               )
1405 |             
1406 |
1407 |
1408 |
1409 | Types 1410 |
1411 |
1412 |
1413 | The permissions.PermissionDescriptor Type 1414 |
1415 |
1416 |                 permissions.PermissionDescriptor = {
1417 |                   name: text,
1418 |                 }
1419 |               
1420 |

1421 | The `permissions.PermissionDescriptor` type represents a {{PermissionDescriptor}}. 1422 |

1423 |
1424 |
1425 |
1426 | The permissions.PermissionState Type 1427 |
1428 |
1429 |                 permissions.PermissionState = "granted" / "denied" / "prompt"
1430 |               
1431 |

1432 | The `permissions.PermissionState` type represents a {{PermissionState}}. 1433 |

1434 |
1435 |
1436 |
1437 |
1438 | Commands 1439 |
1440 |
1441 |
1442 | The permissions.setPermission Command 1443 |
1444 |

1445 | The Set Permission [=command=] simulates user 1446 | modification of a {{PermissionDescriptor}}'s [=permission state=]. 1447 |

1448 |
1449 |
1450 | Command Type 1451 |
1452 |
1453 |
1454 |                     permissions.setPermission = (
1455 |                       method: "permissions.setPermission",
1456 |                       params: permissions.SetPermissionParameters
1457 |                     )
1458 | 
1459 |                     permissions.SetPermissionParameters = {
1460 |                       descriptor: permissions.PermissionDescriptor,
1461 |                       state: permissions.PermissionState,
1462 |                       origin: text,
1463 |                       ? embeddedOrigin: text,
1464 |                       ? userContext: text,
1465 |                     }
1466 |                   
1467 |
1468 |
1469 | Result Type 1470 |
1471 |
1472 | EmptyResult 1473 |
1474 |
1475 |
1477 |

1478 | The [=remote end steps=] with |session| and |command parameters| are: 1479 |

1480 |
    1481 |
  1. Let |descriptor| be the value of the `descriptor` field of |command 1482 | parameters|. 1483 |
  2. 1484 |
  3. Let |permission name| be the value of the `name` field of |descriptor| 1485 | representing {{PermissionDescriptor/name}}. 1486 |
  4. 1487 |
  5. Let |state| be the value of the `state` field of |command parameters|. 1488 |
  6. 1489 |
  7. Let |user context id| be the value of the `userContext` field of |command 1490 | parameters|, if present, and `default` otherwise. 1491 |
  8. 1492 |
  9. If |state| is an inappropriate [=permission state=] for any 1493 | implementation-defined reason, return [=error=] with [=error code=] [=invalid 1494 | argument=]. 1495 |
  10. 1496 |
  11. Let |typedDescriptor| be the object |descriptor| refers to, [=converted to an 1497 | IDL value=] (|descriptor|, |state|) of {{PermissionSetParameters}} |permission 1498 | name|'s [=powerful feature/permission descriptor type=]. If this conversion 1499 | throws an exception, return [=error=] with [=error code=] [=invalid argument=]. 1500 |
  12. 1501 |
  13. Let |origin| be the value of the `origin` field of |command parameters|. 1502 |
  14. 1503 |
  15. Let |embedded origin| be the value of the `embeddedOrigin` field of |command 1504 | parameters|, if present, and |origin| otherwise. 1505 |
  16. 1506 |
  17. Let |key| be the result of [=powerful feature/permission key generation 1507 | algorithm|generating a permission key=] for |descriptor| with |origin| and 1508 | |embedded origin|. 1509 |
  18. 1510 |
  19. Let |user agent| be the [=user agent=] that represents the [=user context=] 1511 | with the id |user context id|. 1512 |
  20. 1513 |
  21. [=Set a permission=] with |typedDescriptor|, |state|, |key|, and |user 1514 | agent|. 1515 |
  22. 1516 |
  23. Return [=success=] with data `null`. 1517 |
  24. 1518 |
1519 |
1520 |
1521 |
1522 |
1523 |
1524 |
1525 |
1526 |

1527 | Permissions Registry 1528 |

1529 |
1530 |

1531 | Purpose 1532 |

1533 |

1534 | This [=W3C Registry=] provides a centralized place to find the [=policy-controlled 1535 | features=] and/or [=powerful features=] of the web platform. Through the [=change 1536 | process=] it also helps assure permissions in the platform are consistently specified 1537 | across various specifications. 1538 |

1539 |

1540 | By splitting the registry into standardized permissions and provisional permissions, the 1541 | registry also provides a way to track the status of these features. 1542 |

1543 |
1544 |
1545 |

1546 | Change Process 1547 |

1548 |

1549 | The change process for adding and/or updating this registry is as follows: 1550 |

1551 |
    1552 |
  1. If necessary, add a "Permissions Policy" section to your specification which includes 1553 | the following: 1554 |
      1555 |
    1. The string that identifies the policy controlled feature (e.g., 1556 | `"super-awesome"`). Make sure the string is linkable by wrapping it a [^dfn^] 1557 | element. 1558 |
    2. 1559 |
    3. The [=policy-controlled feature/default allowlist=] value (e.g. `'self'`). 1560 | 1570 |
    4. 1571 |
    1572 |
  2. 1573 |
  3. Determine if your feature meets the definition of a [=powerful feature=] (i.e., 1574 | requires [=express permission=] to be used). If it does: 1575 |
      1576 |
    1. [=Specifies a powerful feature|Specify a powerful feature=] in your specification 1577 | in conformance with the [[[Permissions]]] specification. 1578 |
    2. 1579 |
    1580 |
  4. 1581 |
  5. Modify either the [=table of standardized permissions=] or the [=table of provisional 1582 | permissions=] filling out each column with the required information. 1583 |
  6. 1584 |
  7. Submit a pull request to the Powerful 1585 | Features Registry Repository on GitHub with your changes. The maintainers of the 1586 | repository will review your pull request and check that everything integrates properly. 1587 |
  8. 1588 |
1589 |
1590 |
1591 |

1592 | Registry table of standardized permissions 1593 |

1594 |

1595 | For a permission to appear in the table of standardized permissions, and thus be 1596 | considered a standardized permission, it needs to meet the following criteria: 1597 |

1598 | 1607 |

1608 | Each [=permission=] is identified by a unique literal string. In the case of 1609 | [[[Permissions-Policy]]], the string identifies a [=policy-controlled features=]. 1610 | Similarly, in the [[[Permissions]]] specification the string identifies a [=powerful 1611 | feature=]. 1612 |

1613 | 1625 | 1626 | 1630 | 1631 | 1634 | 1637 | 1640 | 1643 | 1646 | 1647 | 1648 | 1651 | 1654 | 1657 | 1658 | 1659 | 1662 | 1665 | 1668 | 1671 | 1674 | 1677 | 1680 | 1681 | 1682 | 1685 | 1688 | 1691 | 1694 | 1697 | 1700 | 1703 | 1704 | 1705 | 1708 | 1711 | 1714 | 1717 | 1720 | 1723 | 1726 | 1727 | 1728 | 1731 | 1734 | 1737 | 1740 | 1743 | 1746 | 1749 | 1752 | 1775 |
1627 | Table of standardized 1628 | permissions of the web platform 1629 |
1632 | Identifying string 1633 | 1635 | Is [=policy-controlled feature=]? 1636 | 1638 | Is [=powerful feature=]? 1639 | 1641 | Specification 1642 | 1644 | Implementations 1645 |
1649 | Chromium 1650 | 1652 | Gecko 1653 | 1655 | WebKit 1656 |
1660 | "geolocation" 1661 | 1663 | YES 1664 | 1666 | YES 1667 | 1669 | [[[geolocation]]] 1670 | 1672 | YES 1673 | 1675 | YES 1676 | 1678 | YES 1679 |
1683 | "[=notifications=]" 1684 | 1686 | NO 1687 | 1689 | YES 1690 | 1692 | [[[NOTIFICATIONS]]] 1693 | 1695 | YES 1696 | 1698 | YES 1699 | 1701 | YES 1702 |
1706 | [="push"=] 1707 | 1709 | NO 1710 | 1712 | YES 1713 | 1715 | [[[push-api]]] 1716 | 1718 | YES 1719 | 1721 | YES 1722 | 1724 | YES 1725 |
1729 | "web-share" 1730 | 1732 | YES 1733 | 1735 | NO 1736 | 1738 | [[[Web-Share]]] 1739 | 1741 | YES 1742 | 1744 | YES 1745 | 1747 | YES 1748 |
1776 |
1777 |
1778 |

1779 | Registry table of provisional permissions 1780 |

1781 |

1782 | Provisional permissions are permissions that are not yet [=standardized 1783 | permission|standardized=] (i.e., they are either experimental, still in the incubation 1784 | phase, or are only implemented in a single browser engine). 1785 |

1786 | 1787 | 1790 | 1791 | 1794 | 1797 | 1800 | 1803 | 1806 | 1807 | 1808 | 1811 | 1814 | 1817 | 1818 | 1819 | 1822 | 1825 | 1828 | 1831 | 1834 | 1837 | 1840 | 1841 | 1842 | 1845 | 1848 | 1851 | 1854 | 1857 | 1860 | 1863 | 1864 | 1865 | 1868 | 1871 | 1874 | 1877 | 1880 | 1883 | 1886 | 1889 | 1912 |
1788 | Table of provisional permissions 1789 |
1792 | Identifying string 1793 | 1795 | Is [=policy-controlled feature=]? 1796 | 1798 | Is [=powerful feature=]? 1799 | 1801 | Specification 1802 | 1804 | Implementations 1805 |
1809 | Chromium 1810 | 1812 | Gecko 1813 | 1815 | WebKit 1816 |
1820 | [="accelerometer"=] 1821 | 1823 | YES 1824 | 1826 | YES 1827 | 1829 | [[[orientation-event]]] 1830 | 1832 | YES 1833 | 1835 | NO 1836 | 1838 | NO 1839 |
1843 | "[=window-management=]" 1844 | 1846 | YES 1847 | 1849 | YES 1850 | 1852 | [[[window-management]]] 1853 | 1855 | YES 1856 | 1858 | NO 1859 | 1861 | NO 1862 |
1866 | "[=local-fonts=]" 1867 | 1869 | YES 1870 | 1872 | YES 1873 | 1875 | [[[local-font-access]]] 1876 | 1878 | YES 1879 | 1881 | NO 1882 | 1884 | NO 1885 |
1913 |
1914 |
1915 |
1916 |

1917 | Privacy considerations 1918 |

1919 |

1920 | An adversary could use a [=permission state=] as an element in creating a "fingerprint" 1921 | corresponding to an end-user. Although an adversary can already determine the state of a 1922 | permission by actually using the API, that often leads to a UI prompt being presented to 1923 | the end-user (if the permission was not already [=permission/"granted"=]). Even though this 1924 | API doesn't expose new fingerprinting information to websites, it makes it easier for an 1925 | adversary to have discreet access to this information. 1926 |

1927 |

1928 | A user agent SHOULD provide a means for the user to review, update, and reset the 1929 | [=permission=] [=permission/state=] of [=powerful features=] associated with an [=origin=]. 1930 |

1931 |
1932 |
1933 |

1934 | Security considerations 1935 |

1936 |

1937 | There are no documented security considerations at this time. Readers are instead 1938 | encouraged to read section [[[#privacy-considerations]]]. 1939 |

1940 |
1941 |
1942 |
1943 |

1944 | Acknowledgments 1945 |

1946 |

1947 | The editors would like to thank Adrienne Porter Felt, Anne van Kesteren, Domenic Denicola, 1948 | Jake Archibald and Wendy Seltzer for their help with the API design and editorial work. 1949 |

1950 |
1951 | 1952 | 1953 | --------------------------------------------------------------------------------