- commit
- 6042b58adcc1bce50d5fe52bfa060f53752a9436
- parent
- 24c9746fcdc47ba078f0831bdeeb2dd69d41eafd
- Author
- Tobias Bengfort <tobias.bengfort@posteo.de>
- Date
- 2023-02-25 07:25
Merge branch 'saved-rules-2'
Diffstat
| M | README.md | 1 | - |
| M | src/bg.js | 111 | ++++++++++++++++++++++++++++++++++++------------------------- |
| M | src/popup.css | 8 | ++++++-- |
| M | src/popup.html | 13 | ++++++++----- |
| M | src/popup.js | 13 | +++++++++++-- |
| M | src/settings.css | 2 | ++ |
| M | src/settings.html | 3 | ++- |
| M | src/settings.js | 17 | ++++++++++++----- |
8 files changed, 107 insertions, 61 deletions
diff --git a/README.md b/README.md
@@ -27,7 +27,6 @@ to allow only those requests you want. Definitely for advanced users. 27 27 tried to produce something that works for me rather than copying every 28 28 detail. 29 29 - it is not currently possible to block cookies30 -1 - there is no distinction between temporary and permanent rules31 30 - the popup is not updated while it is open. You have to close and open it 32 31 again to refresh the data. 33 32 - the icon does not show the amount of blocked requests
diff --git a/src/bg.js b/src/bg.js
@@ -4,6 +4,7 @@ var lock = Promise.resolve(); 4 4 5 5 var STORAGE_DEFAULTS = { 6 6 'rules': {}, -1 7 'savedRules': {}, 7 8 'requests': {}, 8 9 'recording': true, 9 10 }; @@ -33,36 +34,44 @@ var storageChange = function(key, fn) { 33 34 }; 34 35 35 36 var setRule = function(context, hostname, type, rule) {36 -1 return storageChange('rules', rules => {37 -1 if (hostname === 'first-party') {38 -1 context = '*';39 -1 }40 -1 if (!rules[context]) {41 -1 rules[context] = {};42 -1 }43 -1 if (!rules[context][hostname]) {44 -1 rules[context][hostname] = {};45 -1 }46 -1 if (rule) {47 -1 rules[context][hostname][type] = rule;48 -1 } else {49 -1 delete rules[context][hostname][type];50 -1 if (Object.keys(rules[context][hostname]).length === 0) {51 -1 delete rules[context][hostname];-1 37 return storageGet('savedRules').then(savedRules => { -1 38 return storageChange('rules', rules => { -1 39 if (hostname === 'first-party') { -1 40 context = '*'; 52 41 }53 -1 if (Object.keys(rules[context]).length === 0) {54 -1 delete rules[context];-1 42 if (!rules[context]) { -1 43 rules[context] = savedRules[context] || {}; 55 44 }56 -1 }57 -1 return rules;-1 45 if (!rules[context][hostname]) { -1 46 rules[context][hostname] = {}; -1 47 } -1 48 if (rule) { -1 49 rules[context][hostname][type] = rule; -1 50 } else { -1 51 delete rules[context][hostname][type]; -1 52 if (Object.keys(rules[context][hostname]).length === 0) { -1 53 delete rules[context][hostname]; -1 54 } -1 55 if (Object.keys(rules[context]).length === 0 && !savedRules[context]) { -1 56 delete rules[context]; -1 57 } -1 58 } -1 59 return rules; -1 60 }); 58 61 }); 59 62 }; 60 6361 -1 var restrictRules = function(rules, context) {62 -1 var restricted = {};63 -1 restricted['*'] = rules['*'] || {};64 -1 restricted[context] = rules[context] || {};65 -1 return restricted;-1 64 var getRules = function(context) { -1 65 return Promise.all([ -1 66 storageGet('rules'), -1 67 storageGet('savedRules'), -1 68 ]).then(([rules, savedRules]) => { -1 69 var restricted = {}; -1 70 restricted['*'] = rules['*'] || savedRules['*'] || {}; -1 71 restricted[context] = rules[context] || savedRules[context] || {}; -1 72 restricted.dirty = !!rules[context]; -1 73 return restricted; -1 74 }); 66 75 }; 67 76 68 77 var pushRequest = function(tabId, hostname, type) { @@ -103,19 +112,20 @@ var getCurrentTab = function() { 103 112 104 113 browser.runtime.onMessage.addListener((msg, sender) => { 105 114 if (msg.type === 'get') {106 -1 return Promise.all([107 -1 getCurrentTab(),108 -1 storageGet('rules'),109 -1 storageGet('requests'),110 -1 storageGet('recording'),111 -1 ]).then(([tab, rules, requests, recording]) => {112 -1 var context = msg.data || getHostname(tab.url);113 -1 return {114 -1 context: context,115 -1 rules: restrictRules(rules, context),116 -1 requests: requests[tab.id] || {},117 -1 recording: recording,118 -1 };-1 115 return getCurrentTab().then(tab => { -1 116 var context = getHostname(tab.url); -1 117 return Promise.all([ -1 118 getRules(context), -1 119 storageGet('requests'), -1 120 storageGet('recording'), -1 121 ]).then(([rules, requests, recording]) => { -1 122 return { -1 123 context: context, -1 124 rules: rules, -1 125 requests: requests[tab.id] || {}, -1 126 recording: recording, -1 127 }; -1 128 }); 119 129 }); 120 130 } else if (msg.type === 'setRule') { 121 131 return setRule( @@ -123,9 +133,21 @@ browser.runtime.onMessage.addListener((msg, sender) => { 123 133 msg.data.hostname, 124 134 msg.data.type, 125 135 msg.data.value,126 -1 ).then(() => storageGet('rules')).then(rules => {127 -1 return restrictRules(rules, msg.data.context);128 -1 });-1 136 ).then(() => getRules(msg.data.context)); -1 137 } else if (msg.type === 'commit') { -1 138 var r; -1 139 return storageChange('rules', rules => { -1 140 r = rules[msg.data]; -1 141 delete rules[msg.data]; -1 142 return rules; -1 143 }).then(() => storageChange('savedRules', savedRules => { -1 144 if (Object.keys(r).length === 0) { -1 145 delete savedRules[msg.data]; -1 146 } else { -1 147 savedRules[msg.data] = r; -1 148 } -1 149 return savedRules; -1 150 })); 129 151 } else if (msg.type === 'securitypolicyviolation') { 130 152 return pushRequest(sender.tab.id, 'inline', msg.data); 131 153 } else if (msg.type === 'toggleRecording') { @@ -155,7 +177,7 @@ browser.webRequest.onBeforeRequest.addListener(details => { 155 177 156 178 return Promise.all([ 157 179 pushRequest(details.tabId, hostname, type),158 -1 storageGet('rules'),-1 180 getRules(context), 159 181 ]).then(([_, rules]) => { 160 182 if (!shared.shouldAllow(rules, context, hostname, type)) { 161 183 if (details.type === 'sub_frame') { @@ -169,12 +191,11 @@ browser.webRequest.onBeforeRequest.addListener(details => { 169 191 }, {urls: ['<all_urls>']}, ['blocking']); 170 192 171 193 browser.webRequest.onHeadersReceived.addListener(function(details) { -1 194 var context = getHostname(details.url); 172 195 return Promise.all([173 -1 storageGet('rules'),-1 196 getRules(context), 174 197 storageGet('recording'), 175 198 ]).then(([rules, recording]) => {176 -1 var context = getHostname(details.url);177 -1178 199 var csp = (type, value) => { 179 200 var name = 'Content-Security-Policy'; 180 201 if (shared.shouldAllow(rules, context, 'inline', type)) {
diff --git a/src/popup.css b/src/popup.css
@@ -6,8 +6,12 @@ 6 6 --text-dark: #fff; 7 7 } 8 89 -1 [name="settings"] {10 -1 float: right;-1 9 .toolbar { -1 10 display: flex; -1 11 gap: 0.5em; -1 12 } -1 13 .toolbar label { -1 14 flex-grow: 1; 11 15 } 12 16 13 17 table {
diff --git a/src/popup.html b/src/popup.html
@@ -6,11 +6,14 @@ 6 6 </head> 7 7 <body> 8 8 <table></table>9 -1 <label>10 -1 <input type="checkbox" name="recording">11 -1 recording12 -1 </label>13 -1 <button type="button" name="settings">Edit rules</button>-1 9 <div class="toolbar"> -1 10 <label> -1 11 <input type="checkbox" name="recording"> -1 12 recording -1 13 </label> -1 14 <button type="button" name="commit" disabled>Commit</button> -1 15 <button type="button" name="settings">Edit rules</button> -1 16 </div> 14 17 <details> 15 18 <summary>Help</summary> 16 19 <p>In the table above, the columns represent different types of requests. The rows represent domains. Numbers (if recording is enabled) show how many requests of a given type the current tab tries to make to the given domain. Red cells are blocked, green cells are allowed. Light green cells are allowed indirectly, e.g. because they represent a sub-domain of an allowed domain. Grey cells are disabled.</p>
diff --git a/src/popup.js b/src/popup.js
@@ -6,6 +6,7 @@ var rules; 6 6 7 7 var table = document.querySelector('table'); 8 8 var recording = document.querySelector('[name="recording"]') -1 9 var commitButton = document.querySelector('[name="commit"]'); 9 10 10 11 var sendMessage = function(type, data) { 11 12 return browser.runtime.sendMessage({type: type, data: data}); @@ -81,6 +82,7 @@ var createCheckbox = function(hostname, type) { 81 82 value: input.checked, 82 83 }).then(newRules => { 83 84 rules = newRules; -1 85 commitButton.disabled = !rules.dirty; 84 86 updateInherit(type); 85 87 }); 86 88 }; @@ -129,12 +131,13 @@ var createRow = function(hostname) { 129 131 return tr; 130 132 }; 131 133132 -1 var loadContext = function(c) {133 -1 sendMessage('get', c).then(data => {-1 134 var loadContext = function() { -1 135 sendMessage('get').then(data => { 134 136 context = data.context; 135 137 requests = data.requests; 136 138 rules = data.rules; 137 139 recording.checked = data.recording; -1 140 commitButton.disabled = !rules.dirty; 138 141 139 142 table.innerHTML = ''; 140 143 table.append(createHeader()); @@ -162,3 +165,9 @@ document.addEventListener('DOMContentLoaded', () => { 162 165 recording.addEventListener('change', event => { 163 166 sendMessage('toggleRecording'); 164 167 }); -1 168 -1 169 commitButton.addEventListener('click', event => { -1 170 sendMessage('commit', context).then(() => { -1 171 commitButton.disabled = true; -1 172 }); -1 173 });
diff --git a/src/settings.css b/src/settings.css
@@ -12,6 +12,7 @@ form {
12 12 height: 100vh;
13 13 display: grid;
14 14 grid-template-rows: 1fr min-content;
-1 15 grid-template-columns: 1fr 1fr;
15 16 grid-gap: 0.5em;
16 17 padding: 0.5em;
17 18 }
@@ -24,4 +25,5 @@ textarea {
24 25 button {
25 26 padding: 0.5em 2em;
26 27 justify-self: end;
-1 28 grid-column: 1 / 3;
27 29 }
diff --git a/src/settings.html b/src/settings.html
@@ -6,7 +6,8 @@ 6 6 </head> 7 7 <body> 8 8 <form>9 -1 <textarea></textarea>-1 9 <textarea class="rules"></textarea> -1 10 <textarea class="savedRules"></textarea> 10 11 <button>Save</button> 11 12 </form> 12 13 <script src="shared.js"></script>
diff --git a/src/settings.js b/src/settings.js
@@ -1,15 +1,22 @@ 1 1 var form = document.querySelector('form');2 -1 var textarea = document.querySelector('textarea');-1 2 var textarea1 = document.querySelector('textarea.rules'); -1 3 var textarea2 = document.querySelector('textarea.savedRules'); 3 44 -1 browser.storage.local.get('rules').then(data => {-1 5 browser.storage.local.get(['rules', 'savedRules']).then(data => { 5 6 var rules = data.rules || {};6 -1 textarea.value = JSON.stringify(rules, null, 2)-1 7 var savedRules = data.savedRules || {}; -1 8 textarea1.value = JSON.stringify(rules, null, 2) -1 9 textarea2.value = JSON.stringify(savedRules, null, 2) 7 10 }); 8 11 9 12 form.addEventListener('submit', event => { 10 13 event.preventDefault();11 -1 var rules = JSON.parse(textarea.value);12 -1 browser.storage.local.set({'rules': rules}).then(() => {-1 14 var rules = JSON.parse(textarea1.value); -1 15 var savedRules = JSON.parse(textarea2.value); -1 16 browser.storage.local.set({ -1 17 'rules': rules, -1 18 'savedRules': savedRules, -1 19 }).then(() => { 13 20 location.reload(); 14 21 }); 15 22 });