Melhorias na interoperabilidade por push na Web

Joe Medley
Joe Medley

Quando o Chrome ofereceu suporte à API Web Push pela primeira vez, ele contava com a Firebase Cloud Messaging (FCM),anteriormente conhecido como Google Cloud Messaging (GCM), serviço push. Isso é necessário usando uma API reservada. Isso permitiu que o navegador Chrome para disponibilizar a API Web Push para desenvolvedores em um horário em que a especificação do protocolo de push da Web ainda estava sendo escrita e fornecida posteriormente autenticação (o remetente da mensagem é quem diz ser) por vez quando o protocolo de push da Web não tinha. Boa notícia: nenhuma das alternativas é verdadeira. mais

O FCM / GCM e o Chrome agora oferecem suporte ao Web Push Protocol padrão, enquanto o remetente a autenticação pode ser alcançada implementando VAPID, ou seja, seu app da Web não precisa mais de um "gcm_sender_id".

Neste artigo, vou descrever primeiro como converter seu servidor atual para usar o Web Push Protocol com o FCM. Em seguida, vou mostrar como implementar VAPID no código do cliente e do servidor.

O FCM oferece suporte ao protocolo de push da Web

Vamos começar com um pouco de contexto. Quando seu aplicativo da Web se registra a assinatura de push recebe o URL de um serviço de push. Seu servidor usará esse endpoint para enviar dados ao usuário pelo seu app da Web. No Chrome, você poderá recebe um endpoint do FCM se você inscrever um usuário sem VAPID. Falaremos sobre VAPID mais tarde). Antes de o FCM oferecer suporte ao protocolo push da Web, era preciso extrair o arquivo ID de registro no final do URL e colocá-lo no cabeçalho antes de fazer uma solicitação à API FCM. Por exemplo, um endpoint do FCM de https://android.googleapis.com/gcm/send/ABCD1234, teria um registro ID: "ABCD1234".

Agora que o FCM oferece suporte ao protocolo Web push, é possível deixar o endpoint intacto e usar o URL como um endpoint do protocolo de push da Web. Isso alinha Firefox e, esperamos, todos os outros navegadores futuros.)

Antes de nos aprofundarmos no VAPID, precisamos verificar se nosso código do servidor está correto. gerencia o endpoint do FCM. Abaixo está um exemplo de como fazer uma solicitação para um push serviço em Node. Observe que estamos adicionando a chave de API à solicitação para o FCM e cabeçalhos de cache válidos. Para outros endpoints de serviços de push, isso não será necessário. Para o Chrome anterior para a versão 52, Opera Android e Samsung Browser, também é necessário incluir um "gcm_sender_id" no manifest.json do seu app da Web. A chave de API e ID do remetente são usados para verificar se o servidor que está fazendo as solicitações está têm permissão para enviar mensagens ao usuário de destino.

const headers = new Headers();
// 12-hour notification time to live.
headers.append('TTL', 12 * 60 * 60);
// Assuming no data is going to be sent
headers.append('Content-Length', 0);

// Assuming you're not using VAPID (read on), this
// proprietary header is needed
if(subscription.endpoint
    .indexOf('https://android.googleapis.com/gcm/send/') === 0) {
    headers.append('Authorization', 'GCM_API_KEY');
}

fetch(subscription.endpoint, {
    method: 'POST',
    headers: headers
})
.then(response => {
    if (response.status !== 201) {
    throw new Error('Unable to send push message');
    }
});

Lembre-se de que esta é uma alteração na API do FCM / GCM, portanto você não precisa atualizar seu basta alterar o código do servidor para definir os cabeçalhos, conforme mostrado acima.

Introdução ao VAPID para identificação do servidor

VAPID é o novo nome curto "Identificação voluntária do servidor de aplicativos". Isso a nova especificação define essencialmente um handshake entre o servidor do aplicativo e o servidor e permite que o serviço de push confirme qual site está enviando as mensagens. Com o VAPID, é possível evitar as etapas específicas do FCM para enviar uma mensagem push. Você não precisam mais de um projeto do Firebase, um gcm_sender_id ou Cabeçalho Authorization.

O processo é bastante simples:

  1. O servidor do aplicativo cria um par de chaves pública/privada. A chave pública é dados ao seu app da Web.
  2. Quando o usuário optar por receber push, adicione a chave pública asubscribe() do objeto de opções da chamada.
  3. Quando o servidor do app enviar uma mensagem push, inclua um JSON Web Token assinado junto com a chave pública.

Vamos analisar essas etapas em detalhes.

Criar um par de chaves públicas/privadas

Eu sou péssima em criptografia, então aqui está a seção relevante das especificações sobre o formato das chaves públicas/privadas VAPID:

Os servidores de aplicativos DEVEM gerar e manter uma assinatura Par de chaves utilizável com assinatura digital de curva elíptica (ECDSA, na sigla em inglês) sobre a curva P-256.

Veja como fazer isso na biblioteca de nós de push da web:

function generateVAPIDKeys() {
    var curve = crypto.createECDH('prime256v1');
    curve.generateKeys();

    return {
    publicKey: curve.getPublicKey(),
    privateKey: curve.getPrivateKey(),
    };
}

Como assinar com a chave pública

Para inscrever um usuário do Chrome para push com a chave pública VAPID, você precisa transmitir a chave pública como um Uint8Array usando o parâmetro applicationServerKey da o métodosubscribe().

const publicKey = new Uint8Array([0x4, 0x37, 0x77, 0xfe, . ]);
serviceWorkerRegistration.pushManager.subscribe(
    {
    userVisibleOnly: true,
    applicationServerKey: publicKey
    }
);

Você vai saber se funcionou examinando o endpoint no objeto de assinatura, se a origem for fcm.googleapis.com, está funcionando.

https://fcm.googleapis.com/fcm/send/ABCD1234

Como enviar uma mensagem push

Para enviar uma mensagem usando VAPID, você precisa criar um protocolo push solicitação com dois cabeçalhos HTTP adicionais: um cabeçalho de autorização e um Cabeçalho "Crypto-Key".

Cabeçalho de autorização

O cabeçalho Authorization é um JSON Web Token (JWT) assinado com "WebPush". na frente dele.

O JWT é uma maneira de compartilhar um objeto JSON com uma segunda parte de modo que o remetente pode assinar e o destinatário pode verificar a assinatura é do remetente esperado. A estrutura de um JWT tem três strings criptografadas. unidas por um único ponto entre eles.

<JWTHeader>.<Payload>.<Signature>

Cabeçalho JWT

O cabeçalho JWT contém o nome do algoritmo usado para assinatura e o tipo de com base no token correto anterior. Para VAPID, isso precisa ser:

{
    "typ": "JWT",
    "alg": "ES256"
}

Em seguida, ele é codificado em base64 e forma a primeira parte do JWT.

Payload

Payload é outro objeto JSON que contém o seguinte:

  • Público-alvo ("aud")
    • Esta é a origem do serviço de push (NÃO é a origem do seu site). Em JavaScript, faça o seguinte para conseguir o público-alvo: const audience = new URL(subscription.endpoint).origin
  • Horário de vencimento ("exp")
    • Esse é o número de segundos até que a solicitação seja considerada como expirou. Isso PRECISA ser realizado dentro de 24 horas após a solicitação ser feita, em UTC.
  • Assunto ("sub")
    • O assunto precisa ser um URL ou um URL do mailto:. Isso fornece um ponto de contato, caso o serviço de push precise entrar em contato com o remetente da mensagem.

Um payload de exemplo pode ser semelhante ao seguinte:

{
    "aud": "http://push-service.example.com",
    "exp": Math.floor((Date.now() / 1000) + (12 * 60 * 60)),
    "sub": "mailto: my-email@some-url.com"
}

Esse objeto JSON tem URL codificado em base64 e forma a segunda parte do JWT.

Assinatura

A assinatura é o resultado da junção do cabeçalho e do payload codificados com uma em seguida, criptografando o resultado usando a chave privada VAPID criada anteriormente. O resultado em si deve ser anexado ao cabeçalho com um ponto.

Não vou mostrar um exemplo de código para isso, porque há várias bibliotecas que usam o cabeçalho e o payload objetos JSON e gerar essa assinatura para você.

O JWT assinado é usado como o cabeçalho de autorização com "WebPush" anexado a e será semelhante a esta:

WebPush eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL2ZjbS5nb29nbGVhcGlzLmNvbSIsImV4cCI6MTQ2NjY2ODU5NCwic3ViIjoibWFpbHRvOnNpbXBsZS1wdXNoLWRlbW9AZ2F1bnRmYWNlLmNvLnVrIn0.Ec0VR8dtf5qb8Fb5Wk91br-evfho9sZT6jBRuQwxVMFyK5S8bhOjk8kuxvilLqTBmDXJM5l3uVrVOQirSsjq0A

Observe alguns detalhes sobre isso. Primeiro, o cabeçalho "Authorization" literalmente contém a palavra "WebPush" seguido de um espaço e do JWT. Além disso, observe os pontos separando o cabeçalho, o payload e a assinatura do JWT.

Cabeçalho Crypto-Key

Além do cabeçalho "Autorização", você precisa adicionar sua chave pública VAPID ao Cabeçalho Crypto-Key como uma string codificada de URL base64 com p256ecdsa= no prefixo.

p256ecdsa=BDd3_hVL9fZi9Ybo2UUzA284WG5FZR30_95YeZJsiApwXKpNcF1rRPF3foIiBHXRdJI2Qhumhf6_LFTeZaNndIo

Quando enviar uma notificação com dados criptografados, você já estão usando o cabeçalho Crypto-Key. Portanto, para adicionar o servidor de aplicativos basta adicionar um ponto e vírgula antes de adicionar o conteúdo acima, o que resulta em:

dh=BGEw2wsHgLwzerjvnMTkbKrFRxdmwJ5S_k7zi7A1coR_sVjHmGrlvzYpAT1n4NPbioFlQkIrTNL8EH4V3ZZ4vJE;
p256ecdsa=BDd3_hVL9fZi9Ybo2UUzA284WG5FZR30_95YeZJsiApwXKpNcF1rRPF3foIiBHXRdJI2Qhumhf6_LFTeZaN

Verdade dessas mudanças

Com o VAPID, você não precisa mais se inscrever em uma conta com o GCM para usar o recurso de push in. Chrome e é possível usar o mesmo caminho de código para inscrever um usuário e enviar uma para um usuário no Chrome e no Firefox. Ambos estão seguindo os padrões.

Tenha em mente que, no Chrome 51 e em versões anteriores, o Opera for No navegador Android e Samsung, você ainda precisa definir o gcm_sender_id no manifesto do seu app da Web e você precisará adicionar o cabeçalho Authorization ao endpoint do FCM que será retornado.

Com o VAPID, é possível se desviar desses requisitos próprios. Se você implementar O VAPID funciona em todos os navegadores que oferecem suporte a push na Web. Como mais navegadores oferecer suporte a VAPID, você pode decidir quando soltar o gcm_sender_id do seu manifesto do aplicativo.