Борьба с нарушениями кода удаленного хостинга

Удаленно размещенный код (RHC) — так в Chrome Web Store называется любой код, выполняемый браузером и загружаемый не из файлов самого расширения, а из других источников. Это, например, JavaScript и WASM. Сюда не входят данные, JSON или CSS.

Почему RHC больше не разрешен?

В Manifest V3 расширениям теперь необходимо включать весь используемый код в само расширение. Раньше можно было динамически внедрять теги <script> с любого URL-адреса в интернете.

Мне сказали, что в моем добавочном номере есть RHC (Random Healthcare Center). Что происходит?

Если ваше расширение было отклонено на этапе проверки с ошибкой Blue Argon , это означает, что наши специалисты считают, что ваше расширение использует удаленно размещенный код. Обычно это происходит из-за попытки расширения добавить тег <script> с удаленным ресурсом (например, из открытого интернета, а не из файлов, включенных в само расширение) или из-за необходимости получить ресурс для прямого выполнения.

Как распознать RHC

Обнаружить нарушения RHC несложно, если знать, на что обращать внимание. Во-первых, проверьте наличие строк "http://" или "https://" в вашем проекте. Если у вас есть нарушение RHC, вы, скорее всего, сможете найти его, обнаружив эти строки. Если у вас используется полная система сборки или зависимости из npm или других сторонних источников, убедитесь, что вы ищете в скомпилированной версии кода, поскольку именно она оценивается магазином. Если вы по-прежнему не можете найти проблему, следующим шагом будет обращение в службу поддержки One Stop Support . Они смогут описать конкретные нарушения и то, что необходимо сделать для скорейшей публикации расширения.

Что делать, если библиотека запрашивает код?

Независимо от происхождения кода, использование RHC запрещено. Это касается и кода, который вы не создавали, но просто используете в качестве зависимости в своем проекте. Некоторые разработчики, использующие Firebase, столкнулись с этой проблемой, когда удаленный код включался для использования в Firebase Auth . Даже если это была собственная библиотека (то есть, принадлежащая Google), исключение для RHC не предусмотрено. Вам необходимо настроить код таким образом, чтобы либо удалить RHC, либо обновить проект, чтобы он изначально не включал этот код. Если вы столкнулись с проблемой, когда RHC загружается не вашим кодом, а используемой вами библиотекой, то лучше всего связаться с автором библиотеки. Сообщите ему об этом и попросите либо найти обходное решение, либо обновить код для его удаления.

Что делать, если вы не можете дождаться обновления библиотеки?

Некоторые библиотеки выпускают обновление практически сразу после получения уведомления, но другие могут отказаться от его выпуска или им может потребоваться время для решения проблемы. В зависимости от характера конкретного нарушения, вам, возможно, не придется ждать, пока оно будет снято с блокировки и успешно завершена проверка. Существует ряд вариантов, позволяющих быстро возобновить работу.

Проведите аудит кода

Вы уверены , что код, вызывающий запрос, действительно необходим? Если его можно просто удалить, или если можно удалить библиотеку, вызывающую запрос, то удалите этот код, и задача будет выполнена.

Или, может быть, существует другая библиотека, предлагающая аналогичные функции? Попробуйте поискать на npmjs.com , GitHub или других сайтах варианты, которые удовлетворяют тем же потребностям.

трясет дерево

Если код, вызывающий нарушение RHC, фактически не используется, его можно автоматически удалить с помощью инструментов сборки. Современные инструменты сборки, такие как webpack , Rollup и Vite (и это лишь некоторые из них), имеют функцию tree-shaking . После включения в вашей системе сборки tree-shaking должен удалить все неиспользуемые пути кода. Это может означать, что у вас будет не только более соответствующая требованиям версия вашего кода, но и более компактная и быстрая! Важно отметить, что не все библиотеки могут быть подвергнуты tree-shaking, но многие — да. В некоторых инструментах, таких как Rollup и Vite, tree-shaking включен по умолчанию. Для его включения необходимо настроить webpack. Если вы не используете систему сборки в качестве части вашего расширения, но используете библиотеки кода, вам настоятельно рекомендуется изучить возможность добавления инструмента сборки в ваш рабочий процесс. Инструменты сборки помогают писать более безопасные, надежные и поддерживаемые проекты.

Специфика реализации tree-shaking зависит от вашего конкретного проекта. Но, если взять простой пример с Rollup, вы можете добавить tree-shaking, просто скомпилировав код вашего проекта. Например, если у вас есть файл main.js, который только авторизуется в Firebase Auth:

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

Тогда вам останется лишь указать Rollup входной файл, плагин, необходимый для загрузки файлов Node.js (@rollup/plugin-node-resolve) , и имя создаваемого выходного файла.

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

Выполнив эту команду в окне терминала, вы получите сгенерированную версию нашего файла main.js , скомпилированную в один файл с именем compiled.js .

Rollup может быть простым, но при этом очень гибко настраивается. Вы можете добавить всевозможную сложную логику и конфигурацию, просто ознакомьтесь с их документацией . Добавление подобных инструментов сборки приведет к уменьшению размера и повышению эффективности кода, и в данном случае решит нашу проблему с удаленно размещенным кодом.

Автоматическое редактирование файлов

Всё более распространённый способ проникновения удалённо размещённого кода в вашу кодовую базу — это использование его в качестве подзависимости подключаемой библиотеки. Если библиотека X хочет import библиотеку Y с CDN, вам всё равно потребуется обновить её, чтобы она загружалась из локального источника. Современные системы сборки позволяют легко создавать плагины для извлечения удалённой ссылки и встраивания её непосредственно в ваш код.

Это означало бы, что при наличии кода, выглядящего следующим образом:

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

Можно было бы создать небольшой плагин для сворачивания данных.

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

После запуска сборки с новым плагином будет обнаружен каждый URL-адрес удаленного import , независимо от того, является ли он нашим кодом, подзависимостью, подподзависимостью или чем-либо еще.

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

Редактирование файлов вручную

Простейший вариант — просто удалить код, вызывающий ошибку RHC. Откройте его в любом текстовом редакторе и удалите строки, нарушающие правила. Однако это обычно не рекомендуется, поскольку такой подход ненадежен и может быть забыт. Это усложняет поддержку проекта, если файл с именем "library.min.js" на самом деле не является файлом library.min.js. Вместо редактирования исходных файлов, более удобным вариантом является использование инструмента, подобного patch-package . Это очень мощный инструмент, позволяющий сохранять изменения в файле, а не в самом файле. Он основан на патч-файлах , аналогичных тем, что используются в системах контроля версий, таких как Git или Subversion . Вам нужно всего лишь вручную изменить код, нарушающий правила, сохранить файл diff и настроить patch-package с изменениями, которые вы хотите применить. Полное руководство можно найти в файле README проекта . Если вы вносите изменения в проект, мы настоятельно рекомендуем вам связаться с проектом и запросить внесение изменений в основной репозиторий. Хотя использование пакета исправлений значительно упрощает управление обновлениями, еще лучше то, что вам нечего исправлять.

Что делать, если код не используется?

По мере роста кодовой базы зависимости (или зависимость зависимости, или зависимость…) могут сохранять участки кода, которые больше не используются. Если один из таких разделов содержит код для загрузки или выполнения RHC, то его необходимо удалить. Неважно, является ли он устаревшим или неиспользуемым. Если он не используется, его следует удалить либо путем оптимизации кода (treeshaking), либо путем внесения изменений в библиотеку для его удаления.

Есть ли какое-нибудь обходное решение?

В целом, нет. АД не допускается. Однако существует небольшое количество случаев, когда это разрешено . Практически всегда это случаи, когда другие варианты невозможны.

API пользовательских скриптов

Пользовательские скрипты — это небольшие фрагменты кода, обычно предоставляемые пользователем, предназначенные для менеджеров пользовательских скриптов, таких как TamperMonkey и Violentmonkey . Эти менеджеры не могут объединять код, написанный пользователями, поэтому API пользовательских скриптов предоставляет способ выполнения кода, предоставленного пользователем. Это не заменяет chrome.scripting.executeScript или другие среды выполнения кода. Пользователи должны включить режим разработчика , чтобы что-либо выполнить. Если команда проверки Chrome Web Store сочтет, что это используется не по назначению (т.е. кодом, предоставленным пользователем), это может быть отклонено или объявление удалено из магазина.

chrome.debugger

API chrome.debugger предоставляет расширениям возможность взаимодействовать с протоколом Chrome Devtools . Это тот же протокол, который используется для инструментов разработчика Chrome и множества других инструментов . С его помощью расширение может запрашивать и выполнять удаленный код. Как и пользовательские скрипты, он не заменяет chrome.scripting и обеспечивает гораздо более удобный пользовательский интерфейс. Во время его использования пользователь будет видеть предупреждающую панель в верхней части окна. Если баннер закрыть или отклонить, сеанс отладки будет завершен.

Скриншот адресной строки Chrome с сообщением «Расширение отладчика начало отладку этого браузера».
Скриншот адресной строки Chrome с сообщением «Расширение отладчика начало отладку этого браузера».

Ипфреймы в изолированной среде

Если вам необходимо выполнить проверку строки как кода и вы находитесь в среде DOM (например, в скрипте контента, а не в сервисном воркере расширения), то другой вариант — использовать изолированный iframe . Расширения по умолчанию не поддерживают такие функции, как eval() , в целях безопасности. Вредоносный код может поставить под угрозу безопасность пользователя. Но когда код выполняется только в заведомо безопасной среде, например, в изолированном от остальной части веб-пространства iframe, эти риски значительно снижаются. В этом контексте можно снять политику безопасности контента, которая блокирует использование eval, что позволит вам запускать любой допустимый код JavaScript.

Если у вас есть сценарий использования, который не описан в данном документе, вы можете обратиться к команде через список рассылки chromium-extensions , чтобы получить обратную связь, или открыть новый запрос в службу поддержки One Stop Support, чтобы получить консультацию.

Что делать, если вы не согласны с вердиктом?

Применение правил может быть сложным процессом, а проверка включает ручной ввод данных, что означает, что команда Chrome Web Store иногда может согласиться изменить решение по проверке. Если вы считаете, что при проверке была допущена ошибка, вы можете обжаловать отказ, используя службу поддержки One Stop Support.