/******************************************************************************* ηMatrix - a browser extension to black/white list requests. Copyright (C) 2014-2019 Raymond Hill Copyright (C) 2019-2022 Alessio Vanni This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. Home: https://gitlab.com/vannilla/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ 'use strict'; (function () { // Switches before, rules after let directiveSort = function (a, b) { let aIsSwitch = a.indexOf(':') !== -1; let bIsSwitch = b.indexOf(':') !== -1; if (aIsSwitch === bIsSwitch) { return a.localeCompare(b); } return aIsSwitch ? -1 : 1; }; let processUserRules = function (response) { let allRules = {}; let permanentRules = {}; let temporaryRules = {}; let rules = response.permanentRules.split(/\n+/); for (let i=rules.length-1; i>=0; --i) { let rule = rules[i].trim(); if (rule.length !== 0) { permanentRules[rule] = allRules[rule] = true; } } rules = response.temporaryRules.split(/\n+/); for (let i=rules.length-1; i>=0; --i) { let rule = rules[i].trim(); if (rule.length !== 0) { temporaryRules[rule] = allRules[rule] = true; } } let permanentList = document.createDocumentFragment(); let temporaryList = document.createDocumentFragment(); let li; rules = Object.keys(allRules).sort(directiveSort); for (let i=0; i .left > ul > li').remove(); document.querySelector('#diff > .left > ul').appendChild(permanentList); uDom('#diff > .right > ul > li').remove(); document.querySelector('#diff > .right > ul').appendChild(temporaryList); uDom('#diff') .toggleClass('dirty', response.temporaryRules !== response.permanentRules); }; // https://github.com/chrisaljoudi/uBlock/issues/757 // Support RequestPolicy rule syntax let fromRequestPolicy = function (content) { let matches = /\[origins-to-destinations\]([^\[]+)/.exec(content); if (matches === null || matches.length !== 2) { return; } return matches[1].trim() .replace(/\|/g, ' ') .replace(/\n/g, ' * allow\n'); }; // https://github.com/gorhill/uMatrix/issues/270 let fromNoScript = function (content) { let noscript = null; try { noscript = JSON.parse(content); } catch (e) { } if (noscript === null || typeof noscript !== 'object' || typeof noscript.prefs !== 'object' || typeof noscript.prefs.clearClick === 'undefined' || typeof noscript.whitelist !== 'string' || typeof noscript.V !== 'string') { return; } let out = new Set(); let reBad = /[a-z]+:\w*$/; let reURL = /[a-z]+:\/\/([0-9a-z.-]+)/; let directives = noscript.whitelist.split(/\s+/); for (let i=directives.length-1; i>=0; --i) { let directive = directives[i].trim(); if (directive === '') { continue; } if (reBad.test(directive)) { continue; } let matches = reURL.exec(directive); if (matches !== null) { directive = matches[1]; } out.add('* ' + directive + ' * allow'); out.add('* ' + directive + ' script allow'); out.add('* ' + directive + ' frame allow'); } return Array.from(out).join('\n'); }; let handleImportFilePicker = function () { let fileReaderOnLoadHandler = function () { if (typeof this.result !== 'string' || this.result === '') { return; } let result = fromRequestPolicy(this.result); if (result === undefined) { result = fromNoScript(this.result); if (result === undefined) { result = this.result; } } if (this.result === '') { return; } let request = { 'what': 'setUserRules', 'temporaryRules': rulesFromHTML('#diff .right li') + '\n' + result, }; vAPI.messaging.send('user-rules.js', request, processUserRules); }; var file = this.files[0]; if (file === undefined || file.name === '') { return; } if (file.type.indexOf('text') !== 0 && file.type !== 'application/json') { return; } let fr = new FileReader(); fr.onload = fileReaderOnLoadHandler; fr.readAsText(file); }; let startImportFilePicker = function () { let input = document.getElementById('importFilePicker'); // Reset to empty string, this will ensure an change event is properly // triggered if the user pick a file, even if it is the same as the last // one picked. input.value = ''; input.click(); }; function exportUserRulesToFile() { vAPI.download({ 'url': 'data:text/plain,' + encodeURIComponent(rulesFromHTML('#diff .left li') + '\n'), 'filename': uDom('[data-i18n="userRulesDefaultFileName"]').text(), }); } var rulesFromHTML = function(selector) { let rules = []; let lis = uDom(selector); for (let i=0; i .right > ul').on('click', 'li', temporaryRulesToggler); vAPI.messaging.send('user-rules.js', { what: 'getUserRules', }, processUserRules); }); })();