runet-censorship-bypass/extensions/chromium/minimalistic-pac-setter/extnesion/sync-pac-script-with-pac-provider.js

289 lines
8.5 KiB
JavaScript
Raw Normal View History

'use strict';
/*
Task 1. Gets IP for host proxy.antizapret.prostovpn.org with dns-lg.com.
This IP is used in block-informer to inform user when proxy is ON.
Task 2. Downloads PAC proxy script from Antizapret and sets it in Chromium settings.
Task 3. Schedules tasks 1 & 2 for every 2 hours.
*/
/*
In background scripts use window.antiCensorRu public variables.
Thay are synced with chrome.storage so they persist restarts.
In pages window.antiCensorRu are not accessible,
use chrome.runtime.getBackgroundPage(..),
avoid old extension.getBackgroundPage.
*/
window.antiCensorRu = {
// PUBLIC
pacProviders: {
Антизапрет: {
pacUrl: 'http://antizapret.prostovpn.org/proxy.pac',
2016-01-17 22:27:54 +03:00
proxyHosts: ['proxy.antizapret.prostovpn.org'],
proxyIps: {'195.154.110.37': true}
},
Антиценз: {
pacUrl: 'https://config.anticenz.org/proxy.pac',
2016-01-18 00:09:55 +03:00
proxyHosts: ['gw2.anticenz.org'],
proxyIps: {'185.120.5.7': true}
2016-01-17 22:27:54 +03:00
},
Обаа_свитчах: {
pacUrl: 'https://drive.google.com/uc?export=download&id=0B-ZCVSvuNWf0akpCOURNS2VCTmc',
2016-01-18 00:09:55 +03:00
proxyHosts: ['gw2.anticenz.org', 'proxy.antizapret.prostovpn.org'],
proxyIps: {'195.154.110.37': true, '185.120.5.7': true}
}
},
2016-01-17 22:27:54 +03:00
_currentPacProviderKey: 'Оба_и_на_свитчах',
get currentPacProviderKey() { return this._currentPacProviderKey },
set currentPacProviderKey(newKey) {
if (newKey && !this.pacProviders[newKey])
throw new IllegalArgumentException('No provider for key:'+newKey);
this._currentPacProviderKey = newKey;
},
get pacProvider() { return this.pacProviders[this.currentPacProviderKey] },
2016-01-26 19:47:09 +03:00
/*
Offer PAC choice if this is the first time extension was installed.
*/
ifFirstInstall: true,
// PROTECTED
pushToStorage(cb) {
// Copy only settable properties.
var onlySettable = {};
for(var key of Object.keys(this))
if (Object.getOwnPropertyDescriptor(this, key).writable && typeof(this[key]) !== 'function')
onlySettable[key] = this[key]
2016-01-26 19:47:09 +03:00
return chrome.storage.local.set(onlySettable, () => cb && cb(chrome.runtime.lastError, onlySettable) );
},
pullFromStorage(cb) {
chrome.storage.local.get(null, storage => {
for(var key of Object.keys(storage))
this[key] = storage[key];
2016-01-26 19:05:23 +03:00
console.log('Synced with storage, any callback?', !!cb);
if (cb)
2016-01-26 18:50:25 +03:00
cb(chrome.runtime.lastError, storage);
});
},
2016-01-26 13:38:40 +03:00
lastPacUpdateStamp: 0,
syncWithPacProvider(cb) {
var cb = cb || (() => {});
var pacSetPromise = new Promise(
(resolve, reject) => setPacScriptFromProvider(
this.pacProvider,
(err, res) => {
if (err)
return reject(err);
2016-01-26 13:38:40 +03:00
this.lastPacUpdateStamp = Date.now();
this.ifFirstInstall = false;
return resolve(res);
}
)
);
return updatePacProxyIps(
this.pacProvider,
ipsError => {
if (ipsError && ipsError.clarification)
ipsError.clarification.ifNotCritical = true;
pacSetPromise.then(
res => this.pushToStorage(
pushError => pushError ? cb(pushError) : cb(ipsError, res)
),
err => cb(err)
)
}
);
},
2016-01-18 00:09:55 +03:00
_periodicUpdateAlarmReason: 'Периодичное обновление PAC-скрипта Антизапрет',
installPac(key, cb) {
2016-01-17 22:27:54 +03:00
if(typeof(key) === 'function') {
cb = key;
key = undefined;
}
if(key)
this.currentPacProviderKey = key;
var cb = asyncLogGroup('Installing PAC...', cb);
2016-01-18 00:09:55 +03:00
chrome.alarms.clear(this._periodicUpdateAlarmReason,
() => chrome.alarms.create(this._periodicUpdateAlarmReason, {
periodInMinutes: 4*60
})
);
this.syncWithPacProvider(cb);
},
clearPac(cb) {
var cb = asyncLogGroup('Cearing PAC...', cb);
chrome.alarms.clearAll( () => chrome.proxy.settings.clear(
{},
() => {
this.currentPacProviderKey = undefined;
return this.pushToStorage(cb);
})
);
}
};
2016-01-26 18:50:25 +03:00
// ON EACH LAUNCH OF EXTENSION
window.storageSyncedPromise = new Promise(
(resolve, reject) => window.antiCensorRu.pullFromStorage(
(err, res) => err ? reject(err) : resolve(res)
)
);
window.storageSyncedPromise.then(
storage => {
chrome.alarms.onAlarm.addListener(
alarm => {
if (alarm.name === window.antiCensorRu._periodicUpdateAlarmReason) {
console.log('Periodic update triggered:', new Date());
window.antiCensorRu.syncWithPacProvider();
}
}
);
2016-01-26 19:05:23 +03:00
console.log('Alarm listener installed. We won\'t miss any PAC update.');
chrome.alarms.get(
window.antiCensorRu._periodicUpdateAlarmReason,
alarm => alarm && console.log(
'Next update is scheduled on', new Date(alarm.scheduledTime).toLocaleString('ru-RU')
)
);
2016-01-26 18:50:25 +03:00
}
);
chrome.runtime.onInstalled.addListener( details => {
2016-01-26 19:05:23 +03:00
console.log('Extension just installed, reason:', details.reason);
2016-01-26 18:50:25 +03:00
window.storageSyncedPromise.then(
storage => {
switch(details.reason) {
case 'update':
2016-01-26 19:05:23 +03:00
console.log('Ah, it\'s just an update or reload. Do nothing.');
//window.antiCensorRu.installPac();
2016-01-26 18:50:25 +03:00
break;
case 'install':
2016-01-26 19:47:09 +03:00
window.antiCensorRu.ifFirstInstall = true;
2016-01-26 18:50:25 +03:00
chrome.runtime.openOptionsPage();
2016-01-18 00:09:55 +03:00
}
}
2016-01-26 18:50:25 +03:00
)
});
// PRIVATE
function asyncLogGroup() {
var args = [].slice.apply(arguments);
var cb = args.pop();
console.group.apply(console, args);
return function() {
console.log('Finished');
console.groupEnd();
var _cb = cb || (() => {});
return _cb.apply(this, arguments);
}
}
function ifSuccessfulCode(status) {
return status >= 200 && status < 300 || status === 304;
}
function httpGet(url, cb) {
var cb = cb || (() => {});
var req = new XMLHttpRequest();
var ifAsync = true;
req.open('GET', url, ifAsync);
req.onload = event => {
if ( !ifSuccessfulCode(req.status) ) {
req.clarification = {message: 'Получен ответ с неудачным HTTP-кодом '+req.status+ '.'};
return cb(req);
}
console.log('GETed with success.');
return cb(null, req.responseText)
};
req.onerror = event => { event.clarification = {message: 'Что-то не так с сетью, проверьте соединение.'}; return cb(event); };
req.send();
}
2016-01-17 22:27:54 +03:00
function updatePacProxyIps(provider, cb) {
if (!provider.proxyHosts) {
console.log(provider+' has no proxies defined.');
return cb(null, null);
}
var cb = asyncLogGroup('Getting IP for '+ provider.proxyHosts.join(', ') +'...', cb);
var failure = {
clarification: {message:'Не удалось получить один или несколько IP адресов для прокси-серверов. Иконка для уведомления об обходе блокировок может не отображаться.'},
errors: {}
};
2016-01-17 22:27:54 +03:00
var i = 0;
for (var proxyHost of provider.proxyHosts) {
httpGet(
'http://www.dns-lg.com/google1/'+ proxyHost +'/A',
(err, res) => {
if (!err) {
provider.proxyIps = provider.proxyIps || {};
provider.proxyIps[ JSON.parse(res).answer[0].rdata ] = true;
} else
failure.errors[proxyHost] = err;
if ( ++i == provider.proxyHosts.length ) {
failure = Object.keys(failure.errors).length ? failure : null;
return cb(failure, provider.proxyIps);
2016-01-17 22:27:54 +03:00
}
}
);
}
}
function setPacScriptFromProvider(provider, cb) {
var cb = asyncLogGroup('Getting pac script from provider...', provider.pacUrl, cb);
2016-01-17 22:27:54 +03:00
httpGet(
provider.pacUrl,
(err, res) => {
if (err) {
err.clarification = {
message: 'Не удалось скачать PAC-скрипт с адреса: ' +provider.pacUrl+ '.',
prev: err.clarification
};
return cb(err);
}
console.log('Clearing chrome proxy settings...');
return chrome.proxy.settings.clear({}, () => {
var config = {
mode: 'pac_script',
pacScript: {
mandatory: false,
data: res
}
};
console.log('Setting chrome proxy settings...');
chrome.proxy.settings.set( {value: config}, cb );
});
}
);
}