Cómo abordar incumplimientos de código alojados de manera remota

El código alojado de forma remota, o RHC, es lo que Chrome Web Store llama a todo lo que ejecuta el navegador y que se carga desde un lugar que no sea los archivos propios de la extensión. Cosas como JavaScript y WASM. No incluye datos ni elementos como JSON o CSS.

¿Por qué ya no se permite RHC?

Con las extensiones de Manifest V3, ahora deben empaquetar todo el código que usan dentro de la extensión. Antes, podías insertar de forma dinámica etiquetas de secuencias de comandos desde cualquier URL en la Web.

Me informaron que mi extensión tiene RHC. ¿Qué sucede?

Si tu extensión se rechazó durante la revisión con un error de Blue Argon, nuestros revisores creen que tu extensión usa código alojado de forma remota. Suele ser el resultado de una extensión que intenta agregar una etiqueta de secuencia de comandos con un recurso remoto (es decir, de la Web abierta, en lugar de los archivos incluidos en la extensión) o de la recuperación de un recurso para ejecutarlo directamente.

Cómo detectar RHC

No es particularmente difícil identificar RHC una vez que se sabe qué buscar. Primero, busca las cadenas "http://" o "https://" en tu proyecto. Si tienes un incumplimiento de RHC, es probable que puedas localizarlo si la encuentras. Si tienes un sistema de compilación completo o usas dependencias de npm o de otras fuentes de terceros, asegúrate de buscar la versión compilada del código, ya que es lo que evalúa la tienda. Si aún así no logras encontrar el problema, el siguiente paso es comunicarte con el equipo de asistencia integral. Allí, podrán describir los incumplimientos específicos y lo que se necesita para que la extensión se publique lo antes posible.

Qué hacer si una biblioteca solicita el código

Independientemente del origen del código, no se permite tener RHC. Esto incluye el código que no creaste, pero que usas como dependencia en tu proyecto. Algunos desarrolladores que usan Firebase tuvieron este problema cuando se incluyó código remoto para su uso en Firebase Auth. Aunque se trata de una biblioteca propia (es decir, propiedad de Google), no se hacen excepciones para RHC. Debes configurar el código para quitar el RHC o actualizar tu proyecto de modo que no se incluya el código desde el principio. Si encuentras un problema en el que no es tu código lo que carga RHC, sino una biblioteca que estás usando, lo mejor que puedes hacer es comunicarte con el autor de la biblioteca. Hazle saber que esto está sucediendo y solicita una solución alternativa o actualizaciones de código para quitarlo.

¿Qué pasa si no puedes esperar una actualización de la biblioteca?

Algunas bibliotecas envían actualizaciones casi inmediatamente después de recibir la notificación, pero otras pueden abandonarse o tardar en solucionar el problema. Según lo que suceda en el incumplimiento específico, es posible que no debas esperar a que se desbloquee y complete una revisión correcta. Hay varias opciones disponibles para volver a funcionar rápidamente.

Audita el código

¿Estás seguro de que el código que genera la solicitud es necesario? Si solo se puede borrar o se puede quitar una biblioteca que la causa, borra ese código y el trabajo estará listo.

Como alternativa, ¿hay otra biblioteca que ofrezca las mismas funciones? Consulta npmjs.com, GitHub o algún otro sitio para ver otras opciones que cumplan con los mismos casos de uso.

Sacudida de árboles

Si el código que causa el incumplimiento de RHC en realidad no se usa, es posible que las herramientas puedan borrarlo de forma automática. Las herramientas de compilación modernas, como webpack, Rollup y Vite (por nombrar algunas), tienen una función llamada eliminación de código no utilizado. Una vez habilitada en el sistema de compilación, la eliminación de código no utilizado debería quitar cualquier ruta de código no utilizada. Esto puede significar que no solo tienes una versión más adecuada del código, sino que también una más eficiente y rápida. Es importante tener en cuenta que no todas las bibliotecas pueden modificarse de forma manual, pero muchas sí. Algunas herramientas, como Rollup y Vite, tienen la eliminación de código no habilitada de forma predeterminada. Se debe configurar Webpack para que se habilite. Si no usas un sistema de compilación como parte de la extensión, pero usas bibliotecas de código, te recomendamos que investigues cómo agregar una herramienta de compilación a tu flujo de trabajo. Las herramientas de compilación te ayudan a escribir proyectos más seguros, confiables y fáciles de mantener.

Los detalles de cómo implementar la eliminación de árboles dependen de tu proyecto específico. Sin embargo, para tomar un ejemplo simple con Rollup, puedes agregar la eliminación de árboles solo con la compilación del código de tu proyecto. Por ejemplo, si tienes un archivo que solo accede a Firebase Auth, llamado 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);
  }
});

Lo único que debes hacer es indicarle a Rollup el archivo de entrada, un complemento necesario para cargar los archivos del nodo @rollup/plugin-node-resolve y el nombre del archivo de salida que está generando.

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

Si ejecutas ese comando en una ventana de terminal, recibirás una versión generada de nuestro archivo main.js, todo compilado en un solo archivo llamado compiled.js.

El proceso de fusión puede ser simple, pero también se puede configurar muy. Puedes agregar todo tipo de lógica y configuración complejas. Para ello, consulta la documentación. Agregar herramientas de compilación de esta manera generará un código más pequeño y eficiente y, en este caso, corregirá nuestro problema de código alojado de forma remota.

Edición automática de archivos

Una forma cada vez más común en que el código alojado de forma remota puede ingresar a tu base de código es como una subdependencia de una biblioteca que incluyes. Si la biblioteca X quiere usar la biblioteca import Y de una CDN, deberás actualizarla para que se cargue desde una fuente local. Con los sistemas de compilación modernos, puedes crear complementos de forma trivial para extraer una referencia remota y, luego, intercalarla directamente en tu código.

Eso significa que el código dado se ve de la siguiente manera:

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

Podrías crear un complemento pequeño de fusión.

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
    }
  }]
};

Una vez que ejecutes la compilación con el complemento nuevo, se descubrirá cada URL remota de import, sin importar si fue o no nuestro código, una subdependencia, una subdependencia o cualquier otro lugar.

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

Edición manual de archivos

La opción más simple es borrar el código que causa el RHC. Ábrelo en el editor de texto que prefieras y borra las líneas infractoras. Por lo general, no es así de recomendable, porque es frágil y podría olvidarse. Se dificulta el mantenimiento del proyecto cuando un archivo llamado "library.min.js" no es en realidad library.min.js. En lugar de editar los archivos sin procesar, una opción un poco más fácil de mantener es usar una herramienta como patch-package. Esta es una opción muy potente que te permite guardar modificaciones en un archivo, en lugar de hacerlo en el archivo en sí. Se basa en archivos de parche, el mismo tipo de elementos que respaldan los sistemas de control de versión, como Git o Subversion. Solo debes modificar de forma manual el código que incumple las políticas, guardar el archivo de diferencia y configurar el paquete de parches con los cambios que desees aplicar. Puedes leer un instructivo completo en el archivo readme del proyecto. Si aplicas parches a un proyecto, te recomendamos que te comuniques con él para solicitar que los cambios se realicen en sentido ascendente. Si bien el paquete de parches facilita la administración de los parches, no tener nada que aplicar parches es aún mejor.

Qué hacer si el código no se usa

A medida que crecen las bases de código, las dependencias (o dependencia de una dependencia o dependencia de...) pueden conservar las instrucciones de código que ya no se usan. Si una de esas secciones incluye código para cargar o ejecutar RHC, deberá quitarse. No importa si está inactiva o no se usa. Si no se usa, se debe quitar, ya sea mediante la eliminación de código o la aplicación de parches en la biblioteca para quitarla.

¿Existe alguna solución alternativa?

En términos generales, no se permiten los RHC. Sin embargo, hay una pequeña cantidad de casos en los que está permitido. Estos son casi siempre casos en los que es imposible para cualquier otra opción.

API de User Scripts

Las secuencias de comandos del usuario son fragmentos pequeños de código que el usuario suele proporcionar, destinados a administradores de secuencias de comandos del usuario, como TamperMonkey y Violentmonkey. Estos administradores no pueden agrupar el código escrito por los usuarios, por lo que la API de User Script expone una forma de ejecutar el código proporcionado por el usuario. Esto no reemplaza a chrome.scripting.executeScript ni a otros entornos de ejecución de código. Los usuarios deben habilitar el modo de desarrollador para ejecutar cualquier cosa. Si el equipo de revisión de Chrome Web Store considera que este se está usando de una manera diferente a la prevista (es decir, con el código proporcionado por el usuario), es posible que se rechace o que se quite de la tienda.

chrome.debugger

La API de chrome.debugger brinda a las extensiones la capacidad de interactuar con el protocolo de herramientas para desarrolladores de Chrome. Este es el mismo protocolo que se utiliza para las Herramientas para desarrolladores de Chrome y una cantidad increíble de otras herramientas. Con él, una extensión puede solicitar y ejecutar código remoto. Al igual que las secuencias de comandos de usuario, no reemplaza a chrome.scripting y ofrece una experiencia del usuario mucho más destacada. Mientras se use, el usuario verá una barra de advertencia en la parte superior de la ventana. Si se cierra o descarta el banner, se finalizará la sesión de depuración.

Captura de pantalla de la barra de direcciones de Chrome con el mensaje "Debugger Extension started debugging this browser"
Captura de pantalla de la barra de direcciones de Chrome con el mensaje "Debugger Extension started debugging this browser".

Iframes con zona de pruebas

Si necesitas evaluar una cadena como código y estás en un entorno del DOM (p.ej., una secuencia de comandos de contenido, en lugar de un service worker de extensión), otra opción es usar un iframe de zona de pruebas. Como medida de seguridad, las extensiones no admiten elementos como eval() de forma predeterminada. El código malicioso podría poner en riesgo la seguridad y la protección de los usuarios. Sin embargo, cuando el código solo se ejecuta en un entorno seguro conocido, como un iframe que se usó como una zona de pruebas del resto de la Web, esos riesgos se reducen considerablemente. En este contexto, la política de seguridad del contenido que bloquea el uso de eval se puede quitar, lo que te permite ejecutar cualquier código JavaScript válido.

Si tienes un caso de uso que no está cubierto, no dudes en comunicarte con el equipo que utiliza la lista de distribución de chromium-extensions para obtener comentarios, o abre un ticket nuevo y solicita ayuda al equipo de Asistencia integral.

Qué hacer si no estás de acuerdo con un veredicto

La aplicación de políticas puede tener matices y la revisión implica entradas manuales, lo que significa que, en ocasiones, el equipo de Chrome Web Store puede aceptar cambiar una decisión relacionada con una opinión. Si crees que se cometió un error durante la revisión, puedes apelar el rechazo mediante la Asistencia integral.