Skip to content

Commit

Permalink
[mv3] Add support for csp= filters
Browse files Browse the repository at this point in the history
Network filters with csp= option will now be enforced.

Caveat: DNR API does not have support for exception csp= rules,
so excepted csp= filters are currently rejected at conversion time.
  • Loading branch information
gorhill committed Nov 5, 2022
1 parent 36bfa27 commit 6f90596
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 11 deletions.
2 changes: 1 addition & 1 deletion platform/mv3/extension/js/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ async function init() {
const { rules, filters, css } = details;
let ruleCount = rules.plain + rules.regex;
if ( popupPanelData.hasOmnipotence ) {
ruleCount += rules.removeparam + rules.redirect;
ruleCount += rules.removeparam + rules.redirect + rules.csp;
}
let specificCount = 0;
if ( css.specific instanceof Object ) {
Expand Down
77 changes: 77 additions & 0 deletions platform/mv3/extension/js/ruleset-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ const REMOVEPARAMS_REALM_START = REGEXES_REALM_END;
const REMOVEPARAMS_REALM_END = REMOVEPARAMS_REALM_START + RULE_REALM_SIZE;
const REDIRECT_REALM_START = REMOVEPARAMS_REALM_END;
const REDIRECT_REALM_END = REDIRECT_REALM_START + RULE_REALM_SIZE;
const CSP_REALM_START = REDIRECT_REALM_END;
const CSP_REALM_END = CSP_REALM_START + RULE_REALM_SIZE;
const TRUSTED_DIRECTIVE_BASE_RULE_ID = 8000000;
const BLOCKING_MODES_RULE_ID = TRUSTED_DIRECTIVE_BASE_RULE_ID + 1;
const CURRENT_CONFIG_BASE_RULE_ID = 9000000;
Expand Down Expand Up @@ -327,11 +329,86 @@ async function updateRedirectRules() {

/******************************************************************************/

async function updateCspRules() {
const [
hasOmnipotence,
rulesetDetails,
dynamicRuleMap,
] = await Promise.all([
browser.permissions.contains({ origins: [ '<all_urls>' ] }),
getEnabledRulesetsDetails(),
getDynamicRules(),
]);

// Fetch csp rules for all enabled rulesets
const toFetch = [];
for ( const details of rulesetDetails ) {
if ( details.rules.csp === 0 ) { continue; }
toFetch.push(fetchJSON(`/rulesets/csp/${details.id}`));
}
const cspRulesets = await Promise.all(toFetch);

// Redirect rules can only be enforced with omnipotence
const newRules = [];
if ( hasOmnipotence ) {
let cspRuleId = CSP_REALM_START;
for ( const rules of cspRulesets ) {
if ( Array.isArray(rules) === false ) { continue; }
for ( const rule of rules ) {
rule.id = cspRuleId++;
newRules.push(rule);
}
}
}

// Add csp rules to dynamic ruleset without affecting rules
// outside csp rules realm.
const newRuleMap = new Map(newRules.map(rule => [ rule.id, rule ]));
const addRules = [];
const removeRuleIds = [];

for ( const oldRule of dynamicRuleMap.values() ) {
if ( oldRule.id < CSP_REALM_START ) { continue; }
if ( oldRule.id >= CSP_REALM_END ) { continue; }
const newRule = newRuleMap.get(oldRule.id);
if ( newRule === undefined ) {
removeRuleIds.push(oldRule.id);
dynamicRuleMap.delete(oldRule.id);
} else if ( JSON.stringify(oldRule) !== JSON.stringify(newRule) ) {
removeRuleIds.push(oldRule.id);
addRules.push(newRule);
dynamicRuleMap.set(oldRule.id, newRule);
}
}

for ( const newRule of newRuleMap.values() ) {
if ( dynamicRuleMap.has(newRule.id) ) { continue; }
addRules.push(newRule);
dynamicRuleMap.set(newRule.id, newRule);
}

if ( addRules.length === 0 && removeRuleIds.length === 0 ) { return; }

if ( removeRuleIds.length !== 0 ) {
console.info(`Remove ${removeRuleIds.length} DNR redirect rules`);
}
if ( addRules.length !== 0 ) {
console.info(`Add ${addRules.length} DNR redirect rules`);
}

return dnr.updateDynamicRules({ addRules, removeRuleIds });
}

/******************************************************************************/

// TODO: group all omnipotence-related rules into one realm.

async function updateDynamicRules() {
return Promise.all([
updateRegexRules(),
updateRemoveparamRules(),
updateRedirectRules(),
updateCspRules(),
]);
}

Expand Down
6 changes: 3 additions & 3 deletions platform/mv3/extension/js/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ function renderNumber(value) {
/******************************************************************************/

function rulesetStats(rulesetId) {
const canRemoveParams = cachedRulesetData.defaultFilteringMode > 1;
const hasOmnipotence = cachedRulesetData.defaultFilteringMode > 1;
const rulesetDetails = rulesetMap.get(rulesetId);
if ( rulesetDetails === undefined ) { return; }
const { rules, filters } = rulesetDetails;
let ruleCount = rules.plain + rules.regex;
if ( canRemoveParams ) {
ruleCount += rules.removeparam + rules.redirect;
if ( hasOmnipotence ) {
ruleCount += rules.removeparam + rules.redirect + rules.csp;
}
const filterCount = filters.accepted;
return { ruleCount, filterCount };
Expand Down
23 changes: 16 additions & 7 deletions platform/mv3/make-rulesets.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,12 +282,6 @@ async function processNetworkFilters(assetDetails, network) {
});
log(`\tredirect=: ${redirects.length}`);

const headers = rules.filter(rule =>
isUnsupported(rule) === false &&
isCsp(rule)
);
log(`\tcsp= (discarded): ${headers.length}`);

const removeparamsGood = rules.filter(rule =>
isUnsupported(rule) === false && isRemoveparam(rule)
);
Expand All @@ -296,6 +290,12 @@ async function processNetworkFilters(assetDetails, network) {
);
log(`\tremoveparams= (accepted/discarded): ${removeparamsGood.length}/${removeparamsBad.length}`);

const csps = rules.filter(rule =>
isUnsupported(rule) === false &&
isCsp(rule)
);
log(`\tcsp=: ${csps.length}`);

const bad = rules.filter(rule =>
isUnsupported(rule)
);
Expand Down Expand Up @@ -328,14 +328,22 @@ async function processNetworkFilters(assetDetails, network) {
);
}

if ( csps.length !== 0 ) {
writeFile(
`${rulesetDir}/csp/${assetDetails.id}.json`,
`${JSON.stringify(csps, replacer, 1)}\n`
);
}

return {
total: rules.length,
plain: plainGood.length,
discarded: redirects.length + headers.length + removeparamsBad.length,
discarded: removeparamsBad.length,
rejected: bad.length,
regex: regexes.length,
removeparam: removeparamsGood.length,
redirect: redirects.length,
csp: csps.length,
};
}

Expand Down Expand Up @@ -1216,6 +1224,7 @@ async function rulesetFromURLs(assetDetails) {
regex: netStats.regex,
removeparam: netStats.removeparam,
redirect: netStats.redirect,
csp: netStats.csp,
discarded: netStats.discarded,
rejected: netStats.rejected,
},
Expand Down

0 comments on commit 6f90596

Please sign in to comment.