[mv3] Add support for permissions= filter option

Related discussion:
https://github.com/uBlockOrigin/uBlock-issues/discussions/2714
This commit is contained in:
Raymond Hill 2023-07-10 11:56:57 -04:00
parent 54e4b8cbec
commit 0f6400c160
No known key found for this signature in database
GPG key ID: 25E1490B761470C2
5 changed files with 40 additions and 29 deletions

View file

@ -310,7 +310,7 @@ async function init() {
const { rules, filters, css } = details;
let ruleCount = rules.plain + rules.regex;
if ( popupPanelData.hasOmnipotence ) {
ruleCount += rules.removeparam + rules.redirect + rules.csp;
ruleCount += rules.removeparam + rules.redirect + rules.modifyHeaders;
}
let specificCount = 0;
if ( typeof css.specific === 'number' ) {

View file

@ -38,8 +38,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 MODIFYHEADERS_REALM_START = REDIRECT_REALM_END;
const MODIFYHEADERS_REALM_END = MODIFYHEADERS_REALM_START + RULE_REALM_SIZE;
const TRUSTED_DIRECTIVE_BASE_RULE_ID = 8000000;
/******************************************************************************/
@ -326,7 +326,7 @@ async function updateRedirectRules() {
/******************************************************************************/
async function updateCspRules() {
async function updateModifyHeadersRules() {
const [
hasOmnipotence,
rulesetDetails,
@ -337,36 +337,36 @@ async function updateCspRules() {
getDynamicRules(),
]);
// Fetch csp rules for all enabled rulesets
// Fetch modifyHeaders 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}`));
if ( details.rules.modifyHeaders === 0 ) { continue; }
toFetch.push(fetchJSON(`/rulesets/modify-headers/${details.id}`));
}
const cspRulesets = await Promise.all(toFetch);
const rulesets = 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 ) {
let ruleId = MODIFYHEADERS_REALM_START;
for ( const rules of rulesets ) {
if ( Array.isArray(rules) === false ) { continue; }
for ( const rule of rules ) {
rule.id = cspRuleId++;
rule.id = ruleId++;
newRules.push(rule);
}
}
}
// Add csp rules to dynamic ruleset without affecting rules
// outside csp rules realm.
// Add modifyHeaders rules to dynamic ruleset without affecting rules
// outside modifyHeaders 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; }
if ( oldRule.id < MODIFYHEADERS_REALM_START ) { continue; }
if ( oldRule.id >= MODIFYHEADERS_REALM_END ) { continue; }
const newRule = newRuleMap.get(oldRule.id);
if ( newRule === undefined ) {
removeRuleIds.push(oldRule.id);
@ -387,10 +387,10 @@ async function updateCspRules() {
if ( addRules.length === 0 && removeRuleIds.length === 0 ) { return; }
if ( removeRuleIds.length !== 0 ) {
ubolLog(`Remove ${removeRuleIds.length} DNR csp rules`);
ubolLog(`Remove ${removeRuleIds.length} DNR modifyHeaders rules`);
}
if ( addRules.length !== 0 ) {
ubolLog(`Add ${addRules.length} DNR csp rules`);
ubolLog(`Add ${addRules.length} DNR modifyHeaders rules`);
}
return dnr.updateDynamicRules({ addRules, removeRuleIds });
@ -405,7 +405,7 @@ async function updateDynamicRules() {
updateRegexRules(),
updateRemoveparamRules(),
updateRedirectRules(),
updateCspRules(),
updateModifyHeadersRules(),
]);
}

View file

@ -46,7 +46,7 @@ function rulesetStats(rulesetId) {
const { rules, filters } = rulesetDetails;
let ruleCount = rules.plain + rules.regex;
if ( hasOmnipotence ) {
ruleCount += rules.removeparam + rules.redirect + rules.csp;
ruleCount += rules.removeparam + rules.redirect + rules.modifyHeaders;
}
const filterCount = filters.accepted;
return { ruleCount, filterCount };

View file

@ -228,7 +228,7 @@ const isRedirect = rule =>
rule.action.type === 'redirect' &&
rule.action.redirect.extensionPath !== undefined;
const isCsp = rule =>
const isModifyHeaders = rule =>
rule.action !== undefined &&
rule.action.type === 'modifyHeaders';
@ -240,7 +240,7 @@ const isRemoveparam = rule =>
const isGood = rule =>
isUnsupported(rule) === false &&
isRedirect(rule) === false &&
isCsp(rule) === false &&
isModifyHeaders(rule) === false &&
isRemoveparam(rule) === false;
/******************************************************************************/
@ -298,11 +298,11 @@ async function processNetworkFilters(assetDetails, network) {
);
log(`\tremoveparams= (accepted/discarded): ${removeparamsGood.length}/${removeparamsBad.length}`);
const csps = rules.filter(rule =>
const modifyHeaders = rules.filter(rule =>
isUnsupported(rule) === false &&
isCsp(rule)
isModifyHeaders(rule)
);
log(`\tcsp=: ${csps.length}`);
log(`\tmodifyHeaders=: ${modifyHeaders.length}`);
const bad = rules.filter(rule =>
isUnsupported(rule)
@ -336,10 +336,10 @@ async function processNetworkFilters(assetDetails, network) {
);
}
if ( csps.length !== 0 ) {
if ( modifyHeaders.length !== 0 ) {
writeFile(
`${rulesetDir}/csp/${assetDetails.id}.json`,
`${JSON.stringify(csps, replacer, 1)}\n`
`${rulesetDir}/modify-headers/${assetDetails.id}.json`,
`${JSON.stringify(modifyHeaders, replacer, 1)}\n`
);
}
@ -351,7 +351,7 @@ async function processNetworkFilters(assetDetails, network) {
regex: regexes.length,
removeparam: removeparamsGood.length,
redirect: redirects.length,
csp: csps.length,
modifyHeaders: modifyHeaders.length,
};
}
@ -966,7 +966,7 @@ async function rulesetFromURLs(assetDetails) {
regex: netStats.regex,
removeparam: netStats.removeparam,
redirect: netStats.redirect,
csp: netStats.csp,
modifyHeaders: netStats.modifyHeaders,
discarded: netStats.discarded,
rejected: netStats.rejected,
},

View file

@ -4441,6 +4441,17 @@ FilterContainer.prototype.dnrFromCompiled = function(op, context, ...args) {
dnrAddRuleError(rule, 'Unsupported modifier exception');
}
break;
case 'permissions':
rule.action.type = 'modifyHeaders';
rule.action.responseHeaders = [{
header: 'permissions-policy',
operation: 'append',
value: rule.__modifierValue.split('|').join(', '),
}];
if ( rule.__modifierAction === AllowAction ) {
dnrAddRuleError(rule, 'Unsupported modifier exception');
}
break;
case 'redirect-rule': {
let priority = rule.priority || 1;
let token = rule.__modifierValue;