Para evitar que scripts maliciosos abusem de APIs sensíveis, como pop-ups, tela cheia etc., os navegadores controlam o acesso a essas APIs por meio de controles ativação. A ativação do usuário é o estado de uma sessão de navegação em relação às ações do usuário: um "ativo" estado normalmente implica que o usuário está está interagindo com a página ou concluiu uma interação desde que a página carregar. Gesto do usuário é um termo conhecido, mas enganoso, para a mesma ideia. Para Por exemplo, um gesto de deslizar ou mover de um usuário não ativa a página e, portanto, não é, do ponto de vista do script, uma ativação do usuário.
Atualmente, os principais navegadores apresentam comportamentos divergentes em relação ao modo como a ativação do usuário
controla as APIs com controle de ativação. No Chrome, a implementação foi baseada
em um modelo baseado em token que acabou sendo complexo demais para definir
em todas as APIs controladas por ativação. Por exemplo, o Chrome foi
permitindo acesso incompleto a APIs com controle de ativação por meio de
postMessage()
e
chamadas do setTimeout()
; e a ativação do usuário não foi
compatível com promessas,
XHR,
Interação com o Gamepad etc. Observe que alguns desses
são bugs conhecidos,
mas que existem há muito tempo.
Na versão 72, o Chrome fornece a ativação do usuário v2, que torna o usuário disponibilidade de ativação concluída para todas as APIs controladas por ativação. Isso resolve as inconsistências mencionadas acima (e algumas outras, como MessageChannels), que acreditamos facilitar o uso da desenvolvimento em torno da ativação do usuário. Além disso, a nova implementação oferece uma implementação de referência para um nova especificação que tem como objetivo reunir todos os navegadores em longo prazo.
Como a ativação do usuário v2 funciona?
A nova API mantém um estado de ativação do usuário de dois bits em cada objeto window
.
na hierarquia de frames: uma parte fixa do estado histórico de ativação do usuário (se um
já viu uma ativação de usuário), e um bit temporário para o estado atual
(se um frame tiver visto uma ativação do usuário em cerca de um segundo). A parte aderente
nunca é redefinido durante a vida útil do frame após ele ser definido. A parte temporária
é definido em cada interação do usuário e é redefinido após um vencimento
(cerca de um segundo) ou com uma chamada para uma API que consome muita ativação
(por exemplo, window.open()
).
Observe que diferentes APIs controladas por ativação dependem da ativação do usuário em diferentes
maneiras a nova API não altera nenhum desses comportamentos específicos da API. Por exemplo:
apenas um pop-up é permitido por ativação do usuário porque o window.open()
consome
a ativação de usuários como antes, o Navigator.prototype.vibrate()
continua
ser eficaz se um frame (ou qualquer um de seus subframes) já tiver visto uma ação do usuário,
e assim por diante.
O que muda?
- A ativação do usuário v2 formaliza a noção de visibilidade da ativação do usuário além dos limites dos frames: uma interação do usuário com um frame específico ativar todos os frames contidos (e somente os frames) independentemente origem. No Chrome 72, temos uma solução temporária para expandir a visibilidade para todos os frames de mesma origem. Essa solução alternativa será removida ter uma maneira de transmita explicitamente a ativação do usuário para subframes.
- quando uma API controlada por ativação é chamada de um frame ativado, mas fora de um código de manipulador de eventos, ele funcionará, desde que a ativação do usuário estado é "ativo" (por exemplo, não expirou nem foi consumido). Antes do usuário na ativação v2, ela falharia incondicionalmente.
- Várias interações do usuário não utilizadas dentro do intervalo de tempo de expiração se fundem em uma única ativação correspondente à última interação.
Exemplos de consistência em APIs controladas por ativação
Confira dois exemplos com janelas pop-up (abertas usando window.open()
) que
mostre como a ativação do usuário v2 torna o comportamento de APIs controladas por ativação
consistentes.
Chamadas setTimeout()
encadeadas
Este exemplo é de
nossa demonstração setTimeout()
.
Se um gerenciador click
tentar abrir um pop-up em um segundo, ele será
ter sucesso, não importa como o código "componha" o atraso. A ativação do usuário v2 atende
essa expectativa, então cada um dos seguintes manipuladores de eventos abre um pop-up em uma
click
(com um atraso de 100 ms):
function popupAfter100ms() {
setTimeout(callWindowOpen, 100);
}
function asyncPopupAfter100ms() {
setTimeout(popupAfter100ms, 0);
}
someButton.addEventListener('click', popupAfter100ms);
someButton.addEventListener('click', asyncPopupAfter100ms);
Sem a ativação do usuário v2, o segundo manipulador de eventos falha em todos os navegadores é treinado e testado. (Até o primeiro não dá certo em alguns casos.
Chamadas postMessage()
entre domínios
Aqui está um exemplo
nossa demonstração postMessage()
.
Suponha que um gerenciador click
em um subframe de origem cruzada envie duas mensagens diretamente.
ao frame principal. O frame principal deve abrir um pop-up
recebendo apenas uma destas mensagens (mas não ambas):
// 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);
});
Sem a ativação do usuário v2, o frame principal não pode abrir um pop-up ao receber a segunda mensagem. Até a primeira mensagem vai falhar se estiver "encadeada" para outro frame de origem cruzada (em outras palavras, se o primeiro receptor encaminhar a mensagem para outro).
Isso funciona com a ativação do usuário v2, tanto na forma original quanto com o encadeamento.