3

In a given browser environment, the supported permissions will likely differ from the registry spec.

At the time of my writing this question, the spec list includes the following names:
  • accelerometer
  • ambient-light-sensor
  • background-fetch
  • background-sync
  • bluetooth
  • camera
  • clipboard-read
  • clipboard-write
  • device-info
  • display-capture
  • geolocation
  • gyroscope
  • magnetometer
  • microphone
  • midi
  • nfc
  • notifications
  • persistent-storage
  • push
  • speaker

The environment support might be not only a subset of the spec list, but also additional permissions not listed in the spec. For example, Chrome 83 supports periodic-background-sync. (I've included a code snippet to demonstrate.)

How can I get an enumerated list of the names of the supported permissions in the current environment? How can I programmatically know what's possible?

// ✅ = supported
// ❌ = not supported

const getPermissionStatus = name => navigator.permissions.query({name});

const logSupportedPermissions = async (...names) => {
  for (const name of names) {
    try {
      const status = await getPermissionStatus(name);
      console.log(`✅ ${name} (${status.state})`)
    }
    catch (err) {
      console.log(`❌ ${name}`)
    }
  }
};

const names = [
  'clipboard-write', // listed, works in Chrome 83
  'periodic-background-sync', // not listed, but works in Chrome 83
  'display-capture', // listed, but throws in Chrome 83
  'a-nonexistent-permission-name', // not listed, throws
];

logSupportedPermissions(...names);
jsejcksn
  • 27,667
  • 4
  • 38
  • 62
  • I think the first line has an issue: you have created a function that wraps navigator.permissions.query but that function, according to mdn, requires an object containing key value pairs, but you are just passing a string, so what is being called is navigator.permissions.query({'clipboard-write'}). You need to actually call navigator.permissions.query({name: 'clipboard-write'). Change the first line to: ```const getPermissionStatus = name => navigator.permissions.query({'name': name});``` and see if that works. – leisheng Jul 03 '20 at 01:43
  • @leisheng See https://stackoverflow.com/a/38948332/438273 – jsejcksn Jul 03 '20 at 03:06
  • read the sources: https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/modules/permissions/permission_descriptor.idl?originalUrl=https:%2F%2Fcs.chromium.org%2Fchromium%2Fsrc%2Fthird_party%2Fblink%2Frenderer%2Fmodules%2Fpermissions%2Fpermission_descriptor.idl – Alex Nikulin Jul 13 '20 at 07:15
  • @AlexNikulin I see that I can look at specific tags which correspond to release versions. Is there a similar (versioned, simple-to-parse) file for Firefox, Edge, etc.? I can get the browser version and then fetch and parse these. – jsejcksn Jul 13 '20 at 08:18
  • @jsejcksn as you can see mozilla refers to chromium too. Edge is webkit too, so you can took from chromium sources (and commented properties as well) – Alex Nikulin Jul 13 '20 at 10:23
  • firefox sources https://dxr.mozilla.org/mozilla-central/source/remote/test/puppeteer/src/protocol.d.ts#874 – Alex Nikulin Jul 13 '20 at 10:24

3 Answers3

2

Take it from browser sources

Alex Nikulin
  • 8,194
  • 4
  • 35
  • 37
0

The Permissions API is still under development and the current spec doesn't allow for checking which permissions are granted nor which ones are available unless queried by the async method you've integrated above.

Perhaps one day something like Object.keys(Permissions.prototype) will become available, just like Object.keys(Navigator.prototype)

For now you'll need to keep consulting the "Browser Support" section in MDN or the registry.

Joe - GMapsBook.com
  • 15,787
  • 4
  • 23
  • 68
0

Like joe said, this is currently not possible, at least not in Chrome 83. The list of supported permissions are not directly accessible from JavaScript, as they only exist in C++ the browser is compiled from.

Note how navigator.permissions.query.toString() in Chrome returns ƒ query() { [native code] }.

That said, Chromium and the Blink engine are open source, so we can take a peek at what's going on.

This file has a big function called ParsePermissionDescriptor that handles the logic of converting the string passed to query and checking it against available permissions. We can examine what this function does:

  PermissionDescriptor* permission =
      NativeValueTraits<PermissionDescriptor>::NativeValue(
          script_state->GetIsolate(), raw_descriptor.V8Value(),
          exception_state);
  if (exception_state.HadException())
    return nullptr;
  const String& name = permission->name();
  if (name == "geolocation")
    return CreatePermissionDescriptor(PermissionName::GEOLOCATION);

So we get the name, then compare it against a string. If they're equal, we return a new PermissionDescriptor.

  if (name == "clipboard-read" || name == "clipboard-write") {
    PermissionName permission_name = PermissionName::CLIPBOARD_READ;
    if (name == "clipboard-write")
      permission_name = PermissionName::CLIPBOARD_WRITE;
    ClipboardPermissionDescriptor* clipboard_permission =
        NativeValueTraits<ClipboardPermissionDescriptor>::NativeValue(
            script_state->GetIsolate(), raw_descriptor.V8Value(),
            exception_state);
    return CreateClipboardPermissionDescriptor(
        permission_name, clipboard_permission->allowWithoutGesture(),
        clipboard_permission->allowWithoutSanitization());
  }

But we're also dealing with these more complex permissions with their own constructors, like CreateClipboardPermissionDescriptor.

At any rate, you can look through the file and try all the values checked by name == "some-string" (notice how the error messages returned for disabled permissions are what you get back with your logSupportedPermissions function) , but I don't know how you'd be able to get that programmatically.

eberts
  • 121
  • 6