Skip to content

Commit

Permalink
Support tracker-allowlist subdomain matching (#2282)
Browse files Browse the repository at this point in the history
* Tracker allowlist subdomain matching (MV2)

* Update expectations for adjusted reference allowlist

* Test MV3 implementation of tracker allowlist against reference tests

* Handle platform exceptions in tracker allowlist tests

* Update reference tests
  • Loading branch information
sammacbeth committed Oct 24, 2023
1 parent f8afe50 commit 0964410
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 17 deletions.
10 changes: 4 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

73 changes: 73 additions & 0 deletions packages/ddg2dnr/test/referenceTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const {
generateTdsRuleset
} = require('../lib/tds')
const { generateCookieBlockingRuleset } = require('../lib/cookies')
const { generateTrackerAllowlistRules } = require('../lib/trackerAllowlist')

function referenceTestPath (...args) {
return require.resolve(path.join('@duckduckgo/privacy-reference-tests', ...args))
Expand Down Expand Up @@ -189,4 +190,76 @@ describe('Reference Tests', /** @this {testFunction} */ () => {
}
}
})

describe('Tracker Allowlist', /** @this {testFunction} */ async function () {
const referenceTests = loadReferenceTestJSONFile('tracker-radar-tests', 'TR-domain-matching', 'tracker_allowlist_matching_tests.json')
let blockAndAllowRules = []

this.beforeAll(/** @this {testFunction} */ async function () {
const blockList = loadReferenceTestJSONFile('tracker-radar-tests', 'TR-domain-matching', 'tracker_allowlist_tds_reference.json')
const allowlistedTrackers = loadReferenceTestJSONFile('tracker-radar-tests', 'TR-domain-matching', 'tracker_allowlist_reference.json')
const mockConfig = {
features: {
trackerAllowlist: {
state: 'enabled',
settings: {
allowlistedTrackers
}
}
}
}
const isRegexSupported = this.browser.isRegexSupported.bind(this.browser)
const { ruleset } = await generateTdsRuleset(
blockList, new Set(), '/', isRegexSupported
)
let ruleId = 10000
blockAndAllowRules = ruleset
for (const { rule } of generateTrackerAllowlistRules(mockConfig)) {
rule.id = ruleId++
blockAndAllowRules.push(rule)
}
})
this.beforeEach(/** @this {testFunction} */ async function () {
await this.browser.addRules(blockAndAllowRules)
})

for (const {
description, site, request, isAllowlisted, exceptPlatforms
} of referenceTests) {
if (exceptPlatforms && exceptPlatforms.includes('web-extension-mv3')) {
continue
}
it(description, /** @this {testFunction} */ async function () {
const actualMatchedRules = await this.browser.testMatchOutcome({
url: request,
initiator: site,
type: 'script'
})
// console.log('xxx', actualMatchedRules)

let actualAction = 'ignore'
const actualRedirects = []
for (const rule of actualMatchedRules) {
if (rule.action.type === 'block') {
actualAction = 'block'
continue
}
}

if (actualAction === 'ignore' && actualRedirects.length > 0) {
actualAction = 'redirect'

// Note - Check the redirection path is correct. Not possible
// currently, since the expected redirect path is a data
// URI instead of the script filename/path.
}

assert.equal(
actualAction,
isAllowlisted ? 'ignore' : 'block',
description
)
})
}
})
})
39 changes: 37 additions & 2 deletions shared/js/background/allowlisted-trackers.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@ const tdsStorage = require('./storage/tds').default
const tldts = require('tldts')
const { getURLWithoutQueryString } = require('./utils')

/**
* @typedef {Object} TrackerAllowlistRule
* @property {string} rule
* @property {string[]} domains
* @property {string} [reason]
*
* @typedef {Object} TrackerAllowlistDomainEntry
* @property {TrackerAllowlistRule[]} rules
*
* @typedef {Record<string, TrackerAllowlistDomainEntry>} TrackerAllowlist
*/

/**
* Check a request against the tracker allowlist.
* @param {string} site URL of the site
* @param {string} request URL to be checked against the allowlist
* @returns {TrackerAllowlistRule | false}
*/
function isTrackerAllowlisted (site, request) {
// check that allowlist exists and is not disabled
if (!tdsStorage.config.features.trackerAllowlist || tdsStorage.config.features.trackerAllowlist.state === 'disabled') {
Expand All @@ -18,7 +36,9 @@ function isTrackerAllowlisted (site, request) {
if (!parsedRequest.domain) {
return false
}
const allowListEntry = tdsStorage.config.features.trackerAllowlist.settings.allowlistedTrackers[parsedRequest.domain]
/** @type {TrackerAllowlist} */
const trackerAllowlist = tdsStorage.config.features.trackerAllowlist.settings.allowlistedTrackers
const allowListEntry = trackerAllowlist[parsedRequest.domain]

if (allowListEntry) {
return _matchesRule(site, request, allowListEntry)
Expand All @@ -27,6 +47,12 @@ function isTrackerAllowlisted (site, request) {
}
}

/**
* @param {string} site
* @param {string} request
* @param {TrackerAllowlistDomainEntry} allowListEntry
* @returns {TrackerAllowlistRule | false}
*/
function _matchesRule (site, request, allowListEntry) {
let matchedRule = null
request = getURLWithoutQueryString(request).split(';')[0]
Expand All @@ -48,7 +74,16 @@ function _matchesRule (site, request, allowListEntry) {
}

if (matchedRule) {
if (matchedRule.domains.includes('<all>') || matchedRule.domains.includes(tldts.parse(site).domain)) {
if (matchedRule.domains.includes('<all>')) {
return matchedRule
}
const { domain, hostname } = tldts.parse(site)
// eTLD+1 match
if (domain && matchedRule.domains.includes(domain)) {
return matchedRule
}
// hostname, or hostname-suffix match
if (hostname && matchedRule.domains.find((d) => d === hostname || hostname.endsWith(`.${d}`))) {
return matchedRule
}
} else {
Expand Down
23 changes: 14 additions & 9 deletions unit-test/background/declarative-net-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ config.features.trackerAllowlist = {
const expectedRuleIdsByConfigName = {
tds: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 21001, 21002, 21003, 21004],
config: [
10001, 10002, 10003, 10004, 10005, 10006, 10007, 10008, 10009, 10010
10001, 10002, 10003, 10004, 10005, 10006, 10007, 10008, 10009, 10010, 10011
]
}

Expand Down Expand Up @@ -104,44 +104,49 @@ const expectedLookupByConfigName = {
10002: {
type: 'trackerAllowlist',
domain: 'allowlist-tracker-1.com',
reason: 'match single resource on single site'
reason: 'match on subdomain'
},
10003: {
type: 'trackerAllowlist',
domain: 'allowlist-tracker-1.com',
reason: 'match single resource on single site'
},
10004: {
type: 'trackerAllowlist',
domain: 'allowlist-tracker-2.com',
reason: 'match single resource on all sites'
},
10004: {
10005: {
type: 'trackerAllowlist',
domain: 'allowlist-tracker-2.com',
reason: 'match all sites and all paths'
},
10005: {
10006: {
type: 'trackerAllowlist',
domain: 'allowlist-tracker-2.com',
reason: 'specific subdomain rule'
},
10006: {
10007: {
type: 'trackerAllowlist',
domain: 'allowlist-tracker-3.com',
reason: 'match all requests'
},
10007: {
10008: {
type: 'unprotectedTemporary',
domain: 'google.com',
reason: 'site breakage'
},
10008: {
10009: {
type: 'unprotectedTemporary',
domain: 'suntrust.com',
reason: 'site breakage'
},
10009: {
10010: {
type: 'contentBlocking',
domain: 'content-blocking.example',
reason: 'site breakage'
},
10010: {
10011: {
type: 'gpc'
}
}
Expand Down

0 comments on commit 0964410

Please sign in to comment.