Skip to content

Conversation

@carlosjeurissen
Copy link
Contributor

Related issue: #790

@carlosjeurissen carlosjeurissen changed the title Add permissions.canAccess proposal Add browser.permissions.canAccess() proposal Mar 28, 2025
Comment on lines 61 to 62
// Can inject scripts only
injectOnly: boolean,
Copy link
Collaborator

@xeenon xeenon Mar 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m not sure what injectOnly is intended to represent. Host access is typically binary — either the extension has access to the host or it doesn’t. When would this field be true? What APIs would be allowed or disallowed in that case?

Unless there’s a concrete and well-defined use case for this, I suggest removing injectOnly to keep the API simple and predictable.

Copy link
Contributor Author

@carlosjeurissen carlosjeurissen Mar 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

injectOnly indicates extensions are allowed to executeScripts but not fetch resources the origin resources.

Currently, in Chrome, activeTab grants both injection access and host access for fetch requests.

While Firefox and Safari do currently not grant host access for fetch requests.

See the following demo:
https://github.com/carlosjeurissen/webext-tech-demo-extensions/tree/main/demos/permissions-active-tab-host-access

If this is not supposed to happen I want my reward money from Google)

Weirdly enough in all browsers running browser.permissions.contains() still gives false.

Nonetheless, injectOnly is not very descriptive and implies the Chrome behaviour is default.

To resolve this, we can replace canAccess and injectOnly with scriptingAccess and hostAccess. This also resolves the repeated canAccess naming in the result.

Copy link
Collaborator

@xeenon xeenon Mar 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. That is currently an oversight in Safari, and maybe Firefox as well. I think we should match Chrome here and not bifurcate host permissions like this. I filed bug 290764 to track fixing this in Safari / WebKit.

The fact that permissions.contains() still gives false is expected, since the activeTab host permissions are scoped to a single tab and not global. If permissions.contains() took a tabId we could fix that too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xeenon currently in Chrome the host permissions are global for the extension and not scoped to a single tab. Just confirmed this in Chrome 134.

@Rob--W What do you think about matching Chrome's behaviour here for Firefox like Safari is considering?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems with the current behaviour in Firefox and Safari with activeTab, the API can only determine scriptingAccess if the API is supplied a tabId, frameId or documentId. Updated the PR to reflect this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@carlosjeurissen activeTab grants host permissions globally in Chrome? That is surprising and not what I understood the feature to do. If only we had a spec…

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not sold on bifurcating host permissions into scripting and host access. That "bug" should not be entombed into this as API.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xeenon currently in Chrome the host permissions are global for the extension and not scoped to a single tab. Just confirmed this in Chrome 134.

@Rob--W What do you think about matching Chrome's behaviour here for Firefox like Safari is considering?

Discussed today at #823
In short, willing to consider aligning. Still wondering whether it would make sense to have a distinction between fetch vs content script access.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rob--W In general extension can already do fetch requests by proxying the requests via the contentScripts. Making a distinction between fetch vs content script access would only make sense if Firefox and Safari do not plan to align with the Chrome behaviour before adding support for permissions.canAccess().

As @zombie mentioned aligning is not straightforward for Firefox at this moment, inclined to design the API returning scriptingAccess and hostAccess or similar naming. Which at some point will both either be true / false once Firefox and Safari align with Chrome.


```ts
dictionary AccessQuery {
url: string,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also support pattern for a match pattern.

@hanguokai
Copy link
Member

It would be best to add a section explaining the differences between permissions.canAccess() and permissions.contains(), as well as guidance on which API to use in different scenarios.

carlosjeurissen and others added 6 commits March 31, 2025 15:25
Co-authored-by: Timothy Hatcher <timothy@hatcher.name>
Co-authored-by: Timothy Hatcher <timothy@hatcher.name>
Co-authored-by: Timothy Hatcher <timothy@hatcher.name>
Co-authored-by: Timothy Hatcher <timothy@hatcher.name>
…tion of accessOnce, fill in Exposed Sensitive Data
@carlosjeurissen
Copy link
Contributor Author

@hanguokai the difference between permissions.contains() vs permissions.canAccess() would be great to document on mdn once permissions.canAccess() is available. As for this PR, updated it to be more clear as to why permissions.contains is not sufficient.

@hanguokai
Copy link
Member

If I understand correctly, developers will use code like this:

async function canDoSomething(url) {
  // check host permission
  const hasPermission = await permissions.contains({ origins: [url] });
  if (!hasPermission) {
    const granted = await permissions.request({ origins: [url] });
    if (!granted) {
      return 'no-permission';
    }
  }

  // check can access
  const canAccess = await permissions.canAccess({ url: url });
  if (!canAccess) {
    return 'no-access';
  }

  return 'yes';
}

const result = await canDoSomething(url);
if (result == 'no-permission') {
  // tell the user I don't have permission to do it
} else if (result == 'no-access') {
  // tell the user that there is nothing I can do
} else {
  doSomething();
}

@carlosjeurissen
Copy link
Contributor Author

@hanguokai There is an edge case to consider in which extensions are granted only temporary hostAccess in the case of activeTab. In this situation, currently permissions.contains() would return false while permissions.canAccess() would return true. However not sure how much of a conscious decision this is based on. It might be a bug in the permissions.contains API.

The way you coded this example does bring up the question how extensions should address the lack of access. As with the current response no indication for this is given. The user might not have granted permanent host permissions. The host permissions might be present but the host is excluded with some enterprise policy. Introducing some reasons property could make sense. Something like disallowedReason: "browserExcluded".

@hanguokai
Copy link
Member

activeTab is tightly bound to a few APIs, so I never check it when I use it.

@xeenon
Copy link
Collaborator

xeenon commented Apr 1, 2025

As with the current response no indication for this is given. The user might not have granted permanent host permissions. The host permissions might be present but the host is excluded with some enterprise policy. Introducing some reasons property could make sense. Something like disallowedReason: "browserExcluded".

Having a reason would be helpful. Some other cases:

  • Users in Safari can deny any host in website settings (either requested or a currently open tab)
  • Users can grant them temporarily for 24 hours — we could include an expiration date property.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants