diff --git a/README.md b/README.md
index 8874c55..d3b2782 100755
--- a/README.md
+++ b/README.md
@@ -10,10 +10,10 @@ This repo contains:
[WebStore](https://chrome.google.com/webstore/detail/npgcnondjocldhldegnakemclmfkngch)
| [Sources](https://github.com/ilyaigpetrov/anti-censorship-russia/tree/master/extensions/chromium/minimalistic-pac-setter)
2. Proof of concept PAC-script generator based on https://github.com/zapret-info/z-i
-3. PAC-scripts performance analyses of scripts generated
+3. ~~PAC-scripts performance analyses of scripts generated~~ (doesn't take parse time into account)
4. Based on the research of step 3 [the final PAC-generator][pac-generator] was written as a Google App Script in JavaScript which is triggered every two hours to generate and publish PAC-script on Google Drive (don't use direct URL without extension, please, URL will be periodically changed to counter abuse).
-[pac-generator]: https://script.google.com/d/18EG6_pPuSqzJaCU8ePzt_VfbvBI2maBIr5O8EMfktkBd5NNYKv8VvG4Y/edit?usp=sharing
+[pac-generator]: https://script.google.com/d/1iSwFilpiahetZ9hNPUK5SATjrNoZ_4i7aV9TWSp58LBhcyg_TuK_Qb5S/edit?usp=sharing
## Why I do This
diff --git a/extensions/chromium/runet-censorship-bypass/.gitignore b/extensions/chromium/runet-censorship-bypass/.gitignore
index c7bfad5..26f3785 100644
--- a/extensions/chromium/runet-censorship-bypass/.gitignore
+++ b/extensions/chromium/runet-censorship-bypass/.gitignore
@@ -1,4 +1,6 @@
node_modules
+node_modules_linux
+node_modules_win
npm-debug.log
-.swp
+*.swp
build/
diff --git a/extensions/chromium/runet-censorship-bypass/gulpfile.js b/extensions/chromium/runet-censorship-bypass/gulpfile.js
index 41da081..0f2ea15 100644
--- a/extensions/chromium/runet-censorship-bypass/gulpfile.js
+++ b/extensions/chromium/runet-censorship-bypass/gulpfile.js
@@ -4,6 +4,7 @@ const gulp = require('gulp');
const del = require('del');
const through = require('through2');
const PluginError = require('gulp-util').PluginError;
+const changed = require('gulp-changed');
const PluginName = 'Template literals';
@@ -21,7 +22,7 @@ const templatePlugin = (context) => through.obj(function(file, encoding, cb) {
const {keys, values} = Object.keys(context).reduce( (acc, key) => {
- const value = context[key];
+ const value = context[key];
acc.keys.push(key);
acc.values.push(value);
return acc;
@@ -44,39 +45,61 @@ const templatePlugin = (context) => through.obj(function(file, encoding, cb) {
gulp.task('default', ['build']);
-gulp.task('clean', function() {
+gulp.task('clean', function(cb) {
- return del.sync('./build');
+ //return del.sync('./build');
+ return cb();
});
const contexts = require('./src/templates-data').contexts;
-gulp.task('_cp-common', ['clean'], function() {
+const excFolder = (name) => [`!./src/**/${name}`, `!./src/**/${name}/**/*`];
+const excluded = [ ...excFolder('test') , ...excFolder('node_modules'), ...excFolder('src') ];
+const commonWoTests = ['./src/extension-common/**/*', ...excluded];
- gulp.src(['./src/extension-common/**/*'])
+const miniDst = './build/extension-mini';
+const fullDst = './build/extension-full';
+
+gulp.task('_cp-common', ['clean'], function(cb) {
+
+ let fins = 0;
+ const intheend = () => {
+ if (++fins === 2) {
+ cb();
+ }
+ };
+
+ gulp.src(commonWoTests)
+ .pipe(changed(miniDst))
.pipe(templatePlugin(contexts.mini))
- .pipe(gulp.dest('./build/extension-mini'))
+ .pipe(gulp.dest(miniDst))
+ .on('end', intheend);
- gulp.src(['./src/extension-common/**/*'])
+ gulp.src(commonWoTests)
+ .pipe(changed(fullDst))
.pipe(templatePlugin(contexts.full))
- .pipe(gulp.dest('./build/extension-full'));
+ .pipe(gulp.dest(fullDst))
+ .on('end', intheend);
});
-gulp.task('_cp-mini', ['_cp-common'], function() {
+gulp.task('_cp-mini', ['_cp-common'], function(cb) {
- gulp.src(['./src/extension-mini/**/*'])
+ gulp.src(['./src/extension-mini/**/*', ...excluded])
+ .pipe(changed(miniDst))
.pipe(templatePlugin(contexts.mini))
- .pipe(gulp.dest('./build/extension-mini'));
-
+ .pipe(gulp.dest(miniDst))
+ .on('end', cb);
});
-gulp.task('_cp-full', ['_cp-common'], function() {
+gulp.task('_cp-full', ['_cp-common'], function(cb) {
- gulp.src(['./src/extension-full/**/*'])
+ gulp.src(['./src/extension-full/**/*', ...excluded])
+ .pipe(changed(fullDst))
.pipe(templatePlugin(contexts.full))
- .pipe(gulp.dest('./build/extension-full'));
+ .pipe(gulp.dest(fullDst))
+ .on('end', cb);
});
diff --git a/extensions/chromium/runet-censorship-bypass/package.json b/extensions/chromium/runet-censorship-bypass/package.json
index e161dd3..5fdf7a3 100644
--- a/extensions/chromium/runet-censorship-bypass/package.json
+++ b/extensions/chromium/runet-censorship-bypass/package.json
@@ -3,14 +3,21 @@
"version": "0.0.19",
"description": "Development tools for chromium extension",
"scripts": {
+ "postinstall": "node --use_strict -e \"const fs = require('fs'), path = 'node_modules/_project-root'; fs.unlink(path, ()=> fs.symlinkSync('..', path, 'dir'));\"",
"lint": "eslint ./src/**/*.js --ignore-pattern vendor",
- "gulp": "gulp"
+ "gulp": "gulp",
+ "test": "mocha --recursive ./src/**/test/*",
+ "start": "cd ./src/extension-common/pages/options/ && npm run build && cd - && npm run gulp"
},
"author": "Ilya Ig. Petrov",
"license": "GPLv3",
"devDependencies": {
+ "chai": "^3.5.0",
"eslint": "^3.15.0",
- "eslint-config-google": "^0.7.1"
+ "eslint-config-google": "^0.7.1",
+ "gulp-changed": "^3.1.0",
+ "mocha": "^3.3.0",
+ "sinon-chrome": "^2.2.1"
},
"dependencies": {
"del": "^2.2.2",
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..fff4a1a 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
@@ -125,16 +125,16 @@
key = prefix + key;
if (value === null) {
- return localStorage.removeItem(key);
+ return window.localStorage.removeItem(key);
}
if (value === undefined) {
- const item = localStorage.getItem(key);
+ const item = window.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));
+ window.localStorage.setItem(key, JSON.stringify(value));
};
@@ -188,6 +188,7 @@
window.apis = {
version: {
ifMini: false,
+ build: chrome.runtime.getManifest().version.replace(/\d+\.\d+\./g, ''),
},
};
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 b4cbac3..96d3263 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
@@ -61,7 +61,7 @@
const ifPrefix = 'if-on-';
const extName = chrome.runtime.getManifest().name;
- const extVersion = chrome.runtime.getManifest().version.replace(/\d+\.\d+\./g, '');
+ const extVersion = window.apis.version.build;
window.apis.errorHandlers = {
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 758ce70..80ede86 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
@@ -12,66 +12,79 @@
const ifIncontinence = 'if-incontinence';
const modsKey = 'mods';
- // Don't keep objects in defaults or at least freeze them!
- const configs = {
+ const getDefaultConfigs = () => ({// Configs user may mutate them and we don't care!
ifProxyHttpsUrlsOnly: {
dflt: false,
label: 'проксировать только HTTPS-сайты',
desc: 'Проксировать только сайты, доступные по шифрованному протоколу HTTPS. Прокси и провайдер смогут видеть только адреса проксируемых HTTPS-сайтов, но не их содержимое. Используйте, если вы не доверяете прокси-серверам ваш HTTP-трафик. Разумеется, что с этой опцией разблокировка HTTP-сайтов работать не будет.',
- index: 0,
+ order: 0,
},
ifUseSecureProxiesOnly: {
dflt: false,
label: 'только шифрованная связь с прокси',
desc: 'Шифровать соединение до прокси от провайдера, используя только прокси типа HTTPS или локальный Tor. Провайдер всё же сможет видеть адреса (но не содержимое) проксируемых ресурсов из протокола DNS (даже с Tor). Опция вряд ли может быть вам полезна, т.к. шифруется не весь трафик, а лишь разблокируемые ресурсы.',
- index: 1,
+ order: 1,
},
ifProhibitDns: {
dflt: false,
label: 'запретить опредление по IP/DNS',
desc: 'Пытается запретить скрипту использовать DNS, без которого определение блокировки по IP работать не будет (т.е. будет разблокироваться меньше сайтов). Используйте, чтобы получить прирост в производительности или если вам кажется, что мы проксируем слишком много сайтов. Запрет действует только для скрипта, браузер и др.программы продолжат использование DNS.',
- index: 2,
+ order: 2,
},
ifProxyOrDie: {
dflt: true,
ifDfltMods: true,
label: 'проксируй или умри!',
desc: 'Запрещает соединение с сайтами напрямую без прокси в случаях, когда все прокси отказывают. Например, если все ВАШИ прокси вдруг недоступны, то добавленные вручную сайты открываться не будут совсем. Однако смысл опции в том, что она препятствует занесению прокси в чёрные списки Хрома. Рекомендуется не отключать.',
- index: 3,
+ order: 3,
},
ifUsePacScriptProxies: {
dflt: true,
+ category: 'ownProxies',
label: 'использовать прокси PAC-скрипта',
desc: 'Использовать прокси-сервера от авторов PAC-скрипта.',
- index: 4,
+ order: 4,
},
ifUseLocalTor: {
dflt: false,
+ category: 'ownProxies',
label: 'использовать СВОЙ локальный Tor',
desc: 'Установите Tor на свой компьютер и используйте его как прокси-сервер. ВАЖНО',
- index: 5,
+ order: 5,
},
exceptions: {
+ category: 'exceptions',
dflt: null,
},
ifMindExceptions: {
dflt: true,
+ category: 'exceptions',
label: 'учитывать исключения',
desc: 'Учитывать сайты, добавленные вручную. Только для своих прокси-серверов! Без своих прокси работать не будет.',
- index: 6,
+ order: 6,
},
customProxyStringRaw: {
dflt: '',
+ category: 'ownProxies',
label: 'использовать СВОИ прокси',
url: 'https://rebrand.ly/ac-own-proxy',
- index: 7,
+ order: 7,
+ },
+ ifProxyMoreDomains: {
+ ifDisabled: true,
+ dflt: false,
+ category: 'ownProxies',
+ label: 'проксировать .onion, .i2p и OpenNIC',
+ desc: 'Проксировать особые домены. Необходима поддержка со стороны СВОИХ прокси.',
+ order: 8,
},
- };
+ });
const getDefaults = function getDefaults() {
+ const configs = getDefaultConfigs();
return Object.keys(configs).reduce((acc, key) => {
acc[key] = configs[key].dflt;
@@ -83,7 +96,15 @@
const getCurrentConfigs = function getCurrentConfigs() {
- const [err, mods, ...warns] = createPacModifiers( kitchenState(modsKey) );
+ const oldMods = kitchenState(modsKey);
+ /*if (oldMods) {
+ // No migration!
+ return oldMods;
+ }*/
+
+ // Client may expect mods.included and mods.excluded!
+ // On first install they are not defined.
+ const [err, mods, ...warns] = createPacModifiers(oldMods);
if (err) {
throw err;
}
@@ -91,26 +112,33 @@
};
- const getOrderedConfigsForUser = function getOrderedConfigs() {
+ const getOrderedConfigsForUser = function getOrderedConfigs(category) {
const pacMods = getCurrentConfigs();
- return Object.keys(configs).reduce((arr, key) => {
+ const configs = getDefaultConfigs();
+ return Object.keys(configs)
+ .sort((keyA, keyB) => configs[keyA].order - configs[keyB].order)
+ .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;
+ const conf = configs[key];
+ if(typeof(conf.order) === 'number') {
+ if(!category || category === (conf.category || 'general')) {
+ conf.value = pacMods[key];
+ conf.key = key;
+ conf.category = category || 'general';
+ arr.push(conf);
+ }
+ }
+ return arr;
- }, []);
+ }, []);
};
const createPacModifiers = function createPacModifiers(mods = {}) {
mods = mods || {}; // null?
+ const configs = getDefaultConfigs();
const ifNoMods = Object.keys(configs)
.every((dProp) => {
@@ -123,7 +151,6 @@
});
- console.log('Input mods:', mods);
const self = {};
Object.assign(self, getDefaults(), mods);
self.ifNoMods = ifNoMods;
@@ -140,7 +167,8 @@
}
}
if (self.ifUseLocalTor) {
- customProxyArray.push('SOCKS5 localhost:9050', 'SOCKS5 localhost:9150');
+ self.torPoints = ['SOCKS5 localhost:9150', 'SOCKS5 localhost:9050'];
+ customProxyArray.push(...self.torPoints);
}
self.filteredCustomsString = '';
@@ -154,7 +182,18 @@
self.customProxyArray = false;
}
- self.included = self.excluded = undefined;
+ [self.included, self.excluded] = [[], []];
+ if (self.ifProxyMoreDomains) {
+ self.moreDomains = [
+ /* Networks */
+ 'onion', 'i2p',
+ /* OpenNIC */
+ 'bbs', 'chan', 'dyn', 'free', 'geek', 'gopher', 'indy',
+ 'libre', 'neo', 'null', 'o', 'oss', 'oz', 'parody', 'pirate',
+ /* OpenNIC Alternatives */
+ 'bazar', 'bit', 'coin', 'emc', 'fur', 'ku', 'lib', 'te', 'ti', 'uu'
+ ];
+ }
if (self.ifMindExceptions && self.exceptions) {
self.included = [];
self.excluded = [];
@@ -175,7 +214,7 @@
});
if (self.included.length && !self.filteredCustomsString) {
return [null, self, new TypeError(
- 'Имеются сайты, добавленные вручную. Они проксироваться не будут, т.к. нет СВОИХ проски, удовлетворяющих вашим запросам!'
+ 'Имеются сайты, добавленные вручную. Они проксироваться не будут, т.к. нет СВОИХ проски, удовлетворяющих вашим требованиям! Если прокси всё же имеются, то проверьте требования (модификаторы).'
)];
}
}
@@ -191,105 +230,140 @@
cook(pacData, pacMods = mandatory()) {
return pacMods.ifNoMods ? pacData : pacData + `${ kitchenStartsMark }
-;+function(global) {
- "use strict";
-
- const originalFindProxyForURL = FindProxyForURL;
- global.FindProxyForURL = function(url, host) {
- ${function() {
-
- let res = pacMods.ifProhibitDns ? `
- global.dnsResolve = function(host) { return null; };
- ` : '';
- if (pacMods.ifProxyHttpsUrlsOnly) {
-
- res += `
- if (!url.startsWith("https")) {
- return "DIRECT";
- }
- `;
- }
- res += `
- const directIfAllowed = ${pacMods.ifProxyOrDie ? '""/* Not allowed. */' : '"; DIRECT"'};
- `;
-
- const ifIncluded = pacMods.included && pacMods.included.length;
- const ifExcluded = pacMods.excluded && pacMods.excluded.length;
- const ifExceptions = ifIncluded || ifExcluded;
-
- if (ifExceptions) {
- res += `
- /* EXCEPTIONS START */
- const dotHost = '.' + host;
- const isHostInDomain = (domain) => dotHost.endsWith('.' + domain);
- const domainReducer = (maxWeight, [domain, ifIncluded]) => {
-
- if (!isHostInDomain(domain)) {
- return maxWeight;
- }
- const newWeightAbs = domain.length;
- if (newWeightAbs < Math.abs(maxWeight)) {
- return maxWeight;
- }
- return newWeightAbs*(ifIncluded ? 1 : -1);
-
- };
-
- const excWeight = ${JSON.stringify(Object.entries(pacMods.exceptions))}.reduce( domainReducer, 0 );
- if (excWeight !== 0) {
- if (excWeight > 0) {
- // Always proxy it!
- ${ pacMods.filteredCustomsString
- ? `return "${pacMods.filteredCustomsString}" + directIfAllowed;`
- : '/* No proxies -- continue. */'
- }
- } else {
- // Never proxy it!
- return "DIRECT";
- }
- }
- /* EXCEPTIONS END */
-`;
- }
- res += `
- const pacProxyString = originalFindProxyForURL(url, host)${
- pacMods.ifProxyOrDie ? '.replace(/DIRECT/g, "")' : ' + directIfAllowed'
- };`;
- if(
- !pacMods.ifUseSecureProxiesOnly &&
- !pacMods.filteredCustomsString &&
- pacMods.ifUsePacScriptProxies
- ) {
- return res + `
- return pacProxyString;`;
- }
-
- return res + `
- let pacProxyArray = pacProxyString.split(/(?:\\s*;\\s*)+/g).filter( (p) => p );
- const ifNoProxies = pacProxyArray${pacMods.ifProxyOrDie ? '.length === 0' : '.every( (p) => /^DIRECT$/i.test(p) )'};
- if (ifNoProxies) {
- // Directs only or null, no proxies.
- return "DIRECT";
- }
- return ` +
+/******/
+/******/;+function(global) {
+/******/ "use strict";
+/******/
+/******/ const originalFindProxyForURL = FindProxyForURL;
+/******/ global.FindProxyForURL = function(url, host) {
+/******/
+ ${
function() {
- if (!pacMods.ifUsePacScriptProxies) {
- return `"${pacMods.filteredCustomsString}"`;
- }
- let filteredPacExp = 'pacProxyString';
- if (pacMods.ifUseSecureProxiesOnly) {
- filteredPacExp =
- 'pacProxyArray.filter( (pStr) => /^HTTPS\\s/.test(pStr) ).join("; ")';
- }
- if ( !pacMods.filteredCustomsString ) {
- return filteredPacExp;
- }
- return `${filteredPacExp} + "; ${pacMods.filteredCustomsString}"`;
+ let res = pacMods.ifProhibitDns ? `
+/******/
+/******/ global.dnsResolve = function(host) { return null; };
+/******/
+/******/` : '';
+ if (pacMods.ifProxyHttpsUrlsOnly) {
- }() + ' + directIfAllowed;'; // Without DIRECT you will get 'PROXY CONN FAILED' pac-error.
+ res += `
+/******/
+/******/ if (!url.startsWith("https")) {
+/******/ return "DIRECT";
+/******/ }
+/******/
+/******/ `;
+ }
+ if (pacMods.ifUseLocalTor) {
- }()}
+ res += `
+/******/
+/******/ if (host.endsWith(".onion")) {
+/******/ return "${pacMods.torPoints.join('; ')}";
+/******/ }
+/******/
+/******/ `;
+ }
+ res += `
+/******/
+/******/ const directIfAllowed = ${pacMods.ifProxyOrDie ? '""/* Not allowed. */' : '"; DIRECT"'};
+/******/`;
+ if (pacMods.filteredCustomsString) {
+ res += `
+/******/
+/******/ const filteredCustomProxies = "; ${pacMods.filteredCustomsString}";
+/******/`;
+ }
+
+ const ifIncluded = pacMods.included && pacMods.included.length;
+ const ifExcluded = pacMods.excluded && pacMods.excluded.length;
+ const ifManualExceptions = ifIncluded || ifExcluded;
+ const finalExceptions = {};
+ if (pacMods.ifProxyMoreDomains) {
+ pacMods.moreDomains.reduce((acc, tld) => {
+
+ acc[tld] = true;
+ return acc;
+
+ }, finalExceptions);
+ }
+ if (pacMods.ifMindExceptions) {
+ Object.assign(finalExceptions, (pacMods.exceptions || {}));
+ }
+ const ifExceptions = Object.keys(finalExceptions).length;
+
+ if (ifExceptions) {
+ res += `
+/******/
+/******/ /* EXCEPTIONS START */
+/******/ const dotHost = '.' + host;
+/******/ const isHostInDomain = (domain) => dotHost.endsWith('.' + domain);
+/******/ const domainReducer = (maxWeight, [domain, ifIncluded]) => {
+/******/
+/******/ if (!isHostInDomain(domain)) {
+/******/ return maxWeight;
+/******/ }
+/******/ const newWeightAbs = domain.length;
+/******/ if (newWeightAbs < Math.abs(maxWeight)) {
+/******/ return maxWeight;
+/******/ }
+/******/ return newWeightAbs*(ifIncluded ? 1 : -1);
+/******/
+/******/ };
+/******/
+/******/ const excWeight = ${ JSON.stringify(Object.entries(finalExceptions)) }.reduce( domainReducer, 0 );
+/******/ if (excWeight !== 0) {
+/******/ if (excWeight < 0) {
+/******/ // Never proxy it!
+/******/ return "DIRECT";
+/******/ }
+/******/ // Always proxy it!
+${ pacMods.filteredCustomsString
+ ? `/******/ return filteredCustomProxies + directIfAllowed;`
+ : '/******/ /* No custom proxies -- continue. */'
+}
+/******/ }
+/******/ /* EXCEPTIONS END */
+`;
+ }
+ res += `
+/******/ const pacScriptProxies = originalFindProxyForURL(url, host)${
+/******/ pacMods.ifProxyOrDie ? '.replace(/DIRECT/g, "")' : ' + directIfAllowed'
+ };`;
+ if(
+ !pacMods.ifUseSecureProxiesOnly &&
+ !pacMods.filteredCustomsString &&
+ pacMods.ifUsePacScriptProxies
+ ) {
+ return res + `
+/******/ return pacScriptProxies + directIfAllowed;`;
+ }
+
+ return res + `
+/******/ let pacProxyArray = pacScriptProxies.split(/(?:\\s*;\\s*)+/g).filter( (p) => p );
+/******/ const ifNoProxies = pacProxyArray${pacMods.ifProxyOrDie ? '.length === 0' : '.every( (p) => /^DIRECT$/i.test(p) )'};
+/******/ if (ifNoProxies) {
+/******/ // Directs only or null, no proxies.
+/******/ return "DIRECT";
+/******/ }
+/******/ return ` +
+ function() {
+
+ if (!pacMods.ifUsePacScriptProxies) {
+ return '';
+ }
+ let filteredPacExp = 'pacScriptProxies';
+ if (pacMods.ifUseSecureProxiesOnly) {
+ filteredPacExp =
+ 'pacProxyArray.filter( (pStr) => /^HTTPS\\s/.test(pStr) ).join("; ")';
+ }
+ return filteredPacExp + ' + ';
+
+ }() + `${pacMods.filteredCustomsString ? 'filteredCustomProxies + ' : ''}directIfAllowed;`; // Without DIRECT you will get 'PROXY CONN FAILED' pac-error.
+
+ }()
+ }
};
@@ -360,15 +434,12 @@
const oldProxies = getCurrentConfigs().filteredCustomsString || '';
const newProxies = pacMods.filteredCustomsString || '';
ifProxiesChanged = oldProxies !== newProxies;
- console.log('Proxies changed from:', oldProxies, 'to', newProxies);
kitchenState(modsKey, pacMods);
}
- console.log('Keep cooked now...', pacMods);
this.setNowAsync(
(err, res, ...setWarns) => {
const accWarns = modsWarns.concat(setWarns); // Acc = accumulated.
- console.log('Try now err:', err);
if (err) {
return cb(err, res, ...accWarns);
}
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 8679370..5706775 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
@@ -169,19 +169,19 @@
pacProviders: {
Антизапрет: {
label: 'Антизапрет',
- desc: 'Альтернативный PAC-скрипт от стороннего разработчика.' +
- ' Блокировка определяется по доменному имени,' +
- ' для некоторых провайдеров есть автоопредление.' +
- '
Страница проекта.',
+ desc: `Альтернативный PAC-скрипт от стороннего разработчика.
+ Работает быстрее, но охватывает меньше сайтов.
+ Блокировка определяется по доменному имени,
+
Страница проекта.`,
order: 0,
pacUrls: ['https://antizapret.prostovpn.org/proxy.pac'],
},
Антицензорити: {
- label: 'Антицензорити (тормозит)',
- desc: 'Основной PAC-скрипт от автора расширения.' +
- ' Блокировка определятся по доменному имени или IP адресу.' +
- ' Работает на switch-ах.
' +
- ' Страница проекта.',
+ label: 'Антицензорити',
+ desc: `Основной PAC-скрипт от автора расширения.
+ Работает медленней, но охватывает больше сайтов.
+ Блокировка определятся по доменному имени или IP адресу.
+ Страница проекта.`,
order: 1,
/*
@@ -193,13 +193,16 @@
// First official, shortened:
'https://rebrand.ly/ac-chrome-anticensority-pac',
// Second official, Cloud Flare with caching:
+ 'https://anticensority.tk/generated-pac-scripts/anticensority.pac',
+ // GitHub.io (anticensority):
+ '\x68\x74\x74\x70\x73\x3a\x2f\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2e\x67\x69\x74\x68\x75\x62\x2e\x69\x6f\x2f\x67\x65\x6e\x65\x72\x61\x74\x65\x64\x2d\x70\x61\x63\x2d\x73\x63\x72\x69\x70\x74\x73\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2e\x70\x61\x63',
+ // GitHub repo (anticensority):
+ '\x68\x74\x74\x70\x73\x3a\x2f\x2f\x72\x61\x77\x2e\x67\x69\x74\x68\x75\x62\x75\x73\x65\x72\x63\x6f\x6e\x74\x65\x6e\x74\x2e\x63\x6f\x6d\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2f\x67\x65\x6e\x65\x72\x61\x74\x65\x64\x2d\x70\x61\x63\x2d\x73\x63\x72\x69\x70\x74\x73\x2f\x6d\x61\x73\x74\x65\x72\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2e\x70\x61\x63',
+ // Old, deprecated:
'https://anticensorship-russia.tk/generated-pac-scripts/anticensority.pac',
- // GitHub.io:
- '\x68\x74\x74\x70\x73\x3a\x2f\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x73\x68\x69\x70\x2d\x72\x75\x73\x73\x69\x61\x2e\x67\x69\x74\x68\x75\x62\x2e\x69\x6f\x2f\x67\x65\x6e\x65\x72\x61\x74\x65\x64\x2d\x70\x61\x63\x2d\x73\x63\x72\x69\x70\x74\x73\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2e\x70\x61\x63', // eslint-disable-line max-len
- // GitHub repo:
- '\x68\x74\x74\x70\x73\x3a\x2f\x2f\x72\x61\x77\x2e\x67\x69\x74\x68\x75\x62\x75\x73\x65\x72\x63\x6f\x6e\x74\x65\x6e\x74\x2e\x63\x6f\x6d\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x73\x68\x69\x70\x2d\x72\x75\x73\x73\x69\x61\x2f\x67\x65\x6e\x65\x72\x61\x74\x65\x64\x2d\x70\x61\x63\x2d\x73\x63\x72\x69\x70\x74\x73\x2f\x6d\x61\x73\x74\x65\x72\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2e\x70\x61\x63', // eslint-disable-line max-len
- // Google Drive (0.17):
- '\x68\x74\x74\x70\x73\x3a\x2f\x2f\x64\x72\x69\x76\x65\x2e\x67\x6f\x6f\x67\x6c\x65\x2e\x63\x6f\x6d\x2f\x75\x63\x3f\x65\x78\x70\x6f\x72\x74\x3d\x64\x6f\x77\x6e\x6c\x6f\x61\x64\x26\x69\x64\x3d\x30\x42\x2d\x5a\x43\x56\x53\x76\x75\x4e\x57\x66\x30\x54\x44\x46\x52\x4f\x47\x35\x46\x62\x55\x39\x4f\x64\x44\x67'], // eslint-disable-line max-len
+ // Google Drive (0.17, anticensority):
+ '\x68\x74\x74\x70\x73\x3a\x2f\x2f\x64\x72\x69\x76\x65\x2e\x67\x6f\x6f\x67\x6c\x65\x2e\x63\x6f\x6d\x2f\x75\x63\x3f\x65\x78\x70\x6f\x72\x74\x3d\x64\x6f\x77\x6e\x6c\x6f\x61\x64\x26\x69\x64\x3d\x30\x42\x32\x6d\x68\x42\x67\x46\x6e\x66\x34\x70\x45\x4c\x56\x6c\x47\x4e\x54\x42\x45\x4d\x58\x4e\x6d\x52\x58\x63',
+ ],
},
onlyOwnSites: {
label: 'Только свои сайты и свои прокси',
@@ -213,7 +216,7 @@
getSortedEntriesForProviders() {
- return Object.entries(this.pacProviders).sort((entryA, entryB) => entryA[1].order - entryB[1].order);
+ return Object.entries(this.pacProviders).sort((entryA, entryB) => entryA[1].order - entryB[1].order).map(([key, prov]) => Object.assign({key: key}, prov));
},
@@ -225,6 +228,16 @@
ifFirstInstall: false,
lastPacUpdateStamp: 0,
+ setTitle() {
+
+ const upDate = new Date(this.lastPacUpdateStamp).toLocaleString('ru-RU')
+ .replace(/:\d+$/, '').replace(/\.\d{4}/, '');
+ chrome.browserAction.setTitle({
+ title: `Обновлялись ${upDate} | Версия ${window.apis.version.build}`,
+ });
+
+ },
+
_currentPacProviderLastModified: 0, // Not initialized.
getLastModifiedForKey(key = mandatory()) {
@@ -331,6 +344,7 @@
this.lastPacUpdateStamp = Date.now();
this.ifFirstInstall = false;
this.setAlarms();
+ this.setTitle();
}
resolve([err, null, ...warns]);
@@ -509,10 +523,10 @@
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;
await new Promise((resolve) => {
+ const ifUpdating = antiCensorRu.version !== oldStorage.version;
if (!ifUpdating) {
// LAUNCH, RELOAD, ENABLE
@@ -527,12 +541,7 @@
const key = antiCensorRu._currentPacProviderKey;
if (key !== null) {
const ifVeryOld = !Object.keys(antiCensorRu.pacProviders).includes(key);
- const ifNeedsForcing = (oldStorage.version < '0.0.0.2') && !localStorage.getItem('provider-backup');
- if ( ifVeryOld || ifNeedsForcing ) {
- if (ifNeedsForcing) {
- console.log('Update forces antizapret...')
- localStorage.setItem('provider-backup', antiCensorRu._currentPacProviderKey);
- }
+ if (ifVeryOld) {
antiCensorRu._currentPacProviderKey = 'Антизапрет';
}
}
@@ -549,6 +558,7 @@
if (antiCensorRu.getPacProvider()) {
antiCensorRu.setAlarms();
}
+ antiCensorRu.setTitle();
/*
History of Changes to Storage (Migration Guide)
diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/70-menu-items.js b/extensions/chromium/runet-censorship-bypass/src/extension-common/70-menu-items.js
new file mode 100644
index 0000000..6008e50
--- /dev/null
+++ b/extensions/chromium/runet-censorship-bypass/src/extension-common/70-menu-items.js
@@ -0,0 +1,63 @@
+'use strict';
+
+{
+
+ window.apis.menus = {
+
+ getItemsAsObject: () => ({
+
+ googleTranslate: {
+ title: 'Через Google Translate',
+ getUrl: (blockedUrl) => (
+ 'https://translate.google.com/translate?hl=&sl=en&tl=ru&anno=2&sandbox=1&u=' + blockedUrl),
+ order: 0,
+ },
+
+ hostTracker: {
+ title: 'Из кэша Google',
+ getUrl: (blockedUrl) => 'http://webcache.googleusercontent.com/search?q=cache:' + blockedUrl,
+ order: 1,
+ },
+
+ archiveOrg: {
+ title: 'Из архива archive.org',
+ getUrl: (blockedUrl) => 'https://web.archive.org/web/*/' + blockedUrl,
+ order: 2,
+ },
+
+ otherUnblock: {
+ title: 'Разблокировать по-другому',
+ getUrl: (blockedUrl) => ('https://rebrand.ly/ac-unblock#' + blockedUrl),
+ order: 3,
+ },
+
+ antizapretInfo: {
+ title: 'Сайт в реестре блокировок?',
+ getUrl: (blockedUrl) => 'https://antizapret.info/index.php?search=' + new URL(blockedUrl).hostname,
+ order: 4,
+ },
+
+ support: {
+ title: 'Документация / Помощь / Поддержка',
+ getUrl: (blockedUrl) => 'https://rebrand.ly/ac-wiki',
+ order: 99,
+ },
+
+ }),
+
+ getItemsAsArray: function() {
+
+ const itemsObj = this.getItemsAsObject();
+ return Object.keys(itemsObj).reduce((acc, key) => {
+
+ acc.push(itemsObj[key]);
+ return acc;
+
+ }, [])
+ .sort((a, b) => a.order - b.order);
+
+ },
+
+ };
+
+}
diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/75-context-menus.js b/extensions/chromium/runet-censorship-bypass/src/extension-common/75-context-menus.js
new file mode 100644
index 0000000..7509c7c
--- /dev/null
+++ b/extensions/chromium/runet-censorship-bypass/src/extension-common/75-context-menus.js
@@ -0,0 +1,45 @@
+'use strict';
+
+{
+
+ const chromified = window.utils.chromified;
+
+ let seqId = 0;
+
+ const createMenuLinkEntry = (title, tab2url) => {
+
+ const id = (++seqId).toString();
+
+ chrome.contextMenus.create({
+ id: id,
+ title: title,
+ contexts: ['browser_action'],
+ }, chromified((err) => {
+
+ if(err) {
+ console.warn('Context menu error ignored:', err);
+ }
+
+ }));
+
+ chrome.contextMenus.onClicked.addListener((info, tab) => {
+
+ if(info.menuItemId === id) {
+ Promise.resolve( tab2url( tab ) )
+ .then( (url) => chrome.tabs.create({url: url}) );
+ }
+
+ });
+
+ };
+
+ window.apis.menus.getItemsAsArray().forEach((item) => {
+
+ createMenuLinkEntry(
+ item.title,
+ (tab) => item.getUrl(tab.url)
+ );
+
+ });
+
+}
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
deleted file mode 100644
index 66e53e5..0000000
--- a/extensions/chromium/runet-censorship-bypass/src/extension-common/80-context-menus.js
+++ /dev/null
@@ -1,72 +0,0 @@
-'use strict';
-
-{
-
- const chromified = window.utils.chromified;
-
- let seqId = 0;
-
- const createMenuLinkEntry = (title, tab2url) => {
-
- const id = (++seqId).toString();
-
- chrome.contextMenus.create({
- id: id,
- title: title,
- contexts: ['browser_action'],
- }, chromified((err) => {
-
- if(err) {
- console.warn('Context menu error ignored:', err);
- }
-
- }));
-
- chrome.contextMenus.onClicked.addListener((info, tab) => {
-
- if(info.menuItemId === id) {
- Promise.resolve( tab2url( tab ) )
- .then( (url) => chrome.tabs.create({url: url}) );
- }
-
- });
-
- };
-
- createMenuLinkEntry(
- 'Сайт доступен из-за границы? Is up?',
- (tab) => `data:text/html;charset=utf8,