diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/37-sync-pac-script-with-pac-provider-api.js b/extensions/chromium/runet-censorship-bypass/37-sync-pac-script-with-pac-provider-api.js similarity index 100% rename from extensions/chromium/runet-censorship-bypass/src/extension-common/37-sync-pac-script-with-pac-provider-api.js rename to extensions/chromium/runet-censorship-bypass/37-sync-pac-script-with-pac-provider-api.js diff --git a/extensions/chromium/runet-censorship-bypass/gulpfile.js b/extensions/chromium/runet-censorship-bypass/gulpfile.js index 94a2c00..034dfcd 100644 --- a/extensions/chromium/runet-censorship-bypass/gulpfile.js +++ b/extensions/chromium/runet-censorship-bypass/gulpfile.js @@ -10,11 +10,11 @@ const PluginName = 'Template literals'; const templatePlugin = (context) => through.obj(function(file, encoding, cb) { - const tjson = '.tmpl.json'; - if (file.path.endsWith(tjson)) { + const suffixes = ['.tmpl.json', 'tmpl.js']; + if ( suffixes.some( (suff) => file.path.endsWith(suff) ) ) { const originalPath = file.path; - file.path = file.path.replace(new RegExp(`${tjson}$`), '.json'); + file.path = file.path.replace(new RegExp(`tmpl.([^.]+)$`), '$1'); if (file.isStream()) { return cb(new PluginError(PluginName, 'Streams are not supported!')); @@ -60,6 +60,7 @@ const commonWoTests = ['./src/extension-common/**/*', ...excluded]; const miniDst = './build/extension-mini'; const fullDst = './build/extension-full'; +const betaDst = './build/extension-beta'; gulp.task('_cp-common', ['clean'], function(cb) { @@ -71,23 +72,28 @@ gulp.task('_cp-common', ['clean'], function(cb) { }; gulp.src(commonWoTests) - .pipe(changed(miniDst)) + //.pipe(changed(miniDst)) .pipe(templatePlugin(contexts.mini)) .pipe(gulp.dest(miniDst)) .on('end', intheend); gulp.src(commonWoTests) - .pipe(changed(fullDst)) + //.pipe(changed(fullDst)) .pipe(templatePlugin(contexts.full)) .pipe(gulp.dest(fullDst)) .on('end', intheend); + gulp.src(commonWoTests) + //.pipe(changed(fullDst)) + .pipe(templatePlugin(contexts.beta)) + .pipe(gulp.dest(betaDst)) + .on('end', intheend); }); gulp.task('_cp-mini', ['_cp-common'], function(cb) { gulp.src(['./src/extension-mini/**/*', ...excluded]) - .pipe(changed(miniDst)) + //.pipe(changed(miniDst)) .pipe(templatePlugin(contexts.mini)) .pipe(gulp.dest(miniDst)) .on('end', cb); @@ -96,12 +102,22 @@ gulp.task('_cp-mini', ['_cp-common'], function(cb) { gulp.task('_cp-full', ['_cp-common'], function(cb) { gulp.src(['./src/extension-full/**/*', ...excluded]) - .pipe(changed(fullDst)) + //.pipe(changed(fullDst)) .pipe(templatePlugin(contexts.full)) .pipe(gulp.dest(fullDst)) .on('end', cb); }); -gulp.task('build:prod', ['_cp-mini', '_cp-full']); +gulp.task('_cp-beta', ['_cp-common'], function(cb) { + + gulp.src(['./src/extension-full/**/*', ...excluded]) + //.pipe(changed(fullDst)) + .pipe(templatePlugin(contexts.beta)) + .pipe(gulp.dest(betaDst)) + .on('end', cb); + +}); + +gulp.task('build:all', ['_cp-mini', '_cp-full', '_cp-beta']); gulp.task('build', ['_cp-full']); diff --git a/extensions/chromium/runet-censorship-bypass/package.json b/extensions/chromium/runet-censorship-bypass/package.json index 5fdf7a3..88854d6 100644 --- a/extensions/chromium/runet-censorship-bypass/package.json +++ b/extensions/chromium/runet-censorship-bypass/package.json @@ -7,7 +7,9 @@ "lint": "eslint ./src/**/*.js --ignore-pattern vendor", "gulp": "gulp", "test": "mocha --recursive ./src/**/test/*", - "start": "cd ./src/extension-common/pages/options/ && npm run build && cd - && npm run gulp" + "subpages": "cd ./src/extension-common/pages/options/ && npm run build && cd -", + "start": "npm run subpages && npm run gulp", + "beta": "npm run subpages && npm run gulp build:all" }, "author": "Ilya Ig. Petrov", "license": "GPLv3", diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/37-sync-pac-script-with-pac-provider-api.tmpl.js b/extensions/chromium/runet-censorship-bypass/src/extension-common/37-sync-pac-script-with-pac-provider-api.tmpl.js new file mode 100644 index 0000000..e2184dc --- /dev/null +++ b/extensions/chromium/runet-censorship-bypass/src/extension-common/37-sync-pac-script-with-pac-provider-api.tmpl.js @@ -0,0 +1,581 @@ +'use strict'; + +/* + Task 1. Gets IPs for proxies of antizapret/anticenz via dns over https. + 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. +*/ + +/* + In background scripts use window.apis.antiCensorRu public variables. + In pages window.apis.antiCensorRu is not accessible, + use chrome.runtime.getBackgroundPage(..), + extension.getBackgroundPage is deprecated + + If you want to catch errors, then call api from setTimeout! + See errorHandlers api for more. + +*/ + +{ // Private namespace starts. + + const mandatory = window.utils.mandatory; + const throwIfError = window.utils.throwIfError; + const chromified = window.utils.chromified; + const timeouted = window.utils.timeouted; + + const clarifyThen = window.apis.errorsLib.clarifyThen; + const Warning = window.apis.errorsLib.Warning; + + const httpLib = window.apis.httpLib; + const handlers = window.apis.errorHandlers; + + const asyncLogGroup = function asyncLogGroup(...args) { + + const cb = args.pop(); + if(!(cb && typeof(cb) === 'function')) { + throw new TypeError('cb must be a function, but got: ' + cb); + } + console.group(...args); + return function(...cbArgs) { + + console.groupEnd(); + console.log('Group finished.'); + cb(...cbArgs); + + }; + + }; + + const setPacAsync = function setPacAsync( + pacData = mandatory(), cb = throwIfError + ) { + + const config = { + mode: 'pac_script', + pacScript: { + mandatory: false, + data: pacData, + }, + }; + console.log('Setting chrome proxy settings...'); + chrome.proxy.settings.set( {value: config}, chromified((err) => { + + if (err) { + return cb(err); + } + handlers.updateControlState( () => { + + if ( !handlers.ifControlled ) { + + console.warn('Failed, other extension is in control.'); + return cb( + new Error( window.utils.messages.whichExtensionHtml() ) + ); + + } + console.log('Successfuly set PAC in proxy settings..'); + cb(); + + }); + + })); + + }; + + const updatePacProxyIps = function updatePacProxyIps( + cb = throwIfError + ) { + + cb = asyncLogGroup( + 'Getting IPs for PAC hosts...', + cb + ); + window.utils.fireRequest('ip-to-host-update-all', cb); + + }; + + const setPacScriptFromProviderAsync = function setPacScriptFromProviderAsync( + provider, lastModifiedStr = mandatory(), cb = throwIfError + ) { + + const pacUrl = provider.pacUrls[0]; + cb = asyncLogGroup( + 'Getting PAC script from provider...', pacUrl, + cb + ); + + httpLib.ifModifiedSince(pacUrl, lastModifiedStr, (err, newLastModifiedStr) => { + + if (!newLastModifiedStr) { + const res = {lastModified: lastModifiedStr}; + const ifWasEverModified = lastModifiedStr !== new Date(0).toUTCString(); + if (ifWasEverModified) { + return cb( + null, res, + new Warning( + 'Ваш PAC-скрипт не нуждается в обновлении. Его дата: ' + + lastModifiedStr + ) + ); + } + } + + // Employ all urls, the latter are fallbacks for the former. + const pacDataPromise = provider.pacUrls.reduce( + (promise, url) => promise.catch( + () => new Promise( + (resolve, reject) => httpLib.get( + url, + (newErr, pacData) => newErr ? reject(newErr) : resolve(pacData) + ) + ) + ), + Promise.reject() + ); + + pacDataPromise.then( + + (pacData) => { + + setPacAsync( + pacData, + (err, res) => cb( + err, + Object.assign(res || {}, {lastModified: newLastModifiedStr}) + ) + ); + + }, + + clarifyThen( + 'Не удалось скачать PAC-скрипт с адресов: [ ' + + provider.pacUrls.join(' , ') + ' ].', + cb + ) + + ); + + }); + + }; + + window.apis.antiCensorRu = { + + version: chrome.runtime.getManifest().version, + + pacProviders: { + Антизапрет: { + label: 'Антизапрет', + desc: \`Альтернативный PAC-скрипт от стороннего разработчика. + Работает быстрее, но охватывает меньше сайтов. + Блокировка определяется по доменному имени, +
Страница проекта.\`, + order: 0, + pacUrls: ['https://antizapret.prostovpn.org/proxy.pac'], + }, + Антицензорити: { + label: 'Антицензорити', + desc: \`Основной PAC-скрипт от автора расширения. + Работает медленней, но охватывает больше сайтов. + Блокировка определятся по доменному имени или IP адресу.
+ Страница проекта.\`, + order: 1, + + /* + Don't use in system configs! Because Windows does poor caching. + Some urls are encoded to counter abuse. + Version: 0.17 + */ + pacUrls: ${JSON.stringify(anticensorityPacUrls, null, 2)}, + /*[ + // First official, shortened: + 'https://rebrand.ly/ac-chrome-anticensority-pac', + // Second official, Cloud Flare with caching: + 'https://anticensority.tk/generated-pac-scripts/anticensority.pac', + // GitHub.io (anticensority): + '\x68\x74\x74\x70\x73\x3a\x2f\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2e\x67\x69\x74\x68\x75\x62\x2e\x69\x6f\x2f\x67\x65\x6e\x65\x72\x61\x74\x65\x64\x2d\x70\x61\x63\x2d\x73\x63\x72\x69\x70\x74\x73\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2e\x70\x61\x63', + // GitHub repo (anticensority): + '\x68\x74\x74\x70\x73\x3a\x2f\x2f\x72\x61\x77\x2e\x67\x69\x74\x68\x75\x62\x75\x73\x65\x72\x63\x6f\x6e\x74\x65\x6e\x74\x2e\x63\x6f\x6d\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2f\x67\x65\x6e\x65\x72\x61\x74\x65\x64\x2d\x70\x61\x63\x2d\x73\x63\x72\x69\x70\x74\x73\x2f\x6d\x61\x73\x74\x65\x72\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2e\x70\x61\x63', + // Old, deprecated: + 'https://anticensorship-russia.tk/generated-pac-scripts/anticensority.pac', + // Google Drive (0.17, anticensority): + '\x68\x74\x74\x70\x73\x3a\x2f\x2f\x64\x72\x69\x76\x65\x2e\x67\x6f\x6f\x67\x6c\x65\x2e\x63\x6f\x6d\x2f\x75\x63\x3f\x65\x78\x70\x6f\x72\x74\x3d\x64\x6f\x77\x6e\x6c\x6f\x61\x64\x26\x69\x64\x3d\x30\x42\x32\x6d\x68\x42\x67\x46\x6e\x66\x34\x70\x45\x4c\x56\x6c\x47\x4e\x54\x42\x45\x4d\x58\x4e\x6d\x52\x58\x63', + ],*/ + }, + onlyOwnSites: { + label: 'Только свои сайты и свои прокси', + desc: 'Проксируются только добавленные вручную сайты через СВОИ вручную добавленные прокси или через локальный Tor.', + order: 99, + pacUrls: [ + 'data:application/x-ns-proxy-autoconfig,' + escape('function FindProxyForURL(){ return "DIRECT"; }'), + ] + } + }, + + getSortedEntriesForProviders() { + + return Object.entries(this.pacProviders).sort((entryA, entryB) => entryA[1].order - entryB[1].order).map(([key, prov]) => Object.assign({key: key}, prov)); + + }, + + _currentPacProviderKey: 'Антизапрет', + + /* Is it the first time extension installed? + Do something, e.g. initiate PAC sync. + */ + ifFirstInstall: false, + lastPacUpdateStamp: 0, + + setTitle() { + + const upDate = new Date(this.lastPacUpdateStamp).toLocaleString('ru-RU') + .replace(/:\\d+$/, '').replace(/\\.\\d{4}/, ''); + chrome.browserAction.setTitle({ + title: \`Обновлялись \${upDate} | Версия \${window.apis.version.build}\`, + }); + + }, + + _currentPacProviderLastModified: 0, // Not initialized. + + getLastModifiedForKey(key = mandatory()) { + + if (this._currentPacProviderKey === key) { + return new Date(this._currentPacProviderLastModified).toUTCString(); + } + return new Date(0).toUTCString(); + + }, + + setLastModified(newValue = mandatory()) { + + this._currentPacProviderLastModified = newValue; + + }, + + mustBeKey(key = mandatory()) { + + if ( !(key === null || this.pacProviders[key]) ) { + throw new TypeError('No provider for key:' + key); + } + + }, + + getCurrentPacProviderKey() { + + return this._currentPacProviderKey; + + }, + + setCurrentPacProviderKey( + newKey = mandatory(), + lastModified = new Date().toUTCString() + ) { + + this.mustBeKey(newKey); + this._currentPacProviderKey = newKey; + this._currentPacProviderLastModified = lastModified; + + }, + + getPacProvider(key) { + + if(key) { + this.mustBeKey(key); + } else { + key = this.getCurrentPacProviderKey(); + } + return this.pacProviders[key]; + + }, + + _periodicUpdateAlarmReason: 'Периодичное обновление PAC-скрипта', + + pushToStorageAsync(cb = throwIfError) { + + console.log('Pushing to storage...'); + + // Copy only settable properties (except functions). + const onlySettable = {}; + for(const key of Object.keys(this)) { + if ( + Object.getOwnPropertyDescriptor(this, key).writable + && typeof(this[key]) !== 'function' + ) { + onlySettable[key] = this[key]; + } + } + + chrome.storage.local.clear( + () => chrome.storage.local.set( + onlySettable, + chromified(cb) + ) + ); + + }, + + syncWithPacProviderAsync( + key = this.currentPacProvierKey, cb = throwIfError) { + + if( typeof(key) === 'function' ) { + cb = key; + key = this.getCurrentPacProviderKey(); + } + cb = asyncLogGroup('Syncing with PAC provider ' + key + '...', cb); + + if (key === null) { + // No pac provider set. + return clarifyThen('Сперва выберите PAC-провайдера.', cb); + } + + const pacProvider = this.getPacProvider(key); + + const pacSetPromise = new Promise( + (resolve, reject) => setPacScriptFromProviderAsync( + pacProvider, + this.getLastModifiedForKey(key), + (err, res, ...warns) => { + + if (!err) { + this.setCurrentPacProviderKey(key, res.lastModified); + this.lastPacUpdateStamp = Date.now(); + this.ifFirstInstall = false; + this.setAlarms(); + this.setTitle(); + } + + resolve([err, null, ...warns]); + + } + ) + ); + + const ipsErrorPromise = new Promise( + (resolve, reject) => updatePacProxyIps( + resolve + ) + ); + + Promise.all([pacSetPromise, ipsErrorPromise]).then( + ([[pacErr, pacRes, ...pacWarns], ipsErr]) => { + + if (pacErr && ipsErr) { + return cb(pacErr, pacRes); + } + const warns = pacWarns; + if (ipsErr) { + warns.push(ipsErr); + } + this.pushToStorageAsync( + (pushErr) => cb(pacErr || pushErr, null, ...warns) + ); + + }, + cb + ); + + }, + + _pacUpdatePeriodInMinutes: 12*60, + get pacUpdatePeriodInMinutes() { + + return this._pacUpdatePeriodInMinutes; + + }, + + setAlarms() { + + let nextUpdateMoment = this.lastPacUpdateStamp + + this._pacUpdatePeriodInMinutes*60*1000; + const now = Date.now(); + if (nextUpdateMoment < now) { + nextUpdateMoment = now; + } + + console.log( + 'Next PAC update is scheduled on', + new Date(nextUpdateMoment).toLocaleString('ru-RU') + ); + + chrome.alarms.create( + this._periodicUpdateAlarmReason, + { + when: nextUpdateMoment, + periodInMinutes: this._pacUpdatePeriodInMinutes, + } + ); + + // ifAlarmTriggered. May be changed in the future. + return nextUpdateMoment === now; + + }, + + installPacAsync(key, cb = throwIfError) { + + console.log('Installing PAC...'); + if (!key) { + throw new Error('Key must be defined.'); + } + if (this.currentProviderKey !== key) { + return this.syncWithPacProviderAsync(key, cb); + } + console.log(key + ' already installed.'); + cb(); + + }, + + clearPacAsync(cb = throwIfError) { + + cb = asyncLogGroup('Cearing alarms and PAC...', cb); + chrome.alarms.clearAll( + () => chrome.proxy.settings.clear( + {}, + chromified((err) => { + + if (err) { + return cb(err); + } + this.setCurrentPacProviderKey(null); + this.pushToStorageAsync( + () => handlers.updateControlState(cb) + ); + + }) + ) + ); + + }, + + }; + + // ON EACH LAUNCH, STARTUP, RELOAD, UPDATE, ENABLE + chrome.storage.local.get(null, chromified( async (err, oldStorage) => { + + if (err) { + throw err; + } + + /* + 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. + */ + const antiCensorRu = window.apis.antiCensorRu; + + chrome.alarms.onAlarm.addListener( + timeouted( (alarm) => { + + if (alarm.name === antiCensorRu._periodicUpdateAlarmReason) { + console.log( + 'Periodic PAC update triggered:', + new Date().toLocaleString('ru-RU') + ); + antiCensorRu.syncWithPacProviderAsync(() => {/* swallow */}); + } + + }) + ); + console.log('Alarm listener installed. We won\\'t miss any PAC update.'); + + window.addEventListener('online', () => { + + console.log('We are online, checking periodic updates...'); + antiCensorRu.setAlarms(); + + }); + + console.log('Keep cooked...'); + await new Promise((resolve) => window.apis.pacKitchen.keepCookedNowAsync(resolve)); + + console.log('Storage on init:', oldStorage); + antiCensorRu.ifFirstInstall = Object.keys(oldStorage).length === 0; + + if (antiCensorRu.ifFirstInstall) { + // INSTALL + console.log('Installing...'); + handlers.switch('on', 'ext-error'); + return chrome.runtime.openOptionsPage(); + } + + // LAUNCH, RELOAD, UPDATE + // Use old or migrate to default. + antiCensorRu._currentPacProviderKey = + oldStorage._currentPacProviderKey || null; + antiCensorRu.lastPacUpdateStamp = + oldStorage.lastPacUpdateStamp || antiCensorRu.lastPacUpdateStamp; + antiCensorRu._currentPacProviderLastModified = + oldStorage._currentPacProviderLastModified + || antiCensorRu._currentPacProviderLastModified; + console.log( + 'Last PAC update was on', + new Date(antiCensorRu.lastPacUpdateStamp).toLocaleString('ru-RU') + ); + + + /* + 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. + */ + + await new Promise((resolve) => { + + const ifUpdating = antiCensorRu.version !== oldStorage.version; + if (!ifUpdating) { + + // LAUNCH, RELOAD, ENABLE + antiCensorRu.pacProviders = oldStorage.pacProviders; + console.log('Extension launched, reloaded or enabled.'); + return resolve(); + + } + + // UPDATE & MIGRATION + console.log('Updating from ', oldStorage.version, 'to', antiCensorRu.version); + const key = antiCensorRu._currentPacProviderKey; + if (key !== null) { + const ifVeryOld = !Object.keys(antiCensorRu.pacProviders).includes(key); + if (ifVeryOld) { + antiCensorRu._currentPacProviderKey = 'Антизапрет'; + } + } + + antiCensorRu.pushToStorageAsync(() => { + + console.log('Extension updated.'); + resolve(); + + }); + + }); + + if (antiCensorRu.getPacProvider()) { + antiCensorRu.setAlarms(); + } + antiCensorRu.setTitle(); + + /* + History of Changes to Storage (Migration Guide) + ----------------------------------------------- + Version 0.0.0.17: + * Remove "Антиценз". + * Rename "Оба_и_на_свитчах" to "Антицензорити" + * Add provider.label and provider.desc. + Version 0.0.0.10: + * Add this.version. + * Change PacProvider.proxyIps from {ip -> Boolean} to {ip -> hostname}. + Version 0.0.0.8-9: + * Change storage.ifNotInstalled to storage.ifFirstInstall. + * Add storage.lastPacUpdateStamp. + **/ + + })); + +} diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/pages/lib/chrome-style/index.css b/extensions/chromium/runet-censorship-bypass/src/extension-common/pages/lib/chrome-style/index.css index a3cc382..497fdd0 100644 --- a/extensions/chromium/runet-censorship-bypass/src/extension-common/pages/lib/chrome-style/index.css +++ b/extensions/chromium/runet-censorship-bypass/src/extension-common/pages/lib/chrome-style/index.css @@ -168,10 +168,10 @@ textarea { min-height: 2em; padding: 3px; outline: none; - +/** /* For better alignment between adjacent buttons and inputs. */ padding-bottom: 4px; - +/**/ } input[type='search'] { diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/pages/options/src/components/App.js b/extensions/chromium/runet-censorship-bypass/src/extension-common/pages/options/src/components/App.js index a6cfdda..32aeeb9 100644 --- a/extensions/chromium/runet-censorship-bypass/src/extension-common/pages/options/src/components/App.js +++ b/extensions/chromium/runet-censorship-bypass/src/extension-common/pages/options/src/components/App.js @@ -79,7 +79,8 @@ export default function getApp(theState) { headers: new Headers(headers), }; - const ghUrl = `https://api.github.com/repos/anticensority/chromium-extension/issues/10/comments${query}`; + //const ghUrl = `https://api.github.com/repos/anticensority/chromium-extension/issues/10/comments${query}`; + const ghUrl = `https://api.github.com/repos/anticensority/for-testing/issues/1/comments${query}`; const [error, comments, etag] = await fetch( ghUrl, diff --git a/extensions/chromium/runet-censorship-bypass/src/templates-data.js b/extensions/chromium/runet-censorship-bypass/src/templates-data.js index 36022f5..eac4931 100644 --- a/extensions/chromium/runet-censorship-bypass/src/templates-data.js +++ b/extensions/chromium/runet-censorship-bypass/src/templates-data.js @@ -2,6 +2,20 @@ const commonContext = { version: '1.3', + anticensorityPacUrls: [ + // First official, shortened: + 'https://rebrand.ly/ac-chrome-anticensority-pac', + // Second official, Cloud Flare with caching: + 'https://anticensority.tk/generated-pac-scripts/anticensority.pac', + // GitHub.io (anticensority): + '\x68\x74\x74\x70\x73\x3a\x2f\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2e\x67\x69\x74\x68\x75\x62\x2e\x69\x6f\x2f\x67\x65\x6e\x65\x72\x61\x74\x65\x64\x2d\x70\x61\x63\x2d\x73\x63\x72\x69\x70\x74\x73\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2e\x70\x61\x63', + // GitHub repo (anticensority): + '\x68\x74\x74\x70\x73\x3a\x2f\x2f\x72\x61\x77\x2e\x67\x69\x74\x68\x75\x62\x75\x73\x65\x72\x63\x6f\x6e\x74\x65\x6e\x74\x2e\x63\x6f\x6d\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2f\x67\x65\x6e\x65\x72\x61\x74\x65\x64\x2d\x70\x61\x63\x2d\x73\x63\x72\x69\x70\x74\x73\x2f\x6d\x61\x73\x74\x65\x72\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2e\x70\x61\x63', + // Old, deprecated: + 'https://anticensorship-russia.tk/generated-pac-scripts/anticensority.pac', + // Google Drive (0.17, anticensority): + '\x68\x74\x74\x70\x73\x3a\x2f\x2f\x64\x72\x69\x76\x65\x2e\x67\x6f\x6f\x67\x6c\x65\x2e\x63\x6f\x6d\x2f\x75\x63\x3f\x65\x78\x70\x6f\x72\x74\x3d\x64\x6f\x77\x6e\x6c\x6f\x61\x64\x26\x69\x64\x3d\x30\x42\x32\x6d\x68\x42\x67\x46\x6e\x66\x34\x70\x45\x4c\x56\x6c\x47\x4e\x54\x42\x45\x4d\x58\x4e\x6d\x52\x58\x63', + ] }; exports.contexts = {}; @@ -26,3 +40,14 @@ exports.contexts.mini = Object.assign({}, commonContext, { scripts_8x: '', }); +exports.contexts.beta = Object.assign({}, commonContext, { + anticensorityPacUrls: ['https://rebrand.ly/ac-beta-pac'], + version: '1.5', + versionSuffix: '', + nameSuffixEn: ' FOR TESTING', + nameSuffixRu: ' ДЛЯ ТЕСТОВ', + extra_permissions: ', "webRequest", "webNavigation"', + persistent: '', + scripts_2x: ', "20-ip-to-host-api.js"', + scripts_8x: ', "80-error-menu.js", "83-last-errors.js", "85-block-informer.js"', +});