From 46cf8eaec0e65cd3159314e19f7a12aadf51c4e0 Mon Sep 17 00:00:00 2001 From: Krzysztof Modras Date: Sat, 28 Oct 2023 10:22:50 +0200 Subject: [PATCH] Scriptlet params edge case fix (#3558) --- packages/adblocker/src/filters/cosmetic.ts | 27 ++++++--- packages/adblocker/test/parsing.test.ts | 70 +++++++++++++++++++++- 2 files changed, 87 insertions(+), 10 deletions(-) diff --git a/packages/adblocker/src/filters/cosmetic.ts b/packages/adblocker/src/filters/cosmetic.ts index 4d815d5f8f..dfaaeec932 100644 --- a/packages/adblocker/src/filters/cosmetic.ts +++ b/packages/adblocker/src/filters/cosmetic.ts @@ -687,6 +687,7 @@ export default class CosmeticFilter implements IFilter { let inRegexp = false; let objectNesting = 0; let lastCharIsBackslash = false; + let inArgument = false; for (; index < selector.length; index += 1) { const char = selector[index]; @@ -715,17 +716,25 @@ export default class CosmeticFilter implements IFilter { inRegexp = false; } } else { - if (char === '"') { - inDoubleQuotes = true; - } else if (char === "'") { - inSingleQuotes = true; - } else if (char === '{') { - objectNesting += 1; - } else if (char === '/') { - inRegexp = true; - } else if (char === ',') { + if (inArgument === false) { + if (char === ' ') { + // ignore + } else if (char === '"' && selector.indexOf('"', index + 1) > 0) { + inDoubleQuotes = true; + } else if (char === "'" && selector.indexOf("'", index + 1) > 0) { + inSingleQuotes = true; + } else if (char === '{' && selector.indexOf('}', index + 1) > 0) { + objectNesting += 1; + } else if (char === '/' && selector.indexOf('/', index + 1) > 0) { + inRegexp = true; + } else { + inArgument = true; + } + } + if (char === ',') { parts.push(selector.slice(lastComaIndex + 1, index).trim()); lastComaIndex = index; + inArgument = false; } } } diff --git a/packages/adblocker/test/parsing.test.ts b/packages/adblocker/test/parsing.test.ts index 0684ba7c3d..b26e9b1bfd 100644 --- a/packages/adblocker/test/parsing.test.ts +++ b/packages/adblocker/test/parsing.test.ts @@ -2146,6 +2146,70 @@ describe('scriptlets arguments parsing', () => { it('complex', () => { for (const [scriptlet, expected] of [ + [ + 'script-name, {x, y', + { + name: 'script-name', + args: ['{x', 'y'], + }, + ], + [ + 'script-name, "x, y', + { + name: 'script-name', + args: ['"x', 'y'], + }, + ], + [ + "script-name, 'x, y", + { + name: 'script-name', + args: ["'x", 'y'], + }, + ], + [ + 'script-name, /x, y', + { + name: 'script-name', + args: ['/x', 'y'], + }, + ], + [ + 'xml-prune,a/b,///,,c', + { + name: 'xml-prune', + args: ['a/b', '///', '', 'c'], + }, + ], + [ + `xml-prune, xpath(//*[name()="MPD"]/@mediaPresentationDuration | //*[name()="Period"][.//*[name()="BaseURL" and contains(text()\\,'/ads-')]] | //*[name()="Period"]/@start), Period[id^="Ad"i], .mpd`, + { + name: 'xml-prune', + args: [ + `xpath(//*[name()="MPD"]/@mediaPresentationDuration | //*[name()="Period"][.//*[name()="BaseURL" and contains(text()\\,'/ads-')]] | //*[name()="Period"]/@start)`, + 'Period[id^="Ad"i]', + '.mpd', + ], + }, + ], + [ + 'xml-prune,a/b,,c', + { + name: 'xml-prune', + args: ['a/b', '', 'c'], + }, + ], + [ + 'xml-prune, xpath(//*[name()="Period"][.//*[@value="Ad"]] | //*[name()="Period"]/@start), [value="Ad"], .mpd', + { + name: 'xml-prune', + args: [ + 'xpath(//*[name()="Period"][.//*[@value="Ad"]] | //*[name()="Period"]/@start)', + '[value="Ad"]', + '.mpd', + ], + }, + ], [ 'acs, Math, /\\}\\s*\\(.*?\\b(self|this|window)\\b.*?\\)/', { @@ -2227,7 +2291,11 @@ describe('scriptlets arguments parsing', () => { 'trusted-replace-fetch-response, /\\"adPlacements.*?\\"\\}\\}\\}\\]\\,/, , url:player?key= method:/post/i bodyUsed:true', { name: 'trusted-replace-fetch-response', - args: ['/\\"adPlacements.*?\\"\\}\\}\\}\\]\\,/', '', 'url:player?key= method:/post/i bodyUsed:true'], + args: [ + '/\\"adPlacements.*?\\"\\}\\}\\}\\]\\,/', + '', + 'url:player?key= method:/post/i bodyUsed:true', + ], }, ], [