fune/toolkit/components/extensions/ExtensionDNR.sys.mjs
Rob Wu 3494ccd426 Bug 1745762 - Add registration of DNR session rules r=rpl
This patch offers the Rule type and updateSessionRules and
getSessionRules to register rules. The actual evaluation of rules and
most of the associated validation is not part of this patch.

Differential Revision: https://phabricator.services.mozilla.com/D154801
2022-08-22 20:44:26 +00:00

116 lines
3.3 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Each extension that uses DNR has one RuleManager. All registered RuleManagers
// are checked whenever a network request occurs. Individual extensions may
// occasionally modify their rules (e.g. via the updateSessionRules API).
const gRuleManagers = [];
// The RuleCondition class represents a rule's "condition" type as described in
// schemas/declarative_net_request.json. This class exists to allow the JS
// engine to use one Shape for all Rule instances.
class RuleCondition {
constructor(cond) {
this.urlFilter = cond.urlFilter;
this.regexFilter = cond.regexFilter;
this.isUrlFilterCaseSensitive = cond.isUrlFilterCaseSensitive;
this.initiatorDomains = cond.initiatorDomains;
this.excludedInitiatorDomains = cond.excludedInitiatorDomains;
this.requestDomains = cond.requestDomains;
this.excludedRequestDomains = cond.excludedRequestDomains;
this.resourceTypes = cond.resourceTypes;
this.excludedResourceTypes = cond.excludedResourceTypes;
this.requestMethods = cond.requestMethods;
this.excludedRequestMethods = cond.excludedRequestMethods;
this.domainType = cond.domainType;
this.tabIds = cond.tabIds;
this.excludedTabIds = cond.excludedTabIds;
}
}
class Rule {
constructor(rule) {
this.id = rule.id;
this.priority = rule.priority;
this.condition = new RuleCondition(rule.condition);
this.action = rule.action;
}
}
class RuleValidator {
constructor(alreadyValidatedRules) {
this.rulesMap = new Map(alreadyValidatedRules.map(r => [r.id, r]));
this.failures = [];
}
removeRuleIds(ruleIds) {
for (const ruleId of ruleIds) {
this.rulesMap.delete(ruleId);
}
}
addRules(rules) {
for (const rule of rules) {
if (this.rulesMap.has(rule.id)) {
this.#collectInvalidRule(rule, `Duplicate rule ID: ${rule.id}`);
continue;
}
const newRule = new Rule(rule);
// TODO bug 1745758: Need more validation, before rules are evaluated.
this.rulesMap.set(rule.id, newRule);
}
}
#collectInvalidRule(rule, message) {
this.failures.push({ rule, message });
}
getValidatedRules() {
return Array.from(this.rulesMap.values());
}
getFailures() {
return this.failures;
}
}
class RuleManager {
constructor(extension) {
this.extension = extension;
this.sessionRules = [];
}
setSessionRules(validatedSessionRules) {
this.sessionRules = validatedSessionRules;
}
getSessionRules() {
return this.sessionRules;
}
}
function getRuleManager(extension, createIfMissing = true) {
let ruleManager = gRuleManagers.find(rm => rm.extension === extension);
if (!ruleManager && createIfMissing) {
ruleManager = new RuleManager(extension);
// TODO bug 1786059: order extensions by "installation time".
gRuleManagers.push(ruleManager);
}
return ruleManager;
}
function clearRuleManager(extension) {
let i = gRuleManagers.findIndex(rm => rm.extension === extension);
if (i !== -1) {
gRuleManagers.splice(i, 1);
}
}
export const ExtensionDNR = {
RuleValidator,
getRuleManager,
clearRuleManager,
};