Handlers using Async/await are prevented from using "sidebarAction.open()" and other APIs requiring user-interaction
Categories
(WebExtensions :: General, enhancement, P5)
Tracking
(Not tracked)
People
(Reporter: bluesky42624, Unassigned)
References
(Depends on 1 open bug, Blocks 1 open bug)
Details
(Whiteboard: [design-decision-approved])
Attachments
(1 file)
2.37 KB,
application/zip
|
Details |
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:107.0) Gecko/20100101 Firefox/107.0
Steps to reproduce:
- Set up a simple test extension with 3 files,
manifest.json
,background.js
, andsidebar.html
, like the attached example. - Open Firefox
- Go to
about:debugging
Load Temporary Add-on...
- Select the
manifest.json
file - Open the background script console through the
Inspect
button - Click on the
about:debugging
page again to give the focus back to the browser instance - Do
Ctrl+Shift+S
(or the exact shortcut defined in themanifest.json
file before)
Actual results:
Case 1 and Case 2 works as expected, but Case 3 with the await call is denied access to the API due to the following error:
Uncaught (in promise) Error: sidebarAction.open may only be called from a user input handler
Expected results:
3 cases are provided in the background.js
file, Case 1 is a simple non-async handler, Case 2 is an async handler without any await
calls within, and finally Case 3 being the typical case of an async handler with an await
call. All three should open the sidebarAction, since all three handlers are essentially no-ops other than that one call to browser.sidebarAction.open();
.
Reporter | ||
Comment 1•2 years ago
|
||
This is especially an issue for Manifest v3 since:
- Manifest v3/non-persistent background pages mean, that all states need to be stored in
browser.storage
browser.storage
is async- Event handlers inside background pages commonly need to access state data, stored data, settings, etc.
- APIs that require being called
from inside the handler for a user action.
prevent any event handlers usingPromises
andasync
/await
's from calling it - There is no workaround, since
browser.storage
is completely async - Data access becomes impossible from background page event handlers needing the use of APIs requiring
user action
Comment 2•2 years ago
|
||
The Bugbug bot thinks this bug should belong to the 'WebExtensions::Untriaged' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.
Updated•2 years ago
|
Comment 3•2 years ago
|
||
The user interaction requirements are already being dropped for browserAction.openPopup
(bug 1755763) and pageAction.openPopup
(bug 1798425). In these cases, the action panel is a floating window on top of the current window, and dismissed when the user clicks elsewhere.
In the sidebarAction API, the panel is a sidebar (at the left). The user can identify the extension by the header that contains the extension icon and name. The sidebar content underneath can be extension-hosted content, or even a remote URL (specified by the extension). This was initially implemented in bug 1208596, with the ability to open the sidebar with user interaction in bug 1341126.
While the ability to open the sidebar without user interaction has potential for abuse, I don't think that it's a great risk, because the same capability already exists in the form of resizing the window and opening a popup next to it. There is the question on what to do when another sidebar already exists; that is already an issue with the current API, but cautiously I'd be inclined to reject the API call when that situation occurs.
If we are somehow reluctant to drop the user interaction requirement altogether, then there are various approaches we can take to balance the desire of users/extensions to open sidebar against abuse patterns:
- Drop the user interaction requirement al together.
- Conditionally drop the user interaction requirement.
- e.g. only after the user has opened the panel at least once
- and/or requiring a permission.
- and/or a preference.
- and/or if the user has opted in via new UI as part of bug 1787179.
- Keep the user interaction requirement, but extent the validity of a user interaction by a number of seconds (arbitrarily chosen, e.g. 5 seconds).
- Keep the status quo (i.e. wontfix this bug) - require user interaction for
sidebarAction.open
.
I'm in favor of dropping the user interaction requirement for sidebarAction.open
. In discussion with the team, there were some mild concerns over potential abuse, but no strong opinions either way.
Comment 4•2 years ago
|
||
:dveditz : Do you see any concern with allowing extensions to open their sidebar without user interaction? More context is available in comment 3.
Updated•2 years ago
|
Comment 5•1 year ago
|
||
In addition to what has been said in comment 3, the team affirmed again that consistency with browserAction.openPopup / pageAction.openPopup is desirable.
Comment 6•16 days ago
|
||
The same underlying issue is still present in other async event handlers, such as situations where a value needs to be retrieved from storage before calling permissions.request()
or interacting with the system clipboard.
To my knowledge the primary concern with passing a user input flag down a promise chain is that this could enable abuse scenarios where an extension holds onto a promise with a valid user interaction and consume it later without the user's knowledge. I think the most obvious way to mitigate this kind of abuse is to make a user interaction invalid a short amount of time after the input. For example, a user input flag might be consumable for up to 200 millisecond after the user initiates the interaction.
The main drawback to this approach is that a fixed time limit may feel arbitrary and unpredictable for extension developers. For example, some browser.storage operations will complete within this time period while others will not. External factors may also impact whether or not a promise chain resolves in time, such as lower powered devices or resource contention on higher power systems.
A fixed lifetime isn't ideal, but at the moment it strikes me as the most practical solution for a material problem facing developers.
Comment 7•14 days ago
|
||
Nowadays the web platform defines the concept of "transient user activation", which is a short-lived period of time where an API gated by user activation can be used. Some APIs consume the transient user activation upon invocation.
Documentation: https://developer.mozilla.org/en-US/docs/Web/Security/User_activation#transient_activation
The recommended value for the timeout is specified to be "at most a few seconds", and in practice Firefox uses 5 seconds in Firefox: https://searchfox.org/mozilla-central/rev/5756c5a3dea4f2896cdb3c8bb15d0ced5e2bf690/modules/libpref/init/StaticPrefList.yaml#4356-4360
I think that we can consider integrating the concept of user activation in the extension framework to support this use case more broadly.
Comment 8•5 days ago
•
|
||
The discussion above on user gesture / user activation fits better at bug 1398833. The request here is specifically about the sidebarAction.open
, for which a potential solution could be to drop the user interaction requirement from the API as noted in comment 3.
Updated•5 days ago
|
Description
•