Para evitar que scripts maliciosos abusem de APIs sensíveis, como pop-ups, tela cheia etc., os navegadores controlam o acesso a essas APIs pela ativação do usuário. 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 estado "ativo" normalmente implica que o usuário está interagendo com a página ou concluiu uma interação desde o carregamento da página. Gesto do usuário é um termo comum, mas enganoso, para a mesma ideia. Por exemplo, um gesto de deslizar ou tocar de um usuário não ativa uma página e, portanto, não é, do ponto de vista do script, uma ativação do usuário.
Os principais navegadores atuais mostram um comportamento muito diferente em relação a como a ativação do usuário
controla as APIs de ativação. No Chrome, a implementação foi baseada
em um modelo baseado em token que acabou sendo muito complexo para definir um comportamento
consistente em todas as APIs com ativação obrigatória. Por exemplo, o Chrome tem
permitido acesso incompleto a APIs controladas por ativação usando
chamadas postMessage()
e
setTimeout()
, e a ativação de usuários não
tinha suporte a promessas,
XHR,
interação com Gamepad etc. Observe que alguns desses
são bugs conhecidos, mas antigos.
Na versão 72, o Chrome envia a ativação do usuário v2, que completa a disponibilidade de ativação para todas as APIs controladas por ativação. Isso resolve as inconsistências mencionadas acima e algumas outras, como MessageChannels, que acreditamos facilitar o desenvolvimento da Web relacionado à ativação do usuário. Além disso, a nova implementação oferece uma implementação de referência para uma especificação proposta que visa reunir todos os navegadores a 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: um bit fixo para o estado de ativação do usuário histórico (se um
frame já tiver mostrado uma ativação do usuário) e um bit transitório para o estado atual
(se um frame tiver mostrado uma ativação do usuário em cerca de um segundo). O bit fixo
nunca é redefinido durante a vida útil do frame depois de ser definido. O bit transitório
é definido em cada interação do usuário e é redefinido após um intervalo
de expiração (cerca de um segundo) ou por uma chamada para uma API que consome ativação
(por exemplo, window.open()
).
Diferentes APIs com ativação obrigatória dependem da ativação do usuário de maneiras
diferentes. A nova API não muda nenhum desses comportamentos específicos da API. Por exemplo,
apenas um pop-up é permitido por ativação do usuário, porque window.open()
consome
a ativação do usuário como costumava ser, Navigator.prototype.vibrate()
continua
a ser eficaz se um frame (ou qualquer um dos subframes) já tiver passado por 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 em limites de frame: uma interação do usuário com um frame específico agora ativa todos os frames que contêm (e apenas esses frames), independentemente da origem. No Chrome 72, temos uma solução temporária para expandir a visibilidade para todos os frames de mesma origem. Vamos remover essa solução alternativa assim que tivermos uma maneira de transmitir explicitamente a ativação do usuário para subframes.
- Quando uma API de ativação restrita é chamada de um frame ativado, mas fora do código do manipulador de eventos, ela vai funcionar desde que o estado de ativação do usuário esteja "ativo" (por exemplo, não tenha expirado nem sido consumido). Antes da ativação do usuário v2, isso falharia incondicionalmente.
- Várias interações do usuário não utilizadas dentro do intervalo de tempo de expiração são mescladas em uma única ativação correspondente à última interação.
Exemplos de consistência em APIs com ativação obrigatória
Confira dois exemplos com janelas pop-up (abertas usando window.open()
) que
mostram como a Ativação do usuário v2 torna o comportamento das APIs com ativação
consistente.
Chamadas setTimeout()
encadeadas
Este exemplo é da
nossa demonstração de setTimeout()
.
Se um gerenciador click
tentar abrir um pop-up em um segundo, ele será
sucedido, não importa como o código "compõe" o atraso. A ativação do usuário v2 atende
a essa expectativa, então cada um dos manipuladores de eventos a seguir abre um pop-up em um
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 versão 2 da ativação do usuário, o segundo manipulador de eventos falha em todos os navegadores que testamos. Até mesmo o primeiro falha em alguns casos.
Chamadas postMessage()
entre domínios
Confira um exemplo da
nossa demonstração de postMessage()
.
Suponha que um manipulador click
em um subframe de origem cruzada envie duas mensagens diretamente
para o frame pai. O frame pai precisa ser capaz de abrir um pop-up ao
receber uma destas mensagens (mas não as duas):
// 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 pai não pode abrir um pop-up ao receber a segunda mensagem. Mesmo a primeira mensagem falha se for "encadeada" a outro frame de origem cruzada, ou seja, se o primeiro destinatário encaminhar a mensagem para outro.
Isso funciona com a Ativação do usuário v2, tanto na forma original quanto com a cadeiação.