xiMatrix

filter net requests according to source, destination and type  https://addons.mozilla.org/firefox/addon/ximatrix/
git clone https://git.ce9e.org/xiMatrix.git

commit
4c4576a713158d9bbad11f211b69ce9194d5539f
parent
c1dc5762c605ebba07ccb7300a44074a7190db94
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2023-12-07 23:02
use async/await syntax

Diffstat

M src/bg.js 262 ++++++++++++++++++++++++++++++-------------------------------

1 files changed, 128 insertions, 134 deletions


diff --git a/src/bg.js b/src/bg.js

@@ -22,88 +22,83 @@ var getHostname = function(url) {
   22    22     return u.hostname;
   23    23 };
   24    24 
   25    -1 var storageGet = function(key) {
   26    -1     return STORAGE_AREAS[key].get(key).then(data => {
   27    -1         return data[key] ?? STORAGE_DEFAULTS[key];
   28    -1     });
   -1    25 var storageGet = async function(key) {
   -1    26     var data = await STORAGE_AREAS[key].get(key);
   -1    27     return data[key] ?? STORAGE_DEFAULTS[key];
   29    28 };
   30    29 
   31    -1 var _storageChange = function(key, fn) {
   32    -1     return storageGet(key).then(oldValue => {
   33    -1         var data = {};
   34    -1         data[key] = fn(oldValue);
   35    -1         return STORAGE_AREAS[key].set(data);
   36    -1     });
   -1    30 var _storageChange = async function(key, fn) {
   -1    31     var oldValue = await storageGet(key);
   -1    32     var data = {};
   -1    33     data[key] = fn(oldValue);
   -1    34     await STORAGE_AREAS[key].set(data);
   37    35 };
   38    36 
   39    -1 var storageChange = function(key, fn) {
   -1    37 var storageChange = async function(key, fn) {
   40    38     lock = lock.then(() => _storageChange(key, fn));
   41    -1     return lock;
   -1    39     await lock;
   42    40 };
   43    41 
   44    -1 var setRule = function(context, hostname, type, rule) {
   45    -1     return storageGet('savedRules').then(savedRules => {
   46    -1         return storageChange('rules', rules => {
   47    -1             if (hostname === 'first-party') {
   48    -1                 context = '*';
   49    -1             }
   50    -1             if (!rules[context]) {
   51    -1                 rules[context] = savedRules[context] || {};
   52    -1             }
   53    -1             if (!rules[context][hostname]) {
   54    -1                 rules[context][hostname] = {};
   -1    42 var setRule = async function(context, hostname, type, rule) {
   -1    43     var savedRules = await storageGet('savedRules');
   -1    44     await storageChange('rules', rules => {
   -1    45         if (hostname === 'first-party') {
   -1    46             context = '*';
   -1    47         }
   -1    48         if (!rules[context]) {
   -1    49             rules[context] = savedRules[context] || {};
   -1    50         }
   -1    51         if (!rules[context][hostname]) {
   -1    52             rules[context][hostname] = {};
   -1    53         }
   -1    54         if (rule) {
   -1    55             rules[context][hostname][type] = rule;
   -1    56         } else {
   -1    57             delete rules[context][hostname][type];
   -1    58             if (Object.keys(rules[context][hostname]).length === 0) {
   -1    59                 delete rules[context][hostname];
   55    60             }
   56    -1             if (rule) {
   57    -1                 rules[context][hostname][type] = rule;
   58    -1             } else {
   59    -1                 delete rules[context][hostname][type];
   60    -1                 if (Object.keys(rules[context][hostname]).length === 0) {
   61    -1                     delete rules[context][hostname];
   62    -1                 }
   63    -1                 if (Object.keys(rules[context]).length === 0 && !savedRules[context]) {
   64    -1                     delete rules[context];
   65    -1                 }
   -1    61             if (Object.keys(rules[context]).length === 0 && !savedRules[context]) {
   -1    62                 delete rules[context];
   66    63             }
   67    -1             return rules;
   68    -1         });
   -1    64         }
   -1    65         return rules;
   69    66     });
   70    67 };
   71    68 
   72    -1 var getRules = function(context) {
   73    -1     return Promise.all([
   -1    69 var getRules = async function(context) {
   -1    70     var [rules, savedRules] = await Promise.all([
   74    71         storageGet('rules'),
   75    72         storageGet('savedRules'),
   76    -1     ]).then(([rules, savedRules]) => {
   77    -1         var restricted = {};
   78    -1         restricted['*'] = rules['*'] || savedRules['*'] || {};
   79    -1         restricted[context] = rules[context] || savedRules[context] || {};
   80    -1         restricted.dirty = !!rules[context];
   81    -1         return restricted;
   82    -1     });
   -1    73     ]);
   -1    74     var restricted = {};
   -1    75     restricted['*'] = rules['*'] || savedRules['*'] || {};
   -1    76     restricted[context] = rules[context] || savedRules[context] || {};
   -1    77     restricted.dirty = !!rules[context];
   -1    78     return restricted;
   83    79 };
   84    80 
   85    -1 var pushRequest = function(tabId, hostname, type) {
   86    -1     return storageGet('recording').then(recording => {
   87    -1         if (recording) {
   88    -1             return storageChange('requests', requests => {
   89    -1                 if (!requests[tabId]) {
   90    -1                     requests[tabId] = {};
   91    -1                 }
   92    -1                 if (!requests[tabId][hostname]) {
   93    -1                     requests[tabId][hostname] = {};
   94    -1                 }
   95    -1                 if (!requests[tabId][hostname][type]) {
   96    -1                     requests[tabId][hostname][type] = 0;
   97    -1                 }
   98    -1                 requests[tabId][hostname][type] += 1;
   99    -1                 return requests;
  100    -1             });
  101    -1         }
  102    -1     });
   -1    81 var pushRequest = async function(tabId, hostname, type) {
   -1    82     var recording = await storageGet('recording');
   -1    83     if (recording) {
   -1    84         await storageChange('requests', requests => {
   -1    85             if (!requests[tabId]) {
   -1    86                 requests[tabId] = {};
   -1    87             }
   -1    88             if (!requests[tabId][hostname]) {
   -1    89                 requests[tabId][hostname] = {};
   -1    90             }
   -1    91             if (!requests[tabId][hostname][type]) {
   -1    92                 requests[tabId][hostname][type] = 0;
   -1    93             }
   -1    94             requests[tabId][hostname][type] += 1;
   -1    95             return requests;
   -1    96         });
   -1    97     }
  103    98 };
  104    99 
  105    -1 var clearRequests = function(tabId) {
  106    -1     return storageChange('requests', requests => {
   -1   100 var clearRequests = async function(tabId) {
   -1   101     await storageChange('requests', requests => {
  107   102         if (requests[tabId]) {
  108   103             delete requests[tabId];
  109   104         }
@@ -111,71 +106,72 @@ var clearRequests = function(tabId) {
  111   106     });
  112   107 };
  113   108 
  114    -1 var getCurrentTab = function() {
  115    -1     return browser.tabs.query({
   -1   109 var getCurrentTab = async function() {
   -1   110     var tabs = await browser.tabs.query({
  116   111         active: true,
  117   112         currentWindow: true,
  118    -1     }).then(tabs => tabs[0]);
   -1   113     });
   -1   114     return tabs[0];
  119   115 };
  120   116 
  121    -1 browser.runtime.onMessage.addListener((msg, sender) => {
   -1   117 browser.runtime.onMessage.addListener(async (msg, sender) => {
  122   118     if (msg.type === 'get') {
  123    -1         return getCurrentTab().then(tab => {
  124    -1             var context = getHostname(tab.url);
  125    -1             return Promise.all([
  126    -1                 getRules(context),
  127    -1                 storageGet('requests'),
  128    -1                 storageGet('recording'),
  129    -1             ]).then(([rules, requests, recording]) => {
  130    -1                 return {
  131    -1                     context: context,
  132    -1                     rules: rules,
  133    -1                     requests: requests[tab.id] || {},
  134    -1                     recording: recording,
  135    -1                 };
  136    -1             });
  137    -1         });
   -1   119         const tab = await getCurrentTab();
   -1   120         const context = getHostname(tab.url);
   -1   121         const [rules, requests, recording] = await Promise.all([
   -1   122             getRules(context),
   -1   123             storageGet('requests'),
   -1   124             storageGet('recording'),
   -1   125         ]);
   -1   126         return {
   -1   127             context: context,
   -1   128             rules: rules,
   -1   129             requests: requests[tab.id] || {},
   -1   130             recording: recording,
   -1   131         };
  138   132     } else if (msg.type === 'setRule') {
  139    -1         return setRule(
   -1   133         await setRule(
  140   134             msg.data.context,
  141   135             msg.data.hostname,
  142   136             msg.data.type,
  143   137             msg.data.value,
  144    -1         ).then(() => getRules(msg.data.context));
   -1   138         );
   -1   139         return await getRules(msg.data.context);
  145   140     } else if (msg.type === 'commit') {
  146    -1         var r;
  147    -1         return storageChange('rules', rules => {
   -1   141         let r;
   -1   142         await storageChange('rules', rules => {
  148   143             r = rules[msg.data];
  149   144             delete rules[msg.data];
  150   145             return rules;
  151    -1         }).then(() => storageChange('savedRules', savedRules => {
   -1   146         });
   -1   147         await storageChange('savedRules', savedRules => {
  152   148             if (Object.keys(r).length === 0) {
  153   149                 delete savedRules[msg.data];
  154   150             } else {
  155   151                 savedRules[msg.data] = r;
  156   152             }
  157   153             return savedRules;
  158    -1         }));
   -1   154         });
  159   155     } else if (msg.type === 'reset') {
  160    -1         return storageChange('rules', rules => {
   -1   156         await storageChange('rules', rules => {
  161   157             delete rules[msg.data];
  162   158             return rules;
  163   159         });
  164   160     } else if (msg.type === 'securitypolicyviolation') {
  165    -1         return pushRequest(sender.tab.id, 'inline', msg.data);
   -1   161         await pushRequest(sender.tab.id, 'inline', msg.data);
  166   162     } else if (msg.type === 'toggleRecording') {
  167    -1         return storageChange('recording', recording => !recording);
   -1   163         await storageChange('recording', recording => !recording);
  168   164     }
  169   165 });
  170   166 
  171   167 browser.tabs.onRemoved.addListener(clearRequests);
  172    -1 browser.webNavigation.onBeforeNavigate.addListener(details => {
   -1   168 browser.webNavigation.onBeforeNavigate.addListener(async details => {
  173   169     if (details.frameId === 0) {
  174    -1         return clearRequests(details.tabId);
   -1   170         await clearRequests(details.tabId);
  175   171     }
  176   172 });
  177   173 
  178    -1 browser.webRequest.onBeforeSendHeaders.addListener(details => {
   -1   174 browser.webRequest.onBeforeSendHeaders.addListener(async details => {
  179   175     var context = getHostname(details.documentUrl || details.url);
  180   176     if (details.frameAncestors && details.frameAncestors.length) {
  181   177         var last = details.frameAncestors.length - 1;
@@ -197,55 +193,53 @@ browser.webRequest.onBeforeSendHeaders.addListener(details => {
  197   193         promises.push(pushRequest(details.tabId, hostname, 'cookie'));
  198   194     }
  199   195 
  200    -1     return Promise.all(promises).then(([rules, ...rest]) => {
  201    -1         if (
  202    -1             details.type !== 'main_frame'
  203    -1             && !shared.shouldAllow(rules, context, hostname, type)
  204    -1         ) {
  205    -1             if (details.type === 'sub_frame') {
  206    -1                 // this can in turn be blocked by a local CSP
  207    -1                 return {redirectUrl: 'data:,' + encodeURIComponent(details.url)};
  208    -1             } else {
  209    -1                 return {cancel: true};
  210    -1             }
  211    -1         }
  212    -1 
  213    -1         if (shared.shouldAllow(rules, context, hostname, 'cookie')) {
  214    -1             return {requestHeaders: details.requestHeaders};
   -1   196     var [rules, ...rest] = await Promise.all(promises);
   -1   197     if (
   -1   198         details.type !== 'main_frame'
   -1   199         && !shared.shouldAllow(rules, context, hostname, type)
   -1   200     ) {
   -1   201         if (details.type === 'sub_frame') {
   -1   202             // this can in turn be blocked by a local CSP
   -1   203             return {redirectUrl: 'data:,' + encodeURIComponent(details.url)};
  215   204         } else {
  216    -1             var filtered = details.requestHeaders.filter(h => !isCookie(h));
  217    -1             return {requestHeaders: filtered};
   -1   205             return {cancel: true};
  218   206         }
  219    -1     });
   -1   207     }
   -1   208 
   -1   209     if (shared.shouldAllow(rules, context, hostname, 'cookie')) {
   -1   210         return {requestHeaders: details.requestHeaders};
   -1   211     } else {
   -1   212         var filtered = details.requestHeaders.filter(h => !isCookie(h));
   -1   213         return {requestHeaders: filtered};
   -1   214     }
  220   215 }, {urls: ['<all_urls>']}, ['blocking', 'requestHeaders']);
  221   216 
  222    -1 browser.webRequest.onHeadersReceived.addListener(details => {
   -1   217 browser.webRequest.onHeadersReceived.addListener(async details => {
  223   218     var context = getHostname(details.url);
  224    -1     return Promise.all([
   -1   219     var [rules, recording] = await Promise.all([
  225   220         getRules(context),
  226   221         storageGet('recording'),
  227    -1     ]).then(([rules, recording]) => {
  228    -1         var csp = (type, value) => {
  229    -1             var name = 'Content-Security-Policy';
  230    -1             if (shared.shouldAllow(rules, context, 'inline', type)) {
  231    -1                 if (recording) {
  232    -1                     name = 'Content-Security-Policy-Report-Only';
  233    -1                 } else {
  234    -1                     return;
  235    -1                 }
   -1   222     ]);
   -1   223     var csp = (type, value) => {
   -1   224         var name = 'Content-Security-Policy';
   -1   225         if (shared.shouldAllow(rules, context, 'inline', type)) {
   -1   226             if (recording) {
   -1   227                 name = 'Content-Security-Policy-Report-Only';
   -1   228             } else {
   -1   229                 return;
  236   230             }
  237    -1             details.responseHeaders.push({
  238    -1                 name: name,
  239    -1                 value: value,
  240    -1             });
  241    -1         };
   -1   231         }
   -1   232         details.responseHeaders.push({
   -1   233             name: name,
   -1   234             value: value,
   -1   235         });
   -1   236     };
  242   237 
  243    -1         csp('css', "style-src 'self' *");
  244    -1         csp('script', "script-src 'self' *");
  245    -1         csp('media', "img-src 'self' *");
   -1   238     csp('css', "style-src 'self' *");
   -1   239     csp('script', "script-src 'self' *");
   -1   240     csp('media', "img-src 'self' *");
  246   241 
  247    -1         return {responseHeaders: details.responseHeaders};
  248    -1     });
   -1   242     return {responseHeaders: details.responseHeaders};
  249   243 }, {
  250   244     urls: ['<all_urls>'],
  251   245     types: ['main_frame'],