|
25 | 25 |
|
26 | 26 | /******************************************************************************/
|
27 | 27 |
|
28 |
| -import { browser, dnr, i18n, runtime } from './ext.js'; |
29 |
| -import { fetchJSON } from './fetch.js'; |
30 |
| -import { getInjectableCount, registerInjectable } from './scripting-manager.js'; |
31 |
| -import { parsedURLromOrigin } from './utils.js'; |
| 28 | +import { |
| 29 | + browser, |
| 30 | + dnr, |
| 31 | + runtime, |
| 32 | +} from './ext.js'; |
| 33 | + |
| 34 | +import { |
| 35 | + CURRENT_CONFIG_BASE_RULE_ID, |
| 36 | + getRulesetDetails, |
| 37 | + getDynamicRules, |
| 38 | + defaultRulesetsFromLanguage, |
| 39 | + enableRulesets, |
| 40 | + getEnabledRulesetsStats, |
| 41 | + updateRegexRules, |
| 42 | +} from './ruleset-manager.js'; |
| 43 | + |
| 44 | +import { |
| 45 | + getInjectableCount, |
| 46 | + registerInjectable, |
| 47 | +} from './scripting-manager.js'; |
| 48 | + |
| 49 | +import { |
| 50 | + matchesTrustedSiteDirective, |
| 51 | + toggleTrustedSiteDirective, |
| 52 | +} from './trusted-sites.js'; |
32 | 53 |
|
33 | 54 | /******************************************************************************/
|
34 | 55 |
|
35 |
| -const RULE_REALM_SIZE = 1000000; |
36 |
| -const REGEXES_REALM_START = 1000000; |
37 |
| -const REGEXES_REALM_END = REGEXES_REALM_START + RULE_REALM_SIZE; |
38 |
| -const TRUSTED_DIRECTIVE_BASE_RULE_ID = 8000000; |
39 |
| -const CURRENT_CONFIG_BASE_RULE_ID = 9000000; |
40 |
| - |
41 | 56 | const rulesetConfig = {
|
42 | 57 | version: '',
|
43 | 58 | enabledRulesets: [],
|
44 | 59 | };
|
45 | 60 |
|
46 | 61 | /******************************************************************************/
|
47 | 62 |
|
48 |
| -let rulesetDetailsPromise; |
49 |
| - |
50 |
| -function getRulesetDetails() { |
51 |
| - if ( rulesetDetailsPromise !== undefined ) { |
52 |
| - return rulesetDetailsPromise; |
53 |
| - } |
54 |
| - rulesetDetailsPromise = fetchJSON('/rulesets/ruleset-details').then(entries => { |
55 |
| - const map = new Map( |
56 |
| - entries.map(entry => [ entry.id, entry ]) |
57 |
| - ); |
58 |
| - return map; |
59 |
| - }); |
60 |
| - return rulesetDetailsPromise; |
61 |
| -} |
62 |
| - |
63 |
| -/******************************************************************************/ |
64 |
| - |
65 |
| -let dynamicRuleMapPromise; |
66 |
| - |
67 |
| -function getDynamicRules() { |
68 |
| - if ( dynamicRuleMapPromise !== undefined ) { |
69 |
| - return dynamicRuleMapPromise; |
70 |
| - } |
71 |
| - dynamicRuleMapPromise = dnr.getDynamicRules().then(rules => { |
72 |
| - const map = new Map( |
73 |
| - rules.map(rule => [ rule.id, rule ]) |
74 |
| - ); |
75 |
| - console.log(`Dynamic rule count: ${map.size}`); |
76 |
| - console.log(`Available dynamic rule count: ${dnr.MAX_NUMBER_OF_DYNAMIC_AND_SESSION_RULES - map.size}`); |
77 |
| - return map; |
78 |
| - }); |
79 |
| - return dynamicRuleMapPromise; |
80 |
| -} |
81 |
| - |
82 |
| -/******************************************************************************/ |
83 |
| - |
84 | 63 | function getCurrentVersion() {
|
85 | 64 | return runtime.getManifest().version;
|
86 | 65 | }
|
@@ -134,276 +113,6 @@ async function saveRulesetConfig() {
|
134 | 113 |
|
135 | 114 | /******************************************************************************/
|
136 | 115 |
|
137 |
| -async function updateRegexRules() { |
138 |
| - const [ |
139 |
| - rulesetDetails, |
140 |
| - dynamicRules |
141 |
| - ] = await Promise.all([ |
142 |
| - getRulesetDetails(), |
143 |
| - dnr.getDynamicRules(), |
144 |
| - ]); |
145 |
| - |
146 |
| - // Avoid testing already tested regexes |
147 |
| - const validRegexSet = new Set( |
148 |
| - dynamicRules.filter(rule => |
149 |
| - rule.condition?.regexFilter && true || false |
150 |
| - ).map(rule => |
151 |
| - rule.condition.regexFilter |
152 |
| - ) |
153 |
| - ); |
154 |
| - const allRules = []; |
155 |
| - const toCheck = []; |
156 |
| - |
157 |
| - // Fetch regexes for all enabled rulesets |
158 |
| - const toFetch = []; |
159 |
| - for ( const details of rulesetDetails.values() ) { |
160 |
| - if ( details.enabled !== true ) { continue; } |
161 |
| - if ( details.rules.regexes === 0 ) { continue; } |
162 |
| - toFetch.push(fetchJSON(`/rulesets/${details.id}.regexes`)); |
163 |
| - } |
164 |
| - const regexRulesets = await Promise.all(toFetch); |
165 |
| - |
166 |
| - // Validate fetched regexes |
167 |
| - let regexRuleId = REGEXES_REALM_START; |
168 |
| - for ( const rules of regexRulesets ) { |
169 |
| - if ( Array.isArray(rules) === false ) { continue; } |
170 |
| - for ( const rule of rules ) { |
171 |
| - rule.id = regexRuleId++; |
172 |
| - const { |
173 |
| - regexFilter: regex, |
174 |
| - isUrlFilterCaseSensitive: isCaseSensitive |
175 |
| - } = rule.condition; |
176 |
| - allRules.push(rule); |
177 |
| - toCheck.push( |
178 |
| - validRegexSet.has(regex) |
179 |
| - ? { isSupported: true } |
180 |
| - : dnr.isRegexSupported({ regex, isCaseSensitive }) |
181 |
| - ); |
182 |
| - } |
183 |
| - } |
184 |
| - |
185 |
| - // Collate results |
186 |
| - const results = await Promise.all(toCheck); |
187 |
| - const newRules = []; |
188 |
| - for ( let i = 0; i < allRules.length; i++ ) { |
189 |
| - const rule = allRules[i]; |
190 |
| - const result = results[i]; |
191 |
| - if ( result instanceof Object && result.isSupported ) { |
192 |
| - newRules.push(rule); |
193 |
| - } else { |
194 |
| - console.info(`${result.reason}: ${rule.condition.regexFilter}`); |
195 |
| - } |
196 |
| - } |
197 |
| - console.info( |
198 |
| - `Rejected regex filters: ${allRules.length-newRules.length} out of ${allRules.length}` |
199 |
| - ); |
200 |
| - |
201 |
| - // Add validated regex rules to dynamic ruleset without affecting rules |
202 |
| - // outside regex rule realm. |
203 |
| - const dynamicRuleMap = await getDynamicRules(); |
204 |
| - const newRuleMap = new Map(newRules.map(rule => [ rule.id, rule ])); |
205 |
| - const addRules = []; |
206 |
| - const removeRuleIds = []; |
207 |
| - for ( const oldRule of dynamicRuleMap.values() ) { |
208 |
| - if ( oldRule.id < REGEXES_REALM_START ) { continue; } |
209 |
| - if ( oldRule.id >= REGEXES_REALM_END ) { continue; } |
210 |
| - const newRule = newRuleMap.get(oldRule.id); |
211 |
| - if ( newRule === undefined ) { |
212 |
| - removeRuleIds.push(oldRule.id); |
213 |
| - dynamicRuleMap.delete(oldRule.id); |
214 |
| - } else if ( JSON.stringify(oldRule) !== JSON.stringify(newRule) ) { |
215 |
| - removeRuleIds.push(oldRule.id); |
216 |
| - addRules.push(newRule); |
217 |
| - dynamicRuleMap.set(oldRule.id, newRule); |
218 |
| - } |
219 |
| - } |
220 |
| - for ( const newRule of newRuleMap.values() ) { |
221 |
| - if ( dynamicRuleMap.has(newRule.id) ) { continue; } |
222 |
| - addRules.push(newRule); |
223 |
| - dynamicRuleMap.set(newRule.id, newRule); |
224 |
| - } |
225 |
| - if ( addRules.length !== 0 || removeRuleIds.length !== 0 ) { |
226 |
| - return dnr.updateDynamicRules({ addRules, removeRuleIds }); |
227 |
| - } |
228 |
| -} |
229 |
| - |
230 |
| -/******************************************************************************/ |
231 |
| - |
232 |
| -async function matchesTrustedSiteDirective(details) { |
233 |
| - const url = parsedURLromOrigin(details.origin); |
234 |
| - if ( url === undefined ) { return false; } |
235 |
| - |
236 |
| - const dynamicRuleMap = await getDynamicRules(); |
237 |
| - let rule = dynamicRuleMap.get(TRUSTED_DIRECTIVE_BASE_RULE_ID); |
238 |
| - if ( rule === undefined ) { return false; } |
239 |
| - const domainSet = new Set(rule.condition.requestDomains); |
240 |
| - let hostname = url.hostname; |
241 |
| - for (;;) { |
242 |
| - if ( domainSet.has(hostname) ) { return true; } |
243 |
| - const pos = hostname.indexOf('.'); |
244 |
| - if ( pos === -1 ) { break; } |
245 |
| - hostname = hostname.slice(pos+1); |
246 |
| - } |
247 |
| - |
248 |
| - return false; |
249 |
| -} |
250 |
| - |
251 |
| -async function addTrustedSiteDirective(details) { |
252 |
| - const url = parsedURLromOrigin(details.origin); |
253 |
| - if ( url === undefined ) { return false; } |
254 |
| - |
255 |
| - const dynamicRuleMap = await getDynamicRules(); |
256 |
| - let rule = dynamicRuleMap.get(TRUSTED_DIRECTIVE_BASE_RULE_ID); |
257 |
| - if ( rule !== undefined ) { |
258 |
| - rule.condition.initiatorDomains = undefined; |
259 |
| - if ( Array.isArray(rule.condition.requestDomains) === false ) { |
260 |
| - rule.condition.requestDomains = []; |
261 |
| - } |
262 |
| - } |
263 |
| - |
264 |
| - if ( rule === undefined ) { |
265 |
| - rule = { |
266 |
| - id: TRUSTED_DIRECTIVE_BASE_RULE_ID, |
267 |
| - action: { |
268 |
| - type: 'allowAllRequests', |
269 |
| - }, |
270 |
| - condition: { |
271 |
| - requestDomains: [ url.hostname ], |
272 |
| - resourceTypes: [ 'main_frame' ], |
273 |
| - }, |
274 |
| - priority: TRUSTED_DIRECTIVE_BASE_RULE_ID, |
275 |
| - }; |
276 |
| - dynamicRuleMap.set(TRUSTED_DIRECTIVE_BASE_RULE_ID, rule); |
277 |
| - } else if ( rule.condition.requestDomains.includes(url.hostname) === false ) { |
278 |
| - rule.condition.requestDomains.push(url.hostname); |
279 |
| - } |
280 |
| - |
281 |
| - await dnr.updateDynamicRules({ |
282 |
| - addRules: [ rule ], |
283 |
| - removeRuleIds: [ TRUSTED_DIRECTIVE_BASE_RULE_ID ], |
284 |
| - }); |
285 |
| - |
286 |
| - return true; |
287 |
| -} |
288 |
| - |
289 |
| -async function removeTrustedSiteDirective(details) { |
290 |
| - const url = parsedURLromOrigin(details.origin); |
291 |
| - if ( url === undefined ) { return false; } |
292 |
| - |
293 |
| - const dynamicRuleMap = await getDynamicRules(); |
294 |
| - let rule = dynamicRuleMap.get(TRUSTED_DIRECTIVE_BASE_RULE_ID); |
295 |
| - if ( rule === undefined ) { return false; } |
296 |
| - rule.condition.initiatorDomains = undefined; |
297 |
| - if ( Array.isArray(rule.condition.requestDomains) === false ) { |
298 |
| - rule.condition.requestDomains = []; |
299 |
| - } |
300 |
| - |
301 |
| - const domainSet = new Set(rule.condition.requestDomains); |
302 |
| - const beforeCount = domainSet.size; |
303 |
| - let hostname = url.hostname; |
304 |
| - for (;;) { |
305 |
| - domainSet.delete(hostname); |
306 |
| - const pos = hostname.indexOf('.'); |
307 |
| - if ( pos === -1 ) { break; } |
308 |
| - hostname = hostname.slice(pos+1); |
309 |
| - } |
310 |
| - |
311 |
| - if ( domainSet.size === beforeCount ) { return false; } |
312 |
| - |
313 |
| - if ( domainSet.size === 0 ) { |
314 |
| - dynamicRuleMap.delete(TRUSTED_DIRECTIVE_BASE_RULE_ID); |
315 |
| - await dnr.updateDynamicRules({ |
316 |
| - removeRuleIds: [ TRUSTED_DIRECTIVE_BASE_RULE_ID ] |
317 |
| - }); |
318 |
| - return false; |
319 |
| - } |
320 |
| - |
321 |
| - rule.condition.requestDomains = Array.from(domainSet); |
322 |
| - |
323 |
| - await dnr.updateDynamicRules({ |
324 |
| - addRules: [ rule ], |
325 |
| - removeRuleIds: [ TRUSTED_DIRECTIVE_BASE_RULE_ID ], |
326 |
| - }); |
327 |
| - |
328 |
| - return false; |
329 |
| -} |
330 |
| - |
331 |
| -async function toggleTrustedSiteDirective(details) { |
332 |
| - return details.state |
333 |
| - ? removeTrustedSiteDirective(details) |
334 |
| - : addTrustedSiteDirective(details); |
335 |
| -} |
336 |
| - |
337 |
| -/******************************************************************************/ |
338 |
| - |
339 |
| -async function enableRulesets(ids) { |
340 |
| - const afterIds = new Set(ids); |
341 |
| - const beforeIds = new Set(await dnr.getEnabledRulesets()); |
342 |
| - const enableRulesetIds = []; |
343 |
| - const disableRulesetIds = []; |
344 |
| - for ( const id of afterIds ) { |
345 |
| - if ( beforeIds.has(id) ) { continue; } |
346 |
| - enableRulesetIds.push(id); |
347 |
| - } |
348 |
| - for ( const id of beforeIds ) { |
349 |
| - if ( afterIds.has(id) ) { continue; } |
350 |
| - disableRulesetIds.push(id); |
351 |
| - } |
352 |
| - if ( enableRulesetIds.length !== 0 || disableRulesetIds.length !== 0 ) { |
353 |
| - return dnr.updateEnabledRulesets({ enableRulesetIds,disableRulesetIds }); |
354 |
| - } |
355 |
| -} |
356 |
| - |
357 |
| -async function getEnabledRulesetsStats() { |
358 |
| - const [ |
359 |
| - rulesetDetails, |
360 |
| - ids, |
361 |
| - ] = await Promise.all([ |
362 |
| - getRulesetDetails(), |
363 |
| - dnr.getEnabledRulesets(), |
364 |
| - ]); |
365 |
| - const out = []; |
366 |
| - for ( const id of ids ) { |
367 |
| - const ruleset = rulesetDetails.get(id); |
368 |
| - if ( ruleset === undefined ) { continue; } |
369 |
| - out.push(ruleset); |
370 |
| - } |
371 |
| - return out; |
372 |
| -} |
373 |
| - |
374 |
| -async function defaultRulesetsFromLanguage() { |
375 |
| - const out = [ 'default' ]; |
376 |
| - |
377 |
| - const dropCountry = lang => { |
378 |
| - const pos = lang.indexOf('-'); |
379 |
| - if ( pos === -1 ) { return lang; } |
380 |
| - return lang.slice(0, pos); |
381 |
| - }; |
382 |
| - |
383 |
| - const langSet = new Set(); |
384 |
| - |
385 |
| - await i18n.getAcceptLanguages().then(langs => { |
386 |
| - for ( const lang of langs.map(dropCountry) ) { |
387 |
| - langSet.add(lang); |
388 |
| - } |
389 |
| - }); |
390 |
| - langSet.add(dropCountry(i18n.getUILanguage())); |
391 |
| - |
392 |
| - const reTargetLang = new RegExp( |
393 |
| - `\\b(${Array.from(langSet).join('|')})\\b` |
394 |
| - ); |
395 |
| - |
396 |
| - const rulesetDetails = await getRulesetDetails(); |
397 |
| - for ( const [ id, details ] of rulesetDetails ) { |
398 |
| - if ( typeof details.lang !== 'string' ) { continue; } |
399 |
| - if ( reTargetLang.test(details.lang) === false ) { continue; } |
400 |
| - out.push(id); |
401 |
| - } |
402 |
| - return out; |
403 |
| -} |
404 |
| - |
405 |
| -/******************************************************************************/ |
406 |
| - |
407 | 116 | async function hasGreatPowers(origin) {
|
408 | 117 | return browser.permissions.contains({
|
409 | 118 | origins: [ `${origin}/*` ]
|
@@ -491,7 +200,9 @@ function onMessage(request, sender, callback) {
|
491 | 200 |
|
492 | 201 | case 'toggleTrustedSiteDirective': {
|
493 | 202 | toggleTrustedSiteDirective(request).then(response => {
|
494 |
| - callback(response); |
| 203 | + registerInjectable().then(( ) => { |
| 204 | + callback(response); |
| 205 | + }); |
495 | 206 | });
|
496 | 207 | return true;
|
497 | 208 | }
|
|
0 commit comments