diff --git a/extensions/chromium/runet-censorship-bypass/extension/00-init-apis.js b/extensions/chromium/runet-censorship-bypass/extension/00-init-apis.js
index 445fd3d..6e55fee 100644
--- a/extensions/chromium/runet-censorship-bypass/extension/00-init-apis.js
+++ b/extensions/chromium/runet-censorship-bypass/extension/00-init-apis.js
@@ -1,74 +1,139 @@
'use strict';
-const IF_DEBUG = false;
+{
-if (!IF_DEBUG) {
- // 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) {
+ const IF_DEBUG = false;
- _meth(...args.map((a) => '' + a));
+ if (!IF_DEBUG) {
+ // 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) {
- };
- });
-}
+ _meth(...args.map((a) => '' + a));
+ };
+ });
+ }
-window.utils = {
+ const self = window.utils = {
- mandatory() {
+ mandatory() {
- throw new TypeError('Missing required argument. ' +
- 'Be explicit if you swallow errors.');
+ throw new TypeError('Missing required argument. ' +
+ 'Be explicit if you swallow errors.');
- },
+ },
- getProp(obj, path = this.mandatory()) {
+ throwIfError(err) {
- 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;
+ if(err) {
+ throw err;
}
- obj = obj[prop];
- }
- return obj[lastProp];
-
- },
-
- areSettingsNotControlledFor(details) {
-
- return ['controlled_by_other', 'not_controllable']
- .some( (prefix) => details.levelOfControl.startsWith(prefix) );
-
- },
-
- messages: {
-
- searchSettingsForUrl(niddle) {
-
- return 'chrome://settings/search#' + (chrome.i18n.getMessage(niddle) || niddle);
},
- whichExtensionHtml() {
+ checkChromeError(betterStack) {
- return chrome.i18n.getMessage('noControl') +
- `
- ${ chrome.i18n.getMessage('which') }
- `;
+ // Chrome API calls your cb in a context different from the point of API
+ // method invokation.
+ const err = chrome.runtime.lastError || chrome.extension.lastError;
+ if (err) {
+ const args = ['API returned error:', err];
+ if (betterStack) {
+ args.push('\n' + betterStack);
+ }
+ console.warn(...args);
+ }
+ return err;
},
- },
+ chromified(cb = self.mandatory(), ...replaceArgs) {
-};
+ const stack = (new Error()).stack;
+ // Take error first callback and convert it to chrome api callback.
+ return function(...args) {
-window.apis = {};
+ if (replaceArgs.length) {
+ args = replaceArgs;
+ }
+ const err = self.checkChromeError(stack);
+ // setTimeout fixes error context.
+ setTimeout( cb.bind(null, err, ...args), 0 );
+
+ };
+
+ },
+
+ getProp(obj, 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;
+ }
+ obj = obj[prop];
+ }
+ return obj[lastProp];
+
+ },
+
+ createStorage(prefix) {
+
+ return function state(key, value) {
+
+ key = prefix + key;
+ if (value === null) {
+ return localStorage.removeItem(key);
+ }
+ if (value === undefined) {
+ const item = localStorage.getItem(key);
+ 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));
+
+ }
+
+ },
+
+ areSettingsNotControlledFor(details) {
+
+ return ['controlled_by_other', 'not_controllable']
+ .some( (prefix) => details.levelOfControl.startsWith(prefix) );
+
+ },
+
+ messages: {
+
+ searchSettingsForUrl(niddle) {
+
+ return 'chrome://settings/search#' + (chrome.i18n.getMessage(niddle) || niddle);
+
+ },
+
+ whichExtensionHtml() {
+
+ return chrome.i18n.getMessage('noControl') +
+ `
+ ${ chrome.i18n.getMessage('which') }
+ `;
+
+ },
+
+ },
+
+ };
+
+ window.apis = {};
+
+}
diff --git a/extensions/chromium/runet-censorship-bypass/extension/11-api-error-handlers.js b/extensions/chromium/runet-censorship-bypass/extension/11-api-error-handlers.js
index 42c0c4c..ab42735 100644
--- a/extensions/chromium/runet-censorship-bypass/extension/11-api-error-handlers.js
+++ b/extensions/chromium/runet-censorship-bypass/extension/11-api-error-handlers.js
@@ -47,23 +47,6 @@
}
- const handlersState = function(key, value) {
-
- key = 'handlers-' + key;
- if (value === null) {
- return localStorage.removeItem(key);
- }
- if (value === undefined) {
- const item = localStorage.getItem(key);
- 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));
-
- };
-
const openAndFocus = (url) => {
chrome.tabs.create(
@@ -78,6 +61,8 @@
window.apis.errorHandlers = {
+ state: window.utils.createStorage('handlers-'),
+
viewErrorVoid(type = window.utils.mandatory(), err) {
let errors = {};
@@ -113,14 +98,14 @@
for(
const name of (eventName ? [eventName] : this.getEventsMap().keys() )
) {
- handlersState( ifPrefix + name, onOffStr === 'on' ? 'on' : null );
+ this.state( ifPrefix + name, onOffStr === 'on' ? 'on' : null );
}
},
isOn(eventName) {
- return handlersState( ifPrefix + eventName);
+ return this.state( ifPrefix + eventName );
},
diff --git a/extensions/chromium/runet-censorship-bypass/extension/13-pac-kitchen.js b/extensions/chromium/runet-censorship-bypass/extension/13-pac-kitchen.js
index bfa2f49..65415a3 100644
--- a/extensions/chromium/runet-censorship-bypass/extension/13-pac-kitchen.js
+++ b/extensions/chromium/runet-censorship-bypass/extension/13-pac-kitchen.js
@@ -2,21 +2,26 @@
{ // Private namespace starts.
- const kitchenStorageKey = 'pac-kitchen-kept-mods';
+ const mandatory = window.utils.mandatory;
+ const throwIfError = window.utils.throwIfError;
+ const chromified = window.utils.chromified;
+
const kitchenStartsMark = '\n\n//%#@@@@@@ PAC_KITCHEN_STARTS @@@@@@#%';
+ const kitchenState = window.utils.createStorage('pac-kitchen-');
+ const ifIncontinence = 'if-incontinence';
const configs = {
ifProxyHttpsUrlsOnly: {
dflt: false,
label: 'проксировать только HTTPS-сайты',
- desc: 'Проксировать только сайты, доступные по шифрованному протоколу HTTPS. Прокси и провайдер смогут видеть только адреса посещаемых вами ресурсов, но не их содержимое.',
+ desc: 'Проксировать только сайты, доступные по шифрованному протоколу HTTPS. Прокси и провайдер смогут видеть только адреса проксируемых ресурсов, но не их содержимое.',
index: 0,
},
ifUseSecureProxiesOnly: {
dflt: false,
label: 'только шифрованная связь с прокси',
- desc: 'Шифровать соединение до прокси от провайдера. Провайдер всё же сможет видеть адреса (но не содержимое) посещаемых вами ресурсов из протокола DNS.',
+ desc: 'Шифровать соединение до прокси от провайдера. Провайдер всё же сможет видеть адреса (но не содержимое) проксируемых ресурсов из протокола DNS.',
index: 1,
},
ifUsePacScriptProxies: {
@@ -53,11 +58,11 @@
const getCurrentConfigs = function getCurrentConfigs() {
- const json = localStorage.getItem(kitchenStorageKey);
- if (!json) {
+ const mods = kitchenState('mods');
+ if (!mods) {
return null;
}
- return new PacModifiers(JSON.parse(json));
+ return new PacModifiers(mods);
};
@@ -122,7 +127,7 @@
getConfigs: getOrderedConfigsForUser,
- cook(pacData, pacMods = window.utils.mandatory()) {
+ cook(pacData, pacMods = mandatory()) {
return pacMods.ifNoMods ? pacData : pacData + `${ kitchenStartsMark }
;+function(global) {
@@ -183,23 +188,20 @@
},
- keepCookedNow(pacMods = window.utils.mandatory(), cb) {
+ _tryNowAsync(details, cb = throwIfError) {
- if (typeof(pacMods) === 'function') {
- cb = pacMods;
- const pacMods = getCurrentConfigs();
- if (!pacMods) {
- return cb(TypeError('PAC mods were never initialized.'));
- }
- } else {
- try {
- pacMods = new PacModifiers(pacMods);
- } catch(e) {
- return cb(e);
- }
- localStorage.setItem(kitchenStorageKey, JSON.stringify(pacMods));
+ if (typeof(details) === 'function') {
+ cb = details;
+ details = undefined;
}
- chrome.proxy.settings.get({}, (details) => {
+
+ new Promise((resolve) =>
+
+ details
+ ? resolve(details)
+ : chrome.proxy.settings.get({}, resolve)
+
+ ).then( (details) => {
if (
details.levelOfControl === 'controlled_by_this_extension'
@@ -211,28 +213,60 @@
new RegExp(kitchenStartsMark + '[\\s\\S]*$', 'g'),
''
);
- return chrome.proxy.settings.set(details, cb);
+ return chrome.proxy.settings.set(details, chromified(cb));
}
}
- return cb(
- null,
- null,
- [new TypeError('PAC-скрипт не обнаружен, но настройки будут активированы при установке PAC-скрипта.')]
- );
+
+ kitchenState(ifIncontinence, true);
+ cb(new TypeError(
+ 'Не найдено активного PAC-скрипта! Изменения будут применены при возвращении контроля настроек прокси или установке нового PAC-скрипта.'
+ ));
});
},
+ checkIncontinence(details) {
+
+ if ( kitchenState(ifIncontinence) ) {
+ this._tryNowAsync(details, () => {/* Swallow. */});
+ }
+
+ },
+
+
+ keepCookedNowAsync(pacMods = mandatory(), cb = throwIfError) {
+
+ if (typeof(pacMods) === 'function') {
+ cb = pacMods;
+ const pacMods = getCurrentConfigs();
+ if (!pacMods) {
+ return cb(TypeError('PAC mods were never initialized and you haven\'t supplied any.'));
+ }
+ } else {
+ try {
+ pacMods = new PacModifiers(pacMods);
+ } catch(e) {
+ return cb(e);
+ }
+ kitchenState('mods', pacMods);
+ }
+ this._tryNowAsync( (err) => cb(null, null, err && [err]) );
+
+ },
+
resetToDefaultsVoid() {
- delete localStorage[kitchenStorageKey];
- this.keepCookedNow({});
+ kitchenState('mods', null);
+ kitchenState(ifIncontinence, null);
+ this.keepCookedNowAsync({});
},
};
+ const pacKitchen = window.apis.pacKitchen;
+
const originalSet = chrome.proxy.settings.set.bind( chrome.proxy.settings );
chrome.proxy.settings.set = function(details, cb) {
@@ -243,10 +277,18 @@
}
const pacMods = getCurrentConfigs();
if (pacMods) {
- pac.data = window.apis.pacKitchen.cook( pac.data, pacMods );
+ pac.data = pacKitchen.cook( pac.data, pacMods );
}
- originalSet({ value: details.value }, cb);
+ originalSet({ value: details.value }, (/* No args. */) => {
+
+ kitchenState(ifIncontinence, null);
+ cb && cb();
+
+ });
};
+ pacKitchen.checkIncontinence();
+ chrome.proxy.settings.onChange.addListener( pacKitchen.checkIncontinence.bind(pacKitchen) );
+
} // Private namespace ends.
diff --git a/extensions/chromium/runet-censorship-bypass/extension/12-api-sync-pac-script-with-pac-provider.js b/extensions/chromium/runet-censorship-bypass/extension/15-api-sync-pac-script-with-pac-provider.js
similarity index 95%
rename from extensions/chromium/runet-censorship-bypass/extension/12-api-sync-pac-script-with-pac-provider.js
rename to extensions/chromium/runet-censorship-bypass/extension/15-api-sync-pac-script-with-pac-provider.js
index fefc98a..a1beec4 100644
--- a/extensions/chromium/runet-censorship-bypass/extension/12-api-sync-pac-script-with-pac-provider.js
+++ b/extensions/chromium/runet-censorship-bypass/extension/15-api-sync-pac-script-with-pac-provider.js
@@ -22,14 +22,9 @@
{ // Private namespace starts.
const mandatory = window.utils.mandatory;
-
- const throwIfError = function throwIfError(err) {
-
- if(err) {
- throw err;
- }
-
- };
+ const throwIfError = window.utils.throwIfError;
+ const chromified = window.utils.chromified;
+ const checkChromeError = window.utils.checkChromeError;
const asyncLogGroup = function asyncLogGroup(...args) {
@@ -48,39 +43,6 @@
};
- const checkChromeError = function checkChromeError(betterStack) {
-
- // Chrome API calls your cb in a context different from the point of API
- // method invokation.
- const err = chrome.runtime.lastError || chrome.extension.lastError;
- if (err) {
- const args = ['API returned error:', err];
- if (betterStack) {
- args.push('\n' + betterStack);
- }
- console.warn(...args);
- }
- return err;
-
- };
-
- const chromified = function chromified(cb = mandatory(), ...replaceArgs) {
-
- const stack = (new Error()).stack;
- // Take error first callback and convert it to chrome api callback.
- return function(...args) {
-
- if (replaceArgs.length) {
- args = replaceArgs;
- }
- const err = checkChromeError(stack);
- // setTimeout fixes error context.
- setTimeout( cb.bind(null, err, ...args), 0 );
-
- };
-
- };
-
class Clarification {
constructor(message = mandatory(), prevClarification) {
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 9369518..3f185e4 100644
--- a/extensions/chromium/runet-censorship-bypass/extension/30-block-informer.js
+++ b/extensions/chromium/runet-censorship-bypass/extension/30-block-informer.js
@@ -14,50 +14,38 @@
Crazy parallel Chrome.
**/
-const antiCensorRu = window.apis.antiCensorRu;
-
-window.chrome.browserAction.setBadgeBackgroundColor({
- color: '#db4b2f',
-});
-
-window.tabWithError2ip = {}; // For errors only: Error? -> Check this IP!
-
{
+ window.chrome.browserAction.setBadgeBackgroundColor({
+ color: '#db4b2f',
+ });
+
const _tabCallbacks = {};
- function afterTabUpdated(tabId, cb) {
- if (_tabCallbacks[tabId])
- _tabCallbacks[tabId].push(cb);
- else _tabCallbacks[tabId] = [cb];
- }
+ const afterTabUpdated = function afterTabUpdated(tabId, cb) {
+
+ if (_tabCallbacks[tabId]) {
+ _tabCallbacks[tabId].push(cb);
+ } else {
+ _tabCallbacks[tabId] = [cb];
+ }
+
+ };
+
+ const onTabUpdate = function onTabUpdate(tabId) {
- function onTabUpdate(tabId) {
if (_tabCallbacks[tabId]) {
_tabCallbacks[tabId].map( (f) => f() );
delete _tabCallbacks[tabId];
}
- }
+
+ };
chrome.tabs.onUpdated.addListener( onTabUpdate );
- function isInsideTabWithIp(requestDetails) {
- return requestDetails.tabId !== -1 && requestDetails.ip;
- }
+ const antiCensorRu = window.apis.antiCensorRu;
- chrome.webRequest.onErrorOccurred.addListener(
- (requestDetails) =>
- isInsideTabWithIp(requestDetails)
- && isProxiedAndInformed(requestDetails),
- {urls: ['']}
- );
-
- chrome.tabs.onRemoved.addListener( (tabId) => {
- onTabUpdate(tabId);
- delete window.tabWithError2ip[tabId];
- });
-
- function updateTitle(requestDetails, cb) {
+ const updateTitle = function updateTitle(requestDetails, cb) {
chrome.browserAction.getTitle(
{tabId: requestDetails.tabId},
@@ -74,6 +62,7 @@ window.tabWithError2ip = {}; // For errors only: Error? -> Check this IP!
const proxyTitle = 'Прокси:';
if (!ifTitleSetAlready) {
+
title = 'Разблокированы:\n' + indent + hostname + '\n'
+ proxyTitle + '\n' + indent + proxyHost;
ifShouldUpdateTitle = true;
@@ -84,6 +73,7 @@ window.tabWithError2ip = {}; // For errors only: Error? -> Check this IP!
});
} else {
+
const hostsProxiesPair = title.split(proxyTitle);
if (hostsProxiesPair[1].indexOf(proxyHost) === -1) {
@@ -95,6 +85,7 @@ window.tabWithError2ip = {}; // For errors only: Error? -> Check this IP!
}
if (hostsProxiesPair[0].indexOf(hostname) === -1) {
+
title = title.replace(
proxyTitle,
indent + hostname + '\n' + proxyTitle
@@ -119,6 +110,7 @@ window.tabWithError2ip = {}; // For errors only: Error? -> Check this IP!
);
}
+
}
if (ifShouldUpdateTitle) {
@@ -132,11 +124,12 @@ window.tabWithError2ip = {}; // For errors only: Error? -> Check this IP!
}
);
- }
+
+ };
let previousUpdateTitleFinished = Promise.resolve();
- function isProxiedAndInformed(requestDetails) {
+ const isProxiedAndInformed = function isProxiedAndInformed(requestDetails) {
if ( !(requestDetails.ip
&& antiCensorRu.isProxied( requestDetails.ip )) ) {
@@ -156,7 +149,14 @@ window.tabWithError2ip = {}; // For errors only: Error? -> Check this IP!
);
return true;
- }
+
+ };
+
+ const isInsideTabWithIp = function isInsideTabWithIp(requestDetails) {
+
+ return requestDetails.tabId !== -1 && requestDetails.ip;
+
+ };
chrome.webRequest.onResponseStarted.addListener(
(requestDetails) => isInsideTabWithIp(requestDetails)
@@ -164,4 +164,11 @@ window.tabWithError2ip = {}; // For errors only: Error? -> Check this IP!
{urls: ['']}
);
+ chrome.webRequest.onErrorOccurred.addListener(
+ (requestDetails) =>
+ isInsideTabWithIp(requestDetails)
+ && isProxiedAndInformed(requestDetails),
+ {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 81bfe34..24663cf 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
@@ -48,6 +48,9 @@
margin: 0.6em 0;
padding: 0;
}
+ #none:checked + label {
+ color: red;
+ }
#configs-panel > header {
margin: 0 0 0.4em;
}
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 044e86d..e94bc25 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
@@ -79,10 +79,11 @@ chrome.runtime.getBackgroundPage( (backgroundPage) =>
const showErrors = (err, warns) => {
warns = warns || [];
+ backgroundPage.console.log('eeeEEEEE',warns)
const warning = warns
.map(
(w) => '✘ ' +
- (w.clarification && w.clarification.message || w.message || '')
+ (w && w.clarification && w.clarification.message || w.message || '')
)
.join('
');
@@ -241,6 +242,7 @@ chrome.runtime.getBackgroundPage( (backgroundPage) =>
} else {
li.innerHTML += `🛈