Kaynağa Gözat

fix: stabilize INIT_FUNC_NAME to pacify AMO (#1694)

tophf 3 yıl önce
ebeveyn
işleme
c381e02d3f

+ 0 - 9
scripts/webpack-util.js

@@ -50,14 +50,6 @@ function getCodeMirrorThemes() {
   .filter(Boolean);
 }
 
-function getUniqIdB64() {
-  return Buffer.from(
-    new Uint32Array(2)
-    .map(() => Math.random() * (2 ** 32))
-    .buffer,
-  ).toString('base64');
-}
-
 function readGlobalsFile(path, babelOpts = {}) {
   const { ast, code = !ast } = babelOpts;
   const filename = entryPathToFilename(path);
@@ -75,5 +67,4 @@ function readGlobalsFile(path, babelOpts = {}) {
 
 exports.addWrapperWithGlobals = addWrapperWithGlobals;
 exports.getCodeMirrorThemes = getCodeMirrorThemes;
-exports.getUniqIdB64 = getUniqIdB64;
 exports.readGlobalsFile = readGlobalsFile;

+ 2 - 2
scripts/webpack.conf.js

@@ -4,14 +4,14 @@ const webpack = require('webpack');
 const TerserPlugin = isProd && require('terser-webpack-plugin');
 const deepmerge = isProd && require('deepmerge');
 const { ListBackgroundScriptsPlugin } = require('./manifest-helper');
-const { addWrapperWithGlobals, getCodeMirrorThemes, getUniqIdB64 } = require('./webpack-util');
+const { addWrapperWithGlobals, getCodeMirrorThemes } = require('./webpack-util');
 const ProtectWebpackBootstrapPlugin = require('./webpack-protect-bootstrap-plugin');
 const projectConfig = require('./plaid.conf');
 const { getVersion } = require('./version-helper');
 const mergedConfig = shallowMerge(defaultOptions, projectConfig);
 
 // Avoiding collisions with globals of a content-mode userscript
-const INIT_FUNC_NAME = `Violentmonkey:${getUniqIdB64()}`;
+const INIT_FUNC_NAME = '**VMInitInjection**';
 const VAULT_ID = 'VAULT_ID';
 const PAGE_MODE_HANDSHAKE = 'PAGE_MODE_HANDSHAKE';
 const VM_VER = getVersion();

+ 0 - 3
src/background/index.js

@@ -121,9 +121,6 @@ initialize(() => {
     api.onPageChanged.getRules(/* for old Chrome */ null, async ([rule]) => {
       const id = rule?.id;
       const newId = process.env.INIT_FUNC_NAME;
-      if (id === newId) {
-        return;
-      }
       if (id) {
         await browser.declarativeContent.onPageChanged.removeRules([id]);
       }

+ 2 - 0
src/background/utils/preinject.js

@@ -19,6 +19,7 @@ let isApplied;
 let injectInto;
 let xhrInject;
 
+const sessionId = getUniqId();
 const API_CONFIG = {
   urls: ['*://*/*'], // `*` scheme matches only http and https
   types: ['main_frame', 'sub_frame'],
@@ -278,6 +279,7 @@ async function prepare(cacheKey, url, isTop) {
     ids: allIds,
     info: { ua },
     errors: errors.filter(err => allIds[err.split('#').pop()]).join('\n'),
+    sessionId,
   });
   propsToClear::forEachValue(val => {
     if (val !== true) bag[val] = env[val];

+ 1 - 1
src/injected/content/index.js

@@ -34,7 +34,7 @@ async function init() {
   );
   assign(ids, data.ids);
   bridge[INJECT_INTO] = data[INJECT_INTO];
-  if (data.expose && !isXml && injectPageSandbox()) {
+  if (data.expose && !isXml && injectPageSandbox(data)) {
     addHandlers({ GetScriptVer: true });
     bridge.post('Expose');
   }

+ 23 - 26
src/injected/content/inject.js

@@ -3,12 +3,6 @@ import { elemByTag, makeElem, nextTask, onElement, sendCmd } from './util';
 import { bindEvents, fireBridgeEvent, META_STR } from '../util';
 import { Run } from './cmd-run';
 
-/* In FF, content scripts running in a same-origin frame cannot directly call parent's functions
- * so we'll use the extension's UUID, which is unique per computer in FF, for messages
- * like VAULT_WRITER to avoid interception by sites that can add listeners for all of our
- * INIT_FUNC_NAME ids even though we change it now with each release. */
-const VAULT_WRITER = `${VM_UUID}${INIT_FUNC_NAME}VW`;
-const VAULT_WRITER_ACK = `${VAULT_WRITER}+`;
 const bridgeIds = bridge.ids;
 let tardyQueue;
 let bridgeInfo;
@@ -25,24 +19,6 @@ let VMInitInjection = window[INIT_FUNC_NAME];
 /** Avoid running repeatedly due to new `documentElement` or with declarativeContent in Chrome.
  * The prop's mode is overridden to be unforgeable by a userscript in content mode. */
 setOwnProp(window, INIT_FUNC_NAME, 1, false);
-if (IS_FIREFOX) {
-  window::on(VAULT_WRITER, evt => {
-    evt::stopImmediatePropagation();
-    if (!frameEventWnd) {
-      // setupVaultId's first event is the frame's contentWindow
-      frameEventWnd = evt::getRelatedTarget();
-    } else {
-      // setupVaultId's second event is the vaultId
-      frameEventWnd::fire(new SafeCustomEvent(VAULT_WRITER_ACK, {
-        __proto__: null,
-        detail: tellBridgeToWriteVault(evt::getDetail(), frameEventWnd),
-      }));
-      frameEventWnd = null;
-    }
-  }, true);
-} else {
-  setOwnProp(global, VAULT_WRITER, tellBridgeToWriteVault, false);
-}
 
 addHandlers({
   /**
@@ -51,12 +27,33 @@ addHandlers({
   InjectList: IS_FIREFOX && injectPageList,
 });
 
-export function injectPageSandbox() {
+export function injectPageSandbox({ sessionId }) {
   pageInjectable = false;
+  const VAULT_WRITER = sessionId + 'VW';
+  const VAULT_WRITER_ACK = VAULT_WRITER + '*';
   const vaultId = safeGetUniqId();
   const handshakeId = safeGetUniqId();
   const contentId = safeGetUniqId();
   const webId = safeGetUniqId();
+  if (IS_FIREFOX) {
+    // In FF, content scripts running in a same-origin frame cannot directly call parent's functions
+    window::on(VAULT_WRITER, evt => {
+      evt::stopImmediatePropagation();
+      if (!frameEventWnd) {
+        // setupVaultId's first event is the frame's contentWindow
+        frameEventWnd = evt::getRelatedTarget();
+      } else {
+        // setupVaultId's second event is the vaultId
+        frameEventWnd::fire(new SafeCustomEvent(VAULT_WRITER_ACK, {
+          __proto__: null,
+          detail: tellBridgeToWriteVault(evt::getDetail(), frameEventWnd),
+        }));
+        frameEventWnd = null;
+      }
+    }, true);
+  } else {
+    setOwnProp(global, VAULT_WRITER, tellBridgeToWriteVault, false);
+  }
   if (useOpener(opener) || useOpener(!IS_TOP && parent)) {
     startHandshake();
   } else {
@@ -134,7 +131,7 @@ export async function injectScripts(data, isXml) {
   if (isXml || data[INJECT_CONTENT_FORCE]) {
     pageInjectable = false;
   } else if (data[INJECT_PAGE] && pageInjectable == null) {
-    injectPageSandbox();
+    injectPageSandbox(data);
   }
   const toContent = data.scripts
     .filter(scr => triageScript(scr) === INJECT_CONTENT)

+ 1 - 0
src/types.d.ts

@@ -219,6 +219,7 @@ declare interface VMInjection extends VMInjectionDisabled {
   /** `page` mode will be necessary */
   page: boolean;
   scripts: VMInjection.Script[];
+  sessionId: string;
 }
 
 /**