mirror of
https://github.com/gorhill/uBlock.git
synced 2024-10-06 09:37:12 +02:00
[mv3] Avoid String.replace() to safely replace templates
String.replace() has side effects which are unwelcomed when replacing template scriplets with code.
This commit is contained in:
parent
7e712246a9
commit
5874312b35
@ -32,6 +32,7 @@ import redirectResourcesMap from './js/redirect-resources.js';
|
|||||||
import { dnrRulesetFromRawLists } from './js/static-dnr-filtering.js';
|
import { dnrRulesetFromRawLists } from './js/static-dnr-filtering.js';
|
||||||
import * as sfp from './js/static-filtering-parser.js';
|
import * as sfp from './js/static-filtering-parser.js';
|
||||||
import * as makeScriptlet from './make-scriptlets.js';
|
import * as makeScriptlet from './make-scriptlets.js';
|
||||||
|
import { safeReplace } from './safe-replace.js';
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
@ -400,14 +401,14 @@ async function processGenericCosmeticFilters(assetDetails, bucketsMap, exclusion
|
|||||||
const selectorLists = bucketsList.map(v => [ v[0], v[1].join(',') ]);
|
const selectorLists = bucketsList.map(v => [ v[0], v[1].join(',') ]);
|
||||||
const originalScriptletMap = await loadAllSourceScriptlets();
|
const originalScriptletMap = await loadAllSourceScriptlets();
|
||||||
|
|
||||||
const patchedScriptlet = originalScriptletMap.get('css-generic')
|
let patchedScriptlet = originalScriptletMap.get('css-generic').replace(
|
||||||
.replace(
|
'$rulesetId$',
|
||||||
'$rulesetId$',
|
assetDetails.id
|
||||||
assetDetails.id
|
);
|
||||||
).replace(
|
patchedScriptlet = safeReplace(patchedScriptlet,
|
||||||
/\bself\.\$genericSelectorMap\$/m,
|
/\bself\.\$genericSelectorMap\$/,
|
||||||
`${JSON.stringify(selectorLists, scriptletJsonReplacer)}`
|
`${JSON.stringify(selectorLists, scriptletJsonReplacer)}`
|
||||||
);
|
);
|
||||||
|
|
||||||
writeFile(
|
writeFile(
|
||||||
`${scriptletDir}/generic/${assetDetails.id}.js`,
|
`${scriptletDir}/generic/${assetDetails.id}.js`,
|
||||||
@ -593,23 +594,26 @@ async function processCosmeticFilters(assetDetails, mapin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const originalScriptletMap = await loadAllSourceScriptlets();
|
const originalScriptletMap = await loadAllSourceScriptlets();
|
||||||
const patchedScriptlet = originalScriptletMap.get('css-specific')
|
let patchedScriptlet = originalScriptletMap.get('css-specific').replace(
|
||||||
.replace(
|
'$rulesetId$',
|
||||||
'$rulesetId$',
|
assetDetails.id
|
||||||
assetDetails.id
|
);
|
||||||
).replace(
|
patchedScriptlet = safeReplace(patchedScriptlet,
|
||||||
/\bself\.\$argsList\$/m,
|
/\bself\.\$argsList\$/,
|
||||||
`${JSON.stringify(argsList, scriptletJsonReplacer)}`
|
`${JSON.stringify(argsList, scriptletJsonReplacer)}`
|
||||||
).replace(
|
);
|
||||||
/\bself\.\$hostnamesMap\$/m,
|
patchedScriptlet = safeReplace(patchedScriptlet,
|
||||||
`${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}`
|
/\bself\.\$hostnamesMap\$/,
|
||||||
).replace(
|
`${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}`
|
||||||
/\bself\.\$entitiesMap\$/m,
|
);
|
||||||
`${JSON.stringify(entitiesMap, scriptletJsonReplacer)}`
|
patchedScriptlet = safeReplace(patchedScriptlet,
|
||||||
).replace(
|
/\bself\.\$entitiesMap\$/,
|
||||||
/\bself\.\$exceptionsMap\$/m,
|
`${JSON.stringify(entitiesMap, scriptletJsonReplacer)}`
|
||||||
`${JSON.stringify(exceptionsMap, scriptletJsonReplacer)}`
|
);
|
||||||
);
|
patchedScriptlet = safeReplace(patchedScriptlet,
|
||||||
|
/\bself\.\$exceptionsMap\$/,
|
||||||
|
`${JSON.stringify(exceptionsMap, scriptletJsonReplacer)}`
|
||||||
|
);
|
||||||
writeFile(`${scriptletDir}/specific/${assetDetails.id}.js`, patchedScriptlet);
|
writeFile(`${scriptletDir}/specific/${assetDetails.id}.js`, patchedScriptlet);
|
||||||
generatedFiles.push(`${assetDetails.id}`);
|
generatedFiles.push(`${assetDetails.id}`);
|
||||||
|
|
||||||
@ -677,23 +681,26 @@ async function processDeclarativeCosmeticFilters(assetDetails, mapin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const originalScriptletMap = await loadAllSourceScriptlets();
|
const originalScriptletMap = await loadAllSourceScriptlets();
|
||||||
const patchedScriptlet = originalScriptletMap.get('css-declarative')
|
let patchedScriptlet = originalScriptletMap.get('css-declarative').replace(
|
||||||
.replace(
|
'$rulesetId$',
|
||||||
'$rulesetId$',
|
assetDetails.id
|
||||||
assetDetails.id
|
);
|
||||||
).replace(
|
patchedScriptlet = safeReplace(patchedScriptlet,
|
||||||
/\bself\.\$argsList\$/m,
|
/\bself\.\$argsList\$/,
|
||||||
`${JSON.stringify(argsList, scriptletJsonReplacer)}`
|
`${JSON.stringify(argsList, scriptletJsonReplacer)}`
|
||||||
).replace(
|
);
|
||||||
/\bself\.\$hostnamesMap\$/m,
|
patchedScriptlet = safeReplace(patchedScriptlet,
|
||||||
`${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}`
|
/\bself\.\$hostnamesMap\$/,
|
||||||
).replace(
|
`${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}`
|
||||||
/\bself\.\$entitiesMap\$/m,
|
);
|
||||||
`${JSON.stringify(entitiesMap, scriptletJsonReplacer)}`
|
patchedScriptlet = safeReplace(patchedScriptlet,
|
||||||
).replace(
|
/\bself\.\$entitiesMap\$/,
|
||||||
/\bself\.\$exceptionsMap\$/m,
|
`${JSON.stringify(entitiesMap, scriptletJsonReplacer)}`
|
||||||
`${JSON.stringify(exceptionsMap, scriptletJsonReplacer)}`
|
);
|
||||||
);
|
patchedScriptlet = safeReplace(patchedScriptlet,
|
||||||
|
/\bself\.\$exceptionsMap\$/,
|
||||||
|
`${JSON.stringify(exceptionsMap, scriptletJsonReplacer)}`
|
||||||
|
);
|
||||||
writeFile(`${scriptletDir}/declarative/${assetDetails.id}.js`, patchedScriptlet);
|
writeFile(`${scriptletDir}/declarative/${assetDetails.id}.js`, patchedScriptlet);
|
||||||
|
|
||||||
if ( contentArray.length !== 0 ) {
|
if ( contentArray.length !== 0 ) {
|
||||||
@ -760,23 +767,26 @@ async function processProceduralCosmeticFilters(assetDetails, mapin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const originalScriptletMap = await loadAllSourceScriptlets();
|
const originalScriptletMap = await loadAllSourceScriptlets();
|
||||||
const patchedScriptlet = originalScriptletMap.get('css-procedural')
|
let patchedScriptlet = originalScriptletMap.get('css-procedural').replace(
|
||||||
.replace(
|
'$rulesetId$',
|
||||||
'$rulesetId$',
|
assetDetails.id
|
||||||
assetDetails.id
|
);
|
||||||
).replace(
|
patchedScriptlet = safeReplace(patchedScriptlet,
|
||||||
/\bself\.\$argsList\$/m,
|
/\bself\.\$argsList\$/,
|
||||||
`${JSON.stringify(argsList, scriptletJsonReplacer)}`
|
`${JSON.stringify(argsList, scriptletJsonReplacer)}`
|
||||||
).replace(
|
);
|
||||||
/\bself\.\$hostnamesMap\$/m,
|
patchedScriptlet = safeReplace(patchedScriptlet,
|
||||||
`${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}`
|
/\bself\.\$hostnamesMap\$/,
|
||||||
).replace(
|
`${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}`
|
||||||
/\bself\.\$entitiesMap\$/m,
|
);
|
||||||
`${JSON.stringify(entitiesMap, scriptletJsonReplacer)}`
|
patchedScriptlet = safeReplace(patchedScriptlet,
|
||||||
).replace(
|
/\bself\.\$entitiesMap\$/,
|
||||||
/\bself\.\$exceptionsMap\$/m,
|
`${JSON.stringify(entitiesMap, scriptletJsonReplacer)}`
|
||||||
`${JSON.stringify(exceptionsMap, scriptletJsonReplacer)}`
|
);
|
||||||
);
|
patchedScriptlet = safeReplace(patchedScriptlet,
|
||||||
|
/\bself\.\$exceptionsMap\$/,
|
||||||
|
`${JSON.stringify(exceptionsMap, scriptletJsonReplacer)}`
|
||||||
|
);
|
||||||
writeFile(`${scriptletDir}/procedural/${assetDetails.id}.js`, patchedScriptlet);
|
writeFile(`${scriptletDir}/procedural/${assetDetails.id}.js`, patchedScriptlet);
|
||||||
|
|
||||||
if ( contentArray.length !== 0 ) {
|
if ( contentArray.length !== 0 ) {
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
import fs from 'fs/promises';
|
import fs from 'fs/promises';
|
||||||
import { builtinScriptlets } from './scriptlets.js';
|
import { builtinScriptlets } from './scriptlets.js';
|
||||||
|
import { safeReplace } from './safe-replace.js';
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
@ -52,25 +53,6 @@ function createScriptletCoreCode(scriptletToken) {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
function safeReplace(text, pattern, replacement, count = 1) {
|
|
||||||
const rePattern = typeof pattern === 'string'
|
|
||||||
? new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
|
|
||||||
: pattern;
|
|
||||||
let out = text;
|
|
||||||
for (;;) {
|
|
||||||
const match = rePattern.exec(out);
|
|
||||||
if ( match === null ) { break; }
|
|
||||||
out = out.slice(0, match.index) +
|
|
||||||
replacement +
|
|
||||||
out.slice(match.index + match[0].length);
|
|
||||||
count -= 1;
|
|
||||||
if ( count === 0 ) { break; }
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
export function init() {
|
export function init() {
|
||||||
for ( const scriptlet of builtinScriptlets ) {
|
for ( const scriptlet of builtinScriptlets ) {
|
||||||
const { name, aliases, fn } = scriptlet;
|
const { name, aliases, fn } = scriptlet;
|
||||||
|
41
platform/mv3/safe-replace.js
Normal file
41
platform/mv3/safe-replace.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
uBlock Origin - a browser extension to block requests.
|
||||||
|
Copyright (C) 2017-present Raymond Hill
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||||
|
|
||||||
|
Home: https://github.com/gorhill/uBlock
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
export function safeReplace(text, pattern, replacement, count = 1) {
|
||||||
|
const rePattern = typeof pattern === 'string'
|
||||||
|
? new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
|
||||||
|
: pattern;
|
||||||
|
let out = text;
|
||||||
|
for (;;) {
|
||||||
|
const match = rePattern.exec(out);
|
||||||
|
if ( match === null ) { break; }
|
||||||
|
out = out.slice(0, match.index) +
|
||||||
|
replacement +
|
||||||
|
out.slice(match.index + match[0].length);
|
||||||
|
count -= 1;
|
||||||
|
if ( count === 0 ) { break; }
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user