2015-12-20 23:28:41 +03:00
'use strict' ;
/ *
2016-02-12 19:00:40 +03:00
Task 1. Gets IPs for proxies of antizapret / anticenz with dns - lg . com .
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 .
2015-12-20 23:28:41 +03:00
* /
/ *
In background scripts use window . antiCensorRu public variables .
In pages window . antiCensorRu are not accessible ,
use chrome . runtime . getBackgroundPage ( . . ) ,
avoid old extension . getBackgroundPage .
* /
window . antiCensorRu = {
// PUBLIC
2016-02-08 12:55:41 +03:00
version : chrome . runtime . getManifest ( ) . version ,
2015-12-20 23:28:41 +03:00
pacProviders : {
Антизапрет : {
pacUrl : 'http://antizapret.prostovpn.org/proxy.pac' ,
2016-01-17 22:27:54 +03:00
proxyHosts : [ 'proxy.antizapret.prostovpn.org' ] ,
2016-02-08 12:55:41 +03:00
proxyIps : {
'195.154.110.37' : 'proxy.antizapret.prostovpn.org'
}
2015-12-20 23:28:41 +03:00
} ,
Антиценз : {
pacUrl : 'https://config.anticenz.org/proxy.pac' ,
2016-01-18 00:09:55 +03:00
proxyHosts : [ 'gw2.anticenz.org' ] ,
2016-02-08 12:55:41 +03:00
proxyIps : {
'5.196.220.114' : 'gw2.anticenz.org'
}
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' ] ,
2016-02-08 12:55:41 +03:00
proxyIps : {
'5.196.220.114' : 'gw2.anticenz.org' ,
'195.154.110.37' : 'proxy.antizapret.prostovpn.org'
}
2015-12-20 23:28:41 +03:00
}
} ,
2016-01-17 22:27:54 +03:00
_currentPacProviderKey : 'О б а _и_на _с витча х ' ,
2015-12-20 23:28:41 +03:00
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
/ *
2016-02-08 12:55:41 +03:00
Is it the first time extension installed ? Do something , e . g . initiate PAC sync .
2016-01-26 19:47:09 +03:00
* /
2016-02-08 12:55:41 +03:00
ifFirstInstall : false ,
lastPacUpdateStamp : 0 ,
2015-12-20 23:28:41 +03:00
// PROTECTED
2016-02-08 12:55:41 +03:00
_periodicUpdateAlarmReason : 'Периодичное обновление PAC-скрипта Антизапрет' ,
2015-12-20 23:28:41 +03:00
pushToStorage ( cb ) {
2016-02-05 19:11:19 +03:00
// 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 ]
return chrome . storage . local . clear (
2016-02-08 12:55:41 +03:00
( ) => chrome . storage . local . set (
onlySettable ,
( ) => cb && cb ( chrome . runtime . lastError , onlySettable )
)
) ;
2015-12-20 23:28:41 +03:00
} ,
pullFromStorage ( cb ) {
chrome . storage . local . get ( null , storage => {
2016-02-08 12:55:41 +03:00
console . log ( 'In storage:' , storage ) ;
2015-12-20 23:28:41 +03:00
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 ) ;
2015-12-20 23:28:41 +03:00
if ( cb )
2016-01-26 18:50:25 +03:00
cb ( chrome . runtime . lastError , storage ) ;
2015-12-20 23:28:41 +03:00
} ) ;
} ,
2016-01-26 13:38:40 +03:00
2015-12-20 23:28:41 +03:00
syncWithPacProvider ( cb ) {
2016-01-26 23:05:21 +03:00
var cb = cb || ( ( ) => { } ) ;
2016-02-12 19:00:40 +03:00
if ( ! this . pacProvider )
return cb ( { clarification : 'Сперва выберите PAC-провайдера.' } ) ;
2016-01-26 23:05:21 +03:00
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 ( ) ;
2016-01-26 23:05:21 +03:00
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 )
)
}
) ;
2015-12-20 23:28:41 +03:00
} ,
2016-02-12 19:00:40 +03:00
setAlarms ( ) {
chrome . alarms . create (
this . _periodicUpdateAlarmReason ,
{ periodInMinutes : 4 * 60 }
) ;
} ,
2015-12-20 23:28:41 +03:00
installPac ( key , cb ) {
2016-01-17 22:27:54 +03:00
2016-02-08 12:55:41 +03:00
if ( typeof ( key ) === 'function' ) {
cb = key ;
key = undefined ;
}
2015-12-20 23:28:41 +03:00
2016-02-08 12:55:41 +03:00
if ( key )
this . currentPacProviderKey = key ;
2015-12-20 23:28:41 +03:00
var cb = asyncLogGroup ( 'Installing PAC...' , cb ) ;
2016-02-12 19:00:40 +03:00
this . setAlarms ( ) ;
2015-12-20 23:28:41 +03:00
2016-02-11 23:07:39 +03:00
return this . syncWithPacProvider ( cb ) ;
2015-12-20 23:28:41 +03:00
} ,
clearPac ( cb ) {
2016-02-08 12:55:41 +03:00
var cb = asyncLogGroup ( 'Cearing alarms and PAC...' , cb ) ;
chrome . alarms . clearAll (
( ) => chrome . proxy . settings . clear (
{ } ,
( ) => {
this . currentPacProviderKey = undefined ;
return this . pushToStorage ( cb ) ;
}
)
) ;
2015-12-20 23:28:41 +03:00
}
} ;
2016-02-11 23:07:39 +03:00
// ON EACH LAUNCH, STARTUP, RELOAD, UPDATE, ENABLE
chrome . storage . local . get ( null , oldStorage => {
2016-01-26 18:50:25 +03:00
2016-02-11 23:07:39 +03:00
console . log ( 'Init on storage:' , oldStorage ) ;
2016-02-12 19:00:40 +03:00
antiCensorRu . ifFirstInstall = Object . keys ( oldStorage ) . length === 0 ;
2016-02-08 12:55:41 +03:00
2016-02-11 23:07:39 +03:00
// Finish each init with this callback setting alarm listeners.
function cb ( err ) {
2016-01-26 18:50:25 +03:00
chrome . alarms . onAlarm . addListener (
alarm => {
2016-02-11 23:07:39 +03:00
if ( alarm . name === antiCensorRu . _periodicUpdateAlarmReason ) {
2016-01-26 18:50:25 +03:00
console . log ( 'Periodic update triggered:' , new Date ( ) ) ;
2016-02-11 23:07:39 +03:00
antiCensorRu . syncWithPacProvider ( ) ;
2016-01-26 18:50:25 +03:00
}
}
) ;
2016-01-26 19:05:23 +03:00
console . log ( 'Alarm listener installed. We won\'t miss any PAC update.' ) ;
chrome . alarms . get (
2016-02-11 23:07:39 +03:00
antiCensorRu . _periodicUpdateAlarmReason ,
alarm => {
2016-02-12 19:00:40 +03:00
if ( alarm )
console . log (
'Next update is scheduled on' , new Date ( alarm . scheduledTime ) . toLocaleString ( 'ru-RU' )
) ;
else if ( ! antiCensorRu . ifFirstInstall && antiCensorRu . pacProvider ) {
antiCensorRu . setAlarms ( ) ;
console . error ( 'KNOWN BUG: Alarms were lost. See issues on GitHub. Don\'t worry, next update was rescheduled.' ) ;
}
2016-02-11 23:07:39 +03:00
}
2016-01-26 19:05:23 +03:00
) ;
2016-02-11 23:07:39 +03:00
}
2016-02-08 12:55:41 +03:00
2016-02-11 23:07:39 +03:00
// INSTALL
if ( antiCensorRu . ifFirstInstall ) {
console . log ( 'Installing...' ) ;
return chrome . runtime . openOptionsPage ( cb ) ;
2016-01-26 18:50:25 +03:00
}
2016-02-08 12:55:41 +03:00
2016-02-11 23:07:39 +03:00
/ *
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 .
* /
// LAUNCH, RELOAD, UPDATE
2016-02-12 19:00:40 +03:00
antiCensorRu . _currentPacProviderKey = oldStorage . _currentPacProviderKey ;
2016-02-11 23:07:39 +03:00
antiCensorRu . lastPacUpdateStamp = oldStorage . lastPacUpdateStamp || antiCensorRu . lastPacUpdateStamp ;
if ( antiCensorRu . version === oldStorage . version ) {
// LAUNCH, RELOAD
console . log ( 'Launch or reload. Do nothing.' ) ;
return cb ( ) ;
}
2016-02-12 19:00:40 +03:00
2016-02-11 23:07:39 +03:00
// UPDATE & MIGRATION
console . log ( 'Updating...' ) ;
2016-02-12 19:00:40 +03:00
return antiCensorRu . pacProvider &&
updatePacProxyIps (
antiCensorRu . pacProvider ,
ipsError => {
if ( ipsError ) ipsError . ifNotCritical = true ;
antiCensorRu . pushToStorage ( pushError => cb ( pushError || ipsError ) ) ;
}
) ;
2016-02-11 23:07:39 +03:00
/ *
History of Changes to Storage ( Migration Guide )
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
Version 0.0 . 0.10
* Added this . version
* PacProvider . proxyIps changed from { ip - > Boolean } to { ip - > hostname }
Version 0.0 . 0.8 - 9
* Changed storage . ifNotInstalled to storage . ifFirstInstall
* Added storage . lastPacUpdateStamp
* * /
2015-12-20 23:28:41 +03:00
} ) ;
// PRIVATE
function asyncLogGroup ( ) {
var args = [ ] . slice . apply ( arguments ) ;
var cb = args . pop ( ) ;
console . group . apply ( console , args ) ;
return function ( ) {
2016-02-08 18:43:23 +03:00
console . log ( 'Finished' ) ;
2015-12-20 23:28:41 +03:00
console . groupEnd ( ) ;
var _cb = cb || ( ( ) => { } ) ;
return _cb . apply ( this , arguments ) ;
}
}
2016-01-26 23:05:21 +03:00
function ifSuccessfulCode ( status ) {
return status >= 200 && status < 300 || status === 304 ;
}
2015-12-20 23:28:41 +03:00
function httpGet ( url , cb ) {
var cb = cb || ( ( ) => { } ) ;
var req = new XMLHttpRequest ( ) ;
var ifAsync = true ;
req . open ( 'GET' , url , ifAsync ) ;
req . onload = event => {
2016-02-05 17:52:04 +03:00
if ( ! ifSuccessfulCode ( req . status ) ) {
2016-01-26 23:05:21 +03:00
req . clarification = { message : 'Получен ответ с неудачным HTTP-кодом ' + req . status + '.' } ;
return cb ( req ) ;
}
2015-12-20 23:28:41 +03:00
console . log ( 'GETed with success.' ) ;
return cb ( null , req . responseText )
} ;
2016-01-26 23:05:21 +03:00
req . onerror = event => { event . clarification = { message : 'Что-то не так с сетью, проверьте соединение.' } ; return cb ( event ) ; } ;
2015-12-20 23:28:41 +03:00
req . send ( ) ;
}
2016-01-17 22:27:54 +03:00
function updatePacProxyIps ( provider , cb ) {
var cb = asyncLogGroup ( 'Getting IP for ' + provider . proxyHosts . join ( ', ' ) + '...' , cb ) ;
2016-01-26 23:05:21 +03:00
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 || { } ;
2016-02-11 23:07:39 +03:00
provider . proxyIps [ JSON . parse ( res ) . answer [ 0 ] . rdata ] = proxyHost ;
2016-01-26 23:05:21 +03:00
} 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
}
}
) ;
}
2015-12-20 23:28:41 +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
2015-12-20 23:28:41 +03:00
httpGet (
provider . pacUrl ,
( err , res ) => {
2016-01-26 23:05:21 +03:00
if ( err ) {
err . clarification = {
message : 'Н е удалось скачать PAC-скрипт с адреса: ' + provider . pacUrl + '.' ,
prev : err . clarification
} ;
2015-12-20 23:28:41 +03:00
return cb ( err ) ;
2016-01-26 23:05:21 +03:00
}
2015-12-20 23:28:41 +03:00
console . log ( 'Clearing chrome proxy settings...' ) ;
return chrome . proxy . settings . clear ( { } , ( ) => {
2016-02-08 12:55:41 +03:00
var config = {
mode : 'pac_script' ,
pacScript : {
mandatory : false ,
data : res
}
} ;
console . log ( 'Setting chrome proxy settings...' ) ;
chrome . proxy . settings . set ( { value : config } , cb ) ;
} ) ;
2015-12-20 23:28:41 +03:00
}
) ;
}