diff --git a/packages/adblocker/src/engine/domains.ts b/packages/adblocker/src/engine/domains.ts index 55962ce300..c6777482fe 100644 --- a/packages/adblocker/src/engine/domains.ts +++ b/packages/adblocker/src/engine/domains.ts @@ -12,11 +12,25 @@ import { StaticDataView, sizeOfUint32Array, sizeOfUTF8 } from '../data-view.js'; import { binLookup, hasUnicode, HASH_INTERNAL_MULT } from '../utils.js'; export class Domains { - public static parse(parts: string[], debug: boolean = false): Domains | undefined { + public static parse( + parts: string[], + { + isNetworkEntities = false, + debug = false, + }: { isNetworkEntities?: boolean | undefined; debug?: boolean | undefined } = {}, + ): Domains | undefined { if (parts.length === 0) { return undefined; } + if (isNetworkEntities === true) { + for (const part of parts) { + if (part.length === 0 || part.startsWith('|') || part.endsWith('|')) { + return undefined; + } + } + } + const entities: number[] = []; const notEntities: number[] = []; const hostnames: number[] = []; @@ -59,7 +73,7 @@ export class Domains { hostnames: hostnames.length !== 0 ? new Uint32Array(hostnames).sort() : undefined, notEntities: notEntities.length !== 0 ? new Uint32Array(notEntities).sort() : undefined, notHostnames: notHostnames.length !== 0 ? new Uint32Array(notHostnames).sort() : undefined, - parts: debug === true ? parts.join(',') : undefined, + parts: debug === true ? parts.join(isNetworkEntities ? '|' : ',') : undefined, }); } diff --git a/packages/adblocker/src/filters/cosmetic.ts b/packages/adblocker/src/filters/cosmetic.ts index df7348c587..bf7220e78b 100644 --- a/packages/adblocker/src/filters/cosmetic.ts +++ b/packages/adblocker/src/filters/cosmetic.ts @@ -263,7 +263,7 @@ export default class CosmeticFilter implements IFilter { // number of labels considered. This allows a compact representation of // hostnames and fast matching without any string copy. if (sharpIndex > 0) { - domains = Domains.parse(line.slice(0, sharpIndex).split(','), debug); + domains = Domains.parse(line.slice(0, sharpIndex).split(','), { debug }); } if (line.endsWith(':remove()')) { diff --git a/packages/adblocker/src/filters/network.ts b/packages/adblocker/src/filters/network.ts index 16e487f5b3..3b99d70b11 100644 --- a/packages/adblocker/src/filters/network.ts +++ b/packages/adblocker/src/filters/network.ts @@ -732,20 +732,12 @@ export default class NetworkFilter implements IFilter { switch (option) { case 'denyallow': { - denyallow = Domains.parse(value.split('|'), debug); + denyallow = Domains.parse(value.split('|'), { isNetworkEntities: true, debug }); break; } case 'domain': case 'from': { - // domain list starting or ending with '|' is invalid - if ( - value.charCodeAt(0) === 124 /* '|' */ || - value.charCodeAt(value.length - 1) === 124 /* '|' */ - ) { - return null; - } - - domains = Domains.parse(value.split('|'), debug); + domains = Domains.parse(value.split('|'), { isNetworkEntities: true, debug }); break; } case 'badfilter': diff --git a/packages/adblocker/test/parsing.test.ts b/packages/adblocker/test/parsing.test.ts index 1b9da5b8b5..fbcfcb999f 100644 --- a/packages/adblocker/test/parsing.test.ts +++ b/packages/adblocker/test/parsing.test.ts @@ -180,6 +180,9 @@ describe('Network filters', () => { it('pprint domain', () => { checkToString('ads$domain=foo.com|bar.co.uk|~baz.io', 'ads$domain='); + checkToString('ads$domain=foo.com|bar.com', 'ads$domain=foo.com|bar.com', true); + checkToString('ads$denyallow=foo.com|bar.co.uk|~baz.io', 'ads$denyallow='); + checkToString('ads$denyallow=foo.com|bar.com', 'ads$denyallow=foo.com|bar.com', true); }); it('pprint with debug=true', () => {