diff --git a/extensions/chromium/runet-censorship-bypass-light/extension/00-init-apis.js b/extensions/chromium/runet-censorship-bypass-light/extension/00-init-apis.js deleted file mode 100644 index deeea8e..0000000 --- a/extensions/chromium/runet-censorship-bypass-light/extension/00-init-apis.js +++ /dev/null @@ -1,33 +0,0 @@ -'use strict'; - -window.utils = { - - areSettingsNotControlledFor(details) { - - return ['controlled_by_other', 'not_controllable'] - .some( (prefix) => details.levelOfControl.startsWith(prefix) ); - - }, - - messages: { - - searchSettingsForUrl(niddle) { - - return 'chrome://settings/search#' + (chrome.i18n.getMessage(niddle) || niddle); - - }, - - whichExtensionHtml() { - - return chrome.i18n.getMessage('noControl') + - ` - ${ chrome.i18n.getMessage('which') } - `; - - }, - - }, - -}; - -window.apis = {}; diff --git a/extensions/chromium/runet-censorship-bypass-light/extension/00-set-pac.js b/extensions/chromium/runet-censorship-bypass-light/extension/00-set-pac.js new file mode 100644 index 0000000..7329e6e --- /dev/null +++ b/extensions/chromium/runet-censorship-bypass-light/extension/00-set-pac.js @@ -0,0 +1,313 @@ +'use strict'; + +console.log('Started.'); + +window.state = { + lastError: null, + ifNotControllable: false, +}; + +window.whichExtensionHtml = ` + + ${chrome.i18n.getMessage('noControl')} + + ${chrome.i18n.getMessage('which')} + `; + +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)); + +}); diff --git a/extensions/chromium/runet-censorship-bypass-light/extension/12-set-pac-url.js b/extensions/chromium/runet-censorship-bypass-light/extension/12-set-pac-url.js deleted file mode 100644 index 42bb04b..0000000 --- a/extensions/chromium/runet-censorship-bypass-light/extension/12-set-pac-url.js +++ /dev/null @@ -1,91 +0,0 @@ -'use strict'; - -window.state = { - lastError: null, - ifNotControlled: false -}; - -function redBadge(msg) { - - window.chrome.browserAction.setBadgeBackgroundColor({ - color: '#db4b2f', - }); - chrome.browserAction.setBadgeText({ - text: msg, - }); - -} - -let defaultColorPromise = new Promise( function (resolve) { - - chrome.browserAction.getBadgeBackgroundColor({}, resolve); - -}); - -function okBadge(msg) { - - defaultColorPromise.then( function (defaultColor) { - window.chrome.browserAction.setBadgeBackgroundColor({ - color: defaultColor, - }); - chrome.browserAction.setBadgeText({ - text: msg, - }); - }); - -} - -function checkControlFor(details) { - - state.ifNotControlled = utils.areSettingsNotControlledFor(details); - if (state.ifNotControlled) { - console.warn('Failed, other extension is in control.'); - redBadge('xCTRL'); - } else { - console.log('Successfuly set PAC in proxy settings..'); - okBadge('ok'); - } - -} - -chrome.proxy.settings.onChange.addListener( checkControlFor ); - -chrome.proxy.onProxyError.addListener((details) => { - - console.error(details); - //if (window.state.ifNotControlled) { - // return; - //} -}); - -chrome.proxy.settings.set( - { - value: { - mode: 'pac_script', - pacScript: { - /* - Don't use in system configs! Because Win does poor caching. - Url is encoded to counter abuse. - Source: CloudFlare - */ - //url: 'https://anticensorship-russia.tk/generated-pac-scripts/on-switches-0.17.pac', - //url: 'https://antizapret.prostovpn.org/proxy.pac', - url: 'http://localhost:8080/on-switches-0.17.pac', - mandatory: true - //url: '\x68\x74\x74\x70\x73\x3a\x2f\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x73\x68\x69\x70\x2d\x72\x75\x73\x73\x69\x61\x2e\x74\x6b\x2f\x67\x65\x6e\x65\x72\x61\x74\x65\x64\x2d\x70\x61\x63\x2d\x73\x63\x72\x69\x70\x74\x73\x2f\x6f\x6e\x2d\x73\x77\x69\x74\x63\x68\x65\x73\x2d\x30\x2e\x31\x37\x2e\x70\x61\x63', - }, - }, - }, - function() { - - const err = chrome.runtime.lastError || chrome.extension.lastError; - if(err) { - alert(333) - redBadge('ERR'); - } else { - alert(11); - chrome.proxy.settings.get({}, checkControlFor); - } - - } -); diff --git a/extensions/chromium/runet-censorship-bypass-light/extension/40-context-menus.js b/extensions/chromium/runet-censorship-bypass-light/extension/40-context-menus.js index 2db6a12..038bf43 100644 --- a/extensions/chromium/runet-censorship-bypass-light/extension/40-context-menus.js +++ b/extensions/chromium/runet-censorship-bypass-light/extension/40-context-menus.js @@ -2,13 +2,38 @@ { - const createMenuLinkEntry = (title, tab2url) => chrome.contextMenus.create({ - title: title, - contexts: ['browser_action'], - onclick: - (menuInfo, tab) => Promise.resolve( tab2url( tab ) ) - .then( (url) => chrome.tabs.create({url: url}) ), - }); + let seqId = 0; + + const createMenuLinkEntry = (title, tab2url) => { + + const id = (++seqId).toString(); + + chrome.runtime.onInstalled.addListener( + () => chrome.contextMenus.create({ + id: id, + title: title, + contexts: ['browser_action'] + }, timeouted(() => { + + const err = chrome.runtime.lastError; + if(err) { + console.warn('CTX MENU ERR', err); + throw err; + } + + })) + ); + + chrome.contextMenus.onClicked.addListener((info, tab) => { + + if(info.menuItemId === id) { + Promise.resolve( tab2url( tab ) ) + .then( (url) => chrome.tabs.create({url: url}) ); + } + + }); + + }; createMenuLinkEntry( 'Сайт доступен из-за границы? Is up?', diff --git a/extensions/chromium/runet-censorship-bypass-light/extension/_locales/en/messages.json b/extensions/chromium/runet-censorship-bypass-light/extension/_locales/en/messages.json index ea37145..e221d4e 100644 --- a/extensions/chromium/runet-censorship-bypass-light/extension/_locales/en/messages.json +++ b/extensions/chromium/runet-censorship-bypass-light/extension/_locales/en/messages.json @@ -1,6 +1,6 @@ { "extName": { - "message": "Light Runet Censorship Bypass" + "message": "Runet Censorship Bypass MICRO" }, "extDesc": { "message": "Circumvent Russian Internet Censorship: https://rebrand.ly/ac-wiki" diff --git a/extensions/chromium/runet-censorship-bypass-light/extension/icons/ext-error-128.png b/extensions/chromium/runet-censorship-bypass-light/extension/icons/ext-error-128.png new file mode 100644 index 0000000..4317d1f Binary files /dev/null and b/extensions/chromium/runet-censorship-bypass-light/extension/icons/ext-error-128.png differ diff --git a/extensions/chromium/runet-censorship-bypass-light/extension/manifest.json b/extensions/chromium/runet-censorship-bypass-light/extension/manifest.json index cdf7578..8c90cd7 100644 --- a/extensions/chromium/runet-censorship-bypass-light/extension/manifest.json +++ b/extensions/chromium/runet-censorship-bypass-light/extension/manifest.json @@ -13,8 +13,6 @@ "permissions": [ "proxy", - "alarms", - "storage", "", "tabs", "contextMenus", @@ -22,10 +20,10 @@ ], "background": { - "persistent": true, + "persistent": false, "scripts": [ - "00-init-apis.js", - "12-set-pac-url.js" + "00-set-pac.js", + "40-context-menus.js" ] }, "browser_action": { diff --git a/extensions/chromium/runet-censorship-bypass-light/extension/pages/show-state/index.html b/extensions/chromium/runet-censorship-bypass-light/extension/pages/show-state/index.html index 45fb4c2..42d1342 100644 --- a/extensions/chromium/runet-censorship-bypass-light/extension/pages/show-state/index.html +++ b/extensions/chromium/runet-censorship-bypass-light/extension/pages/show-state/index.html @@ -1,43 +1,111 @@  - + - Выбор провайдера PAC -
- Обход блокировок Рунета облегчённый +
+
+

Обход блокировок Рунета МИКРО

- - -
-
- - -
-
-
+
+
+
    +
  1. +
  2. +
+
+
+ diff --git a/extensions/chromium/runet-censorship-bypass-light/extension/pages/show-state/index.js b/extensions/chromium/runet-censorship-bypass-light/extension/pages/show-state/index.js index 0d55e8e..5389fba 100644 --- a/extensions/chromium/runet-censorship-bypass-light/extension/pages/show-state/index.js +++ b/extensions/chromium/runet-censorship-bypass-light/extension/pages/show-state/index.js @@ -4,30 +4,58 @@ chrome.runtime.getBackgroundPage( (backgroundPage) => { const state = backgroundPage.state; - if( state.ifNotControlled ) { - document.getElementById('which-extension').innerHTML - = backgroundPage.utils.messages.whichExtensionHtml(); - document.querySelectorAll('.if-not-controlled').forEach( (node) => { - - node.style.display = 'block'; - - }); + if( state.ifNotControllable ) { + document.getElementById('which-extension').innerHTML = backgroundPage.whichExtensionHtml; + document.documentElement.classList.add('if-not-controlled'); } - if (state.lastError) { + if ( state.lastError) { - document.querySelectorAll('.if-error').forEach( (node) => { + const err = ['message', 'stack', 'name'].reduce((acc, prop) => { - node.style.display = 'block'; + acc[prop] = state.lastError[prop]; + return acc; + + }, {}); + document.getElementById('last-error').innerHTML = JSON.stringify(err); + document.documentElement.classList.add('if-error'); - }); - document.getElementById('last-error').innerHTML = state.lastError; } - document.documentElement.style.display = ''; + const setStatusTo = (msg) => { + document.getElementById('status').innerHTML = msg; + }; + + if(localStorage.onOff === 'on') { + document.getElementById('pac-on').checked = true; + } else { + document.getElementById('pac-off').checked = true; + } + document.getElementById('pac-switch').onclick = function(event) { + + if(event.target.tagName !== 'INPUT') { + return true; + } + setStatusTo('Ждите...'); + const cb = () => { + + event.target.checked = true; + setStatusTo('Готово!'); + + }; + if (event.target.id === 'pac-on') { + backgroundPage.switchPac('on', cb); + } else { + backgroundPage.switchPac('off', cb); + } + return false; + + }; // CLOSE BUTTON document.querySelector('.close-button').onclick = () => window.close(); + document.documentElement.style.display = ''; + }); diff --git a/extensions/chromium/runet-censorship-bypass-light/extension/pages/show-state/keep-links-clickable.js b/extensions/chromium/runet-censorship-bypass-light/extension/pages/show-state/keep-links-clickable.js new file mode 100644 index 0000000..8d139cf --- /dev/null +++ b/extensions/chromium/runet-censorship-bypass-light/extension/pages/show-state/keep-links-clickable.js @@ -0,0 +1,37 @@ +'use strict'; +/* +In popup links are not clickable at all, fix it. +On other pages "chrome://" links are not clickable, fix it. +Use only if really required because of performance penalty. +*/ +{ + + const target = document.documentElement; + + const updateLinks = () => { + + const links = document.querySelectorAll('a:not([href=""])'); + for (let i = 0; i < links.length; i++) { + const ln = links[i]; + const location = ln.href; + ln.onclick = function() { + + chrome.tabs.create({active: !this.dataset.inBg, url: location}); + return false; + + }; + } + + }; + + new MutationObserver( updateLinks ) + .observe(target, { + attributes: true, + subtree: true, + childList: true, + characterData: false, + }); + + document.addEventListener('DOMContentLoaded', updateLinks); + +}