"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const electron_1 = require("electron"); const ipcRendererUtils = require("@electron/internal/renderer/ipc-renderer-internal-utils"); const v8Util = process.electronBinding('v8_util'); const IsolatedWorldIDs = { /** * Start of extension isolated world IDs, as defined in * atom_render_frame_observer.h */ ISOLATED_WORLD_EXTENSIONS: 1 << 20 }; let isolatedWorldIds = IsolatedWorldIDs.ISOLATED_WORLD_EXTENSIONS; const extensionWorldId = {}; // https://cs.chromium.org/chromium/src/extensions/renderer/script_injection.cc?type=cs&sq=package:chromium&g=0&l=52 const getIsolatedWorldIdForInstance = () => { // TODO(samuelmaddock): allocate and cleanup IDs return isolatedWorldIds++; }; const escapePattern = function (pattern) { return pattern.replace(/[\\^$+?.()|[\]{}]/g, '\\$&'); }; // Check whether pattern matches. // https://developer.chrome.com/extensions/match_patterns const matchesPattern = function (pattern) { if (pattern === '') return true; const regexp = new RegExp(`^${pattern.split('*').map(escapePattern).join('.*')}$`); const url = `${location.protocol}//${location.host}${location.pathname}`; return url.match(regexp); }; // Run the code with chrome API integrated. const runContentScript = function (extensionId, url, code) { // Assign unique world ID to each extension const worldId = extensionWorldId[extensionId] || (extensionWorldId[extensionId] = getIsolatedWorldIdForInstance()); // store extension ID for content script to read in isolated world v8Util.setHiddenValue(global, `extension-${worldId}`, extensionId); electron_1.webFrame.setIsolatedWorldInfo(worldId, { name: `${extensionId} [${worldId}]` // TODO(samuelmaddock): read `content_security_policy` from extension manifest // csp: manifest.content_security_policy, }); const sources = [{ code, url }]; return electron_1.webFrame.executeJavaScriptInIsolatedWorld(worldId, sources); }; const runAllContentScript = function (scripts, extensionId) { for (const { url, code } of scripts) { runContentScript.call(window, extensionId, url, code); } }; const runStylesheet = function (url, code) { electron_1.webFrame.insertCSS(code); }; const runAllStylesheet = function (css) { for (const { url, code } of css) { runStylesheet.call(window, url, code); } }; // Run injected scripts. // https://developer.chrome.com/extensions/content_scripts const injectContentScript = function (extensionId, script) { if (!process.isMainFrame && !script.allFrames) return; if (!script.matches.some(matchesPattern)) return; if (script.js) { const fire = runAllContentScript.bind(window, script.js, extensionId); if (script.runAt === 'document_start') { process.once('document-start', fire); } else if (script.runAt === 'document_end') { process.once('document-end', fire); } else { document.addEventListener('DOMContentLoaded', fire); } } if (script.css) { const fire = runAllStylesheet.bind(window, script.css); if (script.runAt === 'document_start') { process.once('document-start', fire); } else if (script.runAt === 'document_end') { process.once('document-end', fire); } else { document.addEventListener('DOMContentLoaded', fire); } } }; // Handle the request of chrome.tabs.executeJavaScript. ipcRendererUtils.handle('CHROME_TABS_EXECUTE_SCRIPT', function (event, extensionId, url, code) { return runContentScript.call(window, extensionId, url, code); }); module.exports = (getRenderProcessPreferences) => { // Read the renderer process preferences. const preferences = getRenderProcessPreferences(); if (preferences) { for (const pref of preferences) { if (pref.contentScripts) { for (const script of pref.contentScripts) { injectContentScript(pref.extensionId, script); } } } } };