chore(extensions): remove old renderer code (#25347)
This commit is contained in:
parent
31322400e7
commit
860e14c0da
6 changed files with 1 additions and 306 deletions
|
@ -1,119 +0,0 @@
|
||||||
import { webFrame } from 'electron';
|
|
||||||
|
|
||||||
import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils';
|
|
||||||
|
|
||||||
const v8Util = process._linkedBinding('electron_common_v8_util');
|
|
||||||
|
|
||||||
const IsolatedWorldIDs = {
|
|
||||||
/**
|
|
||||||
* Start of extension isolated world IDs, as defined in
|
|
||||||
* electron_render_frame_observer.h
|
|
||||||
*/
|
|
||||||
ISOLATED_WORLD_EXTENSIONS: 1 << 20
|
|
||||||
};
|
|
||||||
|
|
||||||
let isolatedWorldIds = IsolatedWorldIDs.ISOLATED_WORLD_EXTENSIONS;
|
|
||||||
const extensionWorldId: {[key: string]: number | undefined} = {};
|
|
||||||
|
|
||||||
// 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: string) {
|
|
||||||
return pattern.replace(/[\\^$+?.()|[\]{}]/g, '\\$&');
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check whether pattern matches.
|
|
||||||
// https://developer.chrome.com/extensions/match_patterns
|
|
||||||
const matchesPattern = function (pattern: string) {
|
|
||||||
if (pattern === '<all_urls>') 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 (this: any, extensionId: string, url: string, code: string) {
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
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 webFrame.executeJavaScriptInIsolatedWorld(worldId, sources);
|
|
||||||
};
|
|
||||||
|
|
||||||
const runAllContentScript = function (scripts: Array<Electron.InjectionBase>, extensionId: string) {
|
|
||||||
for (const { url, code } of scripts) {
|
|
||||||
runContentScript.call(window, extensionId, url, code);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const runStylesheet = function (this: any, url: string, code: string) {
|
|
||||||
webFrame.insertCSS(code);
|
|
||||||
};
|
|
||||||
|
|
||||||
const runAllStylesheet = function (css: Array<Electron.InjectionBase>) {
|
|
||||||
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: string, script: Electron.ContentScript) {
|
|
||||||
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: Electron.Event,
|
|
||||||
extensionId: string,
|
|
||||||
url: string,
|
|
||||||
code: string
|
|
||||||
) {
|
|
||||||
return runContentScript.call(window, extensionId, url, code);
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = (entries: Electron.ContentScriptEntry[]) => {
|
|
||||||
for (const entry of entries) {
|
|
||||||
if (entry.contentScripts) {
|
|
||||||
for (const script of entry.contentScripts) {
|
|
||||||
injectContentScript(entry.extensionId, script);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,20 +0,0 @@
|
||||||
export class Event {
|
|
||||||
private listeners: Function[] = []
|
|
||||||
|
|
||||||
addListener (callback: Function) {
|
|
||||||
this.listeners.push(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
removeListener (callback: Function) {
|
|
||||||
const index = this.listeners.indexOf(callback);
|
|
||||||
if (index !== -1) {
|
|
||||||
this.listeners.splice(index, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
emit (...args: any[]) {
|
|
||||||
for (const listener of this.listeners) {
|
|
||||||
listener(...args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
// Implementation of chrome.i18n.getMessage
|
|
||||||
// https://developer.chrome.com/extensions/i18n#method-getMessage
|
|
||||||
//
|
|
||||||
// Does not implement predefined messages:
|
|
||||||
// https://developer.chrome.com/extensions/i18n#overview-predefined
|
|
||||||
|
|
||||||
import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils';
|
|
||||||
|
|
||||||
interface Placeholder {
|
|
||||||
content: string;
|
|
||||||
example?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const getMessages = (extensionId: number) => {
|
|
||||||
try {
|
|
||||||
const data = ipcRendererUtils.invokeSync<string>('CHROME_GET_MESSAGES', extensionId);
|
|
||||||
return JSON.parse(data) || {};
|
|
||||||
} catch {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const replaceNumberedSubstitutions = (message: string, substitutions: string[]) => {
|
|
||||||
return message.replace(/\$(\d+)/, (_, number) => {
|
|
||||||
const index = parseInt(number, 10) - 1;
|
|
||||||
return substitutions[index] || '';
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const replacePlaceholders = (message: string, placeholders: Record<string, Placeholder>, substitutions: string[] | string) => {
|
|
||||||
if (typeof substitutions === 'string') substitutions = [substitutions];
|
|
||||||
if (!Array.isArray(substitutions)) substitutions = [];
|
|
||||||
|
|
||||||
if (placeholders) {
|
|
||||||
Object.keys(placeholders).forEach((name: string) => {
|
|
||||||
let { content } = placeholders[name];
|
|
||||||
const substitutionsArray = Array.isArray(substitutions) ? substitutions : [];
|
|
||||||
content = replaceNumberedSubstitutions(content, substitutionsArray);
|
|
||||||
message = message.replace(new RegExp(`\\$${name}\\$`, 'gi'), content);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return replaceNumberedSubstitutions(message, substitutions);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getMessage = (extensionId: number, messageName: string, substitutions: string[]) => {
|
|
||||||
const messages = getMessages(extensionId);
|
|
||||||
if (Object.prototype.hasOwnProperty.call(messages, messageName)) {
|
|
||||||
const { message, placeholders } = messages[messageName];
|
|
||||||
return replacePlaceholders(message, placeholders, substitutions);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.setup = (extensionId: number) => {
|
|
||||||
return {
|
|
||||||
getMessage (messageName: string, substitutions: string[]) {
|
|
||||||
return getMessage(extensionId, messageName, substitutions);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,86 +0,0 @@
|
||||||
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
|
|
||||||
|
|
||||||
const getStorage = (storageType: string, extensionId: number, callback: Function) => {
|
|
||||||
if (typeof callback !== 'function') throw new TypeError('No callback provided');
|
|
||||||
|
|
||||||
ipcRendererInternal.invoke<string>('CHROME_STORAGE_READ', storageType, extensionId)
|
|
||||||
.then(data => {
|
|
||||||
if (data !== null) {
|
|
||||||
callback(JSON.parse(data));
|
|
||||||
} else {
|
|
||||||
// Disabled due to false positive in StandardJS
|
|
||||||
// eslint-disable-next-line standard/no-callback-literal
|
|
||||||
callback({});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const setStorage = (storageType: string, extensionId: number, storage: Record<string, any>, callback: Function) => {
|
|
||||||
const json = JSON.stringify(storage);
|
|
||||||
ipcRendererInternal.invoke('CHROME_STORAGE_WRITE', storageType, extensionId, json)
|
|
||||||
.then(() => {
|
|
||||||
if (callback) callback();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const getStorageManager = (storageType: string, extensionId: number) => {
|
|
||||||
return {
|
|
||||||
get (keys: string[], callback: Function) {
|
|
||||||
getStorage(storageType, extensionId, (storage: Record<string, any>) => {
|
|
||||||
if (keys == null) return callback(storage);
|
|
||||||
|
|
||||||
let defaults: Record<string, any> = {};
|
|
||||||
switch (typeof keys) {
|
|
||||||
case 'string':
|
|
||||||
keys = [keys];
|
|
||||||
break;
|
|
||||||
case 'object':
|
|
||||||
if (!Array.isArray(keys)) {
|
|
||||||
defaults = keys;
|
|
||||||
keys = Object.keys(keys);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disabled due to false positive in StandardJS
|
|
||||||
// eslint-disable-next-line standard/no-callback-literal
|
|
||||||
if (keys.length === 0) return callback({});
|
|
||||||
|
|
||||||
const items: Record<string, any> = {};
|
|
||||||
keys.forEach((key: string) => {
|
|
||||||
let value = storage[key];
|
|
||||||
if (value == null) value = defaults[key];
|
|
||||||
items[key] = value;
|
|
||||||
});
|
|
||||||
callback(items);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
set (items: Record<string, any>, callback: Function) {
|
|
||||||
getStorage(storageType, extensionId, (storage: Record<string, any>) => {
|
|
||||||
Object.keys(items).forEach(name => { storage[name] = items[name]; });
|
|
||||||
setStorage(storageType, extensionId, storage, callback);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
remove (keys: string[], callback: Function) {
|
|
||||||
getStorage(storageType, extensionId, (storage: Record<string, any>) => {
|
|
||||||
if (!Array.isArray(keys)) keys = [keys];
|
|
||||||
keys.forEach((key: string) => {
|
|
||||||
delete storage[key];
|
|
||||||
});
|
|
||||||
|
|
||||||
setStorage(storageType, extensionId, storage, callback);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
clear (callback: Function) {
|
|
||||||
setStorage(storageType, extensionId, {}, callback);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const setup = (extensionId: number) => ({
|
|
||||||
sync: getStorageManager('sync', extensionId),
|
|
||||||
local: getStorageManager('local', extensionId)
|
|
||||||
});
|
|
|
@ -1,19 +0,0 @@
|
||||||
import { Event } from '@electron/internal/renderer/extensions/event';
|
|
||||||
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
|
|
||||||
|
|
||||||
class WebNavigation {
|
|
||||||
private onBeforeNavigate = new Event()
|
|
||||||
private onCompleted = new Event()
|
|
||||||
|
|
||||||
constructor () {
|
|
||||||
ipcRendererInternal.on('CHROME_WEBNAVIGATION_ONBEFORENAVIGATE', (event: Electron.IpcRendererEvent, details: any) => {
|
|
||||||
this.onBeforeNavigate.emit(details);
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcRendererInternal.on('CHROME_WEBNAVIGATION_ONCOMPLETED', (event: Electron.IpcRendererEvent, details: any) => {
|
|
||||||
this.onCompleted.emit(details);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const setup = () => new WebNavigation();
|
|
|
@ -16,8 +16,7 @@ enum WorldIDs : int32_t {
|
||||||
// IDs created internally by Chrome.
|
// IDs created internally by Chrome.
|
||||||
ISOLATED_WORLD_ID = 999,
|
ISOLATED_WORLD_ID = 999,
|
||||||
|
|
||||||
// Numbers for isolated worlds for extensions are set in
|
// Numbers for isolated worlds for extensions are greater than or equal to
|
||||||
// lib/renderer/content-script-injector.ts, and are greater than or equal to
|
|
||||||
// this number, up to ISOLATED_WORLD_ID_EXTENSIONS_END.
|
// this number, up to ISOLATED_WORLD_ID_EXTENSIONS_END.
|
||||||
ISOLATED_WORLD_ID_EXTENSIONS = 1 << 20,
|
ISOLATED_WORLD_ID_EXTENSIONS = 1 << 20,
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue