Refactor err handlers, unixify newlines, restructure files

This commit is contained in:
Ilya Ig. Petrov 2016-12-01 07:01:20 -08:00
parent 257495168c
commit 6750872ea5
11 changed files with 357 additions and 206 deletions

View File

@ -1,3 +1,7 @@
# Dev
Linting JS: `npm run lint`
# О расширении # О расширении
Обход интернет-цензуры в России пока что не является преступлением. Обход интернет-цензуры в России пока что не является преступлением.

View File

@ -1,56 +0,0 @@
'use strict';
{
const extName = chrome.runtime.getManifest().name;
const notify = (
id,
title,
message,
icon = 'default-128.png',
context = extName
) => chrome.notifications.create(
id,
{
title: title,
message: message,
contextMessage: context,
requireInteraction: true,
type: 'basic',
iconUrl: './icons/' + icon,
}
);
window.addEventListener('error', (err) => {
console.warn('Global error');
notify('Unhandled error', 'Unhandled error', JSON.stringify(err),
'ext-error-128.png');
});
window.addEventListener('unhandledrejection', (event) => {
console.warn('Unhandled rejection. Throwing error.');
event.preventDefault();
throw event.reason;
});
chrome.proxy.onProxyError.addListener((details) => {
console.warn('PAC ERROR:', details);
notify('pac-error', ' PAC !', JSON.stringify(details),
'pac-error-128.png' );
});
chrome.proxy.settings.onChange.addListener((details) => {
console.log('Proxy settings changed.', details);
// const ifOther = details.levelOfControl.startsWith('controlled_by_other');
notify('Proxy change', 'Proxy changed', JSON.stringify(details),
'no-control-128.png');
});
}

View File

@ -0,0 +1,14 @@
'use strict';
window.utils = {
areSettingsNotControlledFor(details) {
return ['controlled_by_other', 'not_controllable']
.some( (prefix) => details.levelOfControl.startsWith(prefix) );
},
};
window.apis = {};

View File

@ -0,0 +1,148 @@
'use strict';
{ // Private namespace
const handlersState = function(key, value) {
console.log(key, value, '!');
key = 'handlers-' + key;
if (value === null) {
return localStorage.removeItem(key);
}
if (value === undefined) {
const item = localStorage.getItem(key);
return item && JSON.parse(item);
}
if (value instanceof Date) {
throw new TypeError('Converting Date format to JSON is not supported.');
}
localStorage.setItem(key, JSON.stringify(value));
};
const ifPrefix = 'if-on-';
window.apis.errorHandlers = {
getEventsMap() {
return new Map([
['pac-error', 'ошибки PAC скриптов'],
['ext-error', 'ошибки расширения'],
['no-control', 'утеря контроля над настройками'],
]);
},
switch(onOffStr, eventName) {
if (!['on', 'off'].includes(onOffStr)) {
throw new TypeError('First argument bust be "on" or "off".');
}
for(
const name of (eventName ? [eventName] : this.getEventsMap().keys() )
) {
handlersState( ifPrefix + name, onOffStr === 'on' ? 'on' : null );
}
},
isOn(eventName) {
return handlersState( ifPrefix + eventName);
},
ifNotControlled: null,
isNotControlled(details) {
this.ifNotControlled = window.utils.areSettingsNotControlledFor( details );
if (this.ifNotControlled) {
chrome.browserAction.disable();
} else {
chrome.browserAction.enable();
}
return this.ifNotControlled;
},
};
}
// INIT
chrome.proxy.settings.get(
{},
(details) => window.apis.errorHandlers.isNotControlled(details)
);
{
const extName = chrome.runtime.getManifest().name;
const mayNotify = function(
id, title, message,
icon = 'default-128.png',
context = extName
) {
if ( !window.apis.errorHandlers.isOn(id) ) {
return;
}
chrome.notifications.create(
id,
{
title: title,
message: message,
contextMessage: context,
requireInteraction: true,
type: 'basic',
iconUrl: './icons/' + icon,
isClickable: true,
}
);
};
window.addEventListener('error', (err) => {
console.warn('GLOBAL ERROR', err);
mayNotify('ext-error', 'Unhandled error', JSON.stringify(err),
'ext-error-128.png');
});
window.addEventListener('unhandledrejection', (event) => {
console.warn('Unhandled rejection. Throwing error.');
event.preventDefault();
throw event.reason;
});
chrome.proxy.onProxyError.addListener((details) => {
if (window.apis.errorHandlers.ifNoControl) {
return;
}
console.warn('PAC ERROR', details);
mayNotify('pac-error', ' PAC !', JSON.stringify(details),
'pac-error-128.png' );
});
chrome.proxy.settings.onChange.addListener((details) => {
console.log('Proxy settings changed.', details);
const noCon = 'no-control';
if ( window.apis.errorHandlers.isNotControlled(details) ) {
mayNotify(noCon, 'Proxy changed', JSON.stringify(details),
'no-control-128.png');
} else {
chrome.notifications.clear( noCon );
}
});
}

View File

@ -9,39 +9,17 @@
*/ */
/* /*
In background scripts use window.antiCensorRu public variables. In background scripts use window.apis.antiCensorRu public variables.
In pages window.antiCensorRu is not accessible, In pages window.apis.antiCensorRu is not accessible,
use chrome.runtime.getBackgroundPage(..), use chrome.runtime.getBackgroundPage(..),
extension.getBackgroundPage is deprecated extension.getBackgroundPage is deprecated
*/ */
{ // Private namespace starts. { // Private namespace starts.
window.antiCensorRu = { window.apis.antiCensorRu = {
version: chrome.runtime.getManifest().version, version: chrome.runtime.getManifest().version,
fixErrorsContext() {
/* `setTimeout` changes context of execution from other window
(e.g. popup) to background window, so we may catch errors
in bg error handlers.
More: https://bugs.chromium.org/p/chromium/issues/detail?id=357568
*/
for(const prop of Object.keys(this)) {
if ( typeof(this[prop]) === 'function' ) {
const method = this[prop];
this[prop] = function(...args) {
setTimeout(method.bind(this, ...args), 0);
};
}
}
},
throw() {
throw new Error('Artificial error');
},
pacProviders: { pacProviders: {
Антизапрет: { Антизапрет: {
pacUrl: 'https://antizapret.prostovpn.org/proxy.pac', pacUrl: 'https://antizapret.prostovpn.org/proxy.pac',
@ -293,6 +271,7 @@
} }
) )
); );
}, },
}; };
@ -307,8 +286,7 @@
E.g. install window may fail to open or be closed by user accidentally. 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. In such case extension _should_ try to work on default parameters.
*/ */
const antiCensorRu = window.antiCensorRu; const antiCensorRu = window.apis.antiCensorRu;
antiCensorRu.fixErrorsContext();
chrome.alarms.onAlarm.addListener( chrome.alarms.onAlarm.addListener(
(alarm) => { (alarm) => {
@ -393,6 +371,7 @@
* Changed storage.ifNotInstalled to storage.ifFirstInstall * Changed storage.ifNotInstalled to storage.ifFirstInstall
* Added storage.lastPacUpdateStamp * Added storage.lastPacUpdateStamp
**/ **/
}); });
function asyncLogGroup(...args) { function asyncLogGroup(...args) {
@ -406,6 +385,7 @@
cb(...cbArgs); cb(...cbArgs);
}; };
} }
function checkChromeError(betterStack) { function checkChromeError(betterStack) {
@ -458,8 +438,7 @@
} }
chrome.proxy.settings.get({}, (details) => { chrome.proxy.settings.get({}, (details) => {
const ifThis = details.levelOfControl.startsWith('controlled_by_this'); if ( window.utils.areSettingsNotControlledFor( details ) ) {
if (!ifThis) {
console.warn('Failed, other extension is in control.'); console.warn('Failed, other extension is in control.');
return cb({clarification: {message: 'Настройки прокси контролирует другое расширение. <a href="chrome://settings/search#proxy">Какое?</a>'}}); return cb({clarification: {message: 'Настройки прокси контролирует другое расширение. <a href="chrome://settings/search#proxy">Какое?</a>'}});
} }
@ -500,6 +479,7 @@
} }
); );
} }
function getIpsFor(host, cb) { function getIpsFor(host, cb) {
@ -600,6 +580,7 @@
} }
) )
); );
} }
function setPacScriptFromProvider(provider, cb) { function setPacScriptFromProvider(provider, cb) {
@ -625,6 +606,7 @@
} }
); );
} }
} }

View File

@ -0,0 +1,23 @@
'use strict';
/* `setTimeout` changes context of execution from other window
(e.g. popup) to background window, so we may catch errors
in bg error handlers.
More: https://bugs.chromium.org/p/chromium/issues/detail?id=357568
*/
// Fix error context of methods of all APIs.
for(const api of Object.keys(window.apis)) {
for(const prop of Object.keys(api)) {
if ( typeof(api[prop]) !== 'function' ) {
continue;
}
const method = api[prop];
api[prop] = function(...args) {
setTimeout(method.bind(this, ...args), 0);
};
}
}

View File

@ -14,6 +14,8 @@
Crazy parallel Chrome. Crazy parallel Chrome.
**/ **/
const antiCensorRu = window.apis.antiCensorRu;
window.chrome.browserAction.setBadgeBackgroundColor({ window.chrome.browserAction.setBadgeBackgroundColor({
color: '#db4b2f', color: '#db4b2f',
}); });
@ -66,7 +68,7 @@ window.tabWithError2ip = {}; // For errors only: Error? -> Check this IP!
(title) => { (title) => {
const ifTitleSetAlready = /\n/.test(title); const ifTitleSetAlready = /\n/.test(title);
const proxyHost = window.antiCensorRu.getPacProvider() const proxyHost = antiCensorRu.getPacProvider()
.proxyIps[requestDetails.ip]; .proxyIps[requestDetails.ip];
const hostname = new URL( requestDetails.url ).hostname; const hostname = new URL( requestDetails.url ).hostname;
@ -141,7 +143,7 @@ window.tabWithError2ip = {}; // For errors only: Error? -> Check this IP!
function isProxiedAndInformed(requestDetails) { function isProxiedAndInformed(requestDetails) {
if ( !(requestDetails.ip if ( !(requestDetails.ip
&& window.antiCensorRu.isProxied( requestDetails.ip )) ) { && antiCensorRu.isProxied( requestDetails.ip )) ) {
return false; return false;
} }

View File

@ -21,7 +21,7 @@
"notifications" "notifications"
], ],
"background": { "background": {
"scripts": ["0-error-handlers.js", "1-sync-pac-script-with-pac-provider.js", "2-block-informer.js", "3-context-menus.js"] "scripts": ["00-init-apis.js", "11-api-error-handlers.js", "12-api-sync-pac-script-with-pac-provider.js", "20-api-fixes.js", "30-block-informer.js", "40-context-menus.js"]
}, },
"browser_action": { "browser_action": {
"default_title": "Этот сайт благословлён", "default_title": "Этот сайт благословлён",

View File

@ -3,6 +3,9 @@
<head> <head>
<title>Выбор провайдера PAC</title> <title>Выбор провайдера PAC</title>
<style> <style>
label {
user-select: none;
}
ul { ul {
list-style-type: none; list-style-type: none;
padding: 0; padding: 0;
@ -39,6 +42,12 @@
footer { footer {
margin: 2em 1em 1em; margin: 2em 1em 1em;
} }
hr {
border-width: 1px 0 0 0;
}
#configs-panel > header {
margin: 0.6em 0 0.4em;
}
</style> </style>
</head> </head>
<body> <body>
@ -49,6 +58,12 @@
Обновлялись: <span class="update-date">...</span> Обновлялись: <span class="update-date">...</span>
</div> </div>
<div id="status">Загрузка...</div> <div id="status">Загрузка...</div>
<hr/>
<div id="configs-panel">
<header>Я ❤️ уведомления:</header>
<ul id="list-of-handlers">
</ul>
</div>
<footer> <footer>
<input type="button" value="Готово" class="close-button">&nbsp;<a href="../debug/index.html" style="text-decoration: none; margin-left: 1em;">Отладка</a> <input type="button" value="Готово" class="close-button">&nbsp;<a href="../debug/index.html" style="text-decoration: none; margin-left: 1em;">Отладка</a>
</footer> </footer>

View File

@ -16,7 +16,7 @@ chrome.runtime.getBackgroundPage( (backgroundPage) => {
}; };
const antiCensorRu = backgroundPage.antiCensorRu; const antiCensorRu = backgroundPage.apis.antiCensorRu;
// SET DATE // SET DATE
@ -182,6 +182,25 @@ chrome://extensions</a>
}; };
} }
const conpanel = document.getElementById('list-of-handlers');
backgroundPage.apis.errorHandlers.getEventsMap().forEach( (value, name) => {
const li = document.createElement('li');
li.innerHTML = `
<input type="checkbox" id="if-on-${name}"/>
<label for="if-on-${name}">${value}</label>`;
const box = li.querySelector('input');
box.checked = backgroundPage.apis.errorHandlers.isOn(name);
box.onclick = function() {
const id = this.id.replace('if-on-', '');
backgroundPage.apis.errorHandlers.switch(this.checked ? 'on' : 'off', id);
};
conpanel.appendChild(li);
});
setStatusTo(''); setStatusTo('');
if (antiCensorRu.ifFirstInstall) { if (antiCensorRu.ifFirstInstall) {
const id = antiCensorRu.currentPacProviderKey || 'none'; const id = antiCensorRu.currentPacProviderKey || 'none';