mirror of
https://github.com/anticensority/runet-censorship-bypass.git
synced 2024-11-24 02:13:43 +03:00
Add help hints, warnings, restyle
This commit is contained in:
parent
797ef68397
commit
fc1b0fcae2
|
@ -1,5 +1,18 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const IF_DEBUG = true;
|
||||||
|
|
||||||
|
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 = {
|
window.utils = {
|
||||||
|
|
||||||
areSettingsNotControlledFor(details) {
|
areSettingsNotControlledFor(details) {
|
||||||
|
|
|
@ -82,8 +82,7 @@
|
||||||
|
|
||||||
const json = JSON.stringify(err, errorJsonReplacer, 0);
|
const json = JSON.stringify(err, errorJsonReplacer, 0);
|
||||||
openAndFocus(
|
openAndFocus(
|
||||||
//'https://rebrand.ly/ac-error/?' + btoa(encodeURIComponent(json))
|
'http://rebrand.ly/ac-error/?json=' + encodeURIComponent(json) + '&version=' + chrome.runtime.getManifest().version
|
||||||
'https://anticensorship-russia.tk/error/?' + json
|
|
||||||
);
|
);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
@ -137,8 +136,11 @@
|
||||||
|
|
||||||
mayNotifyVoid(
|
mayNotifyVoid(
|
||||||
id, title, errOrMessage,
|
id, title, errOrMessage,
|
||||||
icon = 'default-128.png',
|
{
|
||||||
context = extName
|
icon = 'default-128.png',
|
||||||
|
context = extName,
|
||||||
|
ifSticky = true
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
|
|
||||||
if ( !this.isOn(id) ) {
|
if ( !this.isOn(id) ) {
|
||||||
|
@ -152,7 +154,7 @@
|
||||||
title: title,
|
title: title,
|
||||||
message: message,
|
message: message,
|
||||||
contextMessage: context,
|
contextMessage: context,
|
||||||
requireInteraction: true,
|
requireInteraction: ifSticky,
|
||||||
type: 'basic',
|
type: 'basic',
|
||||||
iconUrl: './icons/' + icon,
|
iconUrl: './icons/' + icon,
|
||||||
appIconMaskUrl: './icons/default-mask-128.png',
|
appIconMaskUrl: './icons/default-mask-128.png',
|
||||||
|
@ -168,7 +170,7 @@
|
||||||
|
|
||||||
console.warn(name + ':GLOBAL ERROR', errEvent);
|
console.warn(name + ':GLOBAL ERROR', errEvent);
|
||||||
this.mayNotifyVoid('ext-error', 'Ошибка расширения', errEvent,
|
this.mayNotifyVoid('ext-error', 'Ошибка расширения', errEvent,
|
||||||
'ext-error-128.png');
|
{icon: 'ext-error-128.png'});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -230,7 +232,7 @@
|
||||||
// TOOD: add "view pac script at this line" button.
|
// TOOD: add "view pac script at this line" button.
|
||||||
handlers.mayNotifyVoid('pac-error', 'Ошибка PAC!',
|
handlers.mayNotifyVoid('pac-error', 'Ошибка PAC!',
|
||||||
details.error + '\n' + details.details,
|
details.error + '\n' + details.details,
|
||||||
'pac-error-128.png'
|
{icon: 'pac-error-128.png'}
|
||||||
);
|
);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -244,7 +246,7 @@
|
||||||
noCon,
|
noCon,
|
||||||
chrome.i18n.getMessage('noControl'),
|
chrome.i18n.getMessage('noControl'),
|
||||||
chrome.i18n.getMessage('which'),
|
chrome.i18n.getMessage('which'),
|
||||||
'no-control-128.png'
|
{icon:'no-control-128.png', ifSticky: false}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
chrome.notifications.clear( noCon );
|
chrome.notifications.clear( noCon );
|
||||||
|
|
|
@ -21,22 +21,22 @@
|
||||||
|
|
||||||
{ // Private namespace starts.
|
{ // Private namespace starts.
|
||||||
|
|
||||||
function mandatory() {
|
const mandatory = function mandatory() {
|
||||||
|
|
||||||
throw new TypeError('Missing required argument. ' +
|
throw new TypeError('Missing required argument. ' +
|
||||||
'Be explicit if you swallow errors.');
|
'Be explicit if you swallow errors.');
|
||||||
|
|
||||||
}
|
};
|
||||||
|
|
||||||
function throwIfError(err) {
|
const throwIfError = function throwIfError(err) {
|
||||||
|
|
||||||
if(err) {
|
if(err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
};
|
||||||
|
|
||||||
function asyncLogGroup(...args) {
|
const asyncLogGroup = function asyncLogGroup(...args) {
|
||||||
|
|
||||||
const cb = args.pop();
|
const cb = args.pop();
|
||||||
if(!(cb && typeof(cb) === 'function')) {
|
if(!(cb && typeof(cb) === 'function')) {
|
||||||
|
@ -51,13 +51,13 @@
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
};
|
||||||
|
|
||||||
function checkChromeError(betterStack) {
|
const checkChromeError = function checkChromeError(betterStack) {
|
||||||
|
|
||||||
// Chrome API calls your cb in a context different from the point of API
|
// Chrome API calls your cb in a context different from the point of API
|
||||||
// method invokation.
|
// method invokation.
|
||||||
const err = chrome.runtime.lastError || chrome.extension.lastError || null;
|
const err = chrome.runtime.lastError || chrome.extension.lastError;
|
||||||
if (err) {
|
if (err) {
|
||||||
const args = ['API returned error:', err];
|
const args = ['API returned error:', err];
|
||||||
if (betterStack) {
|
if (betterStack) {
|
||||||
|
@ -67,9 +67,9 @@
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
}
|
};
|
||||||
|
|
||||||
function chromified(cb = mandatory(), ...replaceArgs) {
|
const chromified = function chromified(cb = mandatory(), ...replaceArgs) {
|
||||||
|
|
||||||
const stack = (new Error()).stack;
|
const stack = (new Error()).stack;
|
||||||
// Take error first callback and convert it to chrome api callback.
|
// Take error first callback and convert it to chrome api callback.
|
||||||
|
@ -84,57 +84,355 @@
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
};
|
||||||
|
|
||||||
|
class Clarification {
|
||||||
|
|
||||||
|
constructor(message = mandatory(), prevClarification) {
|
||||||
|
|
||||||
|
this.message = message;
|
||||||
|
if (prevClarification) {
|
||||||
|
this.prev = prevClarification;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const clarify = function clarify(err = mandatory(), message = mandatory(), {data} = {}) {
|
||||||
|
|
||||||
|
err.clarification = new Clarification(message, err.clarification);
|
||||||
|
if (data) {
|
||||||
|
err.clarification.data = data;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class Warning {
|
||||||
|
|
||||||
|
constructor(message) {
|
||||||
|
|
||||||
|
clarify(this, message);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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}, () => {
|
||||||
|
|
||||||
|
const err = checkChromeError();
|
||||||
|
if (err) {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
chrome.proxy.settings.get({}, (details) => {
|
||||||
|
|
||||||
|
if ( window.utils.areSettingsNotControlledFor( details ) ) {
|
||||||
|
|
||||||
|
console.warn('Failed, other extension is in control.');
|
||||||
|
return cb(
|
||||||
|
null, null,
|
||||||
|
[new Warning( window.utils.messages.whichExtensionHtml() )]
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
console.log('Successfuly set PAC in proxy settings..');
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const clarifyErrorThen = function clarifyFetchErrorThen(message, cb) {
|
||||||
|
|
||||||
|
return (err, ...args) => cb( clarify(err || {}, message), ...args );
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const clarifyFetchErrorThen = (cb) => clarifyErrorThen('Что-то не так с сетью, проверьте соединение.', cb);
|
||||||
|
|
||||||
|
const ifModifiedSince = function ifModifiedSince(url = mandatory(), lastModified = mandatory(), cb = mandatory()) {
|
||||||
|
|
||||||
|
const wasModified = new Date(0).toUTCString();
|
||||||
|
const notModifiedCode = 304;
|
||||||
|
fetch(url, {
|
||||||
|
method: 'HEAD',
|
||||||
|
headers: new Headers({
|
||||||
|
'If-Modified-Since': lastModified
|
||||||
|
})
|
||||||
|
}).then(
|
||||||
|
(res) => {
|
||||||
|
cb(
|
||||||
|
null,
|
||||||
|
res.status === notModifiedCode ?
|
||||||
|
false :
|
||||||
|
(res.headers.get('Last-Modified') || wasModified)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
clarifyFetchErrorThen((err) => cb(err, wasModified))
|
||||||
|
);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const httpGet = function httpGet(url, cb = mandatory()) {
|
||||||
|
|
||||||
|
const start = Date.now();
|
||||||
|
fetch(url, {cache: 'no-store'}).then(
|
||||||
|
(res) => {
|
||||||
|
|
||||||
|
const textCb =
|
||||||
|
(err) => res.text().then( (text) => cb(err, text), cb );
|
||||||
|
|
||||||
|
const status = res.status;
|
||||||
|
if ( !( status >= 200 && status < 300 || status === 304 ) ) {
|
||||||
|
return textCb(
|
||||||
|
clarify(
|
||||||
|
res,
|
||||||
|
'Получен ответ с неудачным HTTP-кодом ' + status + '.'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('GETed with success:', url, Date.now() - start);
|
||||||
|
textCb();
|
||||||
|
|
||||||
|
},
|
||||||
|
clarifyFetchErrorThen(cb)
|
||||||
|
);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const getIpsFor = function getIpsFor(host = mandatory(), cb = mandatory()) {
|
||||||
|
|
||||||
|
const types = [1, 28];
|
||||||
|
const promises = types.map(
|
||||||
|
(type) => new Promise((resolve) =>
|
||||||
|
httpGet(
|
||||||
|
'https://dns.google.com/resolve?type=' + type + '&name=' + host,
|
||||||
|
(err, res) => {
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
try {
|
||||||
|
res = JSON.parse(res);
|
||||||
|
console.log('Json parsed.');
|
||||||
|
if (err || res.Status) {
|
||||||
|
const msg = ['Answer', 'Comment', 'Status']
|
||||||
|
.filter( (prop) => res[prop] )
|
||||||
|
.map( (prop) => prop + ': ' + JSON.stringify( res[prop] ) )
|
||||||
|
.join(', \n');
|
||||||
|
clarify(err, 'Сервер (json): ' + msg, {data: res});
|
||||||
|
} else {
|
||||||
|
res = res.Answer || [];
|
||||||
|
res = res.filter(
|
||||||
|
(record) => types.includes(record.type)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
err = clarify(e, 'Сервер (текст): ' + res, err ? {data: err} : null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resolve([err, res]);
|
||||||
|
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
Promise.all(promises).then(
|
||||||
|
([[v4err, v4res], [v6err, v6res]]) => {
|
||||||
|
|
||||||
|
if(v4err) {
|
||||||
|
return cb(v4err, v4res);
|
||||||
|
}
|
||||||
|
const ips = v4res;
|
||||||
|
let warns = null;
|
||||||
|
if (!v6err) {
|
||||||
|
ips.push(...v6res);
|
||||||
|
} else {
|
||||||
|
warns = [v6err];
|
||||||
|
}
|
||||||
|
cb(null, ips, warns);
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const updatePacProxyIps = function updatePacProxyIps(provider, cb = throwIfError) {
|
||||||
|
|
||||||
|
cb = asyncLogGroup(
|
||||||
|
'Getting IP for '+ provider.proxyHosts.join(', ') + '...',
|
||||||
|
cb
|
||||||
|
);
|
||||||
|
let failure = {
|
||||||
|
errors: {},
|
||||||
|
};
|
||||||
|
let hostsProcessed = 0;
|
||||||
|
provider.proxyHosts.forEach(
|
||||||
|
(proxyHost) => getIpsFor(
|
||||||
|
proxyHost,
|
||||||
|
(err, ips, warns) => {
|
||||||
|
|
||||||
|
if (!err) {
|
||||||
|
provider.proxyIps = provider.proxyIps || {};
|
||||||
|
ips.forEach(
|
||||||
|
(ip) => provider.proxyIps[ip] = proxyHost
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (err || warns) {
|
||||||
|
failure.errors[proxyHost] = err || warns;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ++hostsProcessed < provider.proxyHosts.length ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// All hosts were processed.
|
||||||
|
const errorsCount = Object.keys(failure.errors).length;
|
||||||
|
if (!errorsCount) {
|
||||||
|
return cb();
|
||||||
|
}
|
||||||
|
clarify(
|
||||||
|
failure,
|
||||||
|
'Не удалось получить один или несколько IP адресов для' +
|
||||||
|
' прокси-серверов. Иконка для уведомления об обходе' +
|
||||||
|
' блокировок может не отображаться.'
|
||||||
|
);
|
||||||
|
errorsCount === hostsProcessed
|
||||||
|
? cb(failure)
|
||||||
|
: cb(null, null, [failure])
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const setPacScriptFromProviderAsync = function setPacScriptFromProviderAsync(
|
||||||
|
provider = mandatory(), lastModified = mandatory(), cb = throwIfError
|
||||||
|
) {
|
||||||
|
|
||||||
|
const pacUrl = provider.pacUrls[0];
|
||||||
|
cb = asyncLogGroup(
|
||||||
|
'Getting PAC script from provider...', pacUrl,
|
||||||
|
cb
|
||||||
|
);
|
||||||
|
|
||||||
|
ifModifiedSince(pacUrl, lastModified, (err, newLastModified) => {
|
||||||
|
|
||||||
|
if (!newLastModified) {
|
||||||
|
return cb(
|
||||||
|
null,
|
||||||
|
{lastModified},
|
||||||
|
[new Warning('Ваш PAC-скрипт не нуждается в обновлении. Его дата: ' + lastModified)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Employ all urls, the latter are fallbacks for the former.
|
||||||
|
let pacDataPromise = Promise.reject();
|
||||||
|
for(const url of provider.pacUrls) {
|
||||||
|
|
||||||
|
pacDataPromise = pacDataPromise.catch(
|
||||||
|
(err) => new Promise(
|
||||||
|
(resolve, reject) => httpGet(
|
||||||
|
url,
|
||||||
|
(newErr, pacData) => newErr ? reject(newErr) : resolve(pacData)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pacDataPromise.then(
|
||||||
|
(pacData) => {
|
||||||
|
|
||||||
|
setPacAsync(
|
||||||
|
pacData,
|
||||||
|
(err, res) => cb(
|
||||||
|
err,
|
||||||
|
Object.assign(res || {}, {lastModified: newLastModified})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
},
|
||||||
|
clarifyErrorThen(
|
||||||
|
'Не удалось скачать PAC-скрипт с адресов: [ '
|
||||||
|
+ provider.pacUrls.join(' , ') + ' ].',
|
||||||
|
cb
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
window.apis.antiCensorRu = {
|
window.apis.antiCensorRu = {
|
||||||
|
|
||||||
version: chrome.runtime.getManifest().version,
|
version: chrome.runtime.getManifest().version,
|
||||||
|
|
||||||
|
throwAsync() { throw new Error('ABC') }, // TODO: delete
|
||||||
|
|
||||||
pacProviders: {
|
pacProviders: {
|
||||||
Антизапрет: {
|
Антизапрет: {
|
||||||
|
label: 'Антизапрет',
|
||||||
|
desc: 'Альтернативный PAC-скрипт от стороннего разработчика.' +
|
||||||
|
' Блокировка определяется по доменному имени,' +
|
||||||
|
' для некоторых провайдеров есть автоопредление.' +
|
||||||
|
' <br/> <a href="https://antizapret.prostovpn.org">Страница проекта</a>.',
|
||||||
|
|
||||||
pacUrls: ['https://antizapret.prostovpn.org/proxy.pac'],
|
pacUrls: ['https://antizapret.prostovpn.org/proxy.pac'],
|
||||||
proxyHosts: ['proxy.antizapret.prostovpn.org'],
|
proxyHosts: ['proxy.antizapret.prostovpn.org'],
|
||||||
proxyIps: {
|
proxyIps: {
|
||||||
'195.123.209.38': 'proxy.antizapret.prostovpn.org',
|
'195.123.209.38': 'proxy.antizapret.prostovpn.org',
|
||||||
'137.74.171.91': 'proxy.antizapret.prostovpn.org',
|
'137.74.171.91': 'proxy.antizapret.prostovpn.org',
|
||||||
'51.15.39.201': 'proxy.antizapret.prostovpn.org',
|
'51.15.39.201': 'proxy.antizapret.prostovpn.org',
|
||||||
'2a02:27ac::10': 'proxy.antizapret.prostovpn.org',
|
|
||||||
'2001:bc8:4700:2300::1:d07': 'proxy.antizapret.prostovpn.org',
|
'2001:bc8:4700:2300::1:d07': 'proxy.antizapret.prostovpn.org',
|
||||||
|
'2a02:27ac::10': 'proxy.antizapret.prostovpn.org',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Антиценз: {
|
Антицензорити: {
|
||||||
pacUrls: ['https://config.anticenz.org/proxy.pac'],
|
label: 'Антицензорити',
|
||||||
proxyHosts: ['gw2.anticenz.org'],
|
desc: 'Основной PAC-скрипт от автора расширения.' +
|
||||||
proxyIps: {
|
' Блокировка определятся по доменному имени или IP адресу. Работает на switch-ах.' +
|
||||||
'5.196.220.114': 'gw2.anticenz.org',
|
' <br/><a href="https://rebrand.ly/ac-wiki">Страница проекта</a>.',
|
||||||
},
|
|
||||||
},
|
|
||||||
Оба_и_на_свитчах: {
|
|
||||||
/*
|
/*
|
||||||
Don't use in system configs! Because Win does poor caching.
|
Don't use in system configs! Because Windows does poor caching.
|
||||||
Url is encoded to counter abuse.
|
Some urls are encoded to counter abuse.
|
||||||
Version: 0.17
|
Version: 0.17
|
||||||
*/
|
*/
|
||||||
pacUrls: [
|
pacUrls: [
|
||||||
// Cloud Flare
|
// Official, Cloud Flare with caching:
|
||||||
'\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\x74\x6b\x2f\x67\x65\x6e\x65\x72\x61\x74\x65\x64\x2d\x70\x61\x63\x2d\x73\x63\x72\x69\x70\x74\x73\x2f\x6f\x6e\x2d\x73\x77\x69\x74\x63\x68\x65\x73\x2d\x30\x2e\x31\x37\x2e\x70\x61\x63',
|
'https://anticensorship-russia.tk/generated-pac-scripts/anticensority.pac',
|
||||||
// GitHub
|
// GitHub.io:
|
||||||
'\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\x6f\x6e\x2d\x73\x77\x69\x74\x63\x68\x65\x73\x2d\x30\x2e\x31\x37\x2e\x70\x61\x63',
|
'\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',
|
||||||
// Google Drive
|
// 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',
|
||||||
|
// 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'],
|
'\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'],
|
||||||
proxyHosts: ['proxy.antizapret.prostovpn.org', 'gw2.anticenz.org'],
|
proxyHosts: ['proxy.antizapret.prostovpn.org'],
|
||||||
proxyIps: {
|
proxyIps: {
|
||||||
'195.123.209.38': 'proxy.antizapret.prostovpn.org',
|
'195.123.209.38': 'proxy.antizapret.prostovpn.org',
|
||||||
'137.74.171.91': 'proxy.antizapret.prostovpn.org',
|
'137.74.171.91': 'proxy.antizapret.prostovpn.org',
|
||||||
'51.15.39.201': 'proxy.antizapret.prostovpn.org',
|
'51.15.39.201': 'proxy.antizapret.prostovpn.org',
|
||||||
'2a02:27ac::10': 'proxy.antizapret.prostovpn.org',
|
|
||||||
'2001:bc8:4700:2300::1:d07': 'proxy.antizapret.prostovpn.org',
|
'2001:bc8:4700:2300::1:d07': 'proxy.antizapret.prostovpn.org',
|
||||||
'5.196.220.114': 'gw2.anticenz.org',
|
'2a02:27ac::10': 'proxy.antizapret.prostovpn.org',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
_currentPacProviderKey: 'Оба_и_на_свитчах',
|
_currentPacProviderKey: 'Антицензорити',
|
||||||
|
|
||||||
/* Is it the first time extension installed?
|
/* Is it the first time extension installed?
|
||||||
Do something, e.g. initiate PAC sync.
|
Do something, e.g. initiate PAC sync.
|
||||||
|
@ -181,7 +479,7 @@
|
||||||
return this._currentPacProviderKey;
|
return this._currentPacProviderKey;
|
||||||
|
|
||||||
},
|
},
|
||||||
setCurrentPacProviderKey(newKey, lastModified = new Date().toUTCString()) {
|
setCurrentPacProviderKey(newKey = mandatory(), lastModified = new Date().toUTCString()) {
|
||||||
|
|
||||||
this.mustBeKey(newKey);
|
this.mustBeKey(newKey);
|
||||||
this._currentPacProviderKey = newKey;
|
this._currentPacProviderKey = newKey;
|
||||||
|
@ -237,11 +535,7 @@
|
||||||
|
|
||||||
if (key === null) {
|
if (key === null) {
|
||||||
// No pac provider set.
|
// No pac provider set.
|
||||||
return cb({
|
return clarifyErrorThen('Сперва выберите PAC-провайдера.', cb);
|
||||||
clarification: {
|
|
||||||
message: 'Сперва выберите PAC-провайдера.',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const pacProvider = this.getPacProvider(key);
|
const pacProvider = this.getPacProvider(key);
|
||||||
|
@ -250,43 +544,40 @@
|
||||||
(resolve, reject) => setPacScriptFromProviderAsync(
|
(resolve, reject) => setPacScriptFromProviderAsync(
|
||||||
pacProvider,
|
pacProvider,
|
||||||
this.getLastModifiedForKey(key),
|
this.getLastModifiedForKey(key),
|
||||||
(err, res) => {
|
(err, res, warns) => {
|
||||||
|
|
||||||
if (res && res.ifPacSet) {
|
if (!err) {
|
||||||
this.setCurrentPacProviderKey(key, res.lastModified);
|
this.setCurrentPacProviderKey(key, res.lastModified);
|
||||||
this.lastPacUpdateStamp = Date.now();
|
this.lastPacUpdateStamp = Date.now();
|
||||||
this.ifFirstInstall = false;
|
this.ifFirstInstall = false;
|
||||||
this.setAlarms();
|
this.setAlarms();
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve([err, res]);
|
resolve([err, null, warns]);
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const ipsPromise = new Promise(
|
const ipsErrorPromise = new Promise(
|
||||||
(resolve, reject) => updatePacProxyIps(
|
(resolve, reject) => updatePacProxyIps(
|
||||||
pacProvider,
|
pacProvider,
|
||||||
(ipsError) => {
|
resolve
|
||||||
|
|
||||||
if (ipsError && ipsError.clarification) {
|
|
||||||
ipsError.clarification.ifNotCritical = true;
|
|
||||||
}
|
|
||||||
resolve([ipsError]);
|
|
||||||
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
Promise.all([pacSetPromise, ipsPromise]).then(
|
Promise.all([pacSetPromise, ipsErrorPromise]).then(
|
||||||
([[pacErr, pacRes], [ipsErr]]) => {
|
([[pacErr, pacRes, pacWarns], ipsErr]) => {
|
||||||
|
|
||||||
if (pacErr && ipsErr) {
|
if (pacErr && ipsErr) {
|
||||||
return cb(pacErr, pacRes);
|
return cb(pacErr, pacRes);
|
||||||
}
|
}
|
||||||
|
let warns = [...(pacWarns || []), ipsErr].filter( (_) => _ );
|
||||||
|
if (!warns.length) {
|
||||||
|
warns = null;
|
||||||
|
}
|
||||||
this.pushToStorageAsync(
|
this.pushToStorageAsync(
|
||||||
(pushErr) => cb(pacErr || ipsErr || pushErr, pacRes)
|
(pushErr) => cb(pacErr || pushErr, null, warns)
|
||||||
);
|
);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
@ -407,33 +698,55 @@
|
||||||
console.log('Storage on init:', oldStorage);
|
console.log('Storage on init:', oldStorage);
|
||||||
antiCensorRu.ifFirstInstall = Object.keys(oldStorage).length === 0;
|
antiCensorRu.ifFirstInstall = Object.keys(oldStorage).length === 0;
|
||||||
|
|
||||||
if (!antiCensorRu.ifFirstInstall) {
|
if (antiCensorRu.ifFirstInstall) {
|
||||||
// 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')
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// INSTALL
|
// INSTALL
|
||||||
console.log('Installing...');
|
console.log('Installing...');
|
||||||
return chrome.runtime.openOptionsPage();
|
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')
|
||||||
|
);
|
||||||
|
|
||||||
|
const ifUpdating = antiCensorRu.version !== oldStorage.version;
|
||||||
|
console.log('IF_UPD?', ifUpdating, antiCensorRu.version, 'vs', oldStorage.version);
|
||||||
|
|
||||||
|
const pushOnUpdate = () => ifUpdating ? antiCensorRu.pushToStorageAsync() : null;
|
||||||
|
|
||||||
|
if (!ifUpdating) {
|
||||||
|
// LAUNCH, RELOAD, ENABLE
|
||||||
|
antiCensorRu.pacProviders = oldStorage.pacProviders;
|
||||||
|
console.log('Extension launched, reloaded or enabled.');
|
||||||
|
} else {
|
||||||
|
// UPDATE & MIGRATION
|
||||||
|
const key = antiCensorRu._currentPacProviderKey;
|
||||||
|
if (
|
||||||
|
key !== null &&
|
||||||
|
!Object.keys(antiCensorRu.pacProviders).includes(key)
|
||||||
|
) {
|
||||||
|
antiCensorRu._currentPacProviderKey = 'Антицензорити'
|
||||||
|
}
|
||||||
|
console.log('Extension updated.');
|
||||||
|
}
|
||||||
|
|
||||||
if (!antiCensorRu.getPacProvider()) {
|
if (!antiCensorRu.getPacProvider()) {
|
||||||
/*
|
/*
|
||||||
In case of UPDATE:
|
In case of UPDATE:
|
||||||
1. new providers will still be shown.
|
1. new providers will still be shown.
|
||||||
2. new version won't be pushed to storage
|
2. new version won't be pushed to storage
|
||||||
*/
|
*/
|
||||||
return console.log('No PAC provider set. Do nothing.');
|
console.log('No PAC provider set. Do nothing.');
|
||||||
|
return pushOnUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -446,306 +759,24 @@
|
||||||
|
|
||||||
const ifAlarmTriggered = antiCensorRu.setAlarms();
|
const ifAlarmTriggered = antiCensorRu.setAlarms();
|
||||||
|
|
||||||
if (antiCensorRu.version === oldStorage.version) {
|
|
||||||
// LAUNCH, RELOAD, ENABLE
|
|
||||||
antiCensorRu.pacProviders = oldStorage.pacProviders;
|
|
||||||
return console.log('Extension launched, reloaded or enabled.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// UPDATE & MIGRATION
|
|
||||||
console.log('Extension updated.');
|
|
||||||
if (!ifAlarmTriggered) {
|
if (!ifAlarmTriggered) {
|
||||||
antiCensorRu.pushToStorageAsync();
|
return pushOnUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
History of Changes to Storage (Migration Guide)
|
History of Changes to Storage (Migration Guide)
|
||||||
-----------------------------------------------
|
-----------------------------------------------
|
||||||
Version 0.0.0.10
|
Version 0.0.0.17:
|
||||||
* Added this.version
|
* "Антиценз" removed.
|
||||||
* PacProvider.proxyIps changed from {ip -> Boolean} to {ip -> hostname}
|
* "Оба_и_на_свитчах" renamed to "Антицензорити".
|
||||||
Version 0.0.0.8-9
|
Version 0.0.0.10:
|
||||||
* Changed storage.ifNotInstalled to storage.ifFirstInstall
|
* Added this.version.
|
||||||
* Added storage.lastPacUpdateStamp
|
* PacProvider.proxyIps changed from {ip -> Boolean} to {ip -> hostname}.
|
||||||
|
Version 0.0.0.8-9:
|
||||||
|
* Changed storage.ifNotInstalled to storage.ifFirstInstall.
|
||||||
|
* Added storage.lastPacUpdateStamp.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
|
||||||
* result.ifPacSet is true if PAC was set (maybe with non-critical errors).
|
|
||||||
* */
|
|
||||||
function setPacAsync(
|
|
||||||
{pacData = mandatory(), pacUrl = 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}, async () => {
|
|
||||||
|
|
||||||
let err = checkChromeError();
|
|
||||||
let asciiErr;
|
|
||||||
if (err) {
|
|
||||||
if (err.message.startsWith('\'pacScript.data\' supports only ASCII')) {
|
|
||||||
asciiErr = err;
|
|
||||||
asciiErr.clarification = {ifNotCritical: true};
|
|
||||||
err = await new Promise((resolve) => {
|
|
||||||
|
|
||||||
chrome.proxy.settings.set({
|
|
||||||
value: {
|
|
||||||
mode: 'pac_script',
|
|
||||||
pacScript: {
|
|
||||||
url: pacUrl,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
() => resolve( checkChromeError() )
|
|
||||||
);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
if (err) {
|
|
||||||
return cb(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
chrome.proxy.settings.get({}, (details) => {
|
|
||||||
|
|
||||||
if ( window.utils.areSettingsNotControlledFor( details ) ) {
|
|
||||||
console.warn('Failed, other extension is in control.');
|
|
||||||
return cb({clarification: {
|
|
||||||
message: window.utils.messages.whichExtensionHtml(),
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
console.log('Successfuly set PAC in proxy settings..');
|
|
||||||
cb(asciiErr, {ifPacSet: true});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function clarifyFetchErrorThen(cb) {
|
|
||||||
|
|
||||||
return (err) => {
|
|
||||||
|
|
||||||
err.clarification = {
|
|
||||||
message: 'Что-то не так с сетью, проверьте соединение.',
|
|
||||||
};
|
|
||||||
return cb(err);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function ifModifiedSince(url, lastModified = mandatory(), cb = mandatory()) {
|
|
||||||
|
|
||||||
const nowModified = new Date(0).toUTCString();
|
|
||||||
fetch(url, {
|
|
||||||
method: 'HEAD',
|
|
||||||
headers: new Headers({
|
|
||||||
'If-Modified-Since': lastModified
|
|
||||||
})
|
|
||||||
}).then(
|
|
||||||
(res) => {
|
|
||||||
cb(null, res.status === 304 ? false : (res.headers.get('Last-Modified') || nowModified) );
|
|
||||||
},
|
|
||||||
clarifyFetchErrorThen((err) => cb(err, nowModified))
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function httpGet(url, cb = mandatory()) {
|
|
||||||
|
|
||||||
const start = Date.now();
|
|
||||||
fetch(url, {cache: 'no-store'}).then(
|
|
||||||
(res) => {
|
|
||||||
|
|
||||||
const textCb =
|
|
||||||
(err) => res.text().then( (text) => cb(err, text), cb );
|
|
||||||
const status = res.status;
|
|
||||||
if ( !( status >= 200 && status < 300 || status === 304 ) ) {
|
|
||||||
res.clarification = {
|
|
||||||
message: 'Получен ответ с неудачным HTTP-кодом ' + status + '.',
|
|
||||||
};
|
|
||||||
return textCb(res);
|
|
||||||
}
|
|
||||||
console.log('GETed with success:', url, Date.now() - start);
|
|
||||||
textCb();
|
|
||||||
|
|
||||||
},
|
|
||||||
clarifyFetchErrorThen(cb)
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function getIpsFor(host, cb = mandatory()) {
|
|
||||||
|
|
||||||
const types = [1, 28];
|
|
||||||
const promises = types.map(
|
|
||||||
(type) => new Promise((resolve) =>
|
|
||||||
httpGet(
|
|
||||||
'https://dns.google.com/resolve?type=' + type + '&name=' + host,
|
|
||||||
(err, res) => {
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
try {
|
|
||||||
res = JSON.parse(res);
|
|
||||||
console.log('Json parsed.');
|
|
||||||
if (err || res.Status) {
|
|
||||||
const msg = ['Answer', 'Comment', 'Status']
|
|
||||||
.filter( (prop) => res[prop] )
|
|
||||||
.map( (prop) => prop + ': ' + JSON.stringify( res[prop] ) )
|
|
||||||
.join(', \n');
|
|
||||||
err.clarification.message += ' Сервер (json): ' + msg;
|
|
||||||
err.data = err.data || res;
|
|
||||||
} else {
|
|
||||||
res = res.Answer || [];
|
|
||||||
res = res.filter(
|
|
||||||
(record) => types.includes(record.type)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch(e) {
|
|
||||||
err = e || err || {clarification: {message: ''}};
|
|
||||||
err.clarification = err.clarification || {message: ''};
|
|
||||||
err.clarification.message = (
|
|
||||||
err.clarification.message
|
|
||||||
+ ' Сервер (текст): '+ res
|
|
||||||
).trim();
|
|
||||||
err.data = err.data || res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resolve([err, res]);
|
|
||||||
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
Promise.all(promises).then(
|
|
||||||
([[v4err, v4res], [v6err, v6res]]) => {
|
|
||||||
|
|
||||||
if(v4err) {
|
|
||||||
return cb(v4err, v4res);
|
|
||||||
}
|
|
||||||
const ips = v4res;
|
|
||||||
if (!v6err) {
|
|
||||||
ips.push(...v6res);
|
|
||||||
} else {
|
|
||||||
v6err.clarification.ifNotCritical = true;
|
|
||||||
console.warn(v6err);
|
|
||||||
}
|
|
||||||
cb(v6err, ips);
|
|
||||||
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function updatePacProxyIps(provider, cb = throwIfError) {
|
|
||||||
|
|
||||||
cb = asyncLogGroup(
|
|
||||||
'Getting IP for '+ provider.proxyHosts.join(', ') + '...',
|
|
||||||
cb
|
|
||||||
);
|
|
||||||
let failure = {
|
|
||||||
clarification: {
|
|
||||||
message: 'Не удалось получить один или несколько IP адресов для' +
|
|
||||||
' прокси-серверов. Иконка для уведомления об обходе блокировок ' +
|
|
||||||
'может не отображаться.',
|
|
||||||
},
|
|
||||||
errors: {},
|
|
||||||
};
|
|
||||||
let i = 0;
|
|
||||||
provider.proxyHosts.forEach(
|
|
||||||
(proxyHost) => getIpsFor(
|
|
||||||
proxyHost,
|
|
||||||
(err, ips) => {
|
|
||||||
|
|
||||||
if (!err || err.clarification.ifNotCritical) {
|
|
||||||
provider.proxyIps = provider.proxyIps || {};
|
|
||||||
ips.forEach(
|
|
||||||
(ip) => provider.proxyIps[ip] = proxyHost
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
failure.errors[proxyHost] = err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ++i === provider.proxyHosts.length ) {
|
|
||||||
failure = Object.keys(failure.errors).length ? failure : null;
|
|
||||||
cb(failure, provider.proxyIps);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* result.ifPacSet is true if PAC was set.
|
|
||||||
**/
|
|
||||||
function setPacScriptFromProviderAsync(provider = mandatory(), lastModified = mandatory(), cb = throwIfError) {
|
|
||||||
|
|
||||||
const pacUrl = provider.pacUrls[0];
|
|
||||||
cb = asyncLogGroup(
|
|
||||||
'Getting PAC script from provider...', pacUrl,
|
|
||||||
cb
|
|
||||||
);
|
|
||||||
|
|
||||||
ifModifiedSince(pacUrl, lastModified, (err, newLastModified) => {
|
|
||||||
|
|
||||||
if (!newLastModified) {
|
|
||||||
return cb(
|
|
||||||
{clarification: {
|
|
||||||
message: 'Ваш PAC-скрипт не нуждается в обновлении. Его дата: ' + lastModified,
|
|
||||||
ifNotCritical: true,
|
|
||||||
}}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Employ all urls, the latter are fallbacks for the former.
|
|
||||||
let pacDataPromise = Promise.reject();
|
|
||||||
for(const url of provider.pacUrls) {
|
|
||||||
|
|
||||||
pacDataPromise = pacDataPromise.catch(
|
|
||||||
(err) => new Promise(
|
|
||||||
(resolve, reject) => httpGet(
|
|
||||||
url,
|
|
||||||
(newErr, pacData) => newErr ? reject(newErr) : resolve(pacData)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pacDataPromise.then(
|
|
||||||
(pacData) => {
|
|
||||||
|
|
||||||
setPacAsync(
|
|
||||||
{pacData, pacUrl},
|
|
||||||
(err, res) => cb( err, Object.assign(res || {}, {lastModified: newLastModified}) )
|
|
||||||
);
|
|
||||||
|
|
||||||
},
|
|
||||||
(err) => {
|
|
||||||
|
|
||||||
err.clarification = {
|
|
||||||
message: 'Не удалось скачать PAC-скрипт с адресов: [ '
|
|
||||||
+ provider.pacUrls.join(' , ') + ' ].',
|
|
||||||
prev: err.clarification,
|
|
||||||
};
|
|
||||||
return cb(err);
|
|
||||||
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
createMenuLinkEntry(
|
createMenuLinkEntry(
|
||||||
'Сайт доступен из-за границы? Is up?',
|
'Сайт доступен из-за границы?',
|
||||||
(tab) => `data:text/html;charset=utf8,<title>Запрашиваю...</title>
|
(tab) => `data:text/html;charset=utf8,<title>Запрашиваю...</title>
|
||||||
<form class='tracker-form' method='POST'
|
<form class='tracker-form' method='POST'
|
||||||
action='https://www.host-tracker.com/ru/InstantCheck/Create'>
|
action='https://www.host-tracker.com/ru/InstantCheck/Create'>
|
||||||
|
@ -42,8 +42,8 @@
|
||||||
);
|
);
|
||||||
|
|
||||||
createMenuLinkEntry(
|
createMenuLinkEntry(
|
||||||
'У меня проблемы с расширением!',
|
'Руководство / Помощь / Ссылки',
|
||||||
(tab) => 'https://rebrand.ly/ac-support'
|
(tab) => 'https://rebrand.ly/ac-wiki'
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
|
|
||||||
"name": "__MSG_extName__ 0.17",
|
"name": "__MSG_extName__ 0.16",
|
||||||
"default_locale": "ru",
|
"default_locale": "ru",
|
||||||
"description": "__MSG_extDesc__",
|
"description": "__MSG_extDesc__",
|
||||||
"version": "0.0.0.17",
|
"version": "0.0.0.17",
|
||||||
|
|
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 434 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -2,7 +2,11 @@
|
||||||
<html style="display: none">
|
<html style="display: none">
|
||||||
<head>
|
<head>
|
||||||
<title>Выбор провайдера PAC</title>
|
<title>Выбор провайдера PAC</title>
|
||||||
|
<link rel="stylesheet" href="./font-awesome/css/font-awesome.min.css">
|
||||||
<style>
|
<style>
|
||||||
|
:root {
|
||||||
|
--ribbon-color: #4169e1; /* #1a6cc8 */
|
||||||
|
}
|
||||||
div {
|
div {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -27,9 +31,6 @@
|
||||||
input[type="radio"], label {
|
input[type="radio"], label {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.off {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.link-button, .link-button:visited {
|
.link-button, .link-button:visited {
|
||||||
color: #0000EE;
|
color: #0000EE;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
@ -58,6 +59,112 @@
|
||||||
display: none;
|
display: none;
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
li.provider {
|
||||||
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc i {
|
||||||
|
vertical-align: bottom;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
/* Source: https://jsfiddle.net/greypants/zgCb7/ */
|
||||||
|
.tooltip {
|
||||||
|
display: none;
|
||||||
|
white-space: initial;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
.desc {
|
||||||
|
display: table-cell;
|
||||||
|
text-align: right;
|
||||||
|
color: var(--ribbon-color);
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
.desc:hover br .tooltip {
|
||||||
|
display: block;
|
||||||
|
text-align: left;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 2.6em;
|
||||||
|
background-color: var(--ribbon-color);
|
||||||
|
color: white;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.tooltip a {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CSS Triangles - courtesy of Trevor */
|
||||||
|
.desc .tooltip:after {
|
||||||
|
border-top: solid transparent 7px;
|
||||||
|
border-bottom: solid transparent 7px;
|
||||||
|
border-left: solid var(--ribbon-color) 7px;
|
||||||
|
right: -7px;
|
||||||
|
content: "";
|
||||||
|
width: 0;
|
||||||
|
top: 7px;
|
||||||
|
margin-top: -13px;
|
||||||
|
position: absolute;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
/* This bridges the gap so you can mouse into the tooltip without it disappearing
|
||||||
|
.desc .tooltip:before {
|
||||||
|
position: absolute;
|
||||||
|
right: -14px;
|
||||||
|
content: " ";
|
||||||
|
display: block;
|
||||||
|
width: 14px;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
li.provider {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.xyz {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
white-space: initial;
|
||||||
|
word-break: initial;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
right: 1em;
|
||||||
|
z-index: 1;
|
||||||
|
background-color: var(--ribbon-color);
|
||||||
|
padding: 1em;
|
||||||
|
color: white;
|
||||||
|
text-align: initial;
|
||||||
|
}
|
||||||
|
.desc:hover .xyz {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.xyz a {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.desc .xyz:after {
|
||||||
|
border-left: solid transparent 7px;
|
||||||
|
border-bottom: solid var(--ribbon-color) 7px;
|
||||||
|
position: absolute;
|
||||||
|
top: -7px;
|
||||||
|
content: "";
|
||||||
|
width: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
/* This bridges the gap so you can mouse into the tooltip without it disappearing */
|
||||||
|
.desc .xyz:before {
|
||||||
|
position: absolute;
|
||||||
|
top: -14px;
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
height: 22px;
|
||||||
|
left: 0;
|
||||||
|
width: calc(100% + 0.6em);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -68,33 +68,43 @@ chrome.runtime.getBackgroundPage( (backgroundPage) =>
|
||||||
};
|
};
|
||||||
const checkChosenProvider = () => currentProviderRadio().checked = true;
|
const checkChosenProvider = () => currentProviderRadio().checked = true;
|
||||||
|
|
||||||
const showError = (err) => {
|
const showErrors = (err, warns) => {
|
||||||
|
|
||||||
let clarification = err.clarification;
|
warns = warns || [];
|
||||||
const ifNotCritical = clarification && clarification.ifNotCritical;
|
const warning = warns
|
||||||
let message = err.message || '';
|
.map( (w) => '✘ ' + (w.clarification && w.clarification.message || w.message || '') )
|
||||||
|
.join('<br/>');
|
||||||
|
|
||||||
while( clarification ) {
|
let message = '';
|
||||||
message = (clarification && (clarification.message + ' ')) + message;
|
if (err) {
|
||||||
clarification = clarification.prev;
|
let clarification = err.clarification;
|
||||||
|
message = err.message || '';
|
||||||
|
|
||||||
|
while( clarification ) {
|
||||||
|
message = (clarification && (clarification.message + ' ')) + message;
|
||||||
|
clarification = clarification.prev;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
message = message.trim();
|
message = message.trim();
|
||||||
|
if (warning) {
|
||||||
|
message += ' ' + warning;
|
||||||
|
}
|
||||||
setStatusTo(
|
setStatusTo(
|
||||||
`<span style="color:red">
|
`<span style="color:red">
|
||||||
${ifNotCritical ? 'Некритичная ошибка.' : 'Ошибка!'}
|
${err ? '🔥 Ошибка!' : 'Некритичная ошибка.'}
|
||||||
</span>
|
</span>
|
||||||
<br/>
|
<br/>
|
||||||
<span style="font-size: 0.9em; color: darkred">${message}</span>
|
<span style="font-size: 0.9em; color: darkred">${message}</span>
|
||||||
<a href class="link-button">
|
${err ? '<a href class="link-button">[Ещё подробнее]</a>' : ''}`
|
||||||
[Ещё подробнее]
|
|
||||||
</a>`
|
|
||||||
);
|
);
|
||||||
getStatus().querySelector('.link-button').onclick = function() {
|
if (err) {
|
||||||
|
getStatus().querySelector('.link-button').onclick = function() {
|
||||||
|
|
||||||
errorHandlers.viewErrorVoid(err);
|
errorHandlers.viewErrorVoid(err);
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -111,14 +121,13 @@ chrome.runtime.getBackgroundPage( (backgroundPage) =>
|
||||||
|
|
||||||
setStatusTo(beforeStatus);
|
setStatusTo(beforeStatus);
|
||||||
enableDisableInputs();
|
enableDisableInputs();
|
||||||
operation((err) => {
|
operation((err, res, warns) => {
|
||||||
if (err) {
|
if (err || warns) {
|
||||||
showError(err);
|
showErrors(err, warns);
|
||||||
if (err.clarification && err.clarification.ifNotCritical) {
|
|
||||||
onSuccess && onSuccess();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
setStatusTo(afterStatus);
|
setStatusTo(afterStatus);
|
||||||
|
}
|
||||||
|
if (!err) {
|
||||||
onSuccess && onSuccess();
|
onSuccess && onSuccess();
|
||||||
}
|
}
|
||||||
enableDisableInputs();
|
enableDisableInputs();
|
||||||
|
@ -131,12 +140,20 @@ chrome.runtime.getBackgroundPage( (backgroundPage) =>
|
||||||
for(
|
for(
|
||||||
const providerKey of Object.keys(antiCensorRu.pacProviders).sort()
|
const providerKey of Object.keys(antiCensorRu.pacProviders).sort()
|
||||||
) {
|
) {
|
||||||
|
const provider = antiCensorRu.getPacProvider(providerKey);
|
||||||
const li = document.createElement('li');
|
const li = document.createElement('li');
|
||||||
|
li.className = 'provider';
|
||||||
li.innerHTML = `
|
li.innerHTML = `
|
||||||
<input type="radio" name="pacProvider" id="${providerKey}">
|
<input type="radio" name="pacProvider" id="${providerKey}">
|
||||||
<label for="${providerKey}">${providerKey}</label>
|
<label for="${providerKey}"> ${provider.label}</label>
|
||||||
<a href class="link-button checked-radio-panel"
|
<a href class="link-button checked-radio-panel"
|
||||||
id="update-${providerKey}">[обновить]</a>`;
|
id="update-${providerKey}"> [обновить]</a>
|
||||||
|
<div class="desc">
|
||||||
|
<i class="fa fa-question-circle" aria-hidden="true"></i>
|
||||||
|
<div class="tooltip">${provider.desc}</div>
|
||||||
|
<div class="xyz">${provider.desc}</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
li.querySelector('.link-button').onclick =
|
li.querySelector('.link-button').onclick =
|
||||||
() => {
|
() => {
|
||||||
conduct(
|
conduct(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user