mirror of https://github.com/gorhill/uBlock.git
[mv3] Add support for csp= filters
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.
This commit is contained in:
parent
36bfa27c30
commit
6f90596e3b
|
@ -293,7 +293,7 @@ async function init() {
|
||||||
const { rules, filters, css } = details;
|
const { rules, filters, css } = details;
|
||||||
let ruleCount = rules.plain + rules.regex;
|
let ruleCount = rules.plain + rules.regex;
|
||||||
if ( popupPanelData.hasOmnipotence ) {
|
if ( popupPanelData.hasOmnipotence ) {
|
||||||
ruleCount += rules.removeparam + rules.redirect;
|
ruleCount += rules.removeparam + rules.redirect + rules.csp;
|
||||||
}
|
}
|
||||||
let specificCount = 0;
|
let specificCount = 0;
|
||||||
if ( css.specific instanceof Object ) {
|
if ( css.specific instanceof Object ) {
|
||||||
|
|
|
@ -37,6 +37,8 @@ const REMOVEPARAMS_REALM_START = REGEXES_REALM_END;
|
||||||
const REMOVEPARAMS_REALM_END = REMOVEPARAMS_REALM_START + RULE_REALM_SIZE;
|
const REMOVEPARAMS_REALM_END = REMOVEPARAMS_REALM_START + RULE_REALM_SIZE;
|
||||||
const REDIRECT_REALM_START = REMOVEPARAMS_REALM_END;
|
const REDIRECT_REALM_START = REMOVEPARAMS_REALM_END;
|
||||||
const REDIRECT_REALM_END = REDIRECT_REALM_START + RULE_REALM_SIZE;
|
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 TRUSTED_DIRECTIVE_BASE_RULE_ID = 8000000;
|
||||||
const BLOCKING_MODES_RULE_ID = TRUSTED_DIRECTIVE_BASE_RULE_ID + 1;
|
const BLOCKING_MODES_RULE_ID = TRUSTED_DIRECTIVE_BASE_RULE_ID + 1;
|
||||||
const CURRENT_CONFIG_BASE_RULE_ID = 9000000;
|
const CURRENT_CONFIG_BASE_RULE_ID = 9000000;
|
||||||
|
@ -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() {
|
async function updateDynamicRules() {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
updateRegexRules(),
|
updateRegexRules(),
|
||||||
updateRemoveparamRules(),
|
updateRemoveparamRules(),
|
||||||
updateRedirectRules(),
|
updateRedirectRules(),
|
||||||
|
updateCspRules(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,13 +43,13 @@ function renderNumber(value) {
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
function rulesetStats(rulesetId) {
|
function rulesetStats(rulesetId) {
|
||||||
const canRemoveParams = cachedRulesetData.defaultFilteringMode > 1;
|
const hasOmnipotence = cachedRulesetData.defaultFilteringMode > 1;
|
||||||
const rulesetDetails = rulesetMap.get(rulesetId);
|
const rulesetDetails = rulesetMap.get(rulesetId);
|
||||||
if ( rulesetDetails === undefined ) { return; }
|
if ( rulesetDetails === undefined ) { return; }
|
||||||
const { rules, filters } = rulesetDetails;
|
const { rules, filters } = rulesetDetails;
|
||||||
let ruleCount = rules.plain + rules.regex;
|
let ruleCount = rules.plain + rules.regex;
|
||||||
if ( canRemoveParams ) {
|
if ( hasOmnipotence ) {
|
||||||
ruleCount += rules.removeparam + rules.redirect;
|
ruleCount += rules.removeparam + rules.redirect + rules.csp;
|
||||||
}
|
}
|
||||||
const filterCount = filters.accepted;
|
const filterCount = filters.accepted;
|
||||||
return { ruleCount, filterCount };
|
return { ruleCount, filterCount };
|
||||||
|
|
|
@ -282,12 +282,6 @@ async function processNetworkFilters(assetDetails, network) {
|
||||||
});
|
});
|
||||||
log(`\tredirect=: ${redirects.length}`);
|
log(`\tredirect=: ${redirects.length}`);
|
||||||
|
|
||||||
const headers = rules.filter(rule =>
|
|
||||||
isUnsupported(rule) === false &&
|
|
||||||
isCsp(rule)
|
|
||||||
);
|
|
||||||
log(`\tcsp= (discarded): ${headers.length}`);
|
|
||||||
|
|
||||||
const removeparamsGood = rules.filter(rule =>
|
const removeparamsGood = rules.filter(rule =>
|
||||||
isUnsupported(rule) === false && isRemoveparam(rule)
|
isUnsupported(rule) === false && isRemoveparam(rule)
|
||||||
);
|
);
|
||||||
|
@ -296,6 +290,12 @@ async function processNetworkFilters(assetDetails, network) {
|
||||||
);
|
);
|
||||||
log(`\tremoveparams= (accepted/discarded): ${removeparamsGood.length}/${removeparamsBad.length}`);
|
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 =>
|
const bad = rules.filter(rule =>
|
||||||
isUnsupported(rule)
|
isUnsupported(rule)
|
||||||
);
|
);
|
||||||
|
@ -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 {
|
return {
|
||||||
total: rules.length,
|
total: rules.length,
|
||||||
plain: plainGood.length,
|
plain: plainGood.length,
|
||||||
discarded: redirects.length + headers.length + removeparamsBad.length,
|
discarded: removeparamsBad.length,
|
||||||
rejected: bad.length,
|
rejected: bad.length,
|
||||||
regex: regexes.length,
|
regex: regexes.length,
|
||||||
removeparam: removeparamsGood.length,
|
removeparam: removeparamsGood.length,
|
||||||
redirect: redirects.length,
|
redirect: redirects.length,
|
||||||
|
csp: csps.length,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1216,6 +1224,7 @@ async function rulesetFromURLs(assetDetails) {
|
||||||
regex: netStats.regex,
|
regex: netStats.regex,
|
||||||
removeparam: netStats.removeparam,
|
removeparam: netStats.removeparam,
|
||||||
redirect: netStats.redirect,
|
redirect: netStats.redirect,
|
||||||
|
csp: netStats.csp,
|
||||||
discarded: netStats.discarded,
|
discarded: netStats.discarded,
|
||||||
rejected: netStats.rejected,
|
rejected: netStats.rejected,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue