Lidar com violações de código hospedados remotamente

O código hospedado remotamente, ou RHC, é o que a Chrome Web Store chama de qualquer coisa que seja executada pelo navegador e carregada de outro lugar que não os arquivos da extensão. Como JavaScript e WASM. Ele não inclui dados ou coisas como JSON ou CSS.

Por que o RHC não é mais permitido?

Com o Manifest V3, as extensões precisam agrupar todo o código que usam dentro da própria extensão. No passado, era possível injetar dinamicamente tags de script de qualquer URL na Web.

Me disseram que minha extensão tem RHC. O que está acontecendo?

Se a extensão foi rejeitada durante a análise com um erro Blue Argon, nossos revisores acreditam que ela está usando código hospedado remotamente. Isso geralmente é resultado de uma extensão que tenta adicionar uma tag script com um recurso remoto (ou seja, da Web aberta, em vez dos arquivos incluídos na extensão) ou busca um recurso para execução direta.

Como identificar o RHC

Não é difícil identificar o RHC quando você sabe o que procurar. Primeiro, verifique se as strings "http://" ou "https://" estão no seu projeto. Se você tiver uma violação de RHC, provavelmente vai conseguir encontrá-la. Se você tiver um sistema de build completo ou usar dependências do npm ou de outras fontes de terceiros, pesquise a versão compilada do código, já que é isso que a loja avalia. Se você ainda não conseguir encontrar o problema, a próxima etapa é entrar em contato com o Suporte completo. Eles vão poder descrever as violações específicas e o que é necessário para publicar a extensão o mais rápido possível.

O que fazer se uma biblioteca estiver pedindo o código

Não importa de onde o código venha, não é permitido ter RHC. Isso inclui código que você não criou, mas que usa como uma dependência no seu projeto. Alguns desenvolvedores que usam o Firebase tiveram esse problema quando o código remoto era incluído para uso no Firebase Auth. Mesmo que essa fosse uma biblioteca própria (ou seja, de propriedade do Google), nenhuma exceção foi concedida para o RHC. Você precisa configurar o código para remover o RHC ou atualizar seu projeto para não incluir o código desde o início. Se você encontrar um problema em que não é seu código que está carregando o RHC, mas uma biblioteca que você está usando, a melhor ação é entrar em contato com o autor da biblioteca. Informe que isso está acontecendo e peça uma solução alternativa ou atualizações de código para remover o problema.

E se não for possível esperar uma atualização da biblioteca?

Algumas bibliotecas enviam uma atualização quase imediatamente após serem notificadas, mas outras podem ser abandonadas ou levar tempo para resolver o problema. Dependendo do que está acontecendo na violação específica, talvez não seja necessário esperar que ela seja desbloqueada e passe por uma revisão. Há várias opções disponíveis para voltar a trabalhar rapidamente.

Auditar o código

Você tem certeza de que o código que está causando a solicitação é necessário? Se for possível apenas excluir ou remover uma biblioteca que está causando o problema, exclua esse código, e o trabalho estará concluído.

Ou existe outra biblioteca que oferece os mesmos recursos? Confira npmjs.com, o GitHub ou outros sites para encontrar opções que atendam aos mesmos casos de uso.

Tree shaking

Se o código que causa a violação de RHC não estiver sendo usado, ele poderá ser excluído automaticamente por ferramentas. Ferramentas de build modernas, como webpack, Rollup e Vite (para citar algumas), têm um recurso chamado tree-shaking. Depois de ativada no seu sistema de build, o tree shaking deve remover todos os caminhos de código não utilizados. Isso significa que você não só tem uma versão mais compatível do seu código, mas também uma mais enxuta e rápida. É importante observar que nem todas as bibliotecas podem ser eliminadas por tree shaking, mas muitas podem. Algumas ferramentas, como Rollup e Vite, têm a eliminação de código não utilizado ativada por padrão. O webpack precisa ser configurado para que ela seja ativada. Se você não estiver usando um sistema de build como parte da extensão, mas estiver usando bibliotecas de código, recomendamos adicionar uma ferramenta de build ao seu fluxo de trabalho. As ferramentas de build ajudam você a escrever projetos mais seguros, confiáveis e fáceis de manter.

As especificidades de como implementar o tree shaking dependem do seu projeto específico. Mas, para pegar um exemplo simples com o Rollup, você pode adicionar a eliminação de código não utilizado apenas compilando o código do projeto. Por exemplo, se você tiver um arquivo que só faz login no Firebase Auth, chamado main.js:

import { GoogleAuthProvider, initializeAuth } from "firebase/auth";

chrome.identity.getAuthToken({ 'interactive': true }, async (token) => {
  const credential = GoogleAuthProvider.credential(null, token);
  try {
    const app = initializeApp({ ... });
    const auth = initializeAuth(app, { popupRedirectResolver: undefined, persistence: indexDBLocalPersistence });
    const { user } = await auth.signInWithCredential(credential)
    console.log(user)
  } catch (e) {
    console.error(error);
  }
});

Depois, basta informar ao Rollup o arquivo de entrada, um plug-in necessário para carregar arquivos de nó @rollup/plugin-node-resolve e o nome do arquivo de saída que ele está gerando.

npx rollup --input main.js --plugin '@rollup/plugin-node-resolve' --file compiled.js

Ao executar esse comando em uma janela de terminal, você vai receber uma versão gerada do arquivo main.js, tudo compilado em um único arquivo chamado compiled.js.

O agrupamento pode ser simples, mas também é muito configurável. É possível adicionar todos os tipos de lógica e configuração complexas. Basta conferir a documentação. Adicionar ferramentas de build como essa resulta em um código menor e mais eficiente e, nesse caso, corrige o problema do código hospedado remotamente.

Edição automática de arquivos

Uma maneira cada vez mais comum de o código hospedado remotamente entrar na sua base de código é como uma subdependência de uma biblioteca que você está incluindo. Se a biblioteca X quiser import a biblioteca Y de uma CDN, ainda será necessário atualizar para que ela seja carregada de uma origem local. Com sistemas de build modernos, é possível criar plug-ins para extrair uma referência remota e inserir diretamente no seu código.

Isso significa que, dado um código como este:

import moment from "https://unpkg.com/moment@2.29.4/moment.js"
console.log(moment())

Você pode criar um pequeno plug-in de rollup.

import { existsSync } from 'fs';
import fetch from 'node-fetch';

export default {
  plugins: [{
    load: async function transform(id, options, outputOptions) {
      // this code runs over all of out javascript, so we check every import
      // to see if it resolves as a local file, if that fails, we grab it from
      // the network using fetch, and return the contents of that file directly inline
      if (!existsSync(id)) {
        const response = await fetch(id);
        const code = await response.text();

        return code
      }
      return null
    }
  }]
};

Depois de executar o build com o novo plug-in, todos os URLs remotos import serão descobertos, seja nosso código, uma subdependência, subsubdependência ou qualquer outro lugar.

npx rollup --input main.js --config ./rollup.config.mjs --file compiled.js

Edição manual de arquivos

A opção mais simples é excluir o código que está causando o RHC. Abra no editor de texto de sua preferência e exclua as linhas que violam a política. Isso geralmente não é recomendável, porque é frágil e pode ser esquecido. Isso dificulta a manutenção do projeto quando um arquivo chamado "library.min.js" não é library.min.js. Em vez de editar os arquivos brutos, uma opção um pouco mais fácil de manter é usar uma ferramenta como o patch-package. Essa é uma opção muito útil que permite salvar modificações em um arquivo, em vez do arquivo em si. Ele é criado com base em arquivos de patch, o mesmo tipo de coisa que alimenta sistemas de controle de versão como Git ou Subversion. Basta modificar manualmente o código em violação, salvar o arquivo de diff e configurar o patch-package com as mudanças que você quer aplicar. Leia um tutorial completo no readme do projeto. Se você estiver corrigindo um projeto, recomendamos muito que entre em contato com ele para pedir que as mudanças sejam feitas upstream. Embora o patch-package facilite muito o gerenciamento de patches, não ter nada para corrigir é ainda melhor.

O que fazer se o código não estiver sendo usado

À medida que as bases de código crescem, as dependências (ou dependência de uma dependência, ou dependência de…) podem manter caminhos de código que não estão mais sendo usados. Se uma dessas seções incluir código para carregar ou executar o RHC, ela precisará ser removida. Não importa se ele está desativado ou sem uso. Se não estiver sendo usado, ele precisa ser removido, seja por treeshaking ou corrigindo a biblioteca para removê-lo.

Existe alguma solução alternativa?

Em geral, não. O RHC não é permitido. No entanto, há um pequeno número de casos em que isso é permitido. Quase sempre são casos em que é impossível usar qualquer outra opção.

API User Scripts

Os scripts de usuário são pequenos snippets de código geralmente fornecidos pelo usuário, destinados a gerenciadores de scripts de usuário, como TamperMonkey e Violentmonkey. Esses gerentes não podem agrupar códigos escritos por usuários. Por isso, a API User Script expõe uma maneira de executar códigos fornecidos pelo usuário. Isso não é um substituto para chrome.scripting.executeScript ou outros ambientes de execução de código. Os usuários precisam ativar o modo de desenvolvedor para executar qualquer coisa. Se a equipe de análise da Chrome Web Store achar que isso está sendo usado de uma maneira diferente da finalidade pretendida (ou seja, código fornecido pelo usuário), o envio poderá ser rejeitado ou a listagem removida da loja.

chrome.debugger

A API chrome.debugger permite que as extensões interajam com o protocolo do Chrome DevTools. Esse é o mesmo protocolo usado para o Devtools do Chrome e um número incrível de outras ferramentas. Com ele, uma extensão pode solicitar e executar código remoto. Assim como os scripts de usuário, ele não é um substituto para chrome.scripting e tem uma experiência do usuário muito mais notável. Enquanto ele estiver sendo usado, o usuário vai ver uma barra de aviso na parte de cima da janela. Se o banner for fechado ou dispensado, a sessão de depuração será encerrada.

Captura de tela da barra de endereços do Chrome com a mensagem "A extensão do depurador começou a depurar este navegador"
Captura de tela da barra de endereço no Chrome com a mensagem "A extensão do depurador começou a depurar este navegador"

iframes em sandbox

Se você precisar avaliar uma string como código e estiver em um ambiente DOM (por exemplo, um script de conteúdo, em vez de um service worker de extensão), outra opção é usar um iframe em sandbox. Por padrão, as extensões não oferecem suporte a recursos como eval() como medida de segurança. Um código malicioso pode colocar a segurança e a proteção dos usuários em risco. Mas quando o código é executado apenas em um ambiente seguro conhecido, como um iframe que foi isolado do restante da Web, esses riscos são muito reduzidos. Nesse contexto, a Política de Segurança de Conteúdo que bloqueia o uso de eval pode ser suspensa, permitindo que você execute qualquer código JavaScript válido.

Se você tiver um caso de uso que não está coberto, entre em contato com a equipe usando a lista de e-mails chromium-extensions para receber feedback ou abra um novo tíquete para pedir orientação do One Stop Support.

O que fazer se você discordar de um veredicto

A aplicação das políticas pode ter nuances, e a análise envolve entrada manual. Isso significa que a equipe da Chrome Web Store pode concordar em mudar uma decisão de análise. Se você acredita que houve um erro na análise, conteste a rejeição usando o One Stop Support.