Skip to content

Added a new section on User Activation v2. #3851

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Dec 4, 2019
262 changes: 202 additions & 60 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -30260,8 +30260,8 @@ interface <dfn>HTMLIFrameElement</dfn> : <span>HTMLElement</span> {
keyword allows the content to <span>navigate</span> its <span>top-level browsing context</span>;
the <code
data-x="attr-iframe-sandbox-allow-top-navigation-by-user-activation">allow-top-navigation-by-user-activation</code>
keyword behaves similarly but only allows such <span data-x="navigate">navigation</span> when
<span>triggered by user activation</span>; and the <code
keyword behaves similarly but allows such <span data-x="navigate">navigation</span> only when
the browsing context has <span>transient activation</span>; and the <code
data-x="attr-iframe-sandbox-allow-forms">allow-forms</code>, <code
data-x="attr-iframe-sandbox-allow-modals">allow-modals</code>, <code
data-x="attr-iframe-sandbox-allow-orientation-lock">allow-orientation-lock</code>, <code
Expand Down Expand Up @@ -35017,8 +35017,9 @@ interface <dfn>MediaError</dfn> {
<p>A <span>media element</span> is said to be <dfn>allowed to play</dfn> if the user agent and the
system allow media playback in the current context.</p>

<p class="note">For example, a user agent could require that playback is <span>triggered by user
activation</span>, but an exception could be made to allow playback while <span
<p class="example">For example, a user agent could allow playback only when the <span>media
element</span>'s <code>Window</code> object has <span>transient activation</span>, but an
exception could be made to allow playback while <span
data-x="concept-media-muted">muted</span>.</p>

<p>A <span>media element</span> is said to have <dfn>ended playback</dfn> when:</p>
Expand Down Expand Up @@ -47892,8 +47893,8 @@ ldh-str = &lt; as defined in <a href="https://tools.ietf.org/html/rfc1034#
<p>The element's <span>input activation behavior</span> is to run the following steps:</p>

<ol>
<li><p>If the algorithm is not <span>triggered by user activation</span>, then return
without doing anything else.</p></li>
<li><p>If the algorithm is invoked when the element's <code>Window</code> object does not have
<span>transient activation</span>, then return without doing anything else.</p></li>

<li>
<p>Run these steps <span>in parallel</span>:</p>
Expand Down Expand Up @@ -73215,63 +73216,205 @@ END:VCARD</pre>



<h3>Tracking user activation</h3>

<h3>Activation</h3>

<p>Certain elements in HTML have an <span>activation behavior</span>, which means that the user
can activate them. This is always caused by a <code data-x="event-click">click</code> event.</p>
<p>To prevent abuse of certain APIs that could be annoying to users (e.g., opening popups or
vibrating phones), user agents allow these APIs only when the user is actively interacting with
the web page or has interacted with the page at least once. This "active interaction" state is
maintained through the mechanisms defined in this section.</p>

<div w-nodev>

<p>The user agent should allow the user to manually trigger elements that have an <span>activation
behavior</span>, for instance using keyboard or voice input, or through mouse clicks. When the
user triggers an element with a defined <span>activation behavior</span> in a manner other than
clicking it, the default action of the interaction event must be to <span>fire a <code
data-x="event-click">click</code> event</span> at the element.</p>
<!-- interaction event spec point -->
<h4 id="user-activation-data-model">Data model</h4>

<p id="allowed-to-show-a-popup">An algorithm is <dfn data-export="">triggered by user
activation</dfn> if any of the following conditions is true:</p>
<p>For the purpose of tracking user activation, each <code>Window</code> <var>W</var> has a
<dfn>last activation timestamp</dfn>. This is a number indicating the last time <var>W</var> got
an <span>activation notification</span>. It corresponds to a
<span><code>DOMHighResTimeStamp</code></span> value except for two cases: positive infinity
indicates that <var>W</var> has never been activated, while negative infinity indicates that a <a
href="#user-activation-gated-apis">user activation-gated API</a> has <span data-x="consume user
activation">consumed</span> the last user activation of <var>W</var>. The initial value is
positive infinity.</p>

<ul>
<li><p>The <span data-x="concept-task">task</span> in which the algorithm is running is currently
processing an <span>activation behavior</span> whose <code data-x="event-click">click</code>
event's <code data-x="dom-Event-isTrusted">isTrusted</code> attribute is true.</li>
<p>A user agent also defines a <dfn>transient activation duration</dfn>, which is a constant
number indicating how long a user activation is available for certain <a
href="#user-activation-gated-apis">user activation-gated APIs</a> (e.g., for opening popups).</p>

<li>
<p>The <span data-x="concept-task">task</span> in which the algorithm is running is currently
running the event listener for an event whose <code
data-x="dom-Event-isTrusted">isTrusted</code> attribute is true and whose <code
data-x="dom-Event-type">type</code> is one of:</p>
<p class="note">The <span>transient activation duration</span> is expected be at most a few
seconds, so that the user can possibly perceive the link between an interaction with the page and
the page calling the activation-gated API.</p>

<ul class="brief">
<li><code data-x="event-change">change</code></li>
<li><code data-x="event-click">click</code></li>
<li><code data-x="event-contextmenu">contextmenu</code></li>
<li><code data-x="event-dblclick">dblclick</code></li>
<li><code data-x="event-mouseup">mouseup</code></li>
<li><code data-x="event-pointerup">pointerup</code></li>
<li><code data-x="event-reset">reset</code></li>
<li><code data-x="event-submit">submit</code></li>
<li><code data-x="event-touchend">touchend</code></li>
</ul>
<p>These two values imply two boolean user activation states for <var>W</var> as well as
<var>W</var>'s corresponding <span>browsing context</span>:</p>

</li>
<dl>
<dt><dfn data-export="">Sticky activation</dfn></dt>
<dd>
<p>When the <span>current high resolution time</span> is greater than or equal to the <span>last
activation timestamp</span> in <var>W</var>, <var>W</var> is said to have <span>sticky
activation</span>.</p>

<p>This is <var>W</var>'s historical activation state, indicating whether the user has ever
interacted in <var>W</var>. It starts false, then changes to true (and never changes back to
false) when <var>W</var> gets the very first <span>activation notification</span>.</p>

<p>A <span>browsing context</span> <var>B</var> is said to have <span>sticky activation</span>
if <var>B</var>'s <code>WindowProxy</code>'s [[Window]] value has <span>sticky
activation</span>.</p>
</dd>

<dt><dfn data-export="">Transient activation</dfn></dt>
<dd>
<p>When the <span>current high resolution time</span> is greater than or equal to the <span>last
activation timestamp</span> in <var>W</var>, and less than the <span>last activation
timestamp</span> in <var>W</var> plus the <span>transient activation duration</span>, then
<var>W</var> is said to have <span>transient activation</span>.</p>

<p>This is <var>W</var>'s current activation state, indicating whether the user has interacted
in <var>W</var> recently. This starts with a false value, and remains true for a limited time
after every <span>activation notification</span> <var>W</var> gets.</p>

<p>A <span>browsing context</span> <var>B</var> is said to have <span>transient
activation</span> if <var>B</var>'s <code>WindowProxy</code>'s [[Window]] value has
<span>transient activation</span>.</p>

<p>The <span>transient activation</span> state is considered <dfn
data-x="activation-expiry">expired</dfn> if it becomes false because the <span>transient
activation duration</span> time has elapsed since the last user activation. Note that it can
become false even before the expiry time through an <span data-x="consume user
activation">activation consumption</span>.</p>
</dd>
</dl>

<h4 id="user-activation-processing-model">Processing model</h4>

<p>When a user interaction in a <span>browsing context</span> <var>B</var> causes firing of an
<span>activation triggering input event</span> in <var>B</var>, the user agent must perform the
following <dfn>activation notification</dfn> steps <em>before</em> <span
data-x="concept-event-dispatch">dispatching</span> the event:</p>

<ol>
<li>
<p>The <span data-x="concept-task">task</span> in which the algorithm is running was <span
data-x="queue a task">queued</span> by an algorithm that was <span>triggered by user
activation</span>, and the chain of such algorithms started within a user-agent defined
timeframe.</p>
<p>Let <var>browsingContexts</var> be a list consisting of:</p>
<ul>
<li><p><var>B</var>,</p></li>

<li><p>all <span data-x="ancestor browsing context">ancestor browsing contexts</span> of
<var>B</var>, and</p></li>

<p class="example">For example, if a user clicked a button, it might be acceptable for a popup
to result from that after 4 seconds, but it would likely not be acceptable for a popup to result
from that after 4 hours.</p>
<li><p>all the <span data-x="child browsing context">child browsing contexts</span> of
<var>B</var> that have <span data-x="active document">active documents</span> whose
<span>origin</span> is the <span data-x="same origin">same</span> as that of the <span>active
document</span> of <var>B</var>.</p></li>
</ul>
</li>

<li><p>Let <var>windows</var> be the list of <code>Window</code> objects constructed by taking
the [[Window]] internal slot value of <var>browsingContext</var>'s <code>WindowProxy</code>
object for each <var>browsingContext</var> in <var>browsingContexts</var>.</p></li>

<li><p><span data-x="list iterate">For each</span> <var>window</var> in <var>windows</var>, set
<var>window</var>'s <span>last activation timestamp</span> to the <span>current high resolution
time</span>.</p></li>
</ol>

<p>An <dfn>activation triggering input event</dfn> is any event whose <code
data-x="dom-Event-isTrusted">isTrusted</code> attribute is true and whose <code
data-x="dom-Event-type">type</code> is one of:</p>

<ul class="brief">
<li><code data-x="event-change">change</code></li>
<li><code data-x="event-click">click</code></li>
<li><code data-x="event-contextmenu">contextmenu</code></li>
<li><code data-x="event-dblclick">dblclick</code></li>
<li><code data-x="event-mouseup">mouseup</code></li>
<li><code data-x="event-pointerup">pointerup</code></li>
<li><code data-x="event-reset">reset</code></li>
<li><code data-x="event-submit">submit</code></li>
<li><code data-x="event-touchend">touchend</code></li>
</ul>

<p class="XXX">The event set is inconsistent across major browsers. See <a
href="https://github.com/whatwg/html/issues/3849">issue #3849</a>.</p>

<p><span data-x="activation consuming API">Activation consuming APIs</span> defined in this and
other specifications can <dfn data-export="">consume user activation</dfn> by performing the
following steps, given a <code>Window</code> <var>W</var>:</p>

<ol>
<li><p>If <var>W</var>'s <span data-x="window bc">browsing context</span> is null, then
return.</p></li>

<li><p>Let <var>top</var> be <var>W</var>'s <span data-x="window bc">browsing context</span>'s
<span>top-level browsing context</span>.</p></li>

<li><p>Let <var>browsingContexts</var> be the <span>list of the descendant browsing
contexts</span> of <var>top</var>'s <span>active document</span>.</p></li>

<li><p><span data-x="list append">Append</span> <var>top</var> to
<var>browsingContexts</var>.</p></li>

<li><p>Let <var>windows</var> be the list of <code>Window</code> objects constructed by taking
the [[Window]] internal slot value of <var>browsingContext</var>'s <code>WindowProxy</code>
object for each <var>browsingContext</var> of <var>browsingContexts</var>.</p></li>

<li><p><span data-x="list iterate">For each</span> <var>window</var> in <var>windows</var>, if
<var>window</var>'s <span>last activation timestamp</span> is not positive infinity, then set
<var>window</var>'s <span>last activation timestamp</span> to negative infinity.</p></li>
</ol>

<p class="XXX">The spec is not clear about how to traverse a tree of documents. See <a
href="https://github.com/whatwg/html/issues/5020">issue #5020</a>.</p>

<p class="note">Note the asymmetry in the sets of <span data-x="browsing context">browsing
contexts</span> in the page that are affected by an <span>activation notification</span> vs an
<span data-x="consume user activation">activation consumption</span>: an activation consumption
changes (to false) the <span>transient activation</span> states for all browsing contexts in the
page, but an activation notification changes (to true) the states for a subset of those browsing
contexts. The exhaustive nature of consumption here is deliberate: it prevents malicious sites
from making multiple calls to an <span>activation consuming API</span> from a single user
activation (possibly by exploiting a deep hierarchy of <code>iframe</code>s).</p>

<h4 id="user-activation-gated-apis">APIs gated by user activation</h4>

</div>

<p>APIs that are dependent on user activation are classified into three different levels. The
levels are as follows, sorted by their "strength of dependence" on user activation (from weakest
to strongest):</p>

<dl>
<dt><dfn data-x="sticky activation gated api">Sticky activation-gated APIs</dfn></dt>
<dd><p>These APIs require the <span>sticky activation</span> state to be true, so they are blocked
until the very first user activation.</p></dd>

<dt><dfn data-x="transient activation gated api">Transient activation-gated APIs</dfn><dt>
<dd><p>These APIs require the <span>transient activation</span> state to be true, but they don't
<span data-x="consume user activation">consume</span> it, so multiple calls are allowed per user
activation until the transient state <span data-x="activation-expiry">expires</span>.</p></dd>

<dt><dfn data-x="activation consuming api">Transient activation-consuming APIs</dfn></dt>
<dd><p>These APIs require the <span>transient activation</span> state to be true, and they
<span>consume user activation</span> in each call to prevent multiple calls per user
activation.</p></dd>
</dl>



<h3 id="activation">Activation behavior of elements</h3>

<p>Certain elements in HTML have an <span>activation behavior</span>, which means that the user
can activate them. This is always caused by a <code data-x="event-click">click</code> event.</p>

<div w-nodev>

<p>The user agent should allow the user to manually trigger elements that have an <span>activation
behavior</span>, for instance using keyboard or voice input, or through mouse clicks. When the
user triggers an element with a defined <span>activation behavior</span> in a manner other than
clicking it, the default action of the interaction event must be to <span>fire a <code
data-x="event-click">click</code> event</span> at the element.</p>

</div>

<!-- v2 idea: HTMLImageElement.click(x, y); or clickPoint(), if click() can't be done in IE; can
this be emulated in IE by posting a synthetic mouse click event with those X and Y coords?
Expand Down Expand Up @@ -78891,12 +79034,11 @@ console.assert(iframeWindow.frameElement === null);
then:</p>

<ol>
<li><p>If this algorithm is <span>triggered by user activation</span> and <var>A</var>'s
<span>active document</span>'s <span>active sandboxing flag set</span> has its <span>sandboxed
top-level navigation with user activation browsing context flag</span> set, then return
false.</p></li>
<li><p>If <var>A</var> has <span>transient activation</span> and <var>A</var>'s <span>active
document</span>'s <span>active sandboxing flag set</span> has its <span>sandboxed top-level
navigation with user activation browsing context flag</span> set, then return false.</p></li>

<li><p>Otherwise, if this algorithm is not <span>triggered by user activation</span> and
<li><p>Otherwise, if <var>A</var> does not have <span>transient activation</span> and
<var>A</var>'s <span>active document</span>'s <span>active sandboxing flag set</span> has its
<span>sandboxed top-level navigation without user activation browsing context flag</span> set,
then return false.</p></li>
Expand Down Expand Up @@ -79212,8 +79354,8 @@ console.assert(iframeWindow.frameElement === null);
applicable option from the following list:</p>

<dl class="switch">
<dt id="popup-blocker">If the algorithm is not <span>triggered by user activation</span> and
the user agent has been configured to not show popups (i.e. the user agent has a "popup
<dt id="popup-blocker">If <var>current</var> does not have <span>transient activation</span>
and the user agent has been configured to not show popups (i.e. the user agent has a "popup
blocker" enabled)</dt>

<dd><p>The user agent may inform the user that a popup has been blocked.</p></dd>
Expand Down Expand Up @@ -81357,8 +81499,8 @@ interface <dfn>BarProp</dfn> {

<p>This flag <a href="#sandboxLinks">prevents content from navigating their <span>top-level
browsing context</span></a> and <a href="#sandboxClose">prevents content from closing their
<span>top-level browsing context</span></a>. It is consulted only from algorithms that are
<em>not</em> <span>triggered by user activation</span>.</p>
<span>top-level browsing context</span></a>. It is consulted only when the sandboxed browsing
context does not have <span>transient activation</span>.</p>

<p>When the <span>sandboxed top-level navigation without user activation browsing context
flag</span> is <em>not</em> set, content can navigate its <span>top-level browsing
Expand All @@ -81376,8 +81518,8 @@ interface <dfn>BarProp</dfn> {

<p>This flag <a href="#sandboxLinks">prevents content from navigating their <span>top-level
browsing context</span></a> and <a href="#sandboxClose">prevents content from closing their
<span>top-level browsing context</span></a>. It is consulted only from algorithms that
<em>are</em> <span>triggered by user activation</span>.</p>
<span>top-level browsing context</span></a>. It is consulted only when the sandboxed browsing
context has <span>transient activation</span>.</p>

<p>As with the <span>sandboxed top-level navigation without user activation browsing context
flag</span>, this flag only affects the <span>top-level browsing context</span>; if it is not
Expand Down Expand Up @@ -83909,9 +84051,9 @@ interface <dfn>Location</dfn> { // but see also <a href="#the-location-interface
processor), user agents should attempt to mitigate the risk that this is an attempt to exploit the
target software, e.g. by prompting the user to confirm that the <span>source browsing
context</span>'s <span>active document</span>'s <span>origin</span> is to be allowed to invoke the
specified software. In particular, if the <span>navigate</span> algorithm, when it was invoked,
was not <span>triggered by user activation</span>, the user agent should not invoke the external
software package without prior user confirmation.</p>
specified software. In particular, if the <span>navigate</span> algorithm was invoked when
<span>source browsing context</span> does not have <span>transient activation</span>, the user
agent should not invoke the external software package without prior user confirmation.</p>

<p class="example">For example, there could be a vulnerability in the target software's URL
handler which a hostile page would attempt to exploit by tricking a user into clicking a link.</p>
Expand Down