From 79f51186c7ab70e609bdb969a6194944f846b836 Mon Sep 17 00:00:00 2001 From: "Ilya Ig. Petrov" Date: Fri, 24 Feb 2017 11:04:15 +0000 Subject: [PATCH 1/2] Lint as airbnb, refactor chrome.storage for localStorage --- .../runet-censorship-bypass/.eslintrc.js | 17 +- .../runet-censorship-bypass/package.json | 7 +- .../runet-censorship-bypass/problems.txt | 18 + .../src/extension-common/00-init-apis.js | 63 ++-- .../extension-common/11-error-handlers-api.js | 101 +++--- .../src/extension-common/12-errors-lib.js | 7 +- .../src/extension-common/13-http-lib.js | 14 +- .../extension-common/35-pac-kitchen-api.js | 214 +++++------ ...7-sync-pac-script-with-pac-provider-api.js | 279 ++++++++------- .../src/extension-common/80-context-menus.js | 24 +- .../src/extension-full/20-ip-to-host-api.js | 334 +++++++++--------- .../src/extension-full/70-block-informer.js | 66 ++-- .../src/extension-mini/20-for-mini-only.js | 7 +- .../src/templates-data.js | 2 +- 14 files changed, 611 insertions(+), 542 deletions(-) create mode 100644 extensions/chromium/runet-censorship-bypass/problems.txt diff --git a/extensions/chromium/runet-censorship-bypass/.eslintrc.js b/extensions/chromium/runet-censorship-bypass/.eslintrc.js index 0c32908..72f3dfa 100644 --- a/extensions/chromium/runet-censorship-bypass/.eslintrc.js +++ b/extensions/chromium/runet-censorship-bypass/.eslintrc.js @@ -1,5 +1,5 @@ module.exports = { - extends: ['eslint:recommended', 'google'], + extends: ['eslint:recommended', 'airbnb'], env: { browser: true, webextensions: true, @@ -20,14 +20,23 @@ module.exports = { 'no-console': 'off', 'padded-blocks': 'off', 'require-jsdoc': 'off', - - // Taken from airbnb: + 'no-multi-assign': 'off', + 'arrow-parens': ['error', 'always'], + 'no-plusplus': 'off', + 'comma-dangle': ['error', { + arrays: 'always-multiline', + objects: 'always-multiline', + imports: 'always-multiline', + exports: 'always-multiline', + functions: 'ignore', + }], + /* Taken from airbnb: 'max-len': ['error', 100, 2, { ignoreUrls: true, ignoreComments: false, ignoreRegExpLiterals: true, ignoreStrings: true, ignoreTemplateLiterals: true, - }], + }],*/ }, }; diff --git a/extensions/chromium/runet-censorship-bypass/package.json b/extensions/chromium/runet-censorship-bypass/package.json index 7daf769..274cee3 100644 --- a/extensions/chromium/runet-censorship-bypass/package.json +++ b/extensions/chromium/runet-censorship-bypass/package.json @@ -8,8 +8,11 @@ "author": "Ilya Ig. Petrov", "license": "GPLv3", "devDependencies": { - "eslint": "^3.15.0", - "eslint-config-google": "^0.7.1" + "eslint": "^3.16.1", + "eslint-config-airbnb": "^14.1.0", + "eslint-plugin-import": "^2.2.0", + "eslint-plugin-jsx-a11y": "^4.0.0", + "eslint-plugin-react": "^6.10.0" }, "dependencies": { "del": "^2.2.2", diff --git a/extensions/chromium/runet-censorship-bypass/problems.txt b/extensions/chromium/runet-censorship-bypass/problems.txt new file mode 100644 index 0000000..c298699 --- /dev/null +++ b/extensions/chromium/runet-censorship-bypass/problems.txt @@ -0,0 +1,18 @@ + +/mnt/d/__Storage__/Workspace/repos/LATEST/extensions/chromium/runet-censorship-bypass/src/extension-full/20-ip-to-host-api.js + 19:9 error Unexpected dangling '_' in '_match' no-underscore-dangle + 23:35 error Expected property shorthand object-shorthand + 27:9 error Unexpected dangling '_' in '_test' no-underscore-dangle + 53:9 error Unexpected dangling '_' in '_state' no-underscore-dangle + 58:9 error Unexpected dangling '_' in '_createHostObj' no-underscore-dangle + 64:9 error Unexpected dangling '_' in '_getHostObj' no-underscore-dangle + 73:11 error Unexpected dangling '_' in '_antizapret' no-underscore-dangle + 174:9 error Unexpected dangling '_' in '_canonize' no-underscore-dangle + 232:11 error Unexpected dangling '_' in '_purgeOldIpsForSync' no-underscore-dangle + 252:24 error Unexpected dangling '_' in '_addAsync' no-underscore-dangle + 300:7 error Unexpected dangling '_' in '_updateAllAsync' no-underscore-dangle + 308:7 error Unexpected dangling '_' in '_updateAllAsync' no-underscore-dangle + 330:7 error Unexpected dangling '_' in '_replaceAllAsync' no-underscore-dangle + +✖ 13 problems (13 errors, 0 warnings) + diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/00-init-apis.js b/extensions/chromium/runet-censorship-bypass/src/extension-common/00-init-apis.js index 1cb6214..679957f 100644 --- a/extensions/chromium/runet-censorship-bypass/src/extension-common/00-init-apis.js +++ b/extensions/chromium/runet-censorship-bypass/src/extension-common/00-init-apis.js @@ -8,11 +8,11 @@ // I believe logging objects precludes them from being GCed. // I also don't remove logs for sake of client-side troubleshooting // (though no one sent me logs so far). - ['log', 'warn', 'error'].forEach( (meth) => { - const _meth = window.console[meth].bind(console); - window.console[meth] = function(...args) { + ['log', 'warn', 'error'].forEach((meth) => { + const originalMeth = window.console[meth].bind(console); + window.console[meth] = function wrappedForDebug(...args) { - _meth(...args.map((a) => '' + a)); + originalMeth(...args.map((a) => `${a}`/* toString, but safer */)); }; }); @@ -33,7 +33,7 @@ throwIfError(err) { - if(err) { + if (err) { throw err; } @@ -45,7 +45,7 @@ // method invokation. const err = chrome.runtime.lastError || chrome.extension.lastError; if (!err) { - return; + return null; } console.warn('API returned error:', err); return new Error(err.message); // Add stack. @@ -62,7 +62,7 @@ chromified(cb = self.mandatory()) { // Take error first callback and convert it to chrome API callback. - return function(...args) { + return function cbForChromeApi(...args) { const err = self.checkChromeError(); self.timeouted(cb)(err, ...args); @@ -71,35 +71,42 @@ }, - getProp(obj, path = self.mandatory()) { + getProp(targetObj, path = self.mandatory()) { const props = path.split('.'); if (!props.length) { throw new TypeError('Property must be supplied.'); } - const lastProp = props.pop(); - for( const prop of props ) { - if (!(prop in obj)) { - return undefined; + + const ifSupportsInOp = (obj) => + ['object', 'function'].includes(typeof obj); + + return props.reduce((currentObj, prop) => { + + if ( + ifSupportsInOp(currentObj) + && prop in currentObj + ) { + return currentObj[prop]; } - obj = obj[prop]; - } - return obj[lastProp]; + return undefined; + + }, targetObj); }, assert(value) { - if(!value) { + if (!value) { console.assert(value); - throw new Error('Assert failed for:' + value); + throw new Error(`Assert failed for:${value}`); } }, addRequestResponder(requestType, responder) { - if( privates.requestToResponder[requestType] ) { + if (privates.requestToResponder[requestType]) { throw new TypeError(`Request ${requestType} already has responder!`); } privates.requestToResponder[requestType] = responder; @@ -109,9 +116,9 @@ fireRequest(requestType, ...args) { const cb = args.slice(-1)[0]; - self.assert(typeof(cb) === 'function'); + self.assert(typeof cb === 'function'); const responder = privates.requestToResponder[requestType]; - if(responder) { + if (responder) { responder(...args); } else { cb(); @@ -123,18 +130,18 @@ return function state(key, value) { - key = prefix + key; + const prefixedKey = prefix + key; if (value === null) { - return localStorage.removeItem(key); + return localStorage.removeItem(prefixedKey); } if (value === undefined) { - const item = localStorage.getItem(key); + const item = localStorage.getItem(prefixedKey); return item && JSON.parse(item); } if (value instanceof Date) { throw new TypeError('Converting Date format to JSON is not supported.'); } - localStorage.setItem(key, JSON.stringify(value)); + return localStorage.setItem(prefixedKey, JSON.stringify(value)); }; @@ -168,15 +175,15 @@ searchSettingsForUrl(niddle) { - return 'chrome://settings/search#' + (chrome.i18n.getMessage(niddle) || niddle); + return `chrome://settings/search#${(chrome.i18n.getMessage(niddle) || niddle)}`; }, whichExtensionHtml() { - return chrome.i18n.getMessage('noControl') + - ` - ${ chrome.i18n.getMessage('which') } + return `${chrome.i18n.getMessage('noControl')} + + ${chrome.i18n.getMessage('which')} `; }, diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/11-error-handlers-api.js b/extensions/chromium/runet-censorship-bypass/src/extension-common/11-error-handlers-api.js index aaecb3b..a04cc3e 100644 --- a/extensions/chromium/runet-censorship-bypass/src/extension-common/11-error-handlers-api.js +++ b/extensions/chromium/runet-censorship-bypass/src/extension-common/11-error-handlers-api.js @@ -8,38 +8,36 @@ const errorJsonReplacer = function errorJsonReplacer(key, value) { // fooWindow.ErrorEvent !== barWindow.ErrorEvent - if (!( value && value.constructor + if (!(value && value.constructor && ['Error', 'Event'].some( - (suff) => value.constructor.name.endsWith(suff) - ) + (suff) => value.constructor.name.endsWith(suff)) )) { return value; } - const alt = {}; - Object.getOwnPropertyNames(value).forEach(function(key) { + const alt = Object.getOwnPropertyNames(value).reduce( + (acc, ownProp) => + Object.assign(acc, { [ownProp]: value[ownProp] }), + {} + ); - alt[key] = value[key]; - - }, value); - - for(const prop in value) { + for (const prop in value) { // eslint-disable-line no-restricted-syntax if (/^[A-Z]/.test(prop)) { // MOUSEMOVE, CLICK, KEYUP, NONE, etc. - continue; + continue; // eslint-disable-line no-continue } alt[prop] = value[prop]; } if (value.constructor.name === 'ErrorEvent') { - for(const circularProp of - [ // First line are circular props. - 'target', 'srcElement', 'path', 'currentTarget', - 'bubbles', 'cancelBubble', 'cancelable', 'composed', - 'defaultPrevented', 'eventPhase', 'isTrusted', 'returnValue', - 'timeStamp']) { + [ + 'target', 'srcElement', 'path', 'currentTarget', + 'bubbles', 'cancelBubble', 'cancelable', 'composed', + 'defaultPrevented', 'eventPhase', 'isTrusted', 'returnValue', + 'timeStamp', + ].forEach((circularProp) => { delete alt[circularProp]; - } + }); } if (value.name) { @@ -53,8 +51,8 @@ const openAndFocus = function openAndFocus(url) { chrome.tabs.create( - {url: url}, - (tab) => chrome.windows.update(tab.windowId, {focused: true}) + { url }, + (tab) => chrome.windows.update(tab.windowId, { focused: true }) ); }; @@ -69,13 +67,11 @@ viewError(type = window.utils.mandatory(), err) { - const errors = err ? {[type]: err} : this.idToError; + const errors = err ? { [type]: err } : this.idToError; const json = JSON.stringify(errors, errorJsonReplacer, 0); openAndFocus( - 'http://rebrand.ly/ac-error/?json=' + encodeURIComponent(json) + - (type ? '&type=' + encodeURIComponent(type) : '') + - '&version=' + chrome.runtime.getManifest().version + `http://rebrand.ly/ac-error/?json=${encodeURIComponent(json)}${type ? `&type=${encodeURIComponent(type)}` : ''}&version=${chrome.runtime.getManifest().version}` ); }, @@ -93,19 +89,18 @@ switch(onOffStr, eventName) { if (!['on', 'off'].includes(onOffStr)) { - throw new TypeError('First argument bust be "on" or "off".'); - } - for( - const name of (eventName ? [eventName] : this.getEventsMap().keys() ) - ) { - this.state( ifPrefix + name, onOffStr === 'on' ? 'on' : null ); + throw new TypeError('First argument must be "on" or "off".'); } + (eventName ? [eventName] : this.getEventsMap().keys()).forEach( + (name) => + this.state(ifPrefix + name, onOffStr === 'on' ? 'on' : null) + ); }, isOn(eventName) { - return this.state( ifPrefix + eventName ); + return this.state(ifPrefix + eventName); }, @@ -123,7 +118,7 @@ } if (this.ifControlled) { - chrome.browserAction.setIcon( {path: './icons/default-128.png'} ); + chrome.browserAction.setIcon({ path: './icons/default-128.png' }); } else { chrome.browserAction.setIcon({ path: './icons/default-grayscale-128.png', @@ -163,12 +158,12 @@ id, title, errOrMessage, { icon = 'default-128.png', - context = extName + ' ' + extVersion, + context = `${extName} ${extVersion}`, ifSticky = true, } = {} ) { - if ( !this.isOn(id) ) { + if (!this.isOn(id)) { return; } this.idToError[id] = errOrMessage; @@ -176,12 +171,12 @@ chrome.notifications.create( id, { - title: title, - message: message, + title, + message, contextMessage: context, requireInteraction: ifSticky, type: 'basic', - iconUrl: './icons/' + icon, + iconUrl: `./icons/${icon}`, appIconMaskUrl: './icons/default-mask-128.png', isClickable: true, } @@ -193,15 +188,16 @@ win.addEventListener('error', (errEvent) => { - console.warn(name + ':GLOBAL ERROR', errEvent); + console.warn(`${name}:GLOBAL ERROR`, errEvent); this.mayNotify('ext-error', 'Ошибка расширения', errEvent, - {icon: 'ext-error-128.png'}); + { icon: 'ext-error-128.png' } + ); }); win.addEventListener('unhandledrejection', (event) => { - console.warn(name + ': Unhandled rejection. Throwing error.'); + console.warn(`${name}: Unhandled rejection. Throwing error.`); event.preventDefault(); console.log('ev', event); throw event.reason; @@ -225,24 +221,23 @@ chrome.proxy.settings.get( {}, - timeouted( handlers.isControllable.bind(handlers) ) + timeouted(handlers.isControllable.bind(handlers)) ); - chrome.notifications.onClicked.addListener( timeouted( (notId) => { + chrome.notifications.onClicked.addListener(timeouted((notId) => { chrome.notifications.clear(notId); - if(notId === 'no-control') { + if (notId === 'no-control') { return openAndFocus( - window.utils.messages.searchSettingsForUrl('proxy') - ); + window.utils.messages.searchSettingsForUrl('proxy')); } - handlers.viewError(notId); + return handlers.viewError(notId); })); handlers.installListenersOn(window, 'BG'); - chrome.proxy.onProxyError.addListener( timeouted( (details) => { + chrome.proxy.onProxyError.addListener(timeouted((details) => { if (!handlers.ifControlled) { return; @@ -256,26 +251,26 @@ console.warn('PAC ERROR', details); // TOOD: add "view pac script at this line" button. handlers.mayNotify('pac-error', 'Ошибка PAC!', - details.error + '\n' + details.details, - {icon: 'pac-error-128.png'} + `${details.error}\n${details.details}`, + { icon: 'pac-error-128.png' } ); })); - chrome.proxy.settings.onChange.addListener( timeouted( (details) => { + chrome.proxy.settings.onChange.addListener(timeouted((details) => { console.log('Proxy settings changed.', details); const noCon = 'no-control'; const ifWasControllable = handlers.ifControllable; - if ( !handlers.isControllable(details) && ifWasControllable ) { + if (!handlers.isControllable(details) && ifWasControllable) { handlers.mayNotify( noCon, chrome.i18n.getMessage('noControl'), chrome.i18n.getMessage('which'), - {icon: 'no-control-128.png', ifSticky: false} + { icon: 'no-control-128.png', ifSticky: false } ); } else { - chrome.notifications.clear( noCon ); + chrome.notifications.clear(noCon); } })); diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/12-errors-lib.js b/extensions/chromium/runet-censorship-bypass/src/extension-common/12-errors-lib.js index 063cfbd..193cfa9 100644 --- a/extensions/chromium/runet-censorship-bypass/src/extension-common/12-errors-lib.js +++ b/extensions/chromium/runet-censorship-bypass/src/extension-common/12-errors-lib.js @@ -1,4 +1,5 @@ 'use strict'; + /* * Error Library * PURPOSE 1: @@ -32,7 +33,7 @@ }, - clarify: function(err, message = mandatory(), {data} = {}) { + clarify(err, message = mandatory(), { data } = {}) { if (!err) { return err; @@ -46,9 +47,9 @@ }, - clarifyThen: function(message, cb = mandatory()) { + clarifyThen(message, cb = mandatory()) { - return (err, ...args) => cb( self.clarify(err, message), ...args ); + return (err, ...args) => cb(self.clarify(err, message), ...args); }, diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/13-http-lib.js b/extensions/chromium/runet-censorship-bypass/src/extension-common/13-http-lib.js index 4fbe0ec..d9f2f18 100644 --- a/extensions/chromium/runet-censorship-bypass/src/extension-common/13-http-lib.js +++ b/extensions/chromium/runet-censorship-bypass/src/extension-common/13-http-lib.js @@ -39,35 +39,31 @@ get(url, cb = mandatory()) { const start = Date.now(); - fetch(url, {cache: 'no-store'}).then( + fetch(url, { cache: 'no-store' }).then( (res) => { const textCb = (err) => { - console.log('Reading response as text...'); res.text().then( - (text) => { - console.log('Calling CB...'); - cb(err, text); - }, + (text) => cb(err, text), cb ); }; const status = res.status; - if ( !( status >= 200 && status < 300 || status === 304 ) ) { + if (!((status >= 200 && status < 300) || status === 304)) { return textCb( errorsLib.clarify( res, - 'Получен ответ с неудачным HTTP-кодом ' + status + '.' + `Получен ответ с неудачным HTTP-кодом ${status}.` ) ); } console.log('GETed with success:', url, Date.now() - start); - textCb(); + return textCb(); }, errorsLib.clarifyThen(checkCon, cb) diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/35-pac-kitchen-api.js b/extensions/chromium/runet-censorship-bypass/src/extension-common/35-pac-kitchen-api.js index d3d726d..8af714c 100644 --- a/extensions/chromium/runet-censorship-bypass/src/extension-common/35-pac-kitchen-api.js +++ b/extensions/chromium/runet-censorship-bypass/src/extension-common/35-pac-kitchen-api.js @@ -65,36 +65,10 @@ const getDefaults = function getDefaults() { - return Object.keys(configs).reduce((acc, key) => { - - acc[key] = configs[key].dflt; - return acc; - - }, {}); - - }; - - const getCurrentConfigs = function getCurrentConfigs() { - - const mods = kitchenState(modsKey); - return new PacModifiers(mods || {}); - - }; - - const getOrderedConfigsForUser = function getOrderedConfigs() { - - const pacMods = getCurrentConfigs(); - return Object.keys(configs).reduce((arr, key) => { - - const conf = configs[key]; - if(typeof(conf.index) === 'number') { - arr[conf.index] = conf; - conf.value = pacMods[key]; - conf.key = key; - } - return arr; - - }, []); + return Object.keys(configs).reduce((acc, key) => + Object.assign(acc, { [key]: configs[key].dflt }), + {} + ); }; @@ -110,17 +84,17 @@ ); Object.assign(this, defaults, mods); - this.ifNoMods = ifAllDefaults ? true : false; + this.ifNoMods = ifAllDefaults; let customProxyArray = []; if (this.customProxyStringRaw) { customProxyArray = this.customProxyStringRaw .replace(/#.*$/mg, '') // Strip comments. - .split( /(?:[^\S\r\n]*(?:;|\r?\n)+[^\S\r\n]*)+/g ) - .map( (p) => p.trim() ) - .filter( (p) => p && /\s+/g.test(p) ); + .split(/(?:[^\S\r\n]*(?:;|\r?\n)+[^\S\r\n]*)+/g) + .map((p) => p.trim()) + .filter((p) => p && /\s+/g.test(p)); if (this.ifUseSecureProxiesOnly) { - customProxyArray = customProxyArray.filter( (p) => !p.startsWith('HTTP ') ); + customProxyArray = customProxyArray.filter((p) => !p.startsWith('HTTP ')); } } if (this.ifUseLocalTor) { @@ -142,13 +116,13 @@ if (this.ifMindExceptions && this.exceptions) { this.included = []; this.excluded = []; - for(const host of Object.keys(this.exceptions)) { + Object.keys(this.exceptions).forEach((host) => { if (this.exceptions[host]) { this.included.push(host); } else { this.excluded.push(host); } - } + }); if (this.included && !this.filteredCustomsString) { throw new TypeError( 'Проксировать свои сайты можно только через свои прокси. Нет ни одного своего прокси, удовлетворяющего вашим требованиям!' @@ -160,6 +134,73 @@ } + const getCurrentConfigs = function getCurrentConfigs() { + + const mods = kitchenState(modsKey); + return new PacModifiers(mods || {}); + + }; + + const getOrderedConfigsForUser = function getOrderedConfigs() { + + const pacMods = getCurrentConfigs(); + return Object.keys(configs).reduce((arr, key) => { + + const conf = configs[key]; + if (typeof conf.index === 'number') { + Object.assign(arr, { [conf.index]: conf }); + conf.value = pacMods[key]; + conf.key = key; + } + return arr; + + }, []); + + }; + + const privates = {}; + + privates.tryNowAsync = function tryNowAsync(maybeDetails, maybeCb = throwIfError) { + + let cb; + let detailsOrUndefined; + if (typeof maybeDetails === 'function') { + detailsOrUndefined = undefined; + cb = maybeDetails; + } else { + detailsOrUndefined = maybeDetails; + cb = maybeCb; + } + + new Promise((resolve) => ( + detailsOrUndefined + ? resolve(detailsOrUndefined) + : chrome.proxy.settings.get({}, timeouted(resolve)) + )).then((details) => { + + if ( + details.levelOfControl === 'controlled_by_this_extension' + ) { + const pac = window.utils.getProp(details, 'value.pacScript'); + if (pac && pac.data) { + // Delete old kitchen modifications. + pac.data = pac.data.replace( + new RegExp(`${kitchenStartsMark}[\\s\\S]*$`, 'g'), + '' + ); + return chrome.proxy.settings.set(details, chromified(cb)); + } + } + + kitchenState(ifIncontinence, true); + return cb(null, null, new TypeError( + 'Не найдено активного PAC-скрипта! Изменения будут применены при возвращении контроля настроек прокси или установке нового PAC-скрипта.' + )); + + }); + + }; + window.apis.pacKitchen = { getPacMods: getCurrentConfigs, @@ -167,13 +208,13 @@ cook(pacData, pacMods = mandatory()) { - return pacMods.ifNoMods ? pacData : pacData + `${ kitchenStartsMark } + return pacMods.ifNoMods ? pacData : `${pacData}${kitchenStartsMark} ;+function(global) { "use strict"; const originalFindProxyForURL = FindProxyForURL; global.FindProxyForURL = function(url, host) { - ${function() { + ${((function generateNewFindProxyForURL() { let res = pacMods.ifProhibitDns ? ` global.dnsResolve = function(host) { return null; }; @@ -203,42 +244,42 @@ `; } - if( + if ( !pacMods.ifUseSecureProxiesOnly && !pacMods.filteredCustomsString && pacMods.ifUsePacScriptProxies ) { - return res + ` + return `${res} return originalFindProxyForURL(url, host); `; } - return res + ` + return `${res} const originalProxyString = originalFindProxyForURL(url, host); let originalProxyArray = originalProxyString.split(/(?:\\s*;\\s*)+/g).filter( (p) => p ); if (originalProxyArray.every( (p) => /^DIRECT$/i.test(p) )) { // Directs only or null, no proxies. return originalProxyString; } - return ` + - function() { + return ${ + ((function getProxies() { if (!pacMods.ifUsePacScriptProxies) { - return '"' + pacMods.filteredCustomsString + '"'; + return `"${pacMods.filteredCustomsString}"`; } let filteredOriginalsExp = 'originalProxyString'; if (pacMods.ifUseSecureProxiesOnly) { filteredOriginalsExp = 'originalProxyArray.filter( (p) => !p.toUpperCase().startsWith("HTTP ") ).join("; ")'; } - if ( !pacMods.filteredCustomsString ) { + if (!pacMods.filteredCustomsString) { return filteredOriginalsExp; } - return '"' + pacMods.filteredCustomsString + '; " + ' + filteredOriginalsExp; + return `"${pacMods.filteredCustomsString}; " + ${filteredOriginalsExp}`; - }() + ' + "; DIRECT";'; // Without DIRECT you will get 'PROXY CONN FAILED' pac-error. + })())} + "; DIRECT";`; // Without DIRECT you will get 'PROXY CONN FAILED' pac-error. - }()} + })())} }; @@ -246,68 +287,33 @@ }, - _tryNowAsync(details, cb = throwIfError) { - - if (typeof(details) === 'function') { - cb = details; - details = undefined; - } - - new Promise((resolve) => - - details - ? resolve(details) - : chrome.proxy.settings.get({}, timeouted(resolve) ) - - ).then( (details) => { - - if ( - details.levelOfControl === 'controlled_by_this_extension' - ) { - const pac = window.utils.getProp(details, 'value.pacScript'); - if (pac && pac.data) { - // Delete old kitchen modifications. - pac.data = pac.data.replace( - new RegExp(kitchenStartsMark + '[\\s\\S]*$', 'g'), - '' - ); - return chrome.proxy.settings.set(details, chromified(cb)); - } - } - - kitchenState(ifIncontinence, true); - cb(null, null, new TypeError( - 'Не найдено активного PAC-скрипта! Изменения будут применены при возвращении контроля настроек прокси или установке нового PAC-скрипта.' - )); - - }); - - }, - checkIncontinence(details) { - if ( kitchenState(ifIncontinence) ) { - this._tryNowAsync(details, () => {/* Swallow. */}); + if (kitchenState(ifIncontinence)) { + privates.tryNowAsync(details, () => { /* Swallow. */ }); } }, - keepCookedNowAsync(pacMods = mandatory(), cb = throwIfError) { + keepCookedNowAsync(maybePacMods = mandatory(), maybeCb = throwIfError) { - if (typeof(pacMods) === 'function') { - cb = pacMods; + let pacMods; + let cb; + if (typeof maybePacMods === 'function') { + cb = maybePacMods; pacMods = getCurrentConfigs(); } else { try { - pacMods = new PacModifiers(pacMods); - } catch(e) { + pacMods = new PacModifiers(maybePacMods); + } catch (e) { return cb(e); } kitchenState(modsKey, pacMods); + cb = maybeCb; } console.log('Keep cooked now...', pacMods); - this._tryNowAsync( + return privates.tryNowAsync( (err, res, ...warns) => { console.log('Try now err:', err); @@ -320,8 +326,12 @@ return cb(null, res, ...warns); } - const hosts = par.map( (ps) => ps.split(/\s+/)[1] ); - window.utils.fireRequest('ip-to-host-replace-all', hosts, (err, res, ...moreWarns) => cb( err, res, ...warns.concat(moreWarns) )); + const hosts = par.map((ps) => ps.split(/\s+/)[1]); + return window.utils.fireRequest( + 'ip-to-host-replace-all', + hosts, + (ipErr, ipRes, ...ipWarns) => cb(ipErr, ipRes, ...warns.concat(ipWarns)) + ); } ); @@ -340,20 +350,20 @@ const pacKitchen = window.apis.pacKitchen; - const originalSet = chrome.proxy.settings.set.bind( chrome.proxy.settings ); + const originalSet = chrome.proxy.settings.set.bind(chrome.proxy.settings); - chrome.proxy.settings.set = function(details, cb) { + chrome.proxy.settings.set = function modifiedSet(details, cb = () => {}) { const pac = window.utils.getProp(details, 'value.pacScript'); if (!(pac && pac.data)) { return originalSet(details, cb); } const pacMods = getCurrentConfigs(); - pac.data = pacKitchen.cook( pac.data, pacMods ); - originalSet({value: details.value}, (/* No args. */) => { + pac.data = pacKitchen.cook(pac.data, pacMods); + return originalSet({ value: details.value }, (/* No args. */) => { kitchenState(ifIncontinence, null); - cb && cb(); + cb(); }); diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/37-sync-pac-script-with-pac-provider-api.js b/extensions/chromium/runet-censorship-bypass/src/extension-common/37-sync-pac-script-with-pac-provider-api.js index b635575..50fce63 100644 --- a/extensions/chromium/runet-censorship-bypass/src/extension-common/37-sync-pac-script-with-pac-provider-api.js +++ b/extensions/chromium/runet-censorship-bypass/src/extension-common/37-sync-pac-script-with-pac-provider-api.js @@ -35,11 +35,11 @@ const asyncLogGroup = function asyncLogGroup(...args) { const cb = args.pop(); - if(!(cb && typeof(cb) === 'function')) { - throw new TypeError('cb must be a function, but got: ' + cb); + if (!cb || typeof cb !== 'function') { + throw new TypeError(`cb must be a function, but got: ${cb}`); } console.group(...args); - return function(...cbArgs) { + return function finishLogGroup(...cbArgs) { console.groupEnd(); console.log('Group finished.'); @@ -61,23 +61,23 @@ }, }; console.log('Setting chrome proxy settings...'); - chrome.proxy.settings.set( {value: config}, chromified((err) => { + chrome.proxy.settings.set({ value: config }, chromified((err) => { if (err) { return cb(err); } - handlers.updateControlState( () => { + return handlers.updateControlState(() => { - if ( !handlers.ifControlled ) { + if (!handlers.ifControlled) { console.warn('Failed, other extension is in control.'); return cb( - new Error( window.utils.messages.whichExtensionHtml() ) + new Error(window.utils.messages.whichExtensionHtml()) ); } console.log('Successfuly set PAC in proxy settings..'); - cb(); + return cb(); }); @@ -86,25 +86,25 @@ }; const updatePacProxyIps = function updatePacProxyIps( - cb = throwIfError + originalCb = throwIfError ) { - cb = asyncLogGroup( + const cb = asyncLogGroup( 'Getting IPs for PAC hosts...', - cb + originalCb ); window.utils.fireRequest('ip-to-host-update-all', cb); }; const setPacScriptFromProviderAsync = function setPacScriptFromProviderAsync( - provider, lastModified = mandatory(), cb = throwIfError + provider, lastModified = mandatory(), originalCb = throwIfError ) { const pacUrl = provider.pacUrls[0]; - cb = asyncLogGroup( + const cb = asyncLogGroup( 'Getting PAC script from provider...', pacUrl, - cb + originalCb ); httpLib.ifModifiedSince(pacUrl, lastModified, (err, newLastModified) => { @@ -112,10 +112,9 @@ if (!newLastModified) { return cb( null, - {lastModified}, + { lastModified }, new Warning( - 'Ваш PAC-скрипт не нуждается в обновлении. Его дата: ' + - lastModified + `Ваш PAC-скрипт не нуждается в обновлении. Его дата: ${lastModified}.` ) ); } @@ -126,7 +125,7 @@ () => new Promise( (resolve, reject) => httpLib.get( url, - (newErr, pacData) => newErr ? reject(newErr) : resolve(pacData) + (newErr, pacData) => (newErr ? reject(newErr) : resolve(pacData)) ) ) ), @@ -139,29 +138,75 @@ setPacAsync( pacData, - (err, res) => cb( - err, - Object.assign(res || {}, {lastModified: newLastModified}) + (pacErr, pacRes) => cb( + pacErr, + Object.assign(pacRes || {}, { lastModified: newLastModified }) ) ); }, clarifyThen( - 'Не удалось скачать PAC-скрипт с адресов: [ ' - + provider.pacUrls.join(' , ') + ' ].', + `Не удалось скачать PAC-скрипт с адресов: [ ${provider.pacUrls.join(' , ')} ].`, cb ) ); + return undefined; }); }; - window.apis.antiCensorRu = { + const currentVersion = chrome.runtime.getManifest().version; - version: chrome.runtime.getManifest().version, + const privates = { + + pacUpdatePeriodInMinutes: 12 * 60, + periodicUpdateAlarmReason: 'Периодичное обновление PAC-скрипта', + state: window.utils.createStorage('anti-censor-ru-'), + + get version() { + return this.state('version'); + }, + set version(newValue) { + return this.state('version', newValue); + }, + + get ifFirstInstall() { + return this.version === null; + }, + set ifFirstInstall(newValue) { + if (newValue) { + throw new TypeError('ifFirstInstall can\'t be set to true!'); + } + this.version = currentVersion; + }, + + get currentPacProviderKey() { + return this.state('current-pac'); + }, + set currentPacProviderKey(newValue) { + return this.state('current-pac', newValue); + }, + + get lastPacUpdateStamp() { + return this.state('last-pac-update-stamp') || 0; + }, + set lastPacUpdateStamp(newValue) { + return this.state('last-pac-update-stamp', newValue); + }, + + get currentPacProviderLastModified() { + return this.state('current-pac-last-mod') || 0; + }, + set currentPacProviderLastModified(newValue) { + return this.state('current-pac-last-mod', newValue); + }, + + }; + + window.apis.antiCensorRu = { pacProviders: { Антизапрет: { @@ -199,20 +244,24 @@ }, }, - _currentPacProviderKey: 'Антизапрет', - /* Is it the first time extension installed? Do something, e.g. initiate PAC sync. */ - ifFirstInstall: false, - lastPacUpdateStamp: 0, + get ifFirstInstall() { - _currentPacProviderLastModified: 0, // Not initialized. + return privates.ifFirstInstall; + + }, + get lastPacUpdateStamp() { + + return privates.lastPacUpdateStamp; + + }, getLastModifiedForKey(key = mandatory()) { - if (this._currentPacProviderKey === key) { - return new Date(this._currentPacProviderLastModified).toUTCString(); + if (privates.currentPacProviderKey === key) { + return new Date(privates.currentPacProviderLastModified).toUTCString(); } return new Date(0).toUTCString(); @@ -220,21 +269,21 @@ setLastModified(newValue = mandatory()) { - this._currentPacProviderLastModified = newValue; + privates.currentPacProviderLastModified = newValue; }, mustBeKey(key = mandatory()) { - if ( !(key === null || this.pacProviders[key]) ) { - throw new TypeError('No provider for key:' + key); + if (key !== null && !this.pacProviders[key]) { + throw new TypeError(`No provider for key:${key}`); } }, getCurrentPacProviderKey() { - return this._currentPacProviderKey; + return privates.currentPacProviderKey; }, @@ -244,15 +293,17 @@ ) { this.mustBeKey(newKey); - this._currentPacProviderKey = newKey; - this._currentPacProviderLastModified = lastModified; + privates.currentPacProviderKey = newKey; + privates.currentPacProviderLastModified = lastModified; }, - getPacProvider(key) { + getPacProvider(maybeKey) { - if(key) { - this.mustBeKey(key); + let key; + if (maybeKey) { + this.mustBeKey(maybeKey); + key = maybeKey; } else { key = this.getCurrentPacProviderKey(); } @@ -260,40 +311,18 @@ }, - _periodicUpdateAlarmReason: 'Периодичное обновление PAC-скрипта', + syncWithPacProviderAsync(maybeKey = this.currentPacProvierKey, maybeCb = throwIfError) { - pushToStorageAsync(cb = throwIfError) { - - console.log('Pushing to storage...'); - - // Copy only settable properties (except functions). - const onlySettable = {}; - for(const key of Object.keys(this)) { - if ( - Object.getOwnPropertyDescriptor(this, key).writable - && typeof(this[key]) !== 'function' - ) { - onlySettable[key] = this[key]; - } - } - - chrome.storage.local.clear( - () => chrome.storage.local.set( - onlySettable, - chromified(cb) - ) - ); - - }, - - syncWithPacProviderAsync( - key = this.currentPacProvierKey, cb = throwIfError) { - - if( typeof(key) === 'function' ) { - cb = key; + let key; + let originalCb; + if (typeof maybeKey === 'function') { key = this.getCurrentPacProviderKey(); + originalCb = maybeKey; + } else { + key = maybeKey; + originalCb = maybeCb; } - cb = asyncLogGroup('Syncing with PAC provider ' + key + '...', cb); + const cb = asyncLogGroup(`Syncing with PAC provider ${key}...`, originalCb); if (key === null) { // No pac provider set. @@ -303,15 +332,15 @@ const pacProvider = this.getPacProvider(key); const pacSetPromise = new Promise( - (resolve, reject) => setPacScriptFromProviderAsync( + (resolve) => setPacScriptFromProviderAsync( pacProvider, this.getLastModifiedForKey(key), (err, res, ...warns) => { if (!err) { this.setCurrentPacProviderKey(key, res.lastModified); - this.lastPacUpdateStamp = Date.now(); - this.ifFirstInstall = false; + privates.lastPacUpdateStamp = Date.now(); + privates.ifFirstInstall = false; this.setAlarms(); } @@ -322,7 +351,7 @@ ); const ipsErrorPromise = new Promise( - (resolve, reject) => updatePacProxyIps( + (resolve) => updatePacProxyIps( resolve ) ); @@ -337,27 +366,25 @@ if (ipsErr) { warns.push(ipsErr); } - this.pushToStorageAsync( - (pushErr) => cb(pacErr || pushErr, null, ...warns) - ); + return cb(pacErr, null, ...warns); }, cb ); + return undefined; }, - _pacUpdatePeriodInMinutes: 12*60, get pacUpdatePeriodInMinutes() { - return this._pacUpdatePeriodInMinutes; + return privates.pacUpdatePeriodInMinutes; }, setAlarms() { let nextUpdateMoment = this.lastPacUpdateStamp - + this._pacUpdatePeriodInMinutes*60*1000; + + (privates.pacUpdatePeriodInMinutes * 60 * 1000); const now = Date.now(); if (nextUpdateMoment < now) { nextUpdateMoment = now; @@ -369,10 +396,10 @@ ); chrome.alarms.create( - this._periodicUpdateAlarmReason, + privates.periodicUpdateAlarmReason, { when: nextUpdateMoment, - periodInMinutes: this._pacUpdatePeriodInMinutes, + periodInMinutes: privates.pacUpdatePeriodInMinutes, } ); @@ -390,14 +417,14 @@ if (this.currentProviderKey !== key) { return this.syncWithPacProviderAsync(key, cb); } - console.log(key + ' already installed.'); - cb(); + console.log(`${key} already installed.`); + return cb(); }, - clearPacAsync(cb = throwIfError) { + clearPacAsync(originalCb = throwIfError) { - cb = asyncLogGroup('Cearing alarms and PAC...', cb); + const cb = asyncLogGroup('Cearing alarms and PAC...', originalCb); chrome.alarms.clearAll( () => chrome.proxy.settings.clear( {}, @@ -407,9 +434,7 @@ return cb(err); } this.setCurrentPacProviderKey(null); - this.pushToStorageAsync( - () => handlers.updateControlState(cb) - ); + return handlers.updateControlState(cb); }) ) @@ -420,12 +445,7 @@ }; // ON EACH LAUNCH, STARTUP, RELOAD, UPDATE, ENABLE - chrome.storage.local.get(null, chromified( (err, oldStorage) => { - - if (err) { - throw err; - } - + ((async function init() { /* Event handlers that ALWAYS work (even if installation is not done or failed). @@ -435,14 +455,14 @@ const antiCensorRu = window.apis.antiCensorRu; chrome.alarms.onAlarm.addListener( - timeouted( (alarm) => { + timeouted((alarm) => { - if (alarm.name === antiCensorRu._periodicUpdateAlarmReason) { + if (alarm.name === privates.periodicUpdateAlarmReason) { console.log( 'Periodic PAC update triggered:', new Date().toLocaleString('ru-RU') ); - antiCensorRu.syncWithPacProviderAsync(() => {/* swallow */}); + antiCensorRu.syncWithPacProviderAsync(() => { /* swallow */ }); } }) @@ -456,24 +476,14 @@ }); - console.log('Storage on init:', oldStorage); - antiCensorRu.ifFirstInstall = Object.keys(oldStorage).length === 0; - if (antiCensorRu.ifFirstInstall) { // INSTALL console.log('Installing...'); + privates.currentPacProviderKey = 'Антизапрет'; return chrome.runtime.openOptionsPage(); } // LAUNCH, RELOAD, UPDATE - // Use old or migrate to default. - antiCensorRu._currentPacProviderKey = - oldStorage._currentPacProviderKey || null; - antiCensorRu.lastPacUpdateStamp = - oldStorage.lastPacUpdateStamp || antiCensorRu.lastPacUpdateStamp; - antiCensorRu._currentPacProviderLastModified = - oldStorage._currentPacProviderLastModified - || antiCensorRu._currentPacProviderLastModified; console.log( 'Last PAC update was on', new Date(antiCensorRu.lastPacUpdateStamp).toLocaleString('ru-RU') @@ -487,44 +497,48 @@ 2. We have to check storage for migration before using it. Better on each launch then on each pull. */ - const ifUpdating = antiCensorRu.version !== oldStorage.version; + const ifUpdating = currentVersion !== privates.version; if (!ifUpdating) { // LAUNCH, RELOAD, ENABLE - antiCensorRu.pacProviders = oldStorage.pacProviders; console.log('Extension launched, reloaded or enabled.'); } else { // UPDATE & MIGRATION - const key = antiCensorRu._currentPacProviderKey; - if (key !== null) { - const ifVeryOld = !Object.keys(antiCensorRu.pacProviders).includes(key); - const ifWasForced = localStorage.getItem('provider-backup'); - if ( ifVeryOld || !ifWasForced ) { - if (!ifWasForced) { - localStorage.setItem('provider-backup', antiCensorRu._currentPacProviderKey); + // Use old or migrate to defaults. + const oldStorage = await new Promise((resolve) => + chrome.storage.local.get(null, resolve) + ); + if (Object.keys(oldStorage).length) { + // eslint-disable-next-line no-underscore-dangle + let oldKey = oldStorage._currentPacProviderKey; + if (oldKey) { + const ifVeryOld = !Object.keys(antiCensorRu.pacProviders).includes(oldKey); + const ifWasForced = localStorage.getItem('provider-backup'); + if (ifVeryOld || !ifWasForced) { + if (!ifWasForced) { + localStorage.setItem('provider-backup', oldKey); + } + oldKey = 'Антизапрет'; } - antiCensorRu._currentPacProviderKey = 'Антизапрет'; } + privates.currentPacProviderKey = oldKey || null; + // eslint-disable-next-line no-underscore-dangle + privates.currentPacProviderLastModified = oldStorage._currentPacProviderLastModified || 0; + privates.lastPacUpdateStamp = oldStorage.lastPacUpdateStamp || 0; + await new Promise((resolve) => chrome.storage.local.clear(resolve)); } + privates.version = currentVersion; console.log('Extension updated.'); } if (antiCensorRu.getPacProvider()) { - - const ifAlarmTriggered = antiCensorRu.setAlarms(); - - if (ifAlarmTriggered) { - return; // Already pushed. - } - - } - if( ifUpdating ) { - antiCensorRu.pushToStorageAsync(); + antiCensorRu.setAlarms(); } + return undefined; /* History of Changes to Storage (Migration Guide) @@ -540,7 +554,6 @@ * Change storage.ifNotInstalled to storage.ifFirstInstall. * Add storage.lastPacUpdateStamp. **/ - - })); + })()); } diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/80-context-menus.js b/extensions/chromium/runet-censorship-bypass/src/extension-common/80-context-menus.js index fba8207..d722697 100644 --- a/extensions/chromium/runet-censorship-bypass/src/extension-common/80-context-menus.js +++ b/extensions/chromium/runet-censorship-bypass/src/extension-common/80-context-menus.js @@ -12,13 +12,13 @@ chrome.runtime.onInstalled.addListener( () => chrome.contextMenus.create({ - id: id, - title: title, + id, + title, contexts: ['browser_action'], }, timeouted(() => { const err = chrome.runtime.lastError; - if(err) { + if (err) { console.warn('Context menu error:', err); throw err; } @@ -28,9 +28,9 @@ chrome.contextMenus.onClicked.addListener((info, tab) => { - if(info.menuItemId === id) { - Promise.resolve( tab2url( tab ) ) - .then( (url) => chrome.tabs.create({url: url}) ); + if (info.menuItemId === id) { + Promise.resolve(tab2url(tab)) + .then((url) => chrome.tabs.create({ url })); } }); @@ -45,32 +45,32 @@ - ` ); createMenuLinkEntry( 'Сайт в реестре блокировок?', - (tab) => 'https://antizapret.info/index.php?search=' + new URL(tab.url).hostname + (tab) => `https://antizapret.info/index.php?search=${new URL(tab.url).hostname}` ); createMenuLinkEntry( 'Из архива archive.org', - (tab) => 'https://web.archive.org/web/*/' + tab.url + (tab) => `https://web.archive.org/web/*/${tab.url}` ); createMenuLinkEntry( 'Через Google Translate', - (tab) => 'https://translate.google.com/translate?hl=&sl=en&tl=ru&anno=2&sandbox=1&u=' + tab.url + (tab) => `https://translate.google.com/translate?hl=&sl=en&tl=ru&anno=2&sandbox=1&u=${tab.url}` ); createMenuLinkEntry( 'Другие варианты разблокировки', - (tab) => 'https://rebrand.ly/ac-unblock#' + tab.url + (tab) => `https://rebrand.ly/ac-unblock#${tab.url}` ); createMenuLinkEntry( 'У меня проблемы с расширением!', - (tab) => 'https://rebrand.ly/ac-support' + () => 'https://rebrand.ly/ac-support' ); } diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-full/20-ip-to-host-api.js b/extensions/chromium/runet-censorship-bypass/src/extension-full/20-ip-to-host-api.js index d8a4e49..10d999d 100644 --- a/extensions/chromium/runet-censorship-bypass/src/extension-full/20-ip-to-host-api.js +++ b/extensions/chromium/runet-censorship-bypass/src/extension-full/20-ip-to-host-api.js @@ -9,100 +9,42 @@ // IP REGEX starts. const portOpt = '(:\\d+)?'; // The only capturing group, sic! - const ipv4portOpt = '(?:[0-9]{1,3}\\.){3}[0-9]{1,3}' + portOpt; + const ipv4portOpt = `(?:[0-9]{1,3}\\.){3}[0-9]{1,3}${portOpt}`; const ipv6nake = '(?:[0-9a-f]{0,4}:){2,7}[0-9a-f]{0,4}'; - const ipv6portOpt = '(?:' + ipv6nake + '|' + '\\[' + ipv6nake + '\\]' + portOpt + ')'; + const ipv6portOpt = `(?:${ipv6nake}|\\[${ipv6nake}\\]${portOpt})`; - const ipv4Re = new RegExp('^' + ipv4portOpt + '$'); - const ipv6Re = new RegExp('^' + ipv6portOpt + '$'); + const ipv4Re = new RegExp(`^${ipv4portOpt}$`); + const ipv6Re = new RegExp(`^${ipv6portOpt}$`); - const _match = function _match(ipRe, str) { + const reMatchIp = function reMatchIp(ipRe, str) { - const 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}; + return { ifMatched: m.length, port }; }; - const _test = { + const matchIpv4v6 = function matchIpv4v6(str) { - ipv4: _match.bind(null, ipv4Re), - ipv6: _match.bind(null, ipv6Re), - ipv4v6: function(str) { - - let mr = this.ipv4(str); - if (mr.ifMatched) { - mr.ifv4 = true; - mr.canonical = str.replace(mr.port, ''); - return mr; - } - mr = this.ipv6(str); - if (mr.ifMatched) { - mr.ifv6 = true; - mr.canonical = str.replace(mr.port, '').replace(/[\[\]]/g, ''); - return mr; - } + let mr = reMatchIp(ipv4Re, str); + if (mr.ifMatched) { + mr.ifv4 = true; + mr.canonical = str.replace(mr.port, ''); return mr; - - }, + } + mr = reMatchIp(ipv6Re, str); + if (mr.ifMatched) { + mr.ifv6 = true; + mr.canonical = str.replace(mr.port, '').replace(/[[\]]/g, ''); + return mr; + } + return mr; }; // IP REGEX ends. - const _state = window.utils.createStorage('ip-to-host'); - const ip2host = ''; - - const privates = {}; - - const _createHostObj = function _addHostObj(hostStr) { - - return (privates._strToHostObj[hostStr] = {host: hostStr}); - - }; - - const _getHostObj = function _getHostObj(hostStr) { - - return privates._strToHostObj[hostStr] || _createHostObj(hostStr); - - }; - - const reinit = function reinit() { - - // Defaults. - const _antizapret = { - /* Don't use directly, please. - Encoded to counter abuse. */ - host: '\x70\x72\x6f\x78\x79\x2e\x61\x6e\x74\x69\x7a\x61\x70\x72\x65\x74\x2e\x70\x72\x6f\x73\x74\x6f\x76\x70\x6e\x2e\x6f\x72\x67', - }; - privates._strToHostObj = { - [_antizapret.host]: _antizapret, - }; - - privates._ipToHostObj = {}; - for( const ip of [ - // IPs of Antizapret. - '195.123.209.38', - '137.74.171.91', - '51.15.39.201', - '2001:bc8:4700:2300::1:d07', - '2a02:27ac::10', - ] ) { - privates._ipToHostObj[ip] = _antizapret; - } - - // Persisted. - const ipToHost = _state(ip2host); - if (ipToHost) { - for( const ip of Object.keys(ipToHost) ) { - const host = ipToHost[ip]; - privates._ipToHostObj[ip] = _getHostObj(host); - } - } - - }; - - reinit(); + // GET IPS starts. const getIpsFor = function getIpsFor(host, cb = mandatory()) { @@ -113,29 +55,32 @@ const promises = types.map( (type) => new Promise((resolve) => httpLib.get( - 'https://dns.google.com/resolve?type=' + type + '&name=' + host, - (err, res) => { + `https://dns.google.com/resolve?type=${type}&name=${host}`, + (httpErr, httpRes) => { - if (res) { + let res = httpRes; + let err = httpErr; + if (httpRes) { + let jsonRes = {}; try { - res = JSON.parse(res); - console.log('JSON parsed.'); - if (err || res.Status) { + jsonRes = JSON.parse(httpRes); + res = jsonRes; + if (httpErr || jsonRes.Status) { const msg = ['Answer', 'Comment', 'Status'] - .filter( (prop) => res[prop] ) - .map( (prop) => prop + ': ' + JSON.stringify( res[prop] ) ) + .filter((prop) => jsonRes[prop]) + .map((prop) => `${prop}: ${JSON.stringify(jsonRes[prop])}`) .join(', \n'); - err = clarify(err || {}, 'Сервер (json): ' + msg, {data: res}); + err = clarify(httpErr || {}, `Сервер (json): ${msg}`, { data: jsonRes }); } else { - res = res.Answer || []; - res = res.filter( + res = (jsonRes.Answer || []).filter( (record) => types.includes(record.type) - ).map( (ans) => ans.data ); + ).map((ans) => ans.data); } - } catch(e) { + } catch (e) { err = clarify( e, - 'Сервер (текст): ' + res, err ? {data: err} : undefined + `Сервер (текст): ${res}`, + httpErr ? { data: httpErr } : undefined ); } } @@ -148,7 +93,7 @@ Promise.all(promises).then( ([[v4err, v4res], [v6err, v6res]]) => { - if(v4err) { + if (v4err) { return cb(v4err, v4res); } const ips = v4res; @@ -158,77 +103,101 @@ } else { warns = [v6err]; } - cb(null, ips, ...warns); + return cb(null, ips, ...warns); } ); + return undefined; }; - const _canonize = function canonize(addrArr) { + // GET IPS ends. - const ipSet = new Set(); - const hostSet = new Set(); + const ipToHostKey = ''; + const privates = { - for( const addr of addrArr ) { + state: window.utils.createStorage('ip-to-host'), - const ipm = _test.ipv4v6(addr); - if (ipm.ifMatched) { - ipSet.add( ipm.canonical ); - } else { - hostSet.add( addr.replace(/:\d+$/, '') ); - } + createHostObj(hostStr) { - } - - console.log('Canonized hosts/ips:', hostSet.size + '/' + ipSet.size); - return [ipSet, hostSet]; - - }; - - const self = window.apis.ipToHost = { - - persistData() { - - console.log('Persisting ipToHost...', privates); - const ipToHost = {}; - for( const ip of Object.keys(privates._ipToHostObj) ) { - ipToHost[ip] = privates._ipToHostObj[ip].host; - } - _state(ip2host, ipToHost); + return (this.strToHostObj[hostStr] = { host: hostStr }); }, + getHostObj(hostStr) { + + return this.strToHostObj[hostStr] || this.createHostObj(hostStr); + + }, + + reinit() { + + // Defaults. + const antizapret = { + /* Don't use directly, please. + Encoded to counter abuse. */ + host: '\x70\x72\x6f\x78\x79\x2e\x61\x6e\x74\x69\x7a\x61\x70\x72\x65\x74\x2e\x70\x72\x6f\x73\x74\x6f\x76\x70\x6e\x2e\x6f\x72\x67', + }; + this.strToHostObj = { + [antizapret.host]: antizapret, + }; + + this.ipToHostObj = {}; + [ // IPs of Antizapret. + '195.123.209.38', + '137.74.171.91', + '51.15.39.201', + '2001:bc8:4700:2300::1:d07', + '2a02:27ac::10', + ].forEach((ip) => { + this.ipToHostObj[ip] = antizapret; + }); + + // Persisted. + const ipToHost = this.state(ipToHostKey); + if (ipToHost) { + Object.keys(ipToHost).forEach((ip) => { + + const host = ipToHost[ip]; + this.ipToHostObj[ip] = this.getHostObj(host); + + }); + } + + }, + + // POST INIT + resetToDefaults() { - _state(ip2host, null); - reinit(); + this.state(ipToHostKey, null); + this.reinit(); }, - _purgeOldIpsForSync(hostStr) { + purgeOldIpsForSync(hostStr) { console.log('Purging old IPs for', hostStr); - for(const ip of Object.keys(privates._ipToHostObj)) { - if (hostStr === privates._ipToHostObj[ip].host) { - delete privates._ipToHostObj[ip]; + Object.keys(privates.ipToHostObj).forEach((ip) => { + if (hostStr === this.ipToHostObj[ip].host) { + delete this.ipToHostObj[ip]; } - } + }); }, - _addAsync(hostStr, cb = mandatory()) { + addAsync(hostStr, cb = mandatory()) { getIpsFor(hostStr, (err, ips, ...warns) => { console.log('Got IPs + err?:', ips, err); if (!err) { - this._purgeOldIpsForSync(hostStr); + this.purgeOldIpsForSync(hostStr); // Object may be shared, string can't. - const hostObj = _getHostObj(hostStr); - for(const ip of ips) { - privates._ipToHostObj[ip] = hostObj; - } + const hostObj = privates.getHostObj(hostStr); + ips.forEach((ip) => { + privates.ipToHostObj[ip] = hostObj; + }); } return cb(err, null, ...warns); @@ -236,22 +205,22 @@ }, - _updateAllAsync(cb = mandatory()) { + updateAllAsync(cb = mandatory()) { - const hostArr = Object.keys(privates._strToHostObj); + const hostArr = Object.keys(this.strToHostObj); console.log('Update all:', hostArr); const promises = hostArr.map( (hostStr) => new Promise( - (resolve) => this._addAsync( + (resolve) => this.addAsync( hostStr, (...args) => resolve(args) ) ) ); - Promise.all( promises ).then( (cbsRes) => { + Promise.all(promises).then((cbsRes) => { - const errors = cbsRes.map( ([err]) => err ).filter( (err) => err ); + const errors = cbsRes.map(([err]) => err).filter((err) => err); let newError; const ifAllErrors = cbsRes.length === errors.length; if (errors.length) { @@ -270,25 +239,71 @@ return cb(newError); } } - cb(null, null, newError); + return cb(null, null, newError); }); }, - _replaceAllAsync(hostArr = mandatory(), cb) { + replaceAllAsync(maybeHostArr = mandatory(), maybeCb) { - if (typeof(hostArr) === 'function') { - cb = hostArr; - hostArr = Object.keys(privates._strToHostObj); + let hostArr; + let cb; + if (typeof maybeHostArr === 'function') { + hostArr = Object.keys(this.strToHostObj); + cb = maybeHostArr; + } else { + hostArr = maybeHostArr; + cb = maybeCb; } this.resetToDefaults(); - for(const hostStr of hostArr) { - _createHostObj(hostStr); + hostArr.forEach((hostStr) => this.createHostObj(hostStr)); + + this.updateAllAsync(cb); + + }, + }; + + privates.reinit(); + + const canonize = function canonize(addrArr) { + + const ipSet = new Set(); + const hostSet = new Set(); + + addrArr.forEach((addr) => { + + const ipm = matchIpv4v6(addr); + if (ipm.ifMatched) { + ipSet.add(ipm.canonical); + } else { + hostSet.add(addr.replace(/:\d+$/, '')); } - this._updateAllAsync(cb); + }); + + console.log(`Canonized hosts/ips: ${hostSet.size}/${ipSet.size}`); + return [ipSet, hostSet]; + + }; + + const theApi = window.apis.ipToHost = { + + persistData() { + + console.log('Persisting ipToHost...', privates); + const ipToHost = {}; + Object.keys(privates.ipToHostObj).forEach((ip) => { + ipToHost[ip] = privates.ipToHostObj[ip].host; + }); + privates.state(ipToHostKey, ipToHost); + + }, + + resetToDefaults() { + + privates.resetToDefaults(); }, @@ -296,7 +311,7 @@ updateAllAsync(cb = mandatory()) { - this._updateAllAsync((err, ...args) => { + privates.updateAllAsync((err, ...args) => { if (!err) { this.persistData(); @@ -310,14 +325,15 @@ replaceAllAsync(addrArr, cb = mandatory()) { console.log('Replacing...'); - const [ipSet, hostSet] = _canonize(addrArr); - for( const ip of ipSet ) { - const host = _getHostObj(ip); - privates._ipToHostObj[ip] = host; - } + const [ipSet, hostSet] = canonize(addrArr); + ipSet.forEach((ip) => { + + privates.ipToHostObj[ip] = privates.getHostObj(ip); + + }); const hostArr = Array.from(hostSet); - this._replaceAllAsync(hostArr, (allErr, ...args) => { + privates.replaceAllAsync(hostArr, (allErr, ...args) => { if (!allErr) { this.persistData(); @@ -330,7 +346,7 @@ get(ip) { - const tmp = privates._ipToHostObj[ip]; + const tmp = privates.ipToHostObj[ip]; return tmp && tmp.host; }, @@ -338,14 +354,14 @@ }; window.utils.addRequestResponder( - 'ip-to-host-update-all', (...args) => self.updateAllAsync(...args) + 'ip-to-host-update-all', (...args) => theApi.updateAllAsync(...args) ); window.utils.addRequestResponder( - 'ip-to-host-replace-all', (...args) => self.replaceAllAsync(...args) + 'ip-to-host-replace-all', (...args) => theApi.replaceAllAsync(...args) ); window.utils.addRequestResponder( 'ip-to-host-reset-to-defaults', (cb) => { - self.resetToDefaults(); + theApi.resetToDefaults(); cb(); } ); diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-full/70-block-informer.js b/extensions/chromium/runet-censorship-bypass/src/extension-full/70-block-informer.js index 2ab92f1..af83a2c 100644 --- a/extensions/chromium/runet-censorship-bypass/src/extension-full/70-block-informer.js +++ b/extensions/chromium/runet-censorship-bypass/src/extension-full/70-block-informer.js @@ -20,47 +20,52 @@ color: '#db4b2f', }); - const _tabCallbacks = {}; + const privates = {}; + + privates.tabCallbacks = {}; const afterTabUpdated = function afterTabUpdated(tabId, cb) { - if (_tabCallbacks[tabId]) { - _tabCallbacks[tabId].push(cb); + if (privates.tabCallbacks[tabId]) { + privates.tabCallbacks[tabId].push(cb); } else { - _tabCallbacks[tabId] = [cb]; + privates.tabCallbacks[tabId] = [cb]; } }; const onTabUpdate = function onTabUpdate(tabId) { - if (_tabCallbacks[tabId]) { - _tabCallbacks[tabId].map( (f) => f() ); - delete _tabCallbacks[tabId]; + if (privates.tabCallbacks[tabId]) { + privates.tabCallbacks[tabId].map((f) => f()); + delete privates.tabCallbacks[tabId]; } }; - chrome.tabs.onUpdated.addListener( onTabUpdate ); + chrome.tabs.onUpdated.addListener(onTabUpdate); const updateTitle = function updateTitle(requestDetails, proxyHost, cb) { chrome.browserAction.getTitle( - {tabId: requestDetails.tabId}, + { tabId: requestDetails.tabId }, (title) => { const ifTitleSetAlready = /\n/.test(title); - const hostname = new URL( requestDetails.url ).hostname; + const hostname = new URL(requestDetails.url).hostname; let ifShouldUpdateTitle = false; const indent = ' '; const proxyTitle = 'Прокси:'; + let theLatestCb = cb; + let newTitle = title; + if (!ifTitleSetAlready) { - title = 'Разблокированы:\n' + indent + hostname + '\n' - + proxyTitle + '\n' + indent + proxyHost; + newTitle = `Разблокированы:\n${indent}${hostname}\n${proxyTitle}\n` + + `${indent}${proxyHost}`; ifShouldUpdateTitle = true; chrome.browserAction.setBadgeText({ @@ -70,37 +75,36 @@ } else { - const hostsProxiesPair = title.split(proxyTitle); + const hostsProxiesPair = newTitle.split(proxyTitle); if (hostsProxiesPair[1].indexOf(proxyHost) === -1) { - title = title.replace( + newTitle = newTitle.replace( hostsProxiesPair[1], - hostsProxiesPair[1] + '\n' + indent + proxyHost + `${hostsProxiesPair[1]}\n${indent}${proxyHost}` ); ifShouldUpdateTitle = true; } if (hostsProxiesPair[0].indexOf(hostname) === -1) { - title = title.replace( + newTitle = newTitle.replace( proxyTitle, - indent + hostname + '\n' + proxyTitle + `${indent}${hostname}\n${proxyTitle}` ); ifShouldUpdateTitle = true; - const _cb = cb; - cb = () => chrome.browserAction.getBadgeText( - {tabId: requestDetails.tabId}, + theLatestCb = () => chrome.browserAction.getBadgeText( + { tabId: requestDetails.tabId }, (result) => { + const charPrefix = isNaN(result.charAt(0)) ? result.charAt(0) : ''; chrome.browserAction.setBadgeText( { tabId: requestDetails.tabId, - text: (isNaN( result.charAt(0)) && result.charAt(0) || '') - + (hostsProxiesPair[0].split('\n').length - 1), + text: charPrefix + (hostsProxiesPair[0].split('\n').length - 1), } ); - return _cb(); + return cb(); } ); @@ -111,12 +115,12 @@ if (ifShouldUpdateTitle) { chrome.browserAction.setTitle({ - title: title, + title: newTitle, tabId: requestDetails.tabId, }); } - return cb(); + return theLatestCb(); } ); @@ -127,7 +131,7 @@ const tryProxyAndInform = function tryProxyAndInform(requestDetails) { - const host = window.apis.ipToHost.get( requestDetails.ip ); + const host = window.apis.ipToHost.get(requestDetails.ip); if (!host) { return; } @@ -137,7 +141,7 @@ previousUpdateTitleFinished = previousUpdateTitleFinished.then( () => new Promise( (resolve) => { - const cb = () => updateTitle( requestDetails, host, resolve ); + const cb = () => updateTitle(requestDetails, host, resolve); return ifMainFrame ? afterTabUpdated(requestDetails.tabId, cb) : cb(); } @@ -155,11 +159,11 @@ }; - for(const eventName of ['onResponseStarted', 'onErrorOccurred']) { + ['onResponseStarted', 'onErrorOccurred'].forEach((eventName) => chrome.webRequest[eventName].addListener( onRequest, - {urls: ['']} - ); - } + { urls: [''] } + ) + ); } diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-mini/20-for-mini-only.js b/extensions/chromium/runet-censorship-bypass/src/extension-mini/20-for-mini-only.js index cb82cd7..fd8f28e 100644 --- a/extensions/chromium/runet-censorship-bypass/src/extension-mini/20-for-mini-only.js +++ b/extensions/chromium/runet-censorship-bypass/src/extension-mini/20-for-mini-only.js @@ -1,8 +1,5 @@ 'use strict'; -{ +window.apis.version.ifMini = true; +chrome.browserAction.setBadgeText({ text: 'M' }); - window.apis.version.ifMini = true; - chrome.browserAction.setBadgeText({text: 'M'}); - -} diff --git a/extensions/chromium/runet-censorship-bypass/src/templates-data.js b/extensions/chromium/runet-censorship-bypass/src/templates-data.js index 58f3d75..e03d159 100644 --- a/extensions/chromium/runet-censorship-bypass/src/templates-data.js +++ b/extensions/chromium/runet-censorship-bypass/src/templates-data.js @@ -1,7 +1,7 @@ 'use strict'; const commonContext = { - version: '0.21', + version: '0.22', }; exports.contexts = {}; From 1bcb0ca2f360dd2b96a10566e0e9725ed2c943b7 Mon Sep 17 00:00:00 2001 From: "Ilya Ig. Petrov" Date: Sun, 26 Feb 2017 11:20:57 +0000 Subject: [PATCH 2/2] Add version to ext name for debug --- .../src/extension-common/manifest.tmpl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/manifest.tmpl.json b/extensions/chromium/runet-censorship-bypass/src/extension-common/manifest.tmpl.json index 9a515c8..0d5d5e5 100644 --- a/extensions/chromium/runet-censorship-bypass/src/extension-common/manifest.tmpl.json +++ b/extensions/chromium/runet-censorship-bypass/src/extension-common/manifest.tmpl.json @@ -1,7 +1,7 @@ { "manifest_version": 2, - "name": "__MSG_extName__", + "name": "__MSG_extName__ ${version}", "default_locale": "ru", "description": "__MSG_extDesc__", "version": "0.0.${version}",