Rendere l'attivazione utente coerente tra le API

Mustaq Ahmed
Joe Medley
Joe Medley

Per evitare che script dannosi utilizzino in modo illecito API sensibili come i popup, schermo intero e così via, i browser controllano l'accesso a queste API tramite dell'attivazione. L'attivazione utente è lo stato di una sessione di navigazione in relazione alle azioni dell'utente: la generazione implica in genere che l'utente sta interagendo con la pagina o ha completato un'interazione dalla pagina caricamento. Gesto dell'utente è un termine popolare ma fuorviante per la stessa idea. Per Ad esempio, un gesto di scorrimento o di scorrimento dell'utente non attiva la pagina, pertanto non è, dal punto di vista dello script, un'attivazione utente.

Oggi i principali browser mostrano comportamenti molto divergenti riguardo al modo in cui l'attivazione degli utenti controlla le API basate su attivazione. In Chrome, l'implementazione si basava basato su token che si è rivelato troppo complesso per definire il comportamento di tutte le API basate sull'attivazione. Ad esempio, Chrome è stato consentendo l'accesso incompleto alle API con attivazione postMessage() e setTimeout() chiamate; e l'attivazione dell'utente non è stata supportato con Promises, XHR, Interazione con il gamepad e così via. Tieni presente che alcuni dei sono infetti da tempo e molto diffusi.

Nella versione 72, Chrome offre Attivazione utente v2, che rende disponibilità dell'attivazione completata per tutte le API con attivazione. Questa operazione risolve le incoerenze indicate sopra (e altre, come MessageChannels), che riteniamo faciliterebbe il web sull'attivazione dell'utente. Inoltre, la nuova implementazione fornisce un'implementazione di riferimento per una proposta nuova specifica che mira a riunire tutti i browser nel lungo periodo.

Come funziona Attivazione utente v2?

La nuova API mantiene uno stato di attivazione utente a due bit per ogni oggetto window nella gerarchia dei frame: un bit fisso per lo stato storico di attivazione dell'utente (se un il frame ha mai visto l'attivazione di un utente) e un bit temporaneo per lo stato attuale. (se un frame ha rilevato l'attivazione di un utente entro circa un secondo). La punta adesiva non viene mai reimpostato durante il ciclo di vita del frame dopo che è stato impostato. Il bit transitorio viene impostato a ogni interazione dell'utente e viene reimpostato dopo una scadenza di servizio (circa un secondo) o tramite una chiamata a un'API che richiede l'attivazione (ad es. window.open()).

Tieni presente che le diverse API basate sull'attivazione si basano sull'attivazione dell'utente in modi; la nuova API non modificherà nessuno di questi comportamenti specifici dell'API. Ad es. è consentito un solo popup per attivazione utente perché window.open() utilizza come era in passato, Navigator.prototype.vibrate() continua essere efficace se un frame (o uno dei suoi frame secondari) ha subito azioni da parte degli utenti, e così via.

Cosa cambierà?

  • User Activation v2 formalizza la nozione di visibilità dell'attivazione dell'utente oltre i confini del frame: ora l'interazione dell'utente con un determinato frame attivare tutti i frame contenenti (e solo quelli) indipendentemente dai loro origine dati. In Chrome 72 abbiamo una soluzione alternativa temporanea per espandere visibilità a tutti i frame della stessa origine. Rimuoveremo questa soluzione alternativa una volta un modo per trasferire esplicitamente l'attivazione dell'utente ai frame secondari.)
  • Quando un'API basata sull'attivazione viene chiamata da un frame attivato, ma all'esterno del codice di un gestore di eventi, funzionerà finché l'attivazione dell'utente lo stato è "attivo" (ad es. non è scaduto né è stato consumato). Prima dell'utente Attivazione v2, l'azione verrebbe annullata incondizionatamente.
  • Più interazioni di utenti inutilizzati nell'intervallo di tempo di scadenza in un'unica attivazione corrispondente all'ultima interazione.

Esempi di coerenza nelle API basate sull'attivazione

Ecco due esempi di finestre popup (aperte utilizzando window.open()) che mostra come l'attivazione utente v2 genera il comportamento delle API basate sull'attivazione coerente.

Chiamate setTimeout() concatenate

Questo esempio proviene da la nostra demo su setTimeout(). Se un gestore click tenta di aprire un popup entro un secondo, dovrebbe operazione riuscita indipendentemente da come il codice "compone" il ritardo. Attivazione utente v2 soddisfa questa aspettativa, quindi ciascuno dei seguenti gestori di eventi apre un popup click (con un ritardo di 100 ms):

function popupAfter100ms() {
  setTimeout(callWindowOpen, 100);
}

function asyncPopupAfter100ms() {
  setTimeout(popupAfter100ms, 0);
}

someButton.addEventListener('click', popupAfter100ms);
someButton.addEventListener('click', asyncPopupAfter100ms);

Senza Attivazione utente v2, il secondo gestore di eventi ha esito negativo in tutti i browser viene testato. (Anche la prima non funziona in alcuni casi.

Chiamate postMessage() interdominio

Ecco un esempio la nostra demo su postMessage(). Supponiamo che un gestore click in un sottoframe multiorigine invii due messaggi direttamente al frame principale. Il frame principale dovrebbe essere in grado di aprire un popup su quando si ricevono uno di questi messaggi (ma non entrambi):

// Parent frame code
window.addEventListener('message', e => {
  if (e.data === 'open_popup' && e.origin === child_origin)
    window.open('about:blank');
});

// Child frame code:
someButton.addEventListener('click', () => {
  parent.postMessage('hi_there', parent_origin);
  parent.postMessage('open_popup', parent_origin);
});

Senza Attivazione utente v2, il frame principale non può aprire un popup alla ricezione il secondo messaggio. Anche il primo messaggio non funziona se è "collegato" a un altro frame multiorigine (in altre parole, se il primo destinatario inoltra il messaggio a un altro).

Questa impostazione funziona con Attivazione utente v2, sia nel formato originale che con concatenamento.