Skip to content

Commit

Permalink
fix: exception of script injection not respecting aliases (#4376)
Browse files Browse the repository at this point in the history
Co-authored-by: chrmod <chrmod@ghostery.com>
  • Loading branch information
seia-soto and chrmod authored Oct 25, 2024
1 parent e6565c4 commit 3e6c8ea
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 11 deletions.
11 changes: 8 additions & 3 deletions packages/adblocker/src/engine/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
fullLists,
} from '../fetch.js';
import { HTMLSelector } from '../html-filtering.js';
import CosmeticFilter from '../filters/cosmetic.js';
import CosmeticFilter, { normalizeSelector } from '../filters/cosmetic.js';
import NetworkFilter from '../filters/network.js';
import { block } from '../filters/dsl.js';
import { FilterType, IListDiff, IPartialRawDiff, parseFilters } from '../lists.js';
Expand Down Expand Up @@ -1091,7 +1091,10 @@ export default class FilterEngine extends EventEmitter<EngineEventHandlers> {
) {
injectionsDisabled = true;
}
unhideExceptions.set(unhide.getSelector(), unhide);
unhideExceptions.set(
normalizeSelector(unhide, this.resources.getScriptletCanonicalName.bind(this.resources)),
unhide,
);
}

const injections: CosmeticFilter[] = [];
Expand All @@ -1102,7 +1105,9 @@ export default class FilterEngine extends EventEmitter<EngineEventHandlers> {
// Apply unhide rules + dispatch
for (const filter of filters) {
// Make sure `rule` is not un-hidden by a #@# filter
const exception = unhideExceptions.get(filter.getSelector());
const exception = unhideExceptions.get(
normalizeSelector(filter, this.resources.getScriptletCanonicalName.bind(this.resources)),
);

if (exception !== undefined) {
continue;
Expand Down
34 changes: 33 additions & 1 deletion packages/adblocker/src/filters/cosmetic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,29 @@ function computeFilterId(
return hash >>> 0;
}

export function normalizeSelector(
filter: CosmeticFilter,
getScriptletCanonicalName: (name: string) => string | undefined,
): string {
const selector = filter.getSelector();

if (filter.isScriptInject() === false) {
return selector;
}

const parsed = filter.parseScript();
if (parsed === undefined) {
return selector;
}

const canonicalName = getScriptletCanonicalName(parsed.name);
if (canonicalName === undefined) {
return selector;
}

return selector.replace(parsed.name, canonicalName);
}

/***************************************************************************
* Cosmetic filters parsing
* ************************************************************************ */
Expand Down Expand Up @@ -401,6 +424,7 @@ export default class CosmeticFilter implements IFilter {
public readonly rawLine: string | undefined;

private id: number | undefined;
private scriptletDetails: { name: string; args: string[] } | undefined;

constructor({
mask,
Expand All @@ -422,6 +446,7 @@ export default class CosmeticFilter implements IFilter {

this.id = undefined;
this.rawLine = rawLine;
this.scriptletDetails = undefined;
}

public isCosmeticFilter(): this is CosmeticFilter {
Expand Down Expand Up @@ -680,6 +705,10 @@ export default class CosmeticFilter implements IFilter {
}

public parseScript(): { name: string; args: string[] } | undefined {
if (this.scriptletDetails !== undefined) {
return this.scriptletDetails;
}

const selector = this.getSelector();
if (selector.length === 0) {
return undefined;
Expand Down Expand Up @@ -772,7 +801,10 @@ export default class CosmeticFilter implements IFilter {
.replace(REGEXP_UNICODE_BACKSLASH, '\\')
.replace(REGEXP_ESCAPED_COMMA, ','),
);
return { name: parts[0], args };

this.scriptletDetails = { name: parts[0], args };

return this.scriptletDetails;
}

public getScript(getScriptlet: (_: string) => string | undefined): string | undefined {
Expand Down
20 changes: 14 additions & 6 deletions packages/adblocker/src/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,12 +311,7 @@ export default class Resources {
}

public getScriptlet(name: string): string | undefined {
// Scriptlets with names ending with `.fn` is always treated as dependencies
if (name.endsWith('.fn')) {
return undefined;
}

const scriptlet = this.scriptletsByName.get(name.endsWith('.js') ? name : `${name}.js`);
const scriptlet = this.getRawScriptlet(name);

if (scriptlet === undefined) {
return undefined;
Expand All @@ -338,6 +333,19 @@ export default class Resources {
return script;
}

public getScriptletCanonicalName(name: string): string | undefined {
return this.getRawScriptlet(name)?.name;
}

private getRawScriptlet(name: string): Scriptlet | undefined {
// Scriptlets with names ending with `.fn` are always treated as dependencies
if (name.endsWith('.fn')) {
return undefined;
}

return this.scriptletsByName.get(name.endsWith('.js') ? name : `${name}.js`);
}

private getScriptletDependencies(scriptlet: Scriptlet): string[] {
const dependencies: Map<string, string> = new Map();
const queue: string[] = [...scriptlet.dependencies];
Expand Down
28 changes: 27 additions & 1 deletion packages/adblocker/test/engine/engine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,32 @@ foo.com###selector
matches: [],
},

// = unhide +js() exception with aliasing
{
filters: ['foo.com##+js(scriptlet)', 'foo.com#@#+js(scriptlet0)'],
hostname: 'foo.com',
hrefs: [],
injections: [],
matches: [],
},
{
filters: ['foo.com##+js(scriptlet, arg0, arg1)', 'foo.com#@#+js(scriptlet0, arg0, arg1)'],
hostname: 'foo.com',
hrefs: [],
injections: [],
matches: [],
},
{
filters: [
'foo.com##+js(scriptlet , malformed)',
'foo.com#@#+js(scriptlet0 , malformed)',
],
hostname: 'foo.com',
hrefs: [],
injections: [],
matches: [],
},

// = unhide +js() disable
{
filters: [
Expand Down Expand Up @@ -1456,7 +1482,7 @@ foo.com###selector
scriptlets: [
{
name: 'scriptlet.js',
aliases: [],
aliases: ['scriptlet0.js'],
body: 'function scriptlet() {}',
dependencies: [],
executionWorld: 'MAIN',
Expand Down

0 comments on commit 3e6c8ea

Please sign in to comment.