Contact emails
Explainer
https://mustaqahmed.github.io/user-activation-v2/
Spec
Spec proposal to replace currently incomplete section in HTML Living Standard.
TAG review request: https://github.com/w3ctag/design-reviews/issues/295
Summary
Browsers control access to "abusable" of APIs (e.g. opening popups or vibrating) through user activation (or "user gestures"). This lacks a reasonable spec, and major browsers today exhibit widely divergent behavior.
User Activation v2 (UAv2) defines a behavior that is simple enough for cross-browser implementation while supporting all major use cases. In this model, user activation states will be maintained in frames, replacing Chromium’s current stack-based tokens that activation-aware APIs are expected to store/forward as needed.
Link to “Intent to Implement” blink-dev discussion
https://groups.google.com/a/chromium.org/d/msg/blink-dev/bJ2icZEANV4/5VlT_RKrBgAJ
Link to Origin Trial feedback summary
We are currently running a trial on M69 Canary/Dev.
Is this feature supported on all six Blink platforms (Windows, Mac, Linux, Chrome OS, Android, and Android WebView)?
Yes.
Demo link
Shows user activation visibility across the frame tree through popups (needs chrome://flags/#user-activation-v2): https://mustaqahmed.github.io/user-activation-v2/propagation/
Debuggability
UAv2 won’t require DevTools changes: it can be tested through activation-aware APIs (e.g. fullscreen and vibration) in the same way we do today with existing implementations.
However, UAv2 introduces a subtle difference in Chromium when the testing involves interleaved user interaction between the web page and DevTools. One challenge we have with the existing implementation is that is that interactions with DevTools (e.g. typing, clicking) clobber page’s activation state. UAv2’s removal of stack-allocated tokens widens the scope of this clobbering, but only for transient activation state. It’s a narrow corner case, so we don’t think it’s something developers would notice. If this turns out otherwise, we can turn off UAv2 notifications from DevTools to renderer/browser (could be through an option).
Risks
Interoperability and Compatibility
User activation behavior is currently inconsistent among the major browsers in many different ways (e.g. for popups and with triggering events), so the interop question is moot here. UAv2 in fact sets a good direction for future interop: the simplicity of the model makes it easier for the Web to possibly converge in future.
Compat risk should be low because the token-less model of UAv2 would mostly appear as filling incompleteness in current behavior (e.g. with Promise, postMessages, XHR, setTimeout etc). Sources of possible risks are as follows:
User activation visibility changes from renderer-wide to frame-scoped, which won’t work if a child frame tries to access parent’s activation. We haven’t seen any real breakage like this. More importantly, the current renderer-wide visibility model is already broken with site-isolation (except where we added a hack, like this).
We have some risk around popup blocking because of complexities around user activation state during navigations. The cases we have seen so far (e.g. crbug.com/807609 and a very recent one: crbug.com/867599) are implementation cracks rather than model problems, hence fixable.
Edge: No public signals.
Firefox: Mixed signals (publicly reviewed the design, raised a single concern so far).
Safari: No signals.
Web developers: Positive (e.g. appreciated on a popular bug, suggested a tweak).
Ergonomics
UAv2 won’t cause any performance issue.
Activation
Nothing should change from developers’ perspective since they don’t use user activation directly (instead indirectly rely on it through activation-aware APIs).
A polyfill is not applicable: browser shouldn’t let webpages mimic user activation.
Is this feature fully tested by web-platform-tests?
We have partial coverage for UAv2 in wpt today:
Frame-hierarchy visibility is tested through existing fullscreen/ tests containing <iframe>s.
We can’t currently test UAv2 consumption behavior because popups are disabled in wpt.
We plan to add test coverage for UAv2 in an user-API-agnostic way in html/user-activation/ once JS API for querying User Activation ships.
Entry on the feature dashboard
https://www.chromestatus.com/features/5722065667620864
--
You received this message because you are subscribed to the Google Groups "blink-dev" group.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/blink-dev/SN6PR05MB4878404DC6A18E83333311C7DF2F0%40SN6PR05MB4878.namprd05.prod.outlook.com.
We got a bug report that the BeforeInstallPromptEvent.prompt() method can be called repeatedly without a user gesture: https://crbug.com/869756 (btw, dominickn@ and I am responsible for this API but I've assigned to you initially for your opinion; if you just want us to change it to consume the token we can do that).
I'll dive into that below, but firstly, I think this bug shows that there are issues with UAv2 that need to be worked out before it launches. This doesn't just affect BeforeInstallPrompt, but potentially any other API that reads the user gesture token without consuming it. I think the UAv2 team needs to audit all the APIs to see where else this can go wrong. We need some advice on whether we should always consume user gesture tokens when we use them. (The advice given for BIP was not to consume the token, because it's valid to perform several user-gesture-requiring actions within the timeout. It seems this advice is no longer valid, and we should be consuming the token.)
As I said on the bug, we could change BeforeInstallPrompt.prompt() so that it consumes the user gesture token (although this was not the advice given at the time). However, that wouldn't fix what I see as the more critical design issue with UAv2. Let's assume for the rest of this analysis that we've made it consume the token.Correct me if I'm wrong (my understanding of UAv2 is based on a discussion I had with dominickn@). It seems that under UAv1, each execution context had its own user gesture token. This means you could have something like the following sequence:
- User clicks a button. The click handler has a user gesture token. It fires a setTimeout(500).
- The beforeinstallprompt event fires. Inside that event, there is no user gesture token, so you can't show a prompt.
- The setTimeout completes, calling a callback. The callback has the user gesture token which was inherited from the click event handler. We can show a prompt from here.
So it's possible to have a user gesture token available to some contexts (those that were directly or indirectly triggered by a user gesture) but not others, at the same time. It seems that UAv2 is missing that nuance. There is effectively a global user gesture token that lasts until it's consumed. If there's a click event (whose user gesture is not consumed), then the user gesture flag is available to the BIP event and any other event handler that isn't triggered by a user gesture, for an unlimited amount of time. So now we have:
- User clicks a button. The page has a user gesture token. It fires a setTimeout(500).
- The beforeinstallprompt event fires. Inside that event, we have access to the global user gesture token, so we can show a prompt.
- The setTimeout completes, calling a callback. The callback no longer has access to the user gesture token, because it was consumed by the prompt() method.
It seems fundamentally broken that contexts that were neither directly nor indirectly triggered by a user gesture can perform user-gesture-requiring operations (and this seems to be by design in UAv2).
Now you may say "but Matt, a specially crafted site could already do this under UAv1 by carefully managing the user gesture token". Yep, something like this would work under UAv1:let stashed_bip = null;window.addEventListener('click', () => {setTimeout(() => {if (stashed_bip !== null)stashed_bip.prompt();}, 900);});window.addEventListener('beforeinstallprompt', e => {e.preventDefault();stashed_bip = e;});Any click before the "beforeinstallprompt" event will wait 900ms to see if a BIP came in during that time, and if it did, it can show a prompt using the click handler's user gesture token.
However, this requires deliberate effort on part of the site author. All you have to do under UAv2 to achieve the same thing is this:window.addEventListener('beforeinstallprompt', e => {e.preventDefault();e.prompt();});Which can easily be done by accident. In fact, we have a couple of real-world sites (https://dory.withgoogle.com) that exhibit this behaviour by accident. Calling prompt() from within the "beforeinstallprompt" event handler is actually a reasonable thing to do, because other user agents may allow prompt() without a user gesture but show a non-modal dialog. Also there is no longer a timeout under UAv2. The point is that UAv2 makes it significantly easier to accidentally take advantage of a user gesture token in an event handler that was not triggered by a user gesture.
Mustaq, are you now working through
https://github.com/whatwg/html/issues/3859, should we consider this
intent on hold?
--
You received this message because you are subscribed to the Google Groups "blink-dev" group.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/blink-dev/ed650b4f-f586-7312-d83f-d92c80c88df6%40mit.edu.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/blink-dev/CAFUtAY8QMhQoukO3JUr0yWPOyD%3Dx2UDYs-xQvYNp0HnFU%2Bzoeg%40mail.gmail.com.;-Dom.
...
Firefox does not consider a 30sec timeout acceptable for the full-screen
API as a matter of user safety. There is too much potential for abuse
there; the fullscreen prompt needs to be clearly connected to the user
action in the user's mind, and a 30-second lag is far too long for that.
So to have an API with a single uniform timeout we would need to have a
a 1sec timeout across the board (and some confidence that there is no
breakage from that).
> (and we can change things in future if we
> encounter a specific need).
I am pointing to a specific need now, unless the proposal is to have a
1sec timeout across the board.
Usually it's ok for a sight to do something as a direct response to a user
action. "Direct" is a bit hard to define, but a reasonable interpretation
is that nothing else should happen between the user action and the
response.
Today that is partly handled by a consumable token following the
chain of events. Will that go away, and if so, is there any other system
that can connect an action with the result?
A timer might still be good, especially to limit chains of async events
(if those should be allowed at all?), but onclick="window.open()" should
really work regardless how slow a computer is.
--
You received this message because you are subscribed to the Google Groups "blink-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blink-dev+...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/blink-dev/CAARdPYcV0Y6ZFOC9iaF5BDbPj8eT6fKXMfS4Y%3D3Tw2RQmbqpHg%40mail.gmail.com.