mirror of
https://github.com/anticensority/runet-censorship-bypass.git
synced 2024-11-24 02:13:43 +03:00
Handle update errors in popup, add ip lookup method, fix rollbacks (change API)
This commit is contained in:
parent
aa20f220ee
commit
9ef8939127
|
@ -49,15 +49,41 @@
|
|||
|
||||
_currentPacProviderKey: 'Оба_и_на_свитчах',
|
||||
|
||||
isProxied(ip) {
|
||||
|
||||
// Executed on each request with ip. Make it as fast as possible.
|
||||
return this._currentPacProviderKey && this.pacProviders[this._currentPacProviderKey].proxyIps.hasOwnProperty(ip);
|
||||
// The benefit of removing lookups is little, e.g. this._currentProxyIps && this._currentProxyIps.hasOwnProperty(ip);
|
||||
|
||||
},
|
||||
|
||||
mustBeKey(key) {
|
||||
|
||||
if ( !(key === null || this.pacProviders[key]) ) {
|
||||
throw new IllegalArgumentException('No provider for key:' + key);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
get currentPacProviderKey() { return this._currentPacProviderKey },
|
||||
set currentPacProviderKey(newKey) {
|
||||
|
||||
if (newKey && !this.pacProviders[newKey])
|
||||
throw new IllegalArgumentException('No provider for key:' + newKey);
|
||||
this.mustBeKey(newKey);
|
||||
this._currentPacProviderKey = newKey;
|
||||
|
||||
},
|
||||
|
||||
get pacProvider() { return this.pacProviders[this.currentPacProviderKey] },
|
||||
getPacProvider(key) {
|
||||
|
||||
if(key) {
|
||||
this.mustBeKey(key);
|
||||
}
|
||||
else {
|
||||
key = this.currentPacProviderKey;
|
||||
}
|
||||
return this.pacProviders[key];
|
||||
|
||||
},
|
||||
|
||||
/*
|
||||
Is it the first time extension installed? Do something, e.g. initiate PAC sync.
|
||||
|
@ -106,19 +132,28 @@
|
|||
});
|
||||
},
|
||||
|
||||
syncWithPacProvider(cb) {
|
||||
syncWithPacProvider(key, cb) {
|
||||
|
||||
cb = asyncLogGroup('Syncing with PAC provider...', cb);
|
||||
if (!this.pacProvider) {
|
||||
if( !key || typeof(key) === 'function' ) {
|
||||
cb = key;
|
||||
key = this.currentPacProviderKey;
|
||||
}
|
||||
cb = asyncLogGroup('Syncing with PAC provider ' + key + '...', cb);
|
||||
|
||||
if (key === null) {
|
||||
// No pac provider set.
|
||||
return cb({clarification:{message:'Сперва выберите PAC-провайдера.'}});
|
||||
}
|
||||
|
||||
const pacProvider = this.getPacProvider(key);
|
||||
|
||||
const pacSetPromise = new Promise(
|
||||
(resolve, reject) => setPacScriptFromProvider(
|
||||
this.pacProvider,
|
||||
pacProvider,
|
||||
(err, res) => {
|
||||
|
||||
if (!err) {
|
||||
this.currentPacProviderKey = key;
|
||||
this.lastPacUpdateStamp = Date.now();
|
||||
this.ifFirstInstall = false;
|
||||
this.setAlarms();
|
||||
|
@ -132,7 +167,7 @@
|
|||
|
||||
const ipsPromise = new Promise(
|
||||
(resolve, reject) => updatePacProxyIps(
|
||||
this.pacProvider,
|
||||
pacProvider,
|
||||
(ipsError) => {
|
||||
|
||||
if (ipsError && ipsError.clarification) {
|
||||
|
@ -186,28 +221,15 @@
|
|||
|
||||
installPac(key, cb) {
|
||||
|
||||
console.log('Installing PAC');
|
||||
if(typeof(key) === 'function') {
|
||||
cb = key;
|
||||
key = undefined;
|
||||
console.log('Installing PAC...');
|
||||
if (!key) {
|
||||
throw new Error('Key must be defined.');
|
||||
}
|
||||
|
||||
const oldKey = this.currentPacProviderKey;
|
||||
if(key || key !== oldKey) {
|
||||
this.currentPacProviderKey = key;
|
||||
const _cb = cb;
|
||||
cb = (err, res) => {
|
||||
|
||||
if (err && !(err.clarification && err.clarification.ifNotCritical)) {
|
||||
console.log('Rollback privider key.');
|
||||
this.currentPacProviderKey = oldKey;
|
||||
}
|
||||
_cb(err, res);
|
||||
|
||||
};
|
||||
if (this.currentProviderKey !== key) {
|
||||
return this.syncWithPacProvider(key, cb);
|
||||
}
|
||||
|
||||
this.syncWithPacProvider(cb);
|
||||
console.log(key + ' already installed.');
|
||||
cb();
|
||||
|
||||
},
|
||||
|
||||
|
@ -223,7 +245,7 @@
|
|||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
this.currentPacProviderKey = undefined;
|
||||
this.currentPacProviderKey = null;
|
||||
this.pushToStorage(cb);
|
||||
|
||||
}
|
||||
|
@ -236,16 +258,12 @@
|
|||
// ON EACH LAUNCH, STARTUP, RELOAD, UPDATE, ENABLE
|
||||
chrome.storage.local.get(null, (oldStorage) => {
|
||||
|
||||
console.log('Init on storage:', oldStorage);
|
||||
antiCensorRu.ifFirstInstall = Object.keys(oldStorage).length === 0;
|
||||
|
||||
if (!antiCensorRu.ifFirstInstall) {
|
||||
// LAUNCH, RELOAD, UPDATE
|
||||
antiCensorRu._currentPacProviderKey = oldStorage._currentPacProviderKey;
|
||||
antiCensorRu.lastPacUpdateStamp = oldStorage.lastPacUpdateStamp || antiCensorRu.lastPacUpdateStamp;
|
||||
console.log( 'Last PAC update was on', new Date(antiCensorRu.lastPacUpdateStamp).toLocaleString('ru-RU') );
|
||||
}
|
||||
|
||||
checkChromeError();
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
chrome.alarms.onAlarm.addListener(
|
||||
(alarm) => {
|
||||
|
||||
|
@ -265,19 +283,28 @@
|
|||
|
||||
});
|
||||
|
||||
if (antiCensorRu.ifFirstInstall) {
|
||||
console.log('Storage on init:', oldStorage);
|
||||
antiCensorRu.ifFirstInstall = Object.keys(oldStorage).length === 0;
|
||||
|
||||
if (!antiCensorRu.ifFirstInstall) {
|
||||
// LAUNCH, RELOAD, UPDATE
|
||||
antiCensorRu._currentPacProviderKey = oldStorage._currentPacProviderKey || null; // Old or migrate.
|
||||
antiCensorRu.lastPacUpdateStamp = oldStorage.lastPacUpdateStamp || antiCensorRu.lastPacUpdateStamp; // Old or migrate to default.
|
||||
console.log( 'Last PAC update was on', new Date(antiCensorRu.lastPacUpdateStamp).toLocaleString('ru-RU') );
|
||||
}
|
||||
else {
|
||||
// INSTALL
|
||||
console.log('Installing...');
|
||||
chrome.runtime.openOptionsPage();
|
||||
return chrome.runtime.openOptionsPage();
|
||||
}
|
||||
|
||||
if (!antiCensorRu.pacProvider) {
|
||||
return console.log('No PAC provider set. Do nothing.');
|
||||
if (!antiCensorRu.getPacProvider()) {
|
||||
/*
|
||||
In case of UPDATE:
|
||||
1. new providers will still be shown.
|
||||
2. new version won't be pushed to storage
|
||||
*/
|
||||
return console.log('No PAC provider set. Do nothing.');
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -52,13 +52,81 @@ window.tabWithError2ip = {}; // For errors only: Error? -> Check this IP!
|
|||
|
||||
chrome.tabs.onRemoved.addListener( (tabId) => { onTabUpdate(tabId); delete window.tabWithError2ip[tabId] } );
|
||||
|
||||
function updateTitle(requestDetails, cb) {
|
||||
|
||||
chrome.browserAction.getTitle(
|
||||
{ tabId: requestDetails.tabId },
|
||||
(title) => {
|
||||
|
||||
const ifTitleSetAlready = /\n/.test(title);
|
||||
const proxyHost = window.antiCensorRu.getPacProvider().proxyIps[ requestDetails.ip ];
|
||||
|
||||
const hostname = new URL( requestDetails.url ).hostname;
|
||||
|
||||
let ifShouldUpdateTitle = false;
|
||||
const indent = ' ';
|
||||
const proxyTitle = 'Прокси:';
|
||||
|
||||
if (!ifTitleSetAlready) {
|
||||
title = 'Разблокированы:\n'+ indent + hostname +'\n'+ proxyTitle +'\n'+ indent + proxyHost;
|
||||
ifShouldUpdateTitle = true;
|
||||
|
||||
chrome.browserAction.setBadgeText({
|
||||
tabId: requestDetails.tabId,
|
||||
text: requestDetails.type === 'main_frame' ? '1' : '%1'
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
const hostsProxiesPair = title.split(proxyTitle);
|
||||
|
||||
if (hostsProxiesPair[1].indexOf(proxyHost) === -1) {
|
||||
title = title.replace(hostsProxiesPair[1], hostsProxiesPair[1] +'\n'+ indent + proxyHost);
|
||||
ifShouldUpdateTitle = true;
|
||||
}
|
||||
|
||||
if (hostsProxiesPair[0].indexOf(hostname) === -1) {
|
||||
title = title.replace(proxyTitle, indent + hostname +'\n'+ proxyTitle);
|
||||
ifShouldUpdateTitle = true;
|
||||
|
||||
const _cb = cb;
|
||||
cb = () => chrome.browserAction.getBadgeText(
|
||||
{tabId: requestDetails.tabId},
|
||||
(result) => {
|
||||
|
||||
chrome.browserAction.setBadgeText(
|
||||
{
|
||||
tabId: requestDetails.tabId,
|
||||
text: ( isNaN( result.charAt(0) ) && result.charAt(0) || '' ) + (hostsProxiesPair[0].split('\n').length - 1)
|
||||
}
|
||||
);
|
||||
return _cb();
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (ifShouldUpdateTitle) {
|
||||
chrome.browserAction.setTitle({
|
||||
title: title,
|
||||
tabId: requestDetails.tabId
|
||||
});
|
||||
}
|
||||
|
||||
return cb();
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
let previousUpdateTitleFinished = Promise.resolve();
|
||||
|
||||
function isProxiedAndInformed(requestDetails) {
|
||||
|
||||
if (
|
||||
!( window.antiCensorRu.pacProvider && window.antiCensorRu.pacProvider.proxyIps && window.antiCensorRu.pacProvider.proxyIps[ requestDetails.ip ] )
|
||||
) {
|
||||
if ( !(requestDetails.ip && antiCensorRu.isProxied( requestDetails.ip )) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -74,75 +142,6 @@ window.tabWithError2ip = {}; // For errors only: Error? -> Check this IP!
|
|||
);
|
||||
|
||||
return true;
|
||||
|
||||
function updateTitle(requestDetails, cb) {
|
||||
|
||||
chrome.browserAction.getTitle(
|
||||
{ tabId: requestDetails.tabId },
|
||||
(title) => {
|
||||
|
||||
const ifTitleSetAlready = /\n/.test(title);
|
||||
const proxyHost = window.antiCensorRu.pacProvider.proxyIps[ requestDetails.ip ];
|
||||
|
||||
const hostname = new URL( requestDetails.url ).hostname;
|
||||
|
||||
let ifShouldUpdateTitle = false;
|
||||
const indent = ' ';
|
||||
const proxyTitle = 'Прокси:';
|
||||
|
||||
if (!ifTitleSetAlready) {
|
||||
title = 'Разблокированы:\n'+ indent + hostname +'\n'+ proxyTitle +'\n'+ indent + proxyHost;
|
||||
ifShouldUpdateTitle = true;
|
||||
|
||||
chrome.browserAction.setBadgeText({
|
||||
tabId: requestDetails.tabId,
|
||||
text: ifMainFrame ? '1' : '%1'
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
const hostsProxiesPair = title.split(proxyTitle);
|
||||
|
||||
if (hostsProxiesPair[1].indexOf(proxyHost) === -1) {
|
||||
title = title.replace(hostsProxiesPair[1], hostsProxiesPair[1] +'\n'+ indent + proxyHost);
|
||||
ifShouldUpdateTitle = true;
|
||||
}
|
||||
|
||||
if (hostsProxiesPair[0].indexOf(hostname) === -1) {
|
||||
title = title.replace(proxyTitle, indent + hostname +'\n'+ proxyTitle);
|
||||
ifShouldUpdateTitle = true;
|
||||
|
||||
const _cb = cb;
|
||||
cb = () => chrome.browserAction.getBadgeText(
|
||||
{tabId: requestDetails.tabId},
|
||||
(result) => {
|
||||
|
||||
chrome.browserAction.setBadgeText(
|
||||
{
|
||||
tabId: requestDetails.tabId,
|
||||
text: ( isNaN( result.charAt(0) ) && result.charAt(0) || '' ) + (hostsProxiesPair[0].split('\n').length - 1)
|
||||
}
|
||||
);
|
||||
return _cb();
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (ifShouldUpdateTitle) {
|
||||
chrome.browserAction.setTitle({
|
||||
title: title,
|
||||
tabId: requestDetails.tabId
|
||||
});
|
||||
}
|
||||
|
||||
return cb();
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
chrome.webRequest.onResponseStarted.addListener(
|
||||
|
|
|
@ -9,9 +9,10 @@
|
|||
margin: 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
li {
|
||||
li, footer {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
word-break: keep-all;
|
||||
}
|
||||
li > * {
|
||||
vertical-align: middle;
|
||||
|
@ -49,8 +50,7 @@
|
|||
</div>
|
||||
<div id="status">Загрузка...</div>
|
||||
<footer>
|
||||
<input type="button" value="Готово" class="close-button">
|
||||
<a href="../debug/index.html" style="float: right; text-decoration: none">Отладка</a>
|
||||
<input type="button" value="Готово" class="close-button"> <a href="../debug/index.html" style="text-decoration: none; margin-left: 1em;">Отладка</a>
|
||||
</footer>
|
||||
<script src="./index.js"></script>
|
||||
<script src="./keep-links-clickable.js"></script>
|
||||
|
|
|
@ -61,92 +61,114 @@ chrome.runtime.getBackgroundPage( (backgroundPage) => {
|
|||
|
||||
// RADIOS
|
||||
|
||||
const currentRadio = () => {
|
||||
const currentProviderRadio = () => {
|
||||
|
||||
const id = antiCensorRu.currentPacProviderKey || 'none';
|
||||
return document.querySelector('#'+id);
|
||||
|
||||
}
|
||||
const checkChosenProvider = () => currentRadio().checked = true;
|
||||
const triggerChosenProvider = () => currentRadio().click();
|
||||
const checkChosenProvider = () => currentProviderRadio().checked = true;
|
||||
|
||||
const ul = document.querySelector('#list-of-providers');
|
||||
const _firstChild = ul.firstChild;
|
||||
for( const providerKey of Object.keys(antiCensorRu.pacProviders).sort() ) {
|
||||
const li = document.createElement('li');
|
||||
li.innerHTML = '<input type="radio" name="pacProvider" id="' + providerKey + '"> <label for="' + providerKey + '">'+providerKey + '</label> <a href class="link-button checked-radio-panel">[обновить]</a>';
|
||||
li.querySelector('.link-button').onclick = () => { triggerChosenProvider(); return false; };
|
||||
ul.insertBefore( li, _firstChild );
|
||||
}
|
||||
const showError = (err) => {
|
||||
|
||||
const radios = [].slice.apply( document.querySelectorAll('[name=pacProvider]') );
|
||||
for(const radio of radios) {
|
||||
radio.onclick = function(event) {
|
||||
let clarification = err.clarification;
|
||||
const ifNotCritical = clarification && clarification.ifNotCritical;
|
||||
let message = err.message || '';
|
||||
|
||||
const pacKey = event.target.id;
|
||||
if (pacKey === 'none') {
|
||||
return antiCensorRu.clearPac();
|
||||
}
|
||||
|
||||
const enableDisableInputs = function () {
|
||||
|
||||
const inputs = document.querySelectorAll('input');
|
||||
for ( let i = 0; i < inputs.length; i++ ) {
|
||||
inputs[i].disabled = !inputs[i].disabled;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enableDisableInputs();
|
||||
setStatusTo('Установка...');
|
||||
antiCensorRu.installPac(pacKey, (err) => {
|
||||
|
||||
backgroundPage.console.log('Popup callback...');
|
||||
if (!err) {
|
||||
setStatusTo('PAC-скрипт установлен.');
|
||||
checkChosenProvider();
|
||||
}
|
||||
else {
|
||||
const ifNotCritical = err.clarification && err.clarification.ifNotCritical;
|
||||
|
||||
let message = '';
|
||||
let clarification = err.clarification;
|
||||
do {
|
||||
message = message +' '+ (clarification && clarification.message || err.message || '');
|
||||
clarification = clarification && clarification.prev;
|
||||
} while( clarification );
|
||||
message = message.trim();
|
||||
setStatusTo(
|
||||
while( clarification ) {
|
||||
message = (clarification && (clarification.message + ' ')) + message;
|
||||
clarification = clarification.prev;
|
||||
}
|
||||
message = message.trim();
|
||||
setStatusTo(
|
||||
`<span style="color:red">${ifNotCritical ? 'Некритичная ошибка.' : 'Ошибка!'}</span>
|
||||
<br/>
|
||||
<span style="font-size: 0.9em; color: darkred">${message}</span>
|
||||
<button>Сообщить автору</button><br/>
|
||||
<a href class="link-button">[Ещё подробнее]</a>`
|
||||
);
|
||||
getStatus().querySelector('.link-button').onclick = function() {
|
||||
);
|
||||
getStatus().querySelector('.link-button').onclick = function() {
|
||||
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = `
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = `
|
||||
Более подробную информацию можно узнать из логов фоновой страницы:<br/>
|
||||
<a href="chrome://extensions?id=${chrome.runtime.id}" data-in-bg="true">chrome://extensions</a> › Это расширение › Отладка страниц: фоновая страница › Console (DevTools)
|
||||
<br>
|
||||
Ещё: ${JSON.stringify({err: err, stack: err.stack})}
|
||||
`;
|
||||
getStatus().replaceChild(div, this);
|
||||
return false;
|
||||
|
||||
};
|
||||
}
|
||||
enableDisableInputs();
|
||||
});
|
||||
getStatus().replaceChild(div, this);
|
||||
return false;
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
const enableDisableInputs = function () {
|
||||
|
||||
const inputs = document.querySelectorAll('input');
|
||||
for ( let i = 0; i < inputs.length; i++ ) {
|
||||
inputs[i].disabled = !inputs[i].disabled;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const conduct = (beforeStatus, operation, afterStatus, onSuccess) => {
|
||||
|
||||
setStatusTo(beforeStatus);
|
||||
enableDisableInputs();
|
||||
operation((err) => {
|
||||
if (err) {
|
||||
showError(err);
|
||||
}
|
||||
else {
|
||||
setStatusTo(afterStatus);
|
||||
onSuccess && onSuccess();
|
||||
}
|
||||
enableDisableInputs();
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
const ul = document.querySelector('#list-of-providers');
|
||||
const _firstChild = ul.firstChild;
|
||||
for( const providerKey of Object.keys(antiCensorRu.pacProviders).sort() ) {
|
||||
const li = document.createElement('li');
|
||||
li.innerHTML = `<input type="radio" name="pacProvider" id="${providerKey}"> <label for="${providerKey}">${providerKey}</label> <a href class="link-button checked-radio-panel">[обновить]</a>`;
|
||||
li.querySelector('.link-button').onclick = () => { conduct( 'Обновляем...', (cb) => antiCensorRu.syncWithPacProvider(cb), 'Обновлено.' ); return false; };
|
||||
ul.insertBefore( li, _firstChild );
|
||||
}
|
||||
checkChosenProvider();
|
||||
|
||||
const radios = [].slice.apply( document.querySelectorAll('[name=pacProvider]') );
|
||||
for(const radio of radios) {
|
||||
radio.onclick = function(event) {
|
||||
|
||||
if (event.target.id === (antiCensorRu.currentPacProviderKey || 'none')) {
|
||||
return false;
|
||||
}
|
||||
const pacKey = event.target.id;
|
||||
if (pacKey === 'none') {
|
||||
conduct(
|
||||
'Отключение...',
|
||||
(cb) => antiCensorRu.clearPac(cb),
|
||||
'Отключено.',
|
||||
checkChosenProvider
|
||||
);
|
||||
}
|
||||
else {
|
||||
conduct(
|
||||
'Установка...',
|
||||
(cb) => antiCensorRu.installPac(pacKey, cb),
|
||||
'PAC-скрипт установлен.',
|
||||
checkChosenProvider
|
||||
);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
setStatusTo('');
|
||||
checkChosenProvider();
|
||||
if (antiCensorRu.ifFirstInstall) {
|
||||
triggerChosenProvider();
|
||||
currentProviderRadio().click();
|
||||
}
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user