mirror of
https://github.com/anticensority/runet-censorship-bypass.git
synced 2024-11-27 20:03:45 +03:00
Merge remote-tracking branch 'origin/production' into development
This commit is contained in:
commit
64971bb098
|
@ -10,19 +10,19 @@ const PluginName = 'Template literals';
|
||||||
|
|
||||||
const templatePlugin = (context) => through.obj(function(file, encoding, cb) {
|
const templatePlugin = (context) => through.obj(function(file, encoding, cb) {
|
||||||
|
|
||||||
const tjson = '.tmpl.json';
|
const suffixes = ['.tmpl.json', 'tmpl.js'];
|
||||||
if (file.path.endsWith(tjson)) {
|
if ( suffixes.some( (suff) => file.path.endsWith(suff) ) ) {
|
||||||
|
|
||||||
const originalPath = file.path;
|
const originalPath = file.path;
|
||||||
file.path = file.path.replace(new RegExp(`${tjson}$`), '.json');
|
file.path = file.path.replace(new RegExp(`tmpl.([^.]+)$`), '$1');
|
||||||
|
|
||||||
if (file.isStream()) {
|
if (file.isStream()) {
|
||||||
return cb(new PluginError(PluginName, 'Streams not supported!'));
|
return cb(new PluginError(PluginName, 'Streams are not supported!'));
|
||||||
} else if (file.isBuffer()) {
|
} else if (file.isBuffer()) {
|
||||||
|
|
||||||
const {keys, values} = Object.keys(context).reduce( (acc, key) => {
|
const {keys, values} = Object.keys(context).reduce( (acc, key) => {
|
||||||
|
|
||||||
const value = context[key];
|
const value = context[key];
|
||||||
acc.keys.push(key);
|
acc.keys.push(key);
|
||||||
acc.values.push(value);
|
acc.values.push(value);
|
||||||
return acc;
|
return acc;
|
||||||
|
@ -60,6 +60,7 @@ const commonWoTests = ['./src/extension-common/**/*', ...excluded];
|
||||||
|
|
||||||
const miniDst = './build/extension-mini';
|
const miniDst = './build/extension-mini';
|
||||||
const fullDst = './build/extension-full';
|
const fullDst = './build/extension-full';
|
||||||
|
const betaDst = './build/extension-beta';
|
||||||
|
|
||||||
gulp.task('_cp-common', ['clean'], function(cb) {
|
gulp.task('_cp-common', ['clean'], function(cb) {
|
||||||
|
|
||||||
|
@ -71,23 +72,28 @@ gulp.task('_cp-common', ['clean'], function(cb) {
|
||||||
};
|
};
|
||||||
|
|
||||||
gulp.src(commonWoTests)
|
gulp.src(commonWoTests)
|
||||||
.pipe(changed(miniDst))
|
//.pipe(changed(miniDst))
|
||||||
.pipe(templatePlugin(contexts.mini))
|
.pipe(templatePlugin(contexts.mini))
|
||||||
.pipe(gulp.dest(miniDst))
|
.pipe(gulp.dest(miniDst))
|
||||||
.on('end', intheend);
|
.on('end', intheend);
|
||||||
|
|
||||||
gulp.src(commonWoTests)
|
gulp.src(commonWoTests)
|
||||||
.pipe(changed(fullDst))
|
//.pipe(changed(fullDst))
|
||||||
.pipe(templatePlugin(contexts.full))
|
.pipe(templatePlugin(contexts.full))
|
||||||
.pipe(gulp.dest(fullDst))
|
.pipe(gulp.dest(fullDst))
|
||||||
.on('end', intheend);
|
.on('end', intheend);
|
||||||
|
|
||||||
|
gulp.src(commonWoTests)
|
||||||
|
//.pipe(changed(fullDst))
|
||||||
|
.pipe(templatePlugin(contexts.beta))
|
||||||
|
.pipe(gulp.dest(betaDst))
|
||||||
|
.on('end', intheend);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('_cp-mini', ['_cp-common'], function(cb) {
|
gulp.task('_cp-mini', ['_cp-common'], function(cb) {
|
||||||
|
|
||||||
gulp.src(['./src/extension-mini/**/*', ...excluded])
|
gulp.src(['./src/extension-mini/**/*', ...excluded])
|
||||||
.pipe(changed(miniDst))
|
//.pipe(changed(miniDst))
|
||||||
.pipe(templatePlugin(contexts.mini))
|
.pipe(templatePlugin(contexts.mini))
|
||||||
.pipe(gulp.dest(miniDst))
|
.pipe(gulp.dest(miniDst))
|
||||||
.on('end', cb);
|
.on('end', cb);
|
||||||
|
@ -96,11 +102,22 @@ gulp.task('_cp-mini', ['_cp-common'], function(cb) {
|
||||||
gulp.task('_cp-full', ['_cp-common'], function(cb) {
|
gulp.task('_cp-full', ['_cp-common'], function(cb) {
|
||||||
|
|
||||||
gulp.src(['./src/extension-full/**/*', ...excluded])
|
gulp.src(['./src/extension-full/**/*', ...excluded])
|
||||||
.pipe(changed(fullDst))
|
//.pipe(changed(fullDst))
|
||||||
.pipe(templatePlugin(contexts.full))
|
.pipe(templatePlugin(contexts.full))
|
||||||
.pipe(gulp.dest(fullDst))
|
.pipe(gulp.dest(fullDst))
|
||||||
.on('end', cb);
|
.on('end', cb);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('build', ['_cp-mini', '_cp-full']);
|
gulp.task('_cp-beta', ['_cp-common'], function(cb) {
|
||||||
|
|
||||||
|
gulp.src(['./src/extension-full/**/*', ...excluded])
|
||||||
|
//.pipe(changed(fullDst))
|
||||||
|
.pipe(templatePlugin(contexts.beta))
|
||||||
|
.pipe(gulp.dest(betaDst))
|
||||||
|
.on('end', cb);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('build:all', ['_cp-mini', '_cp-full', '_cp-beta']);
|
||||||
|
gulp.task('build', ['_cp-full']);
|
||||||
|
|
|
@ -7,7 +7,9 @@
|
||||||
"lint": "eslint ./src/**/*.js --ignore-pattern vendor",
|
"lint": "eslint ./src/**/*.js --ignore-pattern vendor",
|
||||||
"gulp": "gulp",
|
"gulp": "gulp",
|
||||||
"test": "mocha --recursive ./src/**/test/*",
|
"test": "mocha --recursive ./src/**/test/*",
|
||||||
"start": "cd ./src/extension-common/pages/options/ && npm run build && cd - && npm run gulp"
|
"subpages": "cd ./src/extension-common/pages/options/ && npm run build && cd -",
|
||||||
|
"start": "npm run subpages && npm run gulp",
|
||||||
|
"beta": "npm run subpages && npm run gulp build:all"
|
||||||
},
|
},
|
||||||
"author": "Ilya Ig. Petrov",
|
"author": "Ilya Ig. Petrov",
|
||||||
"license": "GPLv3",
|
"license": "GPLv3",
|
||||||
|
|
|
@ -0,0 +1,581 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/*
|
||||||
|
Task 1. Gets IPs for proxies of antizapret/anticenz via dns over https.
|
||||||
|
These IPs are used in block-informer to inform user when proxy is ON.
|
||||||
|
Task 2. Downloads PAC proxy script from antizapret/anticenz/
|
||||||
|
my Google Drive and sets it in Chromium settings.
|
||||||
|
Task 3. Schedules tasks 1 & 2 for every 4 hours.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
In background scripts use window.apis.antiCensorRu public variables.
|
||||||
|
In pages window.apis.antiCensorRu is not accessible,
|
||||||
|
use chrome.runtime.getBackgroundPage(..),
|
||||||
|
extension.getBackgroundPage is deprecated
|
||||||
|
|
||||||
|
If you want to catch errors, then call api from setTimeout!
|
||||||
|
See errorHandlers api for more.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
{ // Private namespace starts.
|
||||||
|
|
||||||
|
const mandatory = window.utils.mandatory;
|
||||||
|
const throwIfError = window.utils.throwIfError;
|
||||||
|
const chromified = window.utils.chromified;
|
||||||
|
const timeouted = window.utils.timeouted;
|
||||||
|
|
||||||
|
const clarifyThen = window.apis.errorsLib.clarifyThen;
|
||||||
|
const Warning = window.apis.errorsLib.Warning;
|
||||||
|
|
||||||
|
const httpLib = window.apis.httpLib;
|
||||||
|
const handlers = window.apis.errorHandlers;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
console.group(...args);
|
||||||
|
return function(...cbArgs) {
|
||||||
|
|
||||||
|
console.groupEnd();
|
||||||
|
console.log('Group finished.');
|
||||||
|
cb(...cbArgs);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const setPacAsync = function setPacAsync(
|
||||||
|
pacData = mandatory(), cb = throwIfError
|
||||||
|
) {
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
mode: 'pac_script',
|
||||||
|
pacScript: {
|
||||||
|
mandatory: false,
|
||||||
|
data: pacData,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log('Setting chrome proxy settings...');
|
||||||
|
chrome.proxy.settings.set( {value: config}, chromified((err) => {
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
handlers.updateControlState( () => {
|
||||||
|
|
||||||
|
if ( !handlers.ifControlled ) {
|
||||||
|
|
||||||
|
console.warn('Failed, other extension is in control.');
|
||||||
|
return cb(
|
||||||
|
new Error( window.utils.messages.whichExtensionHtml() )
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
console.log('Successfuly set PAC in proxy settings..');
|
||||||
|
cb();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const updatePacProxyIps = function updatePacProxyIps(
|
||||||
|
cb = throwIfError
|
||||||
|
) {
|
||||||
|
|
||||||
|
cb = asyncLogGroup(
|
||||||
|
'Getting IPs for PAC hosts...',
|
||||||
|
cb
|
||||||
|
);
|
||||||
|
window.utils.fireRequest('ip-to-host-update-all', cb);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const setPacScriptFromProviderAsync = function setPacScriptFromProviderAsync(
|
||||||
|
provider, lastModifiedStr = mandatory(), cb = throwIfError
|
||||||
|
) {
|
||||||
|
|
||||||
|
const pacUrl = provider.pacUrls[0];
|
||||||
|
cb = asyncLogGroup(
|
||||||
|
'Getting PAC script from provider...', pacUrl,
|
||||||
|
cb
|
||||||
|
);
|
||||||
|
|
||||||
|
httpLib.ifModifiedSince(pacUrl, lastModifiedStr, (err, newLastModifiedStr) => {
|
||||||
|
|
||||||
|
if (!newLastModifiedStr) {
|
||||||
|
const res = {lastModified: lastModifiedStr};
|
||||||
|
const ifWasEverModified = lastModifiedStr !== new Date(0).toUTCString();
|
||||||
|
if (ifWasEverModified) {
|
||||||
|
return cb(
|
||||||
|
null, res,
|
||||||
|
new Warning(
|
||||||
|
'Ваш PAC-скрипт не нуждается в обновлении. Его дата: ' +
|
||||||
|
lastModifiedStr
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Employ all urls, the latter are fallbacks for the former.
|
||||||
|
const pacDataPromise = provider.pacUrls.reduce(
|
||||||
|
(promise, url) => promise.catch(
|
||||||
|
() => new Promise(
|
||||||
|
(resolve, reject) => httpLib.get(
|
||||||
|
url,
|
||||||
|
(newErr, pacData) => newErr ? reject(newErr) : resolve(pacData)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
Promise.reject()
|
||||||
|
);
|
||||||
|
|
||||||
|
pacDataPromise.then(
|
||||||
|
|
||||||
|
(pacData) => {
|
||||||
|
|
||||||
|
setPacAsync(
|
||||||
|
pacData,
|
||||||
|
(err, res) => cb(
|
||||||
|
err,
|
||||||
|
Object.assign(res || {}, {lastModified: newLastModifiedStr})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
clarifyThen(
|
||||||
|
'Не удалось скачать PAC-скрипт с адресов: [ '
|
||||||
|
+ provider.pacUrls.join(' , ') + ' ].',
|
||||||
|
cb
|
||||||
|
)
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
window.apis.antiCensorRu = {
|
||||||
|
|
||||||
|
version: chrome.runtime.getManifest().version,
|
||||||
|
|
||||||
|
pacProviders: {
|
||||||
|
Антизапрет: {
|
||||||
|
label: 'Антизапрет',
|
||||||
|
desc: \`Альтернативный PAC-скрипт от стороннего разработчика.
|
||||||
|
Работает быстрее, но охватывает меньше сайтов.
|
||||||
|
Блокировка определяется по доменному имени,
|
||||||
|
<br/> <a href="https://antizapret.prostovpn.org">Страница проекта</a>.\`,
|
||||||
|
order: 0,
|
||||||
|
pacUrls: ['https://antizapret.prostovpn.org/proxy.pac'],
|
||||||
|
},
|
||||||
|
Антицензорити: {
|
||||||
|
label: 'Антицензорити',
|
||||||
|
desc: \`Основной PAC-скрипт от автора расширения.
|
||||||
|
Работает медленней, но охватывает больше сайтов.
|
||||||
|
Блокировка определятся по доменному имени или IP адресу.<br/>
|
||||||
|
<a href="https://rebrand.ly/ac-anticensority">Страница проекта</a>.\`,
|
||||||
|
order: 1,
|
||||||
|
|
||||||
|
/*
|
||||||
|
Don't use in system configs! Because Windows does poor caching.
|
||||||
|
Some urls are encoded to counter abuse.
|
||||||
|
Version: 0.17
|
||||||
|
*/
|
||||||
|
pacUrls: ${JSON.stringify(anticensorityPacUrls, null, 2)},
|
||||||
|
/*[
|
||||||
|
// 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',
|
||||||
|
// 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: 'Только свои сайты и свои прокси',
|
||||||
|
desc: 'Проксируются только добавленные вручную сайты через СВОИ вручную добавленные прокси или через локальный Tor.',
|
||||||
|
order: 99,
|
||||||
|
pacUrls: [
|
||||||
|
'data:application/x-ns-proxy-autoconfig,' + escape('function FindProxyForURL(){ return "DIRECT"; }'),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getSortedEntriesForProviders() {
|
||||||
|
|
||||||
|
return Object.entries(this.pacProviders).sort((entryA, entryB) => entryA[1].order - entryB[1].order).map(([key, prov]) => Object.assign({key: key}, prov));
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
_currentPacProviderKey: 'Антизапрет',
|
||||||
|
|
||||||
|
/* Is it the first time extension installed?
|
||||||
|
Do something, e.g. initiate PAC sync.
|
||||||
|
*/
|
||||||
|
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()) {
|
||||||
|
|
||||||
|
if (this._currentPacProviderKey === key) {
|
||||||
|
return new Date(this._currentPacProviderLastModified).toUTCString();
|
||||||
|
}
|
||||||
|
return new Date(0).toUTCString();
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
setLastModified(newValue = mandatory()) {
|
||||||
|
|
||||||
|
this._currentPacProviderLastModified = newValue;
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
mustBeKey(key = mandatory()) {
|
||||||
|
|
||||||
|
if ( !(key === null || this.pacProviders[key]) ) {
|
||||||
|
throw new TypeError('No provider for key:' + key);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
getCurrentPacProviderKey() {
|
||||||
|
|
||||||
|
return this._currentPacProviderKey;
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
setCurrentPacProviderKey(
|
||||||
|
newKey = mandatory(),
|
||||||
|
lastModified = new Date().toUTCString()
|
||||||
|
) {
|
||||||
|
|
||||||
|
this.mustBeKey(newKey);
|
||||||
|
this._currentPacProviderKey = newKey;
|
||||||
|
this._currentPacProviderLastModified = lastModified;
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
getPacProvider(key) {
|
||||||
|
|
||||||
|
if(key) {
|
||||||
|
this.mustBeKey(key);
|
||||||
|
} else {
|
||||||
|
key = this.getCurrentPacProviderKey();
|
||||||
|
}
|
||||||
|
return this.pacProviders[key];
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
_periodicUpdateAlarmReason: 'Периодичное обновление PAC-скрипта',
|
||||||
|
|
||||||
|
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;
|
||||||
|
key = this.getCurrentPacProviderKey();
|
||||||
|
}
|
||||||
|
cb = asyncLogGroup('Syncing with PAC provider ' + key + '...', cb);
|
||||||
|
|
||||||
|
if (key === null) {
|
||||||
|
// No pac provider set.
|
||||||
|
return clarifyThen('Сперва выберите PAC-провайдера.', cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
const pacProvider = this.getPacProvider(key);
|
||||||
|
|
||||||
|
const pacSetPromise = new Promise(
|
||||||
|
(resolve, reject) => setPacScriptFromProviderAsync(
|
||||||
|
pacProvider,
|
||||||
|
this.getLastModifiedForKey(key),
|
||||||
|
(err, res, ...warns) => {
|
||||||
|
|
||||||
|
if (!err) {
|
||||||
|
this.setCurrentPacProviderKey(key, res.lastModified);
|
||||||
|
this.lastPacUpdateStamp = Date.now();
|
||||||
|
this.ifFirstInstall = false;
|
||||||
|
this.setAlarms();
|
||||||
|
this.setTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve([err, null, ...warns]);
|
||||||
|
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const ipsErrorPromise = new Promise(
|
||||||
|
(resolve, reject) => updatePacProxyIps(
|
||||||
|
resolve
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
Promise.all([pacSetPromise, ipsErrorPromise]).then(
|
||||||
|
([[pacErr, pacRes, ...pacWarns], ipsErr]) => {
|
||||||
|
|
||||||
|
if (pacErr && ipsErr) {
|
||||||
|
return cb(pacErr, pacRes);
|
||||||
|
}
|
||||||
|
const warns = pacWarns;
|
||||||
|
if (ipsErr) {
|
||||||
|
warns.push(ipsErr);
|
||||||
|
}
|
||||||
|
this.pushToStorageAsync(
|
||||||
|
(pushErr) => cb(pacErr || pushErr, null, ...warns)
|
||||||
|
);
|
||||||
|
|
||||||
|
},
|
||||||
|
cb
|
||||||
|
);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
_pacUpdatePeriodInMinutes: 12*60,
|
||||||
|
get pacUpdatePeriodInMinutes() {
|
||||||
|
|
||||||
|
return this._pacUpdatePeriodInMinutes;
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
setAlarms() {
|
||||||
|
|
||||||
|
let nextUpdateMoment = this.lastPacUpdateStamp
|
||||||
|
+ this._pacUpdatePeriodInMinutes*60*1000;
|
||||||
|
const now = Date.now();
|
||||||
|
if (nextUpdateMoment < now) {
|
||||||
|
nextUpdateMoment = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
'Next PAC update is scheduled on',
|
||||||
|
new Date(nextUpdateMoment).toLocaleString('ru-RU')
|
||||||
|
);
|
||||||
|
|
||||||
|
chrome.alarms.create(
|
||||||
|
this._periodicUpdateAlarmReason,
|
||||||
|
{
|
||||||
|
when: nextUpdateMoment,
|
||||||
|
periodInMinutes: this._pacUpdatePeriodInMinutes,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// ifAlarmTriggered. May be changed in the future.
|
||||||
|
return nextUpdateMoment === now;
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
installPacAsync(key, cb = throwIfError) {
|
||||||
|
|
||||||
|
console.log('Installing PAC...');
|
||||||
|
if (!key) {
|
||||||
|
throw new Error('Key must be defined.');
|
||||||
|
}
|
||||||
|
if (this.currentProviderKey !== key) {
|
||||||
|
return this.syncWithPacProviderAsync(key, cb);
|
||||||
|
}
|
||||||
|
console.log(key + ' already installed.');
|
||||||
|
cb();
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
clearPacAsync(cb = throwIfError) {
|
||||||
|
|
||||||
|
cb = asyncLogGroup('Cearing alarms and PAC...', cb);
|
||||||
|
chrome.alarms.clearAll(
|
||||||
|
() => chrome.proxy.settings.clear(
|
||||||
|
{},
|
||||||
|
chromified((err) => {
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
this.setCurrentPacProviderKey(null);
|
||||||
|
this.pushToStorageAsync(
|
||||||
|
() => handlers.updateControlState(cb)
|
||||||
|
);
|
||||||
|
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// ON EACH LAUNCH, STARTUP, RELOAD, UPDATE, ENABLE
|
||||||
|
chrome.storage.local.get(null, chromified( async (err, oldStorage) => {
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Event handlers that ALWAYS work (even if installation is not done
|
||||||
|
or failed).
|
||||||
|
E.g. install window may fail to open or be closed by user accidentally.
|
||||||
|
In such case extension _should_ try to work on default parameters.
|
||||||
|
*/
|
||||||
|
const antiCensorRu = window.apis.antiCensorRu;
|
||||||
|
|
||||||
|
chrome.alarms.onAlarm.addListener(
|
||||||
|
timeouted( (alarm) => {
|
||||||
|
|
||||||
|
if (alarm.name === antiCensorRu._periodicUpdateAlarmReason) {
|
||||||
|
console.log(
|
||||||
|
'Periodic PAC update triggered:',
|
||||||
|
new Date().toLocaleString('ru-RU')
|
||||||
|
);
|
||||||
|
antiCensorRu.syncWithPacProviderAsync(() => {/* swallow */});
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
);
|
||||||
|
console.log('Alarm listener installed. We won\\'t miss any PAC update.');
|
||||||
|
|
||||||
|
window.addEventListener('online', () => {
|
||||||
|
|
||||||
|
console.log('We are online, checking periodic updates...');
|
||||||
|
antiCensorRu.setAlarms();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Keep cooked...');
|
||||||
|
await new Promise((resolve) => window.apis.pacKitchen.keepCookedNowAsync(resolve));
|
||||||
|
|
||||||
|
console.log('Storage on init:', oldStorage);
|
||||||
|
antiCensorRu.ifFirstInstall = Object.keys(oldStorage).length === 0;
|
||||||
|
|
||||||
|
if (antiCensorRu.ifFirstInstall) {
|
||||||
|
// INSTALL
|
||||||
|
console.log('Installing...');
|
||||||
|
handlers.switch('on', 'ext-error');
|
||||||
|
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')
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
1. There is no way to check that chrome.runtime.onInstalled wasn't fired
|
||||||
|
except timeout.
|
||||||
|
Otherwise we could put storage migration code only there.
|
||||||
|
2. We have to check storage for migration before using it.
|
||||||
|
Better on each launch then on each pull.
|
||||||
|
*/
|
||||||
|
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
|
||||||
|
const ifUpdating = antiCensorRu.version !== oldStorage.version;
|
||||||
|
if (!ifUpdating) {
|
||||||
|
|
||||||
|
// LAUNCH, RELOAD, ENABLE
|
||||||
|
antiCensorRu.pacProviders = oldStorage.pacProviders;
|
||||||
|
console.log('Extension launched, reloaded or enabled.');
|
||||||
|
return resolve();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// UPDATE & MIGRATION
|
||||||
|
console.log('Updating from ', oldStorage.version, 'to', antiCensorRu.version);
|
||||||
|
const key = antiCensorRu._currentPacProviderKey;
|
||||||
|
if (key !== null) {
|
||||||
|
const ifVeryOld = !Object.keys(antiCensorRu.pacProviders).includes(key);
|
||||||
|
if (ifVeryOld) {
|
||||||
|
antiCensorRu._currentPacProviderKey = 'Антизапрет';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
antiCensorRu.pushToStorageAsync(() => {
|
||||||
|
|
||||||
|
console.log('Extension updated.');
|
||||||
|
resolve();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
if (antiCensorRu.getPacProvider()) {
|
||||||
|
antiCensorRu.setAlarms();
|
||||||
|
}
|
||||||
|
antiCensorRu.setTitle();
|
||||||
|
|
||||||
|
/*
|
||||||
|
History of Changes to Storage (Migration Guide)
|
||||||
|
-----------------------------------------------
|
||||||
|
Version 0.0.0.17:
|
||||||
|
* Remove "Антиценз".
|
||||||
|
* Rename "Оба_и_на_свитчах" to "Антицензорити"
|
||||||
|
* Add provider.label and provider.desc.
|
||||||
|
Version 0.0.0.10:
|
||||||
|
* Add this.version.
|
||||||
|
* Change PacProvider.proxyIps from {ip -> Boolean} to {ip -> hostname}.
|
||||||
|
Version 0.0.0.8-9:
|
||||||
|
* Change storage.ifNotInstalled to storage.ifFirstInstall.
|
||||||
|
* Add storage.lastPacUpdateStamp.
|
||||||
|
**/
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
|
}
|
|
@ -168,10 +168,10 @@ textarea {
|
||||||
min-height: 2em;
|
min-height: 2em;
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
outline: none;
|
outline: none;
|
||||||
<if expr="is_win or is_macosx or is_ios">
|
/*<if expr="is_win or is_macosx or is_ios">*
|
||||||
/* For better alignment between adjacent buttons and inputs. */
|
/* For better alignment between adjacent buttons and inputs. */
|
||||||
padding-bottom: 4px;
|
padding-bottom: 4px;
|
||||||
</if>
|
/*</if>*/
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type='search'] {
|
input[type='search'] {
|
||||||
|
|
|
@ -36,7 +36,7 @@ export default function getApp(theState) {
|
||||||
|
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
status: msg,
|
status: msg || 'Хорошего настроения Вам!',
|
||||||
},
|
},
|
||||||
cb
|
cb
|
||||||
);
|
);
|
||||||
|
@ -79,7 +79,8 @@ export default function getApp(theState) {
|
||||||
headers: new Headers(headers),
|
headers: new Headers(headers),
|
||||||
};
|
};
|
||||||
|
|
||||||
const ghUrl = `https://api.github.com/repos/anticensority/chromium-extension/issues/10/comments${query}`;
|
//const ghUrl = `https://api.github.com/repos/anticensority/chromium-extension/issues/10/comments${query}`;
|
||||||
|
const ghUrl = `https://api.github.com/repos/anticensority/for-testing/issues/1/comments${query}`;
|
||||||
|
|
||||||
const [error, comments, etag] = await fetch(
|
const [error, comments, etag] = await fetch(
|
||||||
ghUrl,
|
ghUrl,
|
||||||
|
@ -156,7 +157,7 @@ export default function getApp(theState) {
|
||||||
|
|
||||||
})();
|
})();
|
||||||
if (!ifNewsWasSet) {
|
if (!ifNewsWasSet) {
|
||||||
this.setStatusTo('Хорошего настроения Вам!');
|
this.setStatusTo();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -206,7 +207,7 @@ export default function getApp(theState) {
|
||||||
};
|
};
|
||||||
|
|
||||||
let messageHtml = err ? errToHtmlMessage(err) : '';
|
let messageHtml = err ? errToHtmlMessage(err) : '';
|
||||||
|
|
||||||
const warningHtml = warns
|
const warningHtml = warns
|
||||||
.filter((w) => w)
|
.filter((w) => w)
|
||||||
.map(
|
.map(
|
||||||
|
|
|
@ -65,7 +65,7 @@ export default function getExcEditor(theState) {
|
||||||
return class ExcEditor extends Component {
|
return class ExcEditor extends Component {
|
||||||
|
|
||||||
modsToOpts(pacMods) {
|
modsToOpts(pacMods) {
|
||||||
|
|
||||||
return Object.keys(pacMods.exceptions || {}).sort().map(
|
return Object.keys(pacMods.exceptions || {}).sort().map(
|
||||||
(excHost) => [excHost, pacMods.exceptions[excHost]]
|
(excHost) => [excHost, pacMods.exceptions[excHost]]
|
||||||
);
|
);
|
||||||
|
@ -100,7 +100,7 @@ export default function getExcEditor(theState) {
|
||||||
},
|
},
|
||||||
{}),
|
{}),
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isHostValid(host) {
|
isHostValid(host) {
|
||||||
|
|
|
@ -41,7 +41,7 @@ export default function getInfoLi() {
|
||||||
.desc {
|
.desc {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
color: var(--ribbon-color);
|
color: var(--ribbon-color);
|
||||||
cursor: help;
|
cursor: help;
|
||||||
padding-left: 0.3em;
|
padding-left: 0.3em;
|
||||||
}
|
}
|
||||||
.tooltip {
|
.tooltip {
|
||||||
|
|
|
@ -38,7 +38,8 @@ export default function getMain(theState) {
|
||||||
|
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
ifModsChangesStashed: false,
|
ifModsChangesAreStashed: false,
|
||||||
|
ifModsChangesAreValid: true,
|
||||||
catToOrderedMods: {
|
catToOrderedMods: {
|
||||||
'general': props.apis.pacKitchen.getOrderedConfigs('general'),
|
'general': props.apis.pacKitchen.getOrderedConfigs('general'),
|
||||||
'ownProxies': props.apis.pacKitchen.getOrderedConfigs('ownProxies'),
|
'ownProxies': props.apis.pacKitchen.getOrderedConfigs('ownProxies'),
|
||||||
|
@ -58,24 +59,46 @@ export default function getMain(theState) {
|
||||||
|
|
||||||
handleModApply(that) {
|
handleModApply(that) {
|
||||||
|
|
||||||
|
if (!that.state.ifModsChangesAreValid) {
|
||||||
|
// Error message must be already set by a config validator.
|
||||||
|
return;
|
||||||
|
}
|
||||||
const modsMutated = that.props.apis.pacKitchen.getPacMods();
|
const modsMutated = that.props.apis.pacKitchen.getPacMods();
|
||||||
const newMods = that.getAllMods().reduce((_, conf) => {
|
const newMods = that.getAllMods().reduce((_, conf) => {
|
||||||
|
|
||||||
modsMutated[conf.key] = conf.value;
|
modsMutated[conf.key] = conf.value;
|
||||||
return modsMutated;
|
return modsMutated;
|
||||||
|
|
||||||
}, modsMutated/*< Needed for index 0*/);
|
}, modsMutated/* Needed for index 0*/);
|
||||||
that.props.funs.conduct(
|
that.props.funs.conduct(
|
||||||
'Применяем настройки...',
|
'Применяем настройки...',
|
||||||
(cb) => that.props.apis.pacKitchen.keepCookedNowAsync(newMods, cb),
|
(cb) => that.props.apis.pacKitchen.keepCookedNowAsync(newMods, cb),
|
||||||
'Настройки применены.',
|
'Настройки применены.',
|
||||||
() => that.setState({ifModsChangesStashed: false})
|
() => that.setState({
|
||||||
|
ifModsChangesAreStashed: false,
|
||||||
|
ifModsChangesAreValid: true,
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleModChange({targetConf, targetIndex, newValue}) {
|
handleModChange({ifValid, targetConf, targetIndex, newValue}) {
|
||||||
|
|
||||||
|
if (ifValid === undefined) {
|
||||||
|
// User input some data, but not validated yet.
|
||||||
|
this.setState({
|
||||||
|
// Make apply button clickable when user only starts writing.
|
||||||
|
ifModsChangesAreStashed: true,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ifValid === false) {
|
||||||
|
this.setState({
|
||||||
|
ifModsChangesAreValid: false,
|
||||||
|
ifModsChangesAreStashed: true,
|
||||||
|
})
|
||||||
|
return;
|
||||||
|
}
|
||||||
const oldCats = this.state.catToOrderedMods;
|
const oldCats = this.state.catToOrderedMods;
|
||||||
const newCats = Object.keys(this.state.catToOrderedMods).reduce((acc, cat) => {
|
const newCats = Object.keys(this.state.catToOrderedMods).reduce((acc, cat) => {
|
||||||
|
|
||||||
|
@ -96,10 +119,11 @@ export default function getMain(theState) {
|
||||||
return acc;
|
return acc;
|
||||||
|
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
catToOrderedMods: newCats,
|
catToOrderedMods: newCats,
|
||||||
ifModsChangesStashed: true,
|
ifModsChangesAreStashed: true,
|
||||||
|
ifModsChangesAreValid: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -108,7 +132,7 @@ export default function getMain(theState) {
|
||||||
|
|
||||||
const applyModsEl = createElement(ApplyMods, Object.assign({}, props,
|
const applyModsEl = createElement(ApplyMods, Object.assign({}, props,
|
||||||
{
|
{
|
||||||
ifInputsDisabled: !this.state.ifModsChangesStashed || props.ifInputsDisabled,
|
ifInputsDisabled: !this.state.ifModsChangesAreStashed || props.ifInputsDisabled,
|
||||||
onClick: linkEvent(this, this.handleModApply),
|
onClick: linkEvent(this, this.handleModApply),
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
|
@ -7,7 +7,7 @@ export default function getModList(theState) {
|
||||||
|
|
||||||
const InfoLi = getInfoLi(theState);
|
const InfoLi = getInfoLi(theState);
|
||||||
|
|
||||||
return class ModList extends Component {
|
return class ModList extends Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
|
||||||
|
@ -26,17 +26,18 @@ export default function getModList(theState) {
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
if (ifChecked === false || !confMeta.ifChild) {
|
if (ifChecked === false || !confMeta.ifChild) {
|
||||||
this.handleNewValue(confMeta, ifChecked);
|
this.handleNewValue(true, confMeta, ifChecked);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleNewValue({ conf, index }, newValue) {
|
handleNewValue(ifValid, { conf, index }, newValue) {
|
||||||
|
|
||||||
this.props.onConfChanged({
|
this.props.onConfChanged({
|
||||||
targetConf: conf,
|
targetConf: conf,
|
||||||
targetIndex: index,
|
targetIndex: index,
|
||||||
newValue: newValue,
|
newValue: newValue,
|
||||||
|
ifValid,
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -54,7 +55,7 @@ export default function getModList(theState) {
|
||||||
const child = ifMayHaveChild && this.state.checks[index]
|
const child = ifMayHaveChild && this.state.checks[index]
|
||||||
&& createElement(
|
&& createElement(
|
||||||
props.childrenOfMod[conf.key],
|
props.childrenOfMod[conf.key],
|
||||||
Object.assign({}, props, {conf, onNewValue: (newValue) => this.handleNewValue(confMeta, newValue)})
|
Object.assign({}, props, {conf, onNewValue: (ifValid, newValue) => this.handleNewValue(ifValid, confMeta, newValue)})
|
||||||
);
|
);
|
||||||
|
|
||||||
return (<InfoLi
|
return (<InfoLi
|
||||||
|
|
|
@ -88,7 +88,7 @@ export default function getPacChooser(theState) {
|
||||||
|
|
||||||
radioClickHandler(event) {
|
radioClickHandler(event) {
|
||||||
|
|
||||||
const checkChosenProvider = () =>
|
const checkChosenProvider = () =>
|
||||||
this.setState({ chosenPacName: this.getCurrentProviderId() });
|
this.setState({ chosenPacName: this.getCurrentProviderId() });
|
||||||
|
|
||||||
const pacKey = event.target.id;
|
const pacKey = event.target.id;
|
||||||
|
|
|
@ -103,7 +103,7 @@ export default function getProxyEditor(theState) {
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
table.editor .add {
|
table.editor .add {
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
}
|
}
|
||||||
table.editor .export {
|
table.editor .export {
|
||||||
/*padding-right: 2px;*/
|
/*padding-right: 2px;*/
|
||||||
|
@ -160,7 +160,7 @@ export default function getProxyEditor(theState) {
|
||||||
};
|
};
|
||||||
const splitBySemi = (proxyString) => proxyString.replace(/#.*$/mg, '').trim().split(/\s*;\s*/g).filter((s) => s);
|
const splitBySemi = (proxyString) => proxyString.replace(/#.*$/mg, '').trim().split(/\s*;\s*/g).filter((s) => s);
|
||||||
const joinBySemi = (strs) => strs.join(';\n') + ';';
|
const joinBySemi = (strs) => strs.join(';\n') + ';';
|
||||||
const normilizeProxyString = (str) => joinBySemi(splitBySemi(str));
|
const normalizeProxyString = (str) => joinBySemi(splitBySemi(str));
|
||||||
|
|
||||||
const PROXY_TYPE_LABEL_PAIRS = [['PROXY', 'PROXY/HTTP'],['HTTPS'],['SOCKS4'],['SOCKS5'],['SOCKS']];
|
const PROXY_TYPE_LABEL_PAIRS = [['PROXY', 'PROXY/HTTP'],['HTTPS'],['SOCKS4'],['SOCKS5'],['SOCKS']];
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ export default function getProxyEditor(theState) {
|
||||||
|
|
||||||
const newValue = `${that.props.proxyStringRaw}; ${type} ${hostname}:${port}`
|
const newValue = `${that.props.proxyStringRaw}; ${type} ${hostname}:${port}`
|
||||||
.trim().replace(/(\s*;\s*)+/, '; ');
|
.trim().replace(/(\s*;\s*)+/, '; ');
|
||||||
that.props.setProxyStringRaw(newValue);
|
that.props.setProxyStringRaw(true, newValue);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +232,7 @@ export default function getProxyEditor(theState) {
|
||||||
const proxyStrings = splitBySemi(that.props.proxyStringRaw);
|
const proxyStrings = splitBySemi(that.props.proxyStringRaw);
|
||||||
proxyStrings.splice(index, 1);
|
proxyStrings.splice(index, 1);
|
||||||
|
|
||||||
that.props.setProxyStringRaw( joinBySemi(proxyStrings) );
|
that.props.setProxyStringRaw(true, joinBySemi(proxyStrings) );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,8 +245,8 @@ export default function getProxyEditor(theState) {
|
||||||
const proxyStrings = splitBySemi(that.props.proxyStringRaw);
|
const proxyStrings = splitBySemi(that.props.proxyStringRaw);
|
||||||
proxyStrings.splice(index - 1, 2, proxyStrings[index], proxyStrings[index-1]);
|
proxyStrings.splice(index - 1, 2, proxyStrings[index], proxyStrings[index-1]);
|
||||||
|
|
||||||
that.props.setProxyStringRaw( joinBySemi(proxyStrings) );
|
that.props.setProxyStringRaw(true, joinBySemi(proxyStrings) );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit(that, event) {
|
handleSubmit(that, event) {
|
||||||
|
@ -366,11 +366,17 @@ export default function getProxyEditor(theState) {
|
||||||
|
|
||||||
super(props);
|
super(props);
|
||||||
this.state = getInitState();
|
this.state = getInitState();
|
||||||
|
this.resetState = linkEvent(this, this.resetState);
|
||||||
|
this.showApply = linkEvent(undefined, props.setProxyStringRaw);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resetState(that, event) {
|
resetState(that, event) {
|
||||||
|
|
||||||
|
that.props.setProxyStringRaw(true, that.props.proxyStringRaw);
|
||||||
|
if (that.state.ifHasErrors) {
|
||||||
|
that.props.funs.setStatusTo(''); // Clear errors
|
||||||
|
}
|
||||||
that.setState(getInitState());
|
that.setState(getInitState());
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
|
@ -417,19 +423,9 @@ export default function getProxyEditor(theState) {
|
||||||
|
|
||||||
handleModeSwitch(that, event) {
|
handleModeSwitch(that, event) {
|
||||||
|
|
||||||
if (that.state.stashedExports !== false) {
|
if (that.state.ifHasErrors) {
|
||||||
const errors = that.getErrorsInStashedExports();
|
return;
|
||||||
if (errors) {
|
|
||||||
that.setState({ifHasErrors: true});
|
|
||||||
that.props.funs.showErrors(...errors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
that.props.setProxyStringRaw(that.state.stashedExports);
|
|
||||||
}
|
}
|
||||||
that.setState({
|
|
||||||
stashedExports: false,
|
|
||||||
ifHasErrors: false,
|
|
||||||
});
|
|
||||||
that.props.onSwitch();
|
that.props.onSwitch();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -437,7 +433,20 @@ export default function getProxyEditor(theState) {
|
||||||
handleTextareaChange(that, event) {
|
handleTextareaChange(that, event) {
|
||||||
|
|
||||||
that.setState({
|
that.setState({
|
||||||
stashedExports: normilizeProxyString(event.target.value),
|
stashedExports: normalizeProxyString(event.target.value),
|
||||||
|
});
|
||||||
|
const errors = that.getErrorsInStashedExports();
|
||||||
|
if (errors) {
|
||||||
|
that.props.setProxyStringRaw(false);
|
||||||
|
that.setState({ifHasErrors: true});
|
||||||
|
that.props.funs.showErrors(...errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// No errors.
|
||||||
|
that.props.setProxyStringRaw(true, that.state.stashedExports);
|
||||||
|
that.setState({
|
||||||
|
stashedExports: false,
|
||||||
|
ifHasErrors: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -451,8 +460,6 @@ export default function getProxyEditor(theState) {
|
||||||
|
|
||||||
render(props) {
|
render(props) {
|
||||||
|
|
||||||
const reset = linkEvent(this, this.resetState);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={linkEvent(this, this.handleSubmit)}>
|
<form onSubmit={linkEvent(this, this.handleSubmit)}>
|
||||||
<table class={scopedCss.editor + ' ' + scopedCss.exportsEditor}>
|
<table class={scopedCss.editor + ' ' + scopedCss.exportsEditor}>
|
||||||
|
@ -463,8 +470,8 @@ export default function getProxyEditor(theState) {
|
||||||
this.state.stashedExports === false
|
this.state.stashedExports === false
|
||||||
? 'Комментарии вырезаются!'
|
? 'Комментарии вырезаются!'
|
||||||
: (this.state.ifHasErrors
|
: (this.state.ifHasErrors
|
||||||
? (<span><a href="" onClick={reset}>Сбросьте изменения</a> или поправьте</span>)
|
? (<span><a href="" onClick={this.resetState} style="color: red">Сбросьте изменения</a> или поправьте</span>)
|
||||||
: (<a href="" onClick={reset}>Сбросить изменения</a>)
|
: (<a href="" onClick={this.resetState}>Сбросить изменения</a>)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</th>
|
</th>
|
||||||
|
@ -484,6 +491,7 @@ SOCKS5 localhost:9150; # Tor Browser
|
||||||
HTTPS 11.22.33.44:3143;
|
HTTPS 11.22.33.44:3143;
|
||||||
PROXY foobar.com:8080; # Not HTTP!`.trim()}
|
PROXY foobar.com:8080; # Not HTTP!`.trim()}
|
||||||
onChange={linkEvent(this, this.handleTextareaChange)}
|
onChange={linkEvent(this, this.handleTextareaChange)}
|
||||||
|
onFocus={this.showApply}
|
||||||
value={
|
value={
|
||||||
this.state.stashedExports !== false
|
this.state.stashedExports !== false
|
||||||
? this.state.stashedExports
|
? this.state.stashedExports
|
||||||
|
@ -525,10 +533,11 @@ PROXY foobar.com:8080; # Not HTTP!`.trim()}
|
||||||
this.state = {
|
this.state = {
|
||||||
proxyStringRaw: newValue,
|
proxyStringRaw: newValue,
|
||||||
ifExportsMode: false,
|
ifExportsMode: false,
|
||||||
|
ifValid: true,
|
||||||
};
|
};
|
||||||
this.handleSwitch = () => this.setState({ifExportsMode: !this.state.ifExportsMode});
|
this.handleSwitch = () => this.setState({ifExportsMode: !this.state.ifExportsMode});
|
||||||
waitingTillMount.push(newValue); // Wait till mount or eat bugs.
|
waitingTillMount.push(newValue); // Wait till mount or eat bugs.
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
@ -546,12 +555,12 @@ PROXY foobar.com:8080; # Not HTTP!`.trim()}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mayEmitNewValue(oldValue, newValue) {
|
mayEmitNewValue(oldValue, newValue, ifValidityChanged) {
|
||||||
|
|
||||||
if ( // Reject: 1) both `false` OR 2) both `===`.
|
if ( // Reject: 1) both `false` OR 2) both `===`.
|
||||||
( Boolean(oldValue) || Boolean(newValue) ) && oldValue !== newValue
|
ifValidityChanged || ( Boolean(oldValue) || Boolean(newValue) ) && oldValue !== newValue
|
||||||
) {
|
) {
|
||||||
this.props.onNewValue(newValue);
|
this.props.onNewValue(this.state.ifValid, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -561,16 +570,25 @@ PROXY foobar.com:8080; # Not HTTP!`.trim()}
|
||||||
const props = Object.assign({
|
const props = Object.assign({
|
||||||
proxyStringRaw: this.state.proxyStringRaw,
|
proxyStringRaw: this.state.proxyStringRaw,
|
||||||
onSwitch: this.handleSwitch,
|
onSwitch: this.handleSwitch,
|
||||||
setProxyStringRaw: (newValue) => {
|
setProxyStringRaw: (ifValid, newValue) => {
|
||||||
|
|
||||||
|
const ifValidityChanged = this.state.ifValid !== ifValid;
|
||||||
|
if (!ifValid) {
|
||||||
|
if (ifValidityChanged || ifValid === undefined) {
|
||||||
|
this.props.onNewValue(ifValid);
|
||||||
|
this.setState({ ifValid });
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const oldValue = this.state.proxyStringRaw;
|
const oldValue = this.state.proxyStringRaw;
|
||||||
localStorage.setItem(UI_RAW, newValue);
|
localStorage.setItem(UI_RAW, newValue);
|
||||||
this.setState({proxyStringRaw: newValue});
|
this.setState({proxyStringRaw: newValue, ifValid});
|
||||||
this.mayEmitNewValue(oldValue, newValue);
|
this.mayEmitNewValue(oldValue, newValue, ifValidityChanged);
|
||||||
|
|
||||||
},
|
},
|
||||||
}, originalProps);
|
}, originalProps);
|
||||||
|
|
||||||
return this.state.ifExportsMode
|
return this.state.ifExportsMode
|
||||||
? createElement(ExportsEditor, props)
|
? createElement(ExportsEditor, props)
|
||||||
: createElement(TabledEditor, props);
|
: createElement(TabledEditor, props);
|
||||||
|
|
|
@ -2,6 +2,20 @@
|
||||||
|
|
||||||
const commonContext = {
|
const commonContext = {
|
||||||
version: '1.3',
|
version: '1.3',
|
||||||
|
anticensorityPacUrls: [
|
||||||
|
// 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',
|
||||||
|
// 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',
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.contexts = {};
|
exports.contexts = {};
|
||||||
|
@ -26,3 +40,14 @@ exports.contexts.mini = Object.assign({}, commonContext, {
|
||||||
scripts_8x: '',
|
scripts_8x: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
exports.contexts.beta = Object.assign({}, commonContext, {
|
||||||
|
anticensorityPacUrls: ['https://rebrand.ly/ac-beta-pac'],
|
||||||
|
version: '1.5',
|
||||||
|
versionSuffix: '',
|
||||||
|
nameSuffixEn: ' FOR TESTING',
|
||||||
|
nameSuffixRu: ' ДЛЯ ТЕСТОВ',
|
||||||
|
extra_permissions: ', "webRequest", "webNavigation"',
|
||||||
|
persistent: '',
|
||||||
|
scripts_2x: ', "20-ip-to-host-api.js"',
|
||||||
|
scripts_8x: ', "80-error-menu.js", "83-last-errors.js", "85-block-informer.js"',
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in New Issue
Block a user