Merge branch 'development' into production

This commit is contained in:
ilyaigpetrov 2020-12-23 14:37:39 +00:00
commit 95bfd3ae9e
24 changed files with 11167 additions and 4518 deletions

View File

@ -15,6 +15,14 @@ This extension uses pac scripts, one of which (anticensority) is generated by th
[pac-generator]: https://github.com/anticensority/pac-script-generator
## Install / Установка
1. [Chrome Web Store](https://rebrand.ly/ac-webstore)
2. [Chrome Web Store (MINI)](https://rebrand.ly/ac-webstore-mini)
3. [Microsoft Edge Add-ons](https://rebrand.ly/ac-msstore)
4. [Microsoft Edge Add-ons (MINI)](https://rebrand.ly/ac-msstore-mini)
5. [FireFox Add-ons (Beta)](https://rebrand.ly/ac-firefox)
## Why I do This
I believe __information mustn't be blocked based on political or other subjective views__.
@ -61,5 +69,3 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
<a href="https://opencollective.com/anticensority/sponsor/7/website" target="_blank"><img src="https://opencollective.com/anticensority/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/anticensority/sponsor/8/website" target="_blank"><img src="https://opencollective.com/anticensority/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/anticensority/sponsor/9/website" target="_blank"><img src="https://opencollective.com/anticensority/sponsor/9/avatar.svg"></a>

View File

@ -1,6 +1,10 @@
# Install
Tested on NodeJS versoin: 12.
Tested on:
NodeJS: v14.13.1.
NPM: 6.14.8.
OS: Linux Mint 20 Xfce Edition.
```
npm install
@ -13,11 +17,25 @@ npm start
# Use your build/extension-beta
# For production:
npm run release
npm start
# Use your build/extension-full or build/extension-mini
```
# Release
# For Reviewers
Steps to reproduce the same zip:
```
npm ci
cd src/extension-common/pages/options/
npm ci
cd -
npm start
# See ./build/extension-full
cd ./build/extension-full
zip -r runet-censorship-bypass-full.zip ./*
```
# Release Instructions
1. `npm run release`
2. `vim src/templates-data.js` and bump version.

View File

@ -46,7 +46,7 @@ const templatePlugin = (context) => through.obj(function(file, encoding, cb) {
const clean = function(cb) {
//return del.sync('./build');
del.sync('./build');
return cb();
};
@ -97,7 +97,7 @@ const copyBeta = function(cb) {
};
const buildAll = gulp.parallel(copyMini, copyFull, copyBeta);
const buildAll = gulp.series(clean, gulp.parallel(copyMini, copyFull, copyBeta));
const buildBeta = copyBeta;
module.exports = {

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@
"test": "mocha --recursive ./src/**/test/*",
"subpages": "cd ./src/extension-common/pages/options/ && npm run build && cd -",
"subpages:dev": "cd ./src/extension-common/pages/options/ && npm run build:dev:nocomp && cd -",
"start": "npm run subpages:dev && npm run gulp buildAll",
"start": "npm run release",
"release": "npm run subpages && npm run gulp buildAll"
},
"author": "Ilya Ig. Petrov",

View File

@ -1,5 +1,7 @@
'use strict';
console.log('Extension started.');
{
const IF_DEBUG = true;
@ -39,15 +41,18 @@
},
lastError: undefined,
checkChromeError() {
// Chrome API calls your cb in a context different from the point of API
// method invokation.
const err = chrome.runtime.lastError || chrome.extension.lastError;
const err = chrome.runtime.lastError || chrome.extension.lastError || self.lastError;
if (!err) {
return;
}
console.warn('API returned error:', err);
delete self.lastError;
return new Error(err.message); // Add stack.
},
@ -153,6 +158,32 @@
},
promisedLocalStorage: {
get(key) {
return new Promise((resolve) => (
chrome.storage.local.get(
key,
window.utils.getOrDie((storage) => resolve(key ? storage[key] : storage)),
)
));
},
set(items) {
return new Promise((resolve) => (
chrome.storage.local.set(items, resolve)
));
},
remove(keys) {
return new Promise((resolve) => (
chrome.storage.local.remove(keys, resolve)
));
},
clear() {
return new Promise((resolve) => (
chrome.storage.local.clear(resolve)
));
},
},
/*
* Possible values for levelOfControl:
*
@ -230,6 +261,15 @@
},
openAndFocus(url) {
chrome.tabs.create(
{url: url},
(tab) => chrome.windows.update(tab.windowId, {focused: true})
);
},
};
const max = 2**16;
@ -252,43 +292,4 @@
},
};
// Shims for FireFox
if (!chrome.proxy.settings) {
const ffxStore = window.utils.createStorage('firefox-only');
chrome.proxy.settings = {
get: (_, cb) => {
let currentSettings = ffxStore('proxySettings') || {};
currentSettings.levelOfControl = 'controlled_by_this_extension'; // May be lie, but this field is required.
cb && cb(currentSettings);
},
onChange: {
addListener: () => {},
},
set: (details, cb) => {
browser.proxy.unregister();
browser.proxy.register('./default.pac.js');
// browser.proxy.onProxyError.addListener((...err) => { console.log('ERROR IN PAC:', ...err) });
browser.runtime.sendMessage(details, {toProxyScript: true});
ffxStore('proxySettings', details);
cb && cb();
},
};
const proxySettings = ffxStore('proxySettings');
if (proxySettings) {
chrome.proxy.settings.set(proxySettings);
}
}
}

View File

@ -53,15 +53,6 @@
};
const openAndFocus = function openAndFocus(url) {
chrome.tabs.create(
{url: url},
(tab) => chrome.windows.update(tab.windowId, {focused: true})
);
};
const ifPrefix = 'if-on-';
const extName = chrome.runtime.getManifest().name;
const extVersion = window.apis.version.build;
@ -75,8 +66,8 @@
const errors = err ? {[type]: err} : this.idToError;
const json = JSON.stringify(errors, errorJsonReplacer, 0);
openAndFocus(
'http://rebrand.ly/ac-error/?json=' + encodeURIComponent(json) +
window.utils.openAndFocus(
'https://rebrand.ly/ac-error/?json=' + encodeURIComponent(json) +
(type ? '&type=' + encodeURIComponent(type) : '') +
'&version=' + chrome.runtime.getManifest().version +
'&useragent=' + encodeURIComponent(navigator.userAgent) +
@ -242,7 +233,7 @@
chrome.notifications.clear(notId);
if(notId === 'no-control') {
return openAndFocus(
return window.utils.openAndFocus(
window.utils.messages.searchSettingsForUrl('proxy')
);
}
@ -252,7 +243,7 @@
handlers.installListenersOn(window, 'BG');
chrome.proxy.onProxyError.addListener( timeouted( (details) => {
(chrome.proxy.onProxyError || chrome.proxy.onError).addListener( timeouted( (details) => {
if (!handlers.ifControlled) {
return;
@ -291,7 +282,7 @@
handlers.mayNotify(
noCon,
chrome.i18n.getMessage('noControl'),
chrome.i18n.getMessage('which'),
chrome.i18n.getMessage('WhichQ'),
{icon: 'no-control-128.png', ifSticky: false}
);
} else {

View File

@ -69,7 +69,7 @@
);
}
console.log('GETed with success:', url, Date.now() - start);
console.log('GETed with success:', url.substr(0, 100), Date.now() - start);
textCb();
},

View File

@ -0,0 +1,64 @@
'use strict';
if (window.apis.platform.ifFirefox) {
const prefix = 'firefox-only';
const originalSet = chrome.proxy.settings.set.bind( chrome.proxy.settings );
chrome.proxy.settings.set = function(details, cb) {
const pac = window.utils.getProp(details, 'value.pacScript') || {};
if (!(pac && pac.data)) {
return originalSet(details, cb);
}
const blob = new Blob([pac.data], { type : 'application/x-ns-proxy-autoconfig' });
const blobUrl = URL.createObjectURL(blob);
originalSet({
value: {
proxyType: 'autoConfig',
autoConfigUrl: blobUrl,
},
}, window.utils.chromified( async (err) => {
if (err) {
window.utils.lastError = err;
cb();
return;
}
await window.utils.promisedLocalStorage.set({ [`${prefix}-pac-data`]: pac.data });
cb();
}));
};
const originalGet = chrome.proxy.settings.get.bind( chrome.proxy.settings );
chrome.proxy.settings.get = function(details, cb) {
originalGet(details, window.utils.chromified(async (err, originalDetails) => {
if (err) {
window.utils.lastError = err;
cb(originalDetails);
return;
}
let pacData = await window.utils.promisedLocalStorage.get(`${prefix}-pac-data`);
if (!pacData || !Object.keys(pacData).length) {
cb(originalDetails);
return;
}
cb(Object.assign(
originalDetails,
{
value: {
mode: 'pac_script',
pacScript: {
data: pacData,
},
},
}
));
}));
};
const originalClear = chrome.proxy.settings.clear.bind( chrome.proxy.settings );
chrome.proxy.settings.clear = async function(details, cb) {
await window.utils.promisedLocalStorage.remove(`${prefix}-pac-data`);
originalClear(details, cb);
};
}

View File

@ -562,7 +562,7 @@ ${
checkIncontinence(details) {
if ( kitchenState(ifIncontinence) ) {
this.setNowAsync(details, () => {/* Swallow. */});
this.setNowAsync(details, (err) => { if (err) { throw err; } }); // TODO: suppress?
}
},
@ -624,27 +624,21 @@ ${
const originalSet = chrome.proxy.settings.set.bind( chrome.proxy.settings );
chrome.proxy.settings.set = function(details, cb) {
const pac = window.utils.getProp(details, 'value.pacScript');
if (!(pac && pac.data)) {
return originalSet(details, cb);
return originalSet(details, window.utils.timeouted(cb));
}
const pacMods = getCurrentConfigs();
pac.data = pacKitchen.cook( pac.data, pacMods );
originalSet({value: details.value}, (/* No args. */) => {
originalSet({value: details.value}, window.utils.chromified((err) => {
kitchenState(ifIncontinence, null);
if (!err) {
kitchenState(ifIncontinence, null);
}
window.utils.lastError = err;
cb && cb();
});
}));
};
pacKitchen.checkIncontinence();
chrome.proxy.settings.onChange.addListener(
timeouted(
pacKitchen.checkIncontinence.bind(pacKitchen)
)
);
} // Private namespace ends.

View File

@ -37,6 +37,7 @@
const timeouted = window.utils.timeouted;
const clarifyThen = window.apis.errorsLib.clarifyThen;
const clarify = window.apis.errorsLib.clarify;
const Warning = window.apis.errorsLib.Warning;
const httpLib = window.apis.httpLib;
@ -59,6 +60,37 @@
};
const doWithoutProxyAsync = (createPromise) => new Promise((resolve, reject) => {
chrome.proxy.settings.get({}, chromified((getErr, settings) => {
if (getErr) {
reject(getErr);
return;
}
const ifWeAreInControl = window.utils.areSettingsControlledFor(settings);
if (!ifWeAreInControl) {
resolve(createPromise());
return;
}
delete settings.levelOfControl;
const setProxyAsync = () => new Promise((setResolve, setReject) => {
console.log('Restoring chrome proxy settings...');
chrome.proxy.settings.set(
settings,
chromified((err) => err ? setReject(err) : setResolve()),
);
});
console.log('Clearing chrome proxy settings...');
chrome.proxy.settings.clear({}, chromified((clearErr) => {
if (clearErr) {
reject(clearErr);
return;
}
createPromise().then((actionResult) => setProxyAsync().then(() => resolve(actionResult)), reject);
}));
}));
});
const setPacAsync = function setPacAsync(
pacData = mandatory(), cb = throwIfError,
) {
@ -71,9 +103,17 @@
},
};
console.log('Setting chrome proxy settings...');
chrome.proxy.settings.set( {value: config}, chromified((err) => {
chrome.proxy.settings.set( { value: config }, chromified((err) => {
if (err) {
if (err.message === 'proxy.settings requires private browsing permission.') {
// window.utils.openAndFocus('https://rebrand.ly/ac-allow-private-windows');
clarifyThen(
chrome.i18n.getMessage('AllowExtensionToRunInPrivateWindows'),
cb,
)(err);
return;
}
return cb(err);
}
handlers.updateControlState( () => {
@ -86,13 +126,12 @@
);
}
console.log('Successfuly set PAC in proxy settings..');
console.log('Successfuly set PAC in proxy settings.');
cb();
});
}));
};
const updatePacProxyIps = function updatePacProxyIps(
@ -143,68 +182,40 @@
}
httpLib.ifModifiedSince(pacUrl, lastModifiedStr, (err, newLastModifiedStr) => {
/*
TODO: Get rid of this dirty hack
IPFS used by AntiZapret always returns last-modified date as new Date(1000) which is 1 sec since unix epoch.
Last-modified isn't changed but target redireciton URL is and this URL should be compared to the last cached URL.
Hack here is to consider 5 seconds since epoch time the same way as the unix epoch start.
If you think etags are the solution then know that etags can't be read from the fetch API, see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers.
*/
/*
TODO: I turn off caching for now because I see no easy way out.
const ifWasEverModified = new Date(lastModifiedStr) - new Date(0) > 5000;
if (!newLastModifiedStr && ifWasEverModified) {
addWarning(
(ifRu
? 'Ваш PAC-скрипт не нуждается в обновлении. Его дата: '
: 'Your PAC-script doesn\\'t need to be updated. It\\'s date: '
) + lastModifiedStr,
);
const res = {lastModified: lastModifiedStr};
return cb(null, res);
}
*/
console.log('Doing without proxy...');
const pacDataPromise = doWithoutProxyAsync(
// 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),
() =>
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(
Promise.reject(),
).catch(
(err) => Promise.reject(clarify(
err,
Object.assign(res || {}, {lastModified: newLastModifiedStr}),
),
);
},
clarifyThen(
chrome.i18n.getMessage('FailedToDownloadPacScriptFromAddresses') + ': [ '
+ provider.pacUrls.join(' , ') + ' ].',
cb,
chrome.i18n.getMessage('FailedToDownloadPacScriptFromAddresses') + ': [ '
+ provider.pacUrls.join(' , ') + ' ].',
)),
),
);
});
).then(
(pacData) => {
setPacAsync(
pacData,
(err, res) => cb(
err,
Object.assign(res || {}, {lastModified: lastModifiedStr}),
),
);
},
cb,
);
};
window.apis.antiCensorRu = {
@ -369,18 +380,18 @@
}
}
chrome.storage.local.clear(
chrome.storage.local.remove(
'antiCensorRu',
() => chrome.storage.local.set(
onlySettable,
{ antiCensorRu: onlySettable },
chromified(cb),
)
),
);
},
syncWithPacProviderAsync(
key = this.currentPacProvierKey, cb = throwIfError) {
if( typeof(key) === 'function' ) {
cb = key;
key = this.getCurrentPacProviderKey();
@ -513,10 +524,18 @@
};
// ON EACH LAUNCH, STARTUP, RELOAD, UPDATE, ENABLE
chrome.storage.local.get(null, chromified( async (err, oldStorage) => {
(async () => {
let oldStorage = await window.utils.promisedLocalStorage.get('antiCensorRu') || {};
if (err) {
throw err;
if (!Object.keys(oldStorage).length) {
const storage = await window.utils.promisedLocalStorage.get(null);
if (storage.version && window.apis.version.isLeq(storage.version, '0.0.1.48')) {
const ffxPacData = storage['firefox-only-pac-data'];
delete storage['firefox-only-pac-data'];
await window.utils.promisedLocalStorage.clear();
await window.utils.promisedLocalStorage.set({ antiCensorRu: storage });
oldStorage = storage;
}
}
/*
@ -535,7 +554,7 @@
'Periodic PAC update triggered:',
new Date().toLocaleString('ru-RU'),
);
antiCensorRu.syncWithPacProviderAsync(() => {/* swallow */});
antiCensorRu.syncWithPacProviderAsync(() => { /* Swallow. */ });
}
})
@ -552,14 +571,15 @@
console.log('Keep cooked...');
await new Promise((resolve) => window.apis.pacKitchen.keepCookedNowAsync(resolve));
console.log('Storage on init:', oldStorage);
//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();
chrome.runtime.openOptionsPage();
return;
}
// LAUNCH, RELOAD, UPDATE
@ -686,6 +706,6 @@
* Add storage.lastPacUpdateStamp.
**/
}));
})();
}

View File

@ -136,5 +136,8 @@
},
"noOwnProxiesError": {
"message": "Proxying of OWN sites is possible only via OWN proxies. No own proxies found that satisfy your requirements."
},
"AllowExtensionToRunInPrivateWindows": {
"message": "For the extension to work it is required to allow it to run in private windows, see <a href='https://rebrand.ly/ac-allow-private-windows'>a HOWTO</a>."
}
}

View File

@ -136,5 +136,8 @@
},
"noOwnProxiesError": {
"message": "Проксировать СВОИ сайты можно только при наличии СВОИХ прокси. Нет своих прокси, удовлетворяющих вашим требованиям."
},
"AllowExtensionToRunInPrivateWindows": {
"message": "Для работы расширения необходимо разрешить запуск в приватных окнах, см. <a href='https://rebrand.ly/ac-allow-private-windows'>инструкции</a>."
}
}

View File

@ -14,6 +14,7 @@
"proxy"
, "alarms"
, "storage"
, "unlimitedStorage"
, "<all_urls>"
, "tabs"
, "contextMenus"
@ -30,6 +31,7 @@
, "11-error-handlers-api.js"
, "12-errors-lib.js"
, "13-http-lib.js"
, "15-firefox-proxy-settings.js"
${scripts_2x}
, "35-pac-kitchen-api.js"
, "37-sync-pac-script-with-pac-provider-api.js"

View File

@ -7,8 +7,10 @@ export default function getLastUpdateDate(theState) {
componentWillMount() {
this.onStorageChangedHandler = (changes) =>
changes.lastPacUpdateStamp.newValue && this.forceUpdate();
this.onStorageChangedHandler = (changes) => {
const ac = changes.antiCensorRu;
return ac && ac.newValue && ac.newValue.lastPacUpdateStamp && this.forceUpdate();
};
chrome.storage.onChanged.addListener( this.onStorageChangedHandler );

View File

@ -40,10 +40,10 @@ chrome.runtime.getBackgroundPage( (bgWindow) =>
([tab]) => resolve(tab),
)
);
winChrome.runtime.sendMessage({ currentTab, eventName: 'POPUP_OPENED' });
// winChrome.runtime.sendMessage({ currentTab, eventName: 'POPUP_OPENED' });
theState.flags.ifInsideOptionsPage = !currentTab || /.*:\/\/extensions\/\?options=/g.test(currentTab.url) || currentTab.url.startsWith('about:addons');
theState.flags.ifInsideEdgeOptionsPage = theState.flags.ifInsideOptionsPage && currentTab.url.startsWith('edge://');
theState.flags.ifInsideEdgeOptionsPage = theState.flags.ifInsideOptionsPage && currentTab && currentTab.url.startsWith('edge://');
theState.currentTab = currentTab;

View File

@ -1,42 +0,0 @@
'use strict';
{
if (!chrome.proxy.settings) {
const ffxStore = window.utils.createStorage('firefox-only');
chrome.proxy.settings = {
get: (_, cb) => {
let currentSettings = ffxStore('proxySettings') || {};
currentSettings.levelOfControl = 'controlled_by_this_extension'; // May be lie, but this field is required.
cb && cb(currentSettings);
},
onChange: {
addListener: () => {},
},
set: (details, cb) => {
browser.proxy.unregister();
browser.proxy.register('./default.pac.js');
// browser.proxy.onProxyError.addListener((...err) => { console.log('ERROR IN PAC:', ...err) });
browser.runtime.sendMessage(details, {toProxyScript: true});
ffxStore('proxySettings', details);
cb && cb();
},
};
const proxySettings = ffxStore('proxySettings');
if (proxySettings) {
chrome.proxy.settings.set(proxySettings);
}
}
}

View File

@ -1,17 +0,0 @@
var coolFind = () => {};
this.FindProxyForURL = function (...args) {
return coolFind(...args);
};
const dnsResolve = this.dnsResolve || (() => null); // Welcome to hell! Someone forgot dns.
browser.runtime.onMessage.addListener((details) => {
const pacData =
details && details.value && details.value.pacScript && details.value.pacScript.data;
if (!pacData) {
throw new Error('Never install empty PAC scripts!');
}
coolFind = (function() { eval(pacData); return FindProxyForURL; })();
});

View File

@ -69,15 +69,12 @@
const reinit = function reinit() {
/* Don't use directly, please.
Encoded to counter abuse.
*/
privates._strToHostObj = [
/* Please, don't use proxies directly (without PAC-script). */
// antizapret.prostovpn.org:
'\x70\x72\x6f\x78\x79\x2e\x61\x6e\x74\x69\x7a\x61\x70\x72\x65\x74\x2e\x70\x72\x6f\x73\x74\x6f\x76\x70\x6e\x2e\x6f\x72\x67', // Antizapret old.
'\x63\x63\x61\x68\x69\x68\x61\x2e\x61\x6e\x74\x69\x7a\x61\x70\x72\x65\x74\x2e\x70\x72\x6f\x73\x74\x6f\x76\x70\x6e\x2e\x6f\x72\x67', // Antizapret for ranges.
'\x70\x72\x6f\x78\x79\x2d\x73\x73\x6c\x2e\x61\x6e\x74\x69\x7a\x61\x70\x72\x65\x74\x2e\x70\x72\x6f\x73\x74\x6f\x76\x70\x6e\x2e\x6f\x72\x67', // Antizapret SSL.
'\x70\x72\x6f\x78\x79\x2d\x6e\x6f\x73\x73\x6c\x2e\x61\x6e\x74\x69\x7a\x61\x70\x72\x65\x74\x2e\x70\x72\x6f\x73\x74\x6f\x76\x70\x6e\x2e\x6f\x72\x67', // Antizapret w/o SSL.
'proxy.antizapret.prostovpn.org',
'proxy-ssl.antizapret.prostovpn.org',
'proxy-nossl.antizapret.prostovpn.org',
].reduce((acc, hostname) => Object.assign(acc, { [hostname]: { host: hostname }}), {
// Defaults:
localhost: { host: 'localhost' },

View File

@ -4,9 +4,13 @@
const timeouted = window.utils.timeouted;
const proxySideErrors = [
'net::ERR_TUNNEL_CONNECTION_FAILED',
];
const isProxied = (requestDetails) => false;
const isProxySideError = (details) =>
/* About !main_frame: Main frame websocket errors are followed by webnavigation errors
which chrome-internals code resets the state of the popup.
*/
details.error === 'net::ERR_TUNNEL_CONNECTION_FAILED' && details.type !== 'main_frame' && isProxied(details) ||
details.error === 'NS_ERROR_CONNECTION_REFUSED' && Boolean(details.proxyInfo);
const urlToA = (url) => new URL(url).host.link(
encodeURIComponent(url),
@ -14,9 +18,7 @@
const isProxyErrorHandledAsync = async (details) => {
if (!proxySideErrors.includes(details.error) || details.type === 'main_frame') {
// Main frame websocket errors are followed by webnavigation errors
// which chrome-internals code resets the state of the popup.
if (!isProxySideError(details)) {
return;
}
let fromPageHref = '';
@ -164,5 +166,4 @@
timeouted(isProxyErrorHandledAsync),
{urls: ['<all_urls>']},
);
}

View File

@ -2,15 +2,15 @@
const pacUrls = [
// GitHub.io (anticensority), cached:
'\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',
'https://anticensority.github.io/generated-pac-scripts/anticensority.pac',
// GitHub repo (anticensority), cached:
'\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',
'https://raw.githubusercontent.com/anticensority/generated-pac-scripts/master/anticensority.pac',
// First official, shortened, not cached:
'https://rebrand.ly/ac-chrome-anticensority-pac',
];
const commonContext = {
version: '1.42',
version: '1.50',
anticensorityPacUrls: [
...pacUrls,
],

File diff suppressed because it is too large Load Diff