runet-censorship-bypass/extensions/chromium/runet-censorship-bypass-light/extension/00-set-pac.js

314 lines
7.0 KiB
JavaScript
Raw Normal View History

2017-02-09 14:45:23 +03:00
'use strict';
console.log('Started.');
window.state = {
lastError: null,
ifNotControllable: false,
};
window.whichExtensionHtml = `
${chrome.i18n.getMessage('noControl')}
<a href="chrome://settings/search#${chrome.i18n.getMessage('proxy')}">
${chrome.i18n.getMessage('which')}
</a>`;
const resetBadge = function resetBadge() {
okBadge('M');
chrome.browserAction.setTitle({title: ''});
};
window.timeouted = (cb) => (...args) => window.setTimeout(() => cb(...args), 0);
const errorJsonReplacer = function errorJsonReplacer(key, value) {
// fooWindow.ErrorEvent !== barWindow.ErrorEvent
if (!( value && value.constructor
&& ['Error', 'Event'].some(
(suff) => value.constructor.name.endsWith(suff)
)
)) {
return value;
}
const alt = {};
Object.getOwnPropertyNames(value).forEach(function(key) {
alt[key] = value[key];
}, value);
for(const prop in value) {
if (/^[A-Z]/.test(prop)) {
// MOUSEMOVE, CLICK, KEYUP, NONE, etc.
continue;
}
alt[prop] = value[prop];
}
if (value.constructor.name === 'ErrorEvent') {
for(const circularProp of
[ // First line are circular props.
'target', 'srcElement', 'path', 'currentTarget',
'bubbles', 'cancelBubble', 'cancelable', 'composed',
'defaultPrevented', 'eventPhase', 'isTrusted', 'returnValue',
'timeStamp']) {
delete alt[circularProp];
}
}
if (value.name) {
alt.name = value.name;
}
return alt;
}
const extName = chrome.runtime.getManifest().name;
chrome.notifications.onClicked.addListener( timeouted( (notId) => {
chrome.notifications.clear(notId);
const err = window.state.lastError;
err.extName = extName;
const type = 'ext-error';
const json = JSON.stringify(err, errorJsonReplacer, 0);
const url = 'http://rebrand.ly/ac-error/?json=' + encodeURIComponent(json)
+ (type ? '&type=' + encodeURIComponent(type) : '')
+ '&version=' + chrome.runtime.getManifest().version;
chrome.tabs.create(
{url: url}
);
}));
const mayNotify = function mayNotify(
id, title, errOrMessage,
{
icon = 'default-128.png',
ifSticky = true,
} = {}
) {
const message = errOrMessage.message || errOrMessage.toString();
chrome.notifications.create(
id,
{
title: title,
message: message,
contextMessage:
extName + ' ' + chrome.runtime.getManifest().version.replace(/\d+\.\d+\./g, ''),
requireInteraction: ifSticky,
type: 'basic',
iconUrl: './icons/' + icon,
isClickable: true,
}
);
}
window.installListenersOn = function installListenersOn(win, name, cb) {
win.addEventListener('error', (errEvent) => {
window.state.lastError = errEvent;
console.warn(name + ':GLOBAL ERROR', errEvent);
mayNotify('ext-error', 'Ошибка расширения!', errEvent, {icon: 'ext-error-128.png'});
});
win.addEventListener('unhandledrejection', (event) => {
console.warn(name + ': Unhandled rejection. Throwing error.');
event.preventDefault();
console.log('ev', event);
throw event.reason;
});
if (cb) {
// In most cases getBackgroundPage( (bg) => installListenersOn
// Without setTimeout errors are swallowed, bug #357568
timeouted(cb)();
}
};
window.installListenersOn(window, 'BG');
const redBadge = function redBadge(msg) {
chrome.browserAction.setBadgeBackgroundColor({
color: '#db4b2f',
});
chrome.browserAction.setBadgeText({
text: msg,
});
};
const defaultColorPromise = new Promise( function (resolve) {
chrome.browserAction.getBadgeBackgroundColor({}, resolve);
});
const okBadge = function okBadge(msg) {
defaultColorPromise.then( function (defaultColor) {
chrome.browserAction.setBadgeBackgroundColor({
color: defaultColor,
});
chrome.browserAction.setBadgeText({
text: msg,
});
});
}
const mandatory = (err) => {
throw new TypeError('This arg is required!');
};
const throwIfError = (err) => {
if (err) {
throw new Error('Got error in cb!');
}
};
const areSettingsNotControllableFor = function areSettingsNotControllable(details = mandatory()) {
state.ifNotControllable = ['controlled_by_other', 'not_controllable']
.some( (pref) => details.levelOfControl.startsWith(pref) );
if (state.ifNotControllable) {
console.warn('Failed, other extension is in control.');
state.ifNotControlled = true;
redBadge('xCTRL');
chrome.browserAction.setTitle({title: 'Другое расширение контролирует прокси'});
} else {
console.log('Settings are under our control.');
state.ifNotControlled = !details.levelOfControl.startsWith('controlled_by_this');
resetBadge();
}
};
chrome.proxy.settings.onChange.addListener( (details) => {
console.log('CHANGED prx');
areSettingsNotControllableFor(details);
});
const updateControlState = function updateControlState(cb = mandatory()) {
chrome.proxy.settings.get({}, timeouted( (details) => {
areSettingsNotControllableFor(details);
cb();
}));
};
const mayUpdatePac = function mayUpdatePac(cb = mandatory()) {
if (Date.now() < (localStorage.lastPacUpdateStamp || 0) + 12*60*60*1000 ) {
console.log('Too early for an update.' );
return cb();
}
fetch('https://rebrand.ly/ac-light-pac').then(
(res) => {
const status = res.status;
if ( !( status >= 200 && status < 300 || status === 304 ) ) {
return cb(new Error('Не удалось скачать скрипт, ошибка ' + status));
}
return res.text();
},
cb
).then( (pacData) => {
console.log('Updating PAC...');
chrome.proxy.settings.set(
{
value: {
mode: 'pac_script',
pacScript: {
// Use only with extension!
data: pacData
},
},
},
timeouted(() => {
const err = chrome.runtime.lastError || chrome.extension.lastError;
if(err) {
console.log('Updated with error:', err);
state.lastError = err;
redBadge('ERR');
chrome.browserAction.setTitle({title: 'Произошла ошибка'});
setTimeout(resetBadge, 10000);
return cb(err);
}
console.log('Updated, no errors.');
localStorage.lastPacUpdateStamp = Date.now();
updateControlState( () => {
if(state.ifNotControlled) {
cb(new Error(window.whichExtensionHtml));
} else {
cb();
}
});
})
);
},
cb
);
};
window.switchPac = function switchPac(onOff, cb = mandatory()) {
if(onOff !== 'off') {
localStorage.onOff = 'on';
chrome.browserAction.setIcon( {path: './icons/default-128.png'} );
return mayUpdatePac(cb);
}
chrome.proxy.settings.clear({}, timeouted(() => {
localStorage.lastPacUpdateStamp = 0;
localStorage.onOff = 'off';
chrome.browserAction.setIcon({
path: './icons/default-grayscale-128.png',
});
cb();
}));
};
resetBadge();
switchPac( localStorage.onOff, (err) => {
updateControlState(() => throwIfError(err));
});