diff --git a/extensions/chromium/runet-censorship-bypass/extension/14-ip-to-host-api.js b/extensions/chromium/runet-censorship-bypass/extension/14-ip-to-host-api.js index 14a65c1..c4f386a 100644 --- a/extensions/chromium/runet-censorship-bypass/extension/14-ip-to-host-api.js +++ b/extensions/chromium/runet-censorship-bypass/extension/14-ip-to-host-api.js @@ -18,7 +18,7 @@ const _match = function _match(ipRe, str) { - let m = (str.match(ipRe) || []).filter( (c) => c ); + const m = (str.match(ipRe) || []).filter( (c) => c ); const port = m.length > 1 ? m.pop() : false; return { ifMatched: m.length, port: port }; @@ -55,17 +55,19 @@ const privates = {}; + const _createHostObj = function _addHostObj(hostStr) { + + return (privates._strToHostObj[hostStr] = { host: hostStr }); + + } + const _getHostObj = function _getHostObj(hostStr) { - let hostObj = privates._strToHostObj[hostStr]; - if (!hostObj) { - hostObj = privates._strToHostObj[hostStr] = { host: hostStr }; - } - return hostObj; + return privates._strToHostObj[hostStr] || _createHostObj(hostStr); }; - const init = function init() { + const reinit = function reinit() { // Defaults. const _antizapret = { @@ -100,7 +102,7 @@ }; - init(); + reinit(); const getIpsFor = function getIpsFor(host, cb = mandatory()) { @@ -200,7 +202,15 @@ resetToDefaultsVoid() { _state(ip2host, null); - init(); + reinit(); + + }, + + _purgeIpsForVoid(hostStr) { + + for(const ip of Object.keys(privates._ipToHostObj)) { + delete privates._ipToHostObj[ip]; + } }, @@ -210,6 +220,7 @@ console.log('IPS', ips); if (!err) { + this._purgeIpsForVoid(hostStr); // Object may be shared, string can't. const hostObj = _getHostObj(hostStr); for(const ip of ips) { @@ -222,14 +233,9 @@ }, - _replaceAllAsync(hostArr = mandatory(), cb) { + updateAllAsync(cb = mandatory()) { - if (typeof(hostArr) === 'function') { - cb = hostArr; - hostArr = Object.keys(privates._strToHostObj); - } - - this.resetToDefaultsVoid(); + const hostArr = Object.keys(privates._strToHostObj); const promises = hostArr.map( (hostStr) => new Promise( (resolve) => this._addAsync(hostStr, (...args) => resolve(args) ) ) @@ -261,6 +267,22 @@ }, + _replaceAllAsync(hostArr = mandatory(), cb) { + + if (typeof(hostArr) === 'function') { + cb = hostArr; + hostArr = Object.keys(privates._strToHostObj); + } + + this.resetToDefaultsVoid(); + for(const hostStr of hostArr) { + _createHostObj(hostStr); + } + + this.updateAllAsync(cb); + + }, + replaceAllAsync(addrArr, cb = mandatory()) { console.log('Replacing...'); @@ -282,12 +304,6 @@ }, - updateAllAsync(cb = mandatory()) { - - this._replaceAllAsync(cb); - - }, - get(ip) { const tmp = privates._ipToHostObj[ip]; diff --git a/extensions/chromium/runet-censorship-bypass/extension/15-pac-kitchen-api.js b/extensions/chromium/runet-censorship-bypass/extension/15-pac-kitchen-api.js index 4ee603a..d1b401c 100644 --- a/extensions/chromium/runet-censorship-bypass/extension/15-pac-kitchen-api.js +++ b/extensions/chromium/runet-censorship-bypass/extension/15-pac-kitchen-api.js @@ -10,6 +10,7 @@ const kitchenState = window.utils.createStorage('pac-kitchen-'); const ifIncontinence = 'if-incontinence'; + // Don't keep objects in defaults or at least freeze them! const configs = { ifProxyHttpsUrlsOnly: { @@ -24,23 +25,35 @@ desc: 'Шифровать соединение до прокси от провайдера. Провайдер всё же сможет видеть адреса (но не содержимое) проксируемых ресурсов из протокола DNS.', index: 1, }, + ifProhibitDns: { + dflt: false, + label: 'запретить опредление по IP/DNS', + desc: 'Пытается запретить скрипту использовать DNS, без которого определение блокировки по IP работать не будет. Используйте, если вам кажется, что мы проксируем слишком много сайтов.', + index: 2, + }, ifUsePacScriptProxies: { dflt: true, label: 'использовать прокси PAC-скрипта', desc: 'Использовать прокси от авторов PAC-скрипта.', - index: 2, + index: 3, }, ifUseLocalTor: { dflt: false, - label: 'использовать свой локальный TOR', - desc: 'Установите TOR на свой компьютер и используйте его как прокси. ВАЖНО', - index: 3, + label: 'использовать СВОЙ локальный TOR', + desc: 'Установите TOR на свой компьютер и используйте его как прокси. ВАЖНО', + index: 4, + }, + exceptions: { + dflt: null, + label: 'учитывать исключения', + desc: 'Учитывать сайты, добавленные вручную. Только для своих прокси! Без своих прокси работать не будет.', + index: 5, }, customProxyStringRaw: { dflt: '', - label: 'использовать свои прокси', + label: 'использовать СВОИ прокси', url: 'https://rebrand.ly/ac-own-proxy', - index: 4, + index: 6, }, }; @@ -59,21 +72,18 @@ const getCurrentConfigs = function getCurrentConfigs() { const mods = kitchenState('mods'); - if (!mods) { - return null; - } - return new PacModifiers(mods); + return new PacModifiers(mods || {}); }; const getOrderedConfigsForUser = function getOrderedConfigs() { - const pacMods = getCurrentConfigs() || {}; + const pacMods = getCurrentConfigs(); return Object.keys(configs).reduce((arr, key) => { const conf = configs[key] arr[conf.index] = conf; - conf.value = (key in pacMods) ? pacMods[key] : conf.dflt; + conf.value = pacMods[key]; conf.key = key; return arr; @@ -89,7 +99,8 @@ const ifAllDefaults = Object.keys(defaults) .every( - (prop) => !(prop in mods) || Boolean(defaults[prop]) === Boolean(mods[prop]) + (prop) => !(prop in mods) + || Boolean(defaults[prop]) === Boolean(mods[prop]) ); Object.assign(this, defaults, mods); @@ -121,13 +132,31 @@ this.filteredCustomsString = ''; } + if (this.exceptions) { + this.included = []; + this.excluded = []; + for(const host of Object.keys(this.exceptions)) { + if (this.exceptions[host]) { + this.included.push(host) + } else { + this.excluded.push(host); + } + } + if (this.included && !this.filteredCustomsString) { + throw new TypeError( + 'Проксировать свои сайты можно только через свои прокси. Нет ни одного своего прокси, удовлетворяющего вашим требованиям!' + ); + } + } + } }; window.apis.pacKitchen = { - getConfigs: getOrderedConfigsForUser, + getPacMods: getCurrentConfigs, + getOrderedConfigs: getOrderedConfigsForUser, cook(pacData, pacMods = mandatory()) { @@ -139,22 +168,42 @@ global.FindProxyForURL = function(url, host) { ${function() { - let res = ''; + let res = pacMods.ifProhibitDns ? ` + global.dnsResolve = function(host) { return null; }; +` : ''; if (pacMods.ifProxyHttpsUrlsOnly) { - res = ` + res += ` if (!url.startsWith("https")) { return "DIRECT"; } `; - if( - !pacMods.ifUseSecureProxiesOnly && - !pacMods.filteredCustomsString && - pacMods.ifUsePacScriptProxies - ) { - return res + ` - return originalFindProxyForURL(url, host);`; - } + } + + if (pacMods.included && pacMods.included.length) { + res += ` + if ( ${JSON.stringify(pacMods.included)}.some( (included) => host.endsWith(included) ) ) { + return "${pacMods.filteredCustomsString}; DIRECT"; + } +`; + } + + if (pacMods.excluded && pacMods.excluded.length) { + res += ` + if ( ${JSON.stringify(pacMods.excluded)}.some( (excluded) => host.endsWith(excluded) ) ) { + return "DIRECT"; + } +`; + } + + if( + !pacMods.ifUseSecureProxiesOnly && + !pacMods.filteredCustomsString && + pacMods.ifUsePacScriptProxies + ) { + return res + ` + return originalFindProxyForURL(url, host); +`; } return res + ` @@ -296,9 +345,7 @@ return originalSet(details, cb); } const pacMods = getCurrentConfigs(); - if (pacMods) { - pac.data = pacKitchen.cook( pac.data, pacMods ); - } + pac.data = pacKitchen.cook( pac.data, pacMods ); originalSet({ value: details.value }, (/* No args. */) => { kitchenState(ifIncontinence, null); diff --git a/extensions/chromium/runet-censorship-bypass/extension/30-block-informer.js b/extensions/chromium/runet-censorship-bypass/extension/30-block-informer.js index 95f40e0..e20a0a5 100644 --- a/extensions/chromium/runet-censorship-bypass/extension/30-block-informer.js +++ b/extensions/chromium/runet-censorship-bypass/extension/30-block-informer.js @@ -125,11 +125,11 @@ let previousUpdateTitleFinished = Promise.resolve(); - const isProxiedAndInformed = function isProxiedAndInformed(requestDetails) { + const tryProxyAndInform = function tryProxyAndInform(requestDetails) { const host = window.apis.ipToHost.get( requestDetails.ip ); if (!host) { - return false; + return; } const ifMainFrame = requestDetails.type === 'main_frame'; @@ -144,27 +144,27 @@ ) ); - return true; - }; const isInsideTabWithIp = function isInsideTabWithIp(requestDetails) { - return requestDetails.tabId !== -1 && requestDetails.ip; }; - chrome.webRequest.onResponseStarted.addListener( - (requestDetails) => isInsideTabWithIp(requestDetails) - && isProxiedAndInformed(requestDetails), - {urls: ['']} - ); + const onRequest = function onRequest(requestDetails) { - chrome.webRequest.onErrorOccurred.addListener( - (requestDetails) => - isInsideTabWithIp(requestDetails) - && isProxiedAndInformed(requestDetails), - {urls: ['']} - ); + const ifInsideTabWithIp = requestDetails.tabId !== -1 && requestDetails.ip; + if (ifInsideTabWithIp) { + tryProxyAndInform(requestDetails); + } + + }; + + for(const eventName of ['onResponseStarted', 'onErrorOccurred']) { + chrome.webRequest[eventName].addListener( + onRequest, + {urls: ['']} + ); + } } diff --git a/extensions/chromium/runet-censorship-bypass/extension/pages/choose-pac-provider/index.html b/extensions/chromium/runet-censorship-bypass/extension/pages/choose-pac-provider/index.html index 1da693d..edd9651 100755 --- a/extensions/chromium/runet-censorship-bypass/extension/pages/choose-pac-provider/index.html +++ b/extensions/chromium/runet-censorship-bypass/extension/pages/choose-pac-provider/index.html @@ -6,23 +6,25 @@ :root { --ribbon-color: #4169e1; /* #1a6cc8 */ } - div, section { + body { + margin-left: 0; + margin-right: 0; + } + .main-padded { + margin: 0 17px; + } + div, section, header { margin: 0; padding: 0; } - header { - margin: 0 0 0.4em; + + .valign-parent { + display: flex; + align-items: center; } - section header { - display: block; - border-bottom: 1px solid #558abb; - border-left: 5px solid #1048ac; - margin: 0; - position: relative; - height: 2em; - background-color: DodgerBlue; - color: white; + section header h4 { + margin: 0 0 0 0.7em; } label { @@ -46,6 +48,14 @@ cursor: pointer; } + hr { + border-width: 1px 0 0 0; + margin: 0 0 0.6em 0; + padding: 0; + } + + /* COMMON */ + .link-button, .link-button:visited { color: #0000EE; text-decoration: none; @@ -54,27 +64,30 @@ text-decoration: underline; } - .checked-radio-panel { - visibility: hidden; - } - input:checked ~ .checked-radio-panel { - visibility: visible; - } - hr { - border-width: 1px 0 0 0; - margin: 0.6em 0; - padding: 0; - } - #none:checked + label { - color: red; - } .if-not-controlled { display: none; color: red; } - li.info-row { + + /* PAC PROVIDER */ + + .update-button { + visibility: hidden; + } + input:checked ~ .update-button { + visibility: inherit; + } + + #none:checked + label { + color: red; + } + + /* INFO SIGNS */ + + .info-row { display: table; width: 100%; + position: relative; } .info-sign { @@ -84,11 +97,15 @@ margin-left: 0.1em; } .info-url { - float: right; text-decoration: none; - line-height: initial; - vertical-align: bottom !important; + + float: right; + text-align: right; + + line-height: normal !important; + vertical-align: top !important; } + /* Source: https://jsfiddle.net/greypants/zgCb7/ */ .desc { display: table-cell; @@ -137,16 +154,76 @@ left: 75%; width: calc(25% + 0.6em); } - #custom-proxy-string-raw ~ textarea { + + /* PAC MODS & EXCEPTIONS */ + + #mods-custom-proxy-string-raw ~ textarea { width: 100%; height: 7em; margin-top: 0.3em; font-size: 0.9em; } - #custom-proxy-string-raw:not(:checked) ~ textarea { + #mods-custom-proxy-string-raw:not(:checked) ~ textarea { display: none; } + #this-yes:disabled + label { + color: grey; + text-decoration: line-through; + } + + /* EXCEPTIONS */ + + #right-flexed-editor { + flex-grow: 99; + + max-height: 100%; + display: flex; + flex-direction: column; + } + #right-flexed-editor > * { + width: 100%; + } + #except-editor { + border-radius: 0 !important; + border-bottom: 0; + max-height: 1.6em !important; + min-height: 1.6em !important; + + flex-grow: 99; + } + #bottom-flexed-editor { + flex-grow: 99; + position: relative; + } + + select#exceptions-select { + color: black; + background: transparent; + border-radius: 0; + box-shadow: none; + text-shadow: none; + padding: 0; + + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 100%; + } + + #exc-flex-container { + position: relative; + display: flex; + } + #exc-flex-container > * { + flex-grow: 1; + padding: 0; + margin: 0; + } + + /* CONTROL RAW = BUTTON + LINK */ + .control-row { display: table; width: 100%; @@ -160,107 +237,194 @@ text-align: right; } - select#exceptions-select { - color: black; - background: transparent; - border-radius: 0; - box-shadow: none; - text-shadow: none; - padding: 0; - } - #flex-right { - flex-grow: 99; - } - #flex-right > * { - width: 100%; - } - #except-editor { - border-radius: 0 !important; - border-bottom: 0; - height: 1.6em !important; - min-height: 1.6em !important; + .main-nav { + display: flex; + flex-direction: column; + counter-reset: line; } - #flex-container { - position: relative; - padding: 0; - margin: 0; - display: flex; + /* ACCORDION */ + + .accordion-radio { + display: none; } - #flex-container > * { - flex-grow: 1; + .accordion-title { + position: relative; + height: 1.8em; + border-bottom: 1px solid #558abb; + } + .accordion-title label:before { + content: counter(line) '.'; + counter-increment: line; + padding-left: 0.2em; + } + .accordion-title label { + background-color: transparent; + color: black; + padding-left: 5px; + } + .accordion-radio:checked + section { + order: 0; + } + + #status { + padding: 0 0.3em 1em; + } + .status { + order: 2; + /*border-left: 5px solid DodgerBlue;*/ + margin-bottom: 0.5em; + } + + .accordion-radio:checked + section .accordion-title { + margin-top: 0.3em; /* Short gap. */ + } + .accordion-radio:checked + section .accordion-title label, + .accordion-title:hover label + { + background-color: DodgerBlue; + color: white; + padding-left: 0; + border-left: 5px solid #1048ac; + } + .accordion-title label { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + } + .accordion-radio:not(:checked) + section .accordion-content { + /* Hide, but preclude width resizes. */ + height: 0px !important; + line-height: 0px !important; padding: 0; margin: 0; + display: block; + visibility: hidden; + transform:scaleY(0.5); + } + + .accordion-radio:not(:checked) + section .accordion-content * { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + + .accordion-radio + section .accordion-content .acc-padded { + margin: 0.6em 0 1em 0.5em; } - - + + + - - - PAC-скрипт - - Отключить - - - Обновлялись: ... - - Загрузка... + + + + + + + + + PAC-скрипт + + + + + + Отключить + + + Обновлялись: ... + + + + + + + + + + + + Проксировать этот сайт? + + + + + + 🔄︎ авто + ✔ да + ✘ нет + Весь список + + + + + + + + + + + + + + + + + + Модификаторы PAC-скрипта + + + + + + + + К изначальным! + + + + + + + + + + + + + Уведомления + + + + + + + + + + + + - - Проксировать этот сайт? - - - 🔄︎ авто - ✔ да - ✘ нет - Весь список - - - - - google.com - yandex.ru - yandex.ru - yandex.ru - yandex.ru - yandex.ru - yandex.ru - yandex.ru - yandex.ru - yandex.ru - yandex.ru - yandex.ru - yandex.ru - yandex.ru - yandex.ru - yandex.ru - yandex.ru - - - - - - - - - К изначальным! - - - - - Я ❤️ уведомления: - - + + + + Загрузка... + + + diff --git a/extensions/chromium/runet-censorship-bypass/extension/pages/choose-pac-provider/index.js b/extensions/chromium/runet-censorship-bypass/extension/pages/choose-pac-provider/index.js index 342e498..5995d06 100755 --- a/extensions/chromium/runet-censorship-bypass/extension/pages/choose-pac-provider/index.js +++ b/extensions/chromium/runet-censorship-bypass/extension/pages/choose-pac-provider/index.js @@ -173,7 +173,7 @@ chrome.runtime.getBackgroundPage( (backgroundPage) => li.innerHTML = ` ${provider.label} - [обновить] ` + infoSign(provider.desc); li.querySelector('.link-button').onclick = @@ -224,39 +224,74 @@ chrome.runtime.getBackgroundPage( (backgroundPage) => // EXCEPTIONS PANEL - chrome.tabs.query({ active: true, currentWindow: true }, ([tab]) => { - - /* - console.log(tab); - const opt = document.createElement('option'); - opt.text = - opt.selected = true; - opt.style.backgroundColor = 'green !important'; - opt.style.background = 'green !important'; - - const sl = document.getElementById('exceptions-select'); - sl.insertBefore( opt, sl.firstChild ); - */ - - document.getElementById('except-editor').value = new URL(tab.url).hostname; - - }); - - // PAC MODS PANEL - { const pacKitchen = backgroundPage.apis.pacKitchen; + chrome.tabs.query({ active: true, currentWindow: true }, ([tab]) => { + + document.getElementById('except-editor').value = new URL(tab.url).hostname; + + }); + + { + + const pacMods = pacKitchen.getPacMods(); + const exc = pacMods.exceptions || {}; + + const addOption = function addOption(host) { + + const opt = document.createElement('option'); + opt.text = host; + document.getElementById('exceptions-select').add(opt); + + } + + for(const host of Object.keys(exc).sort()) { + addOption(host); + } + + document.getElementById('this-yes').onclick = function() { + + const pacMods = pacKitchen.getPacMods(); + if (!pacMods.filteredCustomsString) { + showErrors( new TypeError( + 'Проксировать СВОИ сайты можно только при наличии СВОИХ прокси (см.«Модификаторы»).' + )); + return false; + } + const host = document.getElementById('except-editor').value; + const ValidHostnameRegex = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/; + if(!ValidHostnameRegex.test(host)) { + showErrors(new TypeError('Должно быть только доменное имя, без протокола и пути. Попробуйте ещё раз.')); + return false; + } + + pacMods.exceptions = pacMods.exceptions || {}; + pacMods.exceptions[host] = true; + pacKitchen.keepCookedNowAsync( + pacMods, + (err) => err + ? showErrors(err) + : addOption(host) + ); + + } + + } + + // PAC MODS PANEL + const modPanel = document.getElementById('pac-mods'); const _firstChild = modPanel.firstChild; const keyToLi = {}; const customProxyStringKey = 'customProxyStringRaw'; const uiRaw = 'ui-proxy-string-raw'; - pacKitchen.getConfigs().forEach( (conf) => { + + for(const conf of pacKitchen.getOrderedConfigs()) { const key = conf.key; - const iddy = conf.key.replace(/([A-Z])/g, (_, p) => '-' + p.toLowerCase()); + const iddy = 'mods-' + conf.key.replace(/([A-Z])/g, (_, p) => '-' + p.toLowerCase()); const li = document.createElement('li'); li.className = 'info-row'; keyToLi[key] = li; @@ -283,7 +318,7 @@ HTTPS 11.22.33.44:8080;">${conf.value || localStorage.getItem(uiRaw) || ''} { const configs = Object.keys(keyToLi).reduce( (configs, key) => { @@ -298,7 +333,7 @@ HTTPS 11.22.33.44:8080;">${conf.value || localStorage.getItem(uiRaw) || ''}${conf.value || localStorage.getItem(uiRaw) || ''}