Pitch: como limitei regras MV3 apenas aos webmails autorizados
Transparência: eu desenvolvo o Mailshade, uma extensão para Chrome licenciada
sob AGPL-3.0-or-later que bloqueia requisições para domínios conhecidos de
pixels de rastreamento em webmails. O projeto é o exemplo concreto deste texto;
o padrão de permissões serve para outras extensões com integrações opcionais por
site.
Um pixel de rastreamento costuma ser uma imagem minúscula carregada de um
servidor controlado pelo remetente ou por uma plataforma de marketing. A
requisição pode revelar que a mensagem foi aberta. Links também podem passar
por redirecionadores reconhecíveis antes de chegar ao destino.
O objetivo do Mailshade não é prometer “privacidade total”. O modelo é mais
restrito: bloquear requisições para domínios conhecidos de pixels de
rastreamento, avisar antes de redirecionamentos reconhecidos e mostrar um
histórico local das detecções.
O que realmente autoriza uma integração
A extensão oferece integrações separadas para Gmail, Outlook web, Microsoft
365, Superhuman, Yahoo Mail e Proton Mail. Eu não queria que habilitar apenas um
desses clientes ativasse o mesmo comportamento em todos os outros.
Também não queria tratar uma preferência sincronizada como se fosse uma
permissão atual do Chrome.
Por isso, um cliente só entra no conjunto ativo quando duas condições são
verdadeiras:
- o usuário o habilitou nas configurações; e
- o perfil atual do Chrome possui a permissão opcional para aquela origem.
Uma configuração pode chegar a outro perfil pelo Chrome Sync. A permissão de
host continua sendo verificada localmente. gmail: true não concede acesso por
si só.
for (const client of supportedClients) {
if (!settings.clients[client]) continue;
try {
const origins = hostPatternsForClient(client);
const granted =
origins.length > 0 && (await chrome.permissions.contains({ origins }));
if (granted) {
enabledInitiatorDomains.push(...initiatorDomainsFor(client));
}
} catch {
// Em caso de erro, este cliente fica fora do escopo ativo.
}
}
O manifesto declara permissões opcionais para os webmails compatíveis. O
Mailshade não solicita <all_urls>. A tela de onboarding explica o motivo antes
de cada concessão.
Regras empacotadas como modelo, não como autoridade global
Os rulesets estáticos empacotados permanecem desativados. Em tempo de execução,
a extensão cria regras dinâmicas com initiatorDomains derivados apenas dos
webmails que passaram pelas duas verificações.
const desiredRules =
enabledInitiatorDomains.length === 0
? []
: templates.map((rule) => ({
id: BLOCK_RULE_OFFSET + rule.id,
priority: rule.priority ?? 1,
action: { type: "block" },
condition: {
urlFilter: rule.condition.urlFilter,
resourceTypes: rule.condition.resourceTypes?.length
? [...rule.condition.resourceTypes]
: ["image", "ping"],
initiatorDomains: [...enabledInitiatorDomains],
},
}));
Recalcular o conjunto desejado é mais simples do que confiar somente em
transições incrementais. Uma permissão pode ser revogada na página de extensões,
uma configuração pode chegar fora de ordem e o service worker pode reiniciar
entre duas operações.
O invariante fica assim:
regras ativas = modelos revisados × clientes habilitados × permissões atuais
Reservei ainda uma faixa de IDs para que a reconciliação remova somente as
regras pertencentes a esse componente.
Falhar reduzindo o escopo
Três decisões foram importantes:
- sem cliente autorizado, o conjunto desejado é vazio;
- se a verificação de permissão falha, o cliente é tratado como desabilitado;
- se o modelo de regras não pode ser carregado, as regras dinâmicas antigas do
Mailshade são removidas antes de propagar o erro.
O último ponto evita que uma falha na rotina de controle deixe ativo o escopo de
uma configuração anterior.
Também serializo as reconciliações. Dois eventos concorrentes de configuração e
permissão não devem permitir que o estado mais antigo seja aplicado por último.
Dados locais e exceções explícitas
O relatório usa IndexedDB local. Para detectar rastreadores conhecidos e
atribuir cada detecção, a extensão processa metadados do remetente,
identificadores opacos fornecidos pelo webmail e URLs relevantes de imagens e
links. O corpo da mensagem não é armazenado, e o histórico de detecções não é
enviado ao Mailshade.
Isso não significa “nenhum dado é processado”. Preferências criadas pelo usuário
podem passar pelo Chrome Sync quando a sincronização está habilitada. Os fluxos
opcionais de compra e ativação podem envolver a Polar e auth.mailshade.org,
conforme a operação. Relatos de falha são opcionais, exigem consentimento
explícito e são enviados apenas pelas páginas de interface da extensão; os
scripts de conteúdo e o service worker não iniciam esse envio.
Essa descrição mais longa é menos chamativa que “zero dados”, mas corresponde ao
fluxo real.
Limites que ficam visíveis
O Mailshade não desabilita todas as imagens, não reconhece todo método de
rastreamento e não torna o email anônimo. Um redirecionamento só é apresentado
como decodificado quando o destino realmente está contido na URL. As regras de
permissão para domínios de rastreadores adicionados pelo usuário têm prioridade
maior que as regras de bloqueio.
Os testes mais úteis não verificam apenas se uma regra conhecida bloqueia. Eles
verificam também se nenhuma regra continua ativa fora do escopo autorizado após
sync, revogação de permissão, falha de carregamento ou reinício do service worker.
O código correspondente à versão publicada, com checksum, está em
https://mailshade.org/source/. A página do projeto fica em
https://mailshade.org/.
Tenho interesse especial em feedback sobre a reconciliação entre preferências
sincronizadas e permissões locais. Quem mantém extensões com várias permissões
opcionais prefere reconstruir todo o conjunto desejado ou aplicar diferenças
incrementais?