mirror of
				https://github.com/anticensority/runet-censorship-bypass.git
				synced 2025-11-04 01:47:54 +03:00 
			
		
		
		
	Lint as airbnb, refactor chrome.storage for localStorage
This commit is contained in:
		
							parent
							
								
									a606d25227
								
							
						
					
					
						commit
						79f51186c7
					
				| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
module.exports = {
 | 
					module.exports = {
 | 
				
			||||||
  extends: ['eslint:recommended', 'google'],
 | 
					  extends: ['eslint:recommended', 'airbnb'],
 | 
				
			||||||
    env: {
 | 
					    env: {
 | 
				
			||||||
      browser: true,
 | 
					      browser: true,
 | 
				
			||||||
      webextensions: true,
 | 
					      webextensions: true,
 | 
				
			||||||
| 
						 | 
					@ -20,14 +20,23 @@ module.exports = {
 | 
				
			||||||
      'no-console': 'off',
 | 
					      'no-console': 'off',
 | 
				
			||||||
      'padded-blocks': 'off',
 | 
					      'padded-blocks': 'off',
 | 
				
			||||||
      'require-jsdoc': 'off',
 | 
					      'require-jsdoc': 'off',
 | 
				
			||||||
 | 
					      'no-multi-assign': 'off',
 | 
				
			||||||
      // Taken from airbnb:
 | 
					      'arrow-parens': ['error', 'always'],
 | 
				
			||||||
 | 
					      'no-plusplus': 'off',
 | 
				
			||||||
 | 
					      'comma-dangle': ['error', {
 | 
				
			||||||
 | 
					        arrays: 'always-multiline',
 | 
				
			||||||
 | 
					        objects: 'always-multiline',
 | 
				
			||||||
 | 
					        imports: 'always-multiline',
 | 
				
			||||||
 | 
					        exports: 'always-multiline',
 | 
				
			||||||
 | 
					        functions: 'ignore',
 | 
				
			||||||
 | 
					      }],
 | 
				
			||||||
 | 
					      /* Taken from airbnb:
 | 
				
			||||||
      'max-len': ['error', 100, 2, {
 | 
					      'max-len': ['error', 100, 2, {
 | 
				
			||||||
        ignoreUrls: true,
 | 
					        ignoreUrls: true,
 | 
				
			||||||
        ignoreComments: false,
 | 
					        ignoreComments: false,
 | 
				
			||||||
        ignoreRegExpLiterals: true,
 | 
					        ignoreRegExpLiterals: true,
 | 
				
			||||||
        ignoreStrings: true,
 | 
					        ignoreStrings: true,
 | 
				
			||||||
        ignoreTemplateLiterals: true,
 | 
					        ignoreTemplateLiterals: true,
 | 
				
			||||||
      }],
 | 
					      }],*/
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,8 +8,11 @@
 | 
				
			||||||
  "author": "Ilya Ig. Petrov",
 | 
					  "author": "Ilya Ig. Petrov",
 | 
				
			||||||
  "license": "GPLv3",
 | 
					  "license": "GPLv3",
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "eslint": "^3.15.0",
 | 
					    "eslint": "^3.16.1",
 | 
				
			||||||
    "eslint-config-google": "^0.7.1"
 | 
					    "eslint-config-airbnb": "^14.1.0",
 | 
				
			||||||
 | 
					    "eslint-plugin-import": "^2.2.0",
 | 
				
			||||||
 | 
					    "eslint-plugin-jsx-a11y": "^4.0.0",
 | 
				
			||||||
 | 
					    "eslint-plugin-react": "^6.10.0"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "del": "^2.2.2",
 | 
					    "del": "^2.2.2",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										18
									
								
								extensions/chromium/runet-censorship-bypass/problems.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								extensions/chromium/runet-censorship-bypass/problems.txt
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,18 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/mnt/d/__Storage__/Workspace/repos/LATEST/extensions/chromium/runet-censorship-bypass/src/extension-full/20-ip-to-host-api.js
 | 
				
			||||||
 | 
					   19:9   error  Unexpected dangling '_' in '_match'               no-underscore-dangle
 | 
				
			||||||
 | 
					   23:35  error  Expected property shorthand                       object-shorthand
 | 
				
			||||||
 | 
					   27:9   error  Unexpected dangling '_' in '_test'                no-underscore-dangle
 | 
				
			||||||
 | 
					   53:9   error  Unexpected dangling '_' in '_state'               no-underscore-dangle
 | 
				
			||||||
 | 
					   58:9   error  Unexpected dangling '_' in '_createHostObj'       no-underscore-dangle
 | 
				
			||||||
 | 
					   64:9   error  Unexpected dangling '_' in '_getHostObj'          no-underscore-dangle
 | 
				
			||||||
 | 
					   73:11  error  Unexpected dangling '_' in '_antizapret'          no-underscore-dangle
 | 
				
			||||||
 | 
					  174:9   error  Unexpected dangling '_' in '_canonize'            no-underscore-dangle
 | 
				
			||||||
 | 
					  232:11  error  Unexpected dangling '_' in '_purgeOldIpsForSync'  no-underscore-dangle
 | 
				
			||||||
 | 
					  252:24  error  Unexpected dangling '_' in '_addAsync'            no-underscore-dangle
 | 
				
			||||||
 | 
					  300:7   error  Unexpected dangling '_' in '_updateAllAsync'      no-underscore-dangle
 | 
				
			||||||
 | 
					  308:7   error  Unexpected dangling '_' in '_updateAllAsync'      no-underscore-dangle
 | 
				
			||||||
 | 
					  330:7   error  Unexpected dangling '_' in '_replaceAllAsync'     no-underscore-dangle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					✖ 13 problems (13 errors, 0 warnings)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,11 +8,11 @@
 | 
				
			||||||
    // I believe logging objects precludes them from being GCed.
 | 
					    // I believe logging objects precludes them from being GCed.
 | 
				
			||||||
    // I also don't remove logs for sake of client-side troubleshooting
 | 
					    // I also don't remove logs for sake of client-side troubleshooting
 | 
				
			||||||
    // (though no one sent me logs so far).
 | 
					    // (though no one sent me logs so far).
 | 
				
			||||||
    ['log', 'warn', 'error'].forEach( (meth) => {
 | 
					    ['log', 'warn', 'error'].forEach((meth) => {
 | 
				
			||||||
      const _meth = window.console[meth].bind(console);
 | 
					      const originalMeth = window.console[meth].bind(console);
 | 
				
			||||||
      window.console[meth] = function(...args) {
 | 
					      window.console[meth] = function wrappedForDebug(...args) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _meth(...args.map((a) => '' + a));
 | 
					        originalMeth(...args.map((a) => `${a}`/* toString, but safer */));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
| 
						 | 
					@ -33,7 +33,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    throwIfError(err) {
 | 
					    throwIfError(err) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if(err) {
 | 
					      if (err) {
 | 
				
			||||||
        throw err;
 | 
					        throw err;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,7 +45,7 @@
 | 
				
			||||||
      // method invokation.
 | 
					      // method invokation.
 | 
				
			||||||
      const err = chrome.runtime.lastError || chrome.extension.lastError;
 | 
					      const err = chrome.runtime.lastError || chrome.extension.lastError;
 | 
				
			||||||
      if (!err) {
 | 
					      if (!err) {
 | 
				
			||||||
        return;
 | 
					        return null;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      console.warn('API returned error:', err);
 | 
					      console.warn('API returned error:', err);
 | 
				
			||||||
      return new Error(err.message); // Add stack.
 | 
					      return new Error(err.message); // Add stack.
 | 
				
			||||||
| 
						 | 
					@ -62,7 +62,7 @@
 | 
				
			||||||
    chromified(cb = self.mandatory()) {
 | 
					    chromified(cb = self.mandatory()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Take error first callback and convert it to chrome API callback.
 | 
					      // Take error first callback and convert it to chrome API callback.
 | 
				
			||||||
      return function(...args) {
 | 
					      return function cbForChromeApi(...args) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const err = self.checkChromeError();
 | 
					        const err = self.checkChromeError();
 | 
				
			||||||
        self.timeouted(cb)(err, ...args);
 | 
					        self.timeouted(cb)(err, ...args);
 | 
				
			||||||
| 
						 | 
					@ -71,35 +71,42 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    getProp(obj, path = self.mandatory()) {
 | 
					    getProp(targetObj, path = self.mandatory()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const props = path.split('.');
 | 
					      const props = path.split('.');
 | 
				
			||||||
      if (!props.length) {
 | 
					      if (!props.length) {
 | 
				
			||||||
        throw new TypeError('Property must be supplied.');
 | 
					        throw new TypeError('Property must be supplied.');
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      const lastProp = props.pop();
 | 
					
 | 
				
			||||||
      for( const prop of props ) {
 | 
					      const ifSupportsInOp = (obj) =>
 | 
				
			||||||
        if (!(prop in obj)) {
 | 
					        ['object', 'function'].includes(typeof obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return props.reduce((currentObj, prop) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (
 | 
				
			||||||
 | 
					          ifSupportsInOp(currentObj)
 | 
				
			||||||
 | 
					          && prop in currentObj
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					          return currentObj[prop];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        return undefined;
 | 
					        return undefined;
 | 
				
			||||||
        }
 | 
					
 | 
				
			||||||
        obj = obj[prop];
 | 
					      }, targetObj);
 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return obj[lastProp];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert(value) {
 | 
					    assert(value) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if(!value) {
 | 
					      if (!value) {
 | 
				
			||||||
        console.assert(value);
 | 
					        console.assert(value);
 | 
				
			||||||
        throw new Error('Assert failed for:' + value);
 | 
					        throw new Error(`Assert failed for:${value}`);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    addRequestResponder(requestType, responder) {
 | 
					    addRequestResponder(requestType, responder) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if( privates.requestToResponder[requestType] ) {
 | 
					      if (privates.requestToResponder[requestType]) {
 | 
				
			||||||
        throw new TypeError(`Request ${requestType} already has responder!`);
 | 
					        throw new TypeError(`Request ${requestType} already has responder!`);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      privates.requestToResponder[requestType] = responder;
 | 
					      privates.requestToResponder[requestType] = responder;
 | 
				
			||||||
| 
						 | 
					@ -109,9 +116,9 @@
 | 
				
			||||||
    fireRequest(requestType, ...args) {
 | 
					    fireRequest(requestType, ...args) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const cb = args.slice(-1)[0];
 | 
					      const cb = args.slice(-1)[0];
 | 
				
			||||||
      self.assert(typeof(cb) === 'function');
 | 
					      self.assert(typeof cb === 'function');
 | 
				
			||||||
      const responder = privates.requestToResponder[requestType];
 | 
					      const responder = privates.requestToResponder[requestType];
 | 
				
			||||||
      if(responder) {
 | 
					      if (responder) {
 | 
				
			||||||
        responder(...args);
 | 
					        responder(...args);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        cb();
 | 
					        cb();
 | 
				
			||||||
| 
						 | 
					@ -123,18 +130,18 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return function state(key, value) {
 | 
					      return function state(key, value) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        key = prefix + key;
 | 
					        const prefixedKey = prefix + key;
 | 
				
			||||||
        if (value === null) {
 | 
					        if (value === null) {
 | 
				
			||||||
          return localStorage.removeItem(key);
 | 
					          return localStorage.removeItem(prefixedKey);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (value === undefined) {
 | 
					        if (value === undefined) {
 | 
				
			||||||
          const item = localStorage.getItem(key);
 | 
					          const item = localStorage.getItem(prefixedKey);
 | 
				
			||||||
          return item && JSON.parse(item);
 | 
					          return item && JSON.parse(item);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (value instanceof Date) {
 | 
					        if (value instanceof Date) {
 | 
				
			||||||
          throw new TypeError('Converting Date format to JSON is not supported.');
 | 
					          throw new TypeError('Converting Date format to JSON is not supported.');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        localStorage.setItem(key, JSON.stringify(value));
 | 
					        return localStorage.setItem(prefixedKey, JSON.stringify(value));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -168,15 +175,15 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      searchSettingsForUrl(niddle) {
 | 
					      searchSettingsForUrl(niddle) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return 'chrome://settings/search#' + (chrome.i18n.getMessage(niddle) || niddle);
 | 
					        return `chrome://settings/search#${(chrome.i18n.getMessage(niddle) || niddle)}`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      whichExtensionHtml() {
 | 
					      whichExtensionHtml() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return chrome.i18n.getMessage('noControl') +
 | 
					        return `${chrome.i18n.getMessage('noControl')}
 | 
				
			||||||
          ` <a href="${ this.searchSettingsForUrl('proxy') }">
 | 
					          <a href="${this.searchSettingsForUrl('proxy')}">
 | 
				
			||||||
            ${ chrome.i18n.getMessage('which') }
 | 
					            ${chrome.i18n.getMessage('which')}
 | 
				
			||||||
          </a>`;
 | 
					          </a>`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,38 +8,36 @@
 | 
				
			||||||
  const errorJsonReplacer = function errorJsonReplacer(key, value) {
 | 
					  const errorJsonReplacer = function errorJsonReplacer(key, value) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // fooWindow.ErrorEvent !== barWindow.ErrorEvent
 | 
					    // fooWindow.ErrorEvent !== barWindow.ErrorEvent
 | 
				
			||||||
    if (!( value && value.constructor
 | 
					    if (!(value && value.constructor
 | 
				
			||||||
      && ['Error', 'Event'].some(
 | 
					      && ['Error', 'Event'].some(
 | 
				
			||||||
        (suff) => value.constructor.name.endsWith(suff)
 | 
					        (suff) => value.constructor.name.endsWith(suff))
 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
    )) {
 | 
					    )) {
 | 
				
			||||||
      return value;
 | 
					      return value;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const alt = {};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Object.getOwnPropertyNames(value).forEach(function(key) {
 | 
					    const alt = Object.getOwnPropertyNames(value).reduce(
 | 
				
			||||||
 | 
					      (acc, ownProp) =>
 | 
				
			||||||
 | 
					        Object.assign(acc, { [ownProp]: value[ownProp] }),
 | 
				
			||||||
 | 
					      {}
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        alt[key] = value[key];
 | 
					    for (const prop in value) { // eslint-disable-line no-restricted-syntax
 | 
				
			||||||
 | 
					 | 
				
			||||||
    }, value);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for(const prop in value) {
 | 
					 | 
				
			||||||
      if (/^[A-Z]/.test(prop)) {
 | 
					      if (/^[A-Z]/.test(prop)) {
 | 
				
			||||||
        // MOUSEMOVE, CLICK, KEYUP, NONE, etc.
 | 
					        // MOUSEMOVE, CLICK, KEYUP, NONE, etc.
 | 
				
			||||||
        continue;
 | 
					        continue; // eslint-disable-line no-continue
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      alt[prop] = value[prop];
 | 
					      alt[prop] = value[prop];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (value.constructor.name === 'ErrorEvent') {
 | 
					    if (value.constructor.name === 'ErrorEvent') {
 | 
				
			||||||
      for(const circularProp of
 | 
					      [
 | 
				
			||||||
        [  // First line are circular props.
 | 
					 | 
				
			||||||
        'target', 'srcElement', 'path', 'currentTarget',
 | 
					        'target', 'srcElement', 'path', 'currentTarget',
 | 
				
			||||||
        'bubbles', 'cancelBubble', 'cancelable', 'composed',
 | 
					        'bubbles', 'cancelBubble', 'cancelable', 'composed',
 | 
				
			||||||
        'defaultPrevented', 'eventPhase', 'isTrusted', 'returnValue',
 | 
					        'defaultPrevented', 'eventPhase', 'isTrusted', 'returnValue',
 | 
				
			||||||
          'timeStamp']) {
 | 
					        'timeStamp',
 | 
				
			||||||
 | 
					      ].forEach((circularProp) => {
 | 
				
			||||||
        delete alt[circularProp];
 | 
					        delete alt[circularProp];
 | 
				
			||||||
      }
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (value.name) {
 | 
					    if (value.name) {
 | 
				
			||||||
| 
						 | 
					@ -53,8 +51,8 @@
 | 
				
			||||||
  const openAndFocus = function openAndFocus(url) {
 | 
					  const openAndFocus = function openAndFocus(url) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    chrome.tabs.create(
 | 
					    chrome.tabs.create(
 | 
				
			||||||
      {url: url},
 | 
					      { url },
 | 
				
			||||||
      (tab) => chrome.windows.update(tab.windowId, {focused: true})
 | 
					      (tab) => chrome.windows.update(tab.windowId, { focused: true })
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
| 
						 | 
					@ -69,13 +67,11 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    viewError(type = window.utils.mandatory(), err) {
 | 
					    viewError(type = window.utils.mandatory(), err) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const errors = err ? {[type]: err} : this.idToError;
 | 
					      const errors = err ? { [type]: err } : this.idToError;
 | 
				
			||||||
      const json = JSON.stringify(errors, errorJsonReplacer, 0);
 | 
					      const json = JSON.stringify(errors, errorJsonReplacer, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      openAndFocus(
 | 
					      openAndFocus(
 | 
				
			||||||
        'http://rebrand.ly/ac-error/?json=' + encodeURIComponent(json) +
 | 
					        `http://rebrand.ly/ac-error/?json=${encodeURIComponent(json)}${type ? `&type=${encodeURIComponent(type)}` : ''}&version=${chrome.runtime.getManifest().version}`
 | 
				
			||||||
          (type ? '&type=' + encodeURIComponent(type) : '') +
 | 
					 | 
				
			||||||
          '&version=' + chrome.runtime.getManifest().version
 | 
					 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
| 
						 | 
					@ -93,19 +89,18 @@
 | 
				
			||||||
    switch(onOffStr, eventName) {
 | 
					    switch(onOffStr, eventName) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (!['on', 'off'].includes(onOffStr)) {
 | 
					      if (!['on', 'off'].includes(onOffStr)) {
 | 
				
			||||||
        throw new TypeError('First argument bust be "on" or "off".');
 | 
					        throw new TypeError('First argument must be "on" or "off".');
 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      for(
 | 
					 | 
				
			||||||
        const name of (eventName ? [eventName] : this.getEventsMap().keys() )
 | 
					 | 
				
			||||||
      ) {
 | 
					 | 
				
			||||||
        this.state( ifPrefix + name, onOffStr === 'on' ? 'on' : null );
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      (eventName ? [eventName] : this.getEventsMap().keys()).forEach(
 | 
				
			||||||
 | 
					        (name) =>
 | 
				
			||||||
 | 
					          this.state(ifPrefix + name, onOffStr === 'on' ? 'on' : null)
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    isOn(eventName) {
 | 
					    isOn(eventName) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return this.state( ifPrefix + eventName );
 | 
					      return this.state(ifPrefix + eventName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -123,7 +118,7 @@
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (this.ifControlled) {
 | 
					      if (this.ifControlled) {
 | 
				
			||||||
        chrome.browserAction.setIcon( {path: './icons/default-128.png'} );
 | 
					        chrome.browserAction.setIcon({ path: './icons/default-128.png' });
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        chrome.browserAction.setIcon({
 | 
					        chrome.browserAction.setIcon({
 | 
				
			||||||
          path: './icons/default-grayscale-128.png',
 | 
					          path: './icons/default-grayscale-128.png',
 | 
				
			||||||
| 
						 | 
					@ -163,12 +158,12 @@
 | 
				
			||||||
      id, title, errOrMessage,
 | 
					      id, title, errOrMessage,
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        icon = 'default-128.png',
 | 
					        icon = 'default-128.png',
 | 
				
			||||||
        context = extName + ' ' + extVersion,
 | 
					        context = `${extName} ${extVersion}`,
 | 
				
			||||||
        ifSticky = true,
 | 
					        ifSticky = true,
 | 
				
			||||||
      } = {}
 | 
					      } = {}
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if ( !this.isOn(id) ) {
 | 
					      if (!this.isOn(id)) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      this.idToError[id] = errOrMessage;
 | 
					      this.idToError[id] = errOrMessage;
 | 
				
			||||||
| 
						 | 
					@ -176,12 +171,12 @@
 | 
				
			||||||
      chrome.notifications.create(
 | 
					      chrome.notifications.create(
 | 
				
			||||||
        id,
 | 
					        id,
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          title: title,
 | 
					          title,
 | 
				
			||||||
          message: message,
 | 
					          message,
 | 
				
			||||||
          contextMessage: context,
 | 
					          contextMessage: context,
 | 
				
			||||||
          requireInteraction: ifSticky,
 | 
					          requireInteraction: ifSticky,
 | 
				
			||||||
          type: 'basic',
 | 
					          type: 'basic',
 | 
				
			||||||
          iconUrl: './icons/' + icon,
 | 
					          iconUrl: `./icons/${icon}`,
 | 
				
			||||||
          appIconMaskUrl: './icons/default-mask-128.png',
 | 
					          appIconMaskUrl: './icons/default-mask-128.png',
 | 
				
			||||||
          isClickable: true,
 | 
					          isClickable: true,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -193,15 +188,16 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      win.addEventListener('error', (errEvent) => {
 | 
					      win.addEventListener('error', (errEvent) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        console.warn(name + ':GLOBAL ERROR', errEvent);
 | 
					        console.warn(`${name}:GLOBAL ERROR`, errEvent);
 | 
				
			||||||
        this.mayNotify('ext-error', 'Ошибка расширения', errEvent,
 | 
					        this.mayNotify('ext-error', 'Ошибка расширения', errEvent,
 | 
				
			||||||
          {icon: 'ext-error-128.png'});
 | 
					          { icon: 'ext-error-128.png' }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      win.addEventListener('unhandledrejection', (event) => {
 | 
					      win.addEventListener('unhandledrejection', (event) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        console.warn(name + ': Unhandled rejection. Throwing error.');
 | 
					        console.warn(`${name}: Unhandled rejection. Throwing error.`);
 | 
				
			||||||
        event.preventDefault();
 | 
					        event.preventDefault();
 | 
				
			||||||
        console.log('ev', event);
 | 
					        console.log('ev', event);
 | 
				
			||||||
        throw event.reason;
 | 
					        throw event.reason;
 | 
				
			||||||
| 
						 | 
					@ -225,24 +221,23 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  chrome.proxy.settings.get(
 | 
					  chrome.proxy.settings.get(
 | 
				
			||||||
    {},
 | 
					    {},
 | 
				
			||||||
    timeouted( handlers.isControllable.bind(handlers) )
 | 
					    timeouted(handlers.isControllable.bind(handlers))
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  chrome.notifications.onClicked.addListener( timeouted( (notId) => {
 | 
					  chrome.notifications.onClicked.addListener(timeouted((notId) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    chrome.notifications.clear(notId);
 | 
					    chrome.notifications.clear(notId);
 | 
				
			||||||
    if(notId === 'no-control') {
 | 
					    if (notId === 'no-control') {
 | 
				
			||||||
      return openAndFocus(
 | 
					      return openAndFocus(
 | 
				
			||||||
        window.utils.messages.searchSettingsForUrl('proxy')
 | 
					        window.utils.messages.searchSettingsForUrl('proxy'));
 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    handlers.viewError(notId);
 | 
					    return handlers.viewError(notId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  }));
 | 
					  }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handlers.installListenersOn(window, 'BG');
 | 
					  handlers.installListenersOn(window, 'BG');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  chrome.proxy.onProxyError.addListener( timeouted( (details) => {
 | 
					  chrome.proxy.onProxyError.addListener(timeouted((details) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!handlers.ifControlled) {
 | 
					    if (!handlers.ifControlled) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
| 
						 | 
					@ -256,26 +251,26 @@
 | 
				
			||||||
    console.warn('PAC ERROR', details);
 | 
					    console.warn('PAC ERROR', details);
 | 
				
			||||||
    // TOOD: add "view pac script at this line" button.
 | 
					    // TOOD: add "view pac script at this line" button.
 | 
				
			||||||
    handlers.mayNotify('pac-error', 'Ошибка PAC!',
 | 
					    handlers.mayNotify('pac-error', 'Ошибка PAC!',
 | 
				
			||||||
      details.error + '\n' + details.details,
 | 
					      `${details.error}\n${details.details}`,
 | 
				
			||||||
      {icon: 'pac-error-128.png'}
 | 
					      { icon: 'pac-error-128.png' }
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  }));
 | 
					  }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  chrome.proxy.settings.onChange.addListener( timeouted( (details) => {
 | 
					  chrome.proxy.settings.onChange.addListener(timeouted((details) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    console.log('Proxy settings changed.', details);
 | 
					    console.log('Proxy settings changed.', details);
 | 
				
			||||||
    const noCon = 'no-control';
 | 
					    const noCon = 'no-control';
 | 
				
			||||||
    const ifWasControllable = handlers.ifControllable;
 | 
					    const ifWasControllable = handlers.ifControllable;
 | 
				
			||||||
    if ( !handlers.isControllable(details) && ifWasControllable ) {
 | 
					    if (!handlers.isControllable(details) && ifWasControllable) {
 | 
				
			||||||
      handlers.mayNotify(
 | 
					      handlers.mayNotify(
 | 
				
			||||||
        noCon,
 | 
					        noCon,
 | 
				
			||||||
        chrome.i18n.getMessage('noControl'),
 | 
					        chrome.i18n.getMessage('noControl'),
 | 
				
			||||||
        chrome.i18n.getMessage('which'),
 | 
					        chrome.i18n.getMessage('which'),
 | 
				
			||||||
        {icon: 'no-control-128.png', ifSticky: false}
 | 
					        { icon: 'no-control-128.png', ifSticky: false }
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      chrome.notifications.clear( noCon );
 | 
					      chrome.notifications.clear(noCon);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  }));
 | 
					  }));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
'use strict';
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  Error Library
 | 
					 *  Error Library
 | 
				
			||||||
 *  PURPOSE 1:
 | 
					 *  PURPOSE 1:
 | 
				
			||||||
| 
						 | 
					@ -32,7 +33,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    clarify: function(err, message = mandatory(), {data} = {}) {
 | 
					    clarify(err, message = mandatory(), { data } = {}) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (!err) {
 | 
					      if (!err) {
 | 
				
			||||||
        return err;
 | 
					        return err;
 | 
				
			||||||
| 
						 | 
					@ -46,9 +47,9 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    clarifyThen: function(message, cb = mandatory()) {
 | 
					    clarifyThen(message, cb = mandatory()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return (err, ...args) => cb( self.clarify(err, message), ...args );
 | 
					      return (err, ...args) => cb(self.clarify(err, message), ...args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,35 +39,31 @@
 | 
				
			||||||
    get(url, cb = mandatory()) {
 | 
					    get(url, cb = mandatory()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const start = Date.now();
 | 
					      const start = Date.now();
 | 
				
			||||||
      fetch(url, {cache: 'no-store'}).then(
 | 
					      fetch(url, { cache: 'no-store' }).then(
 | 
				
			||||||
        (res) => {
 | 
					        (res) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          const textCb =
 | 
					          const textCb =
 | 
				
			||||||
            (err) => {
 | 
					            (err) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              console.log('Reading response as text...');
 | 
					 | 
				
			||||||
              res.text().then(
 | 
					              res.text().then(
 | 
				
			||||||
                (text) => {
 | 
					                (text) => cb(err, text),
 | 
				
			||||||
                  console.log('Calling CB...');
 | 
					 | 
				
			||||||
                  cb(err, text);
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                cb
 | 
					                cb
 | 
				
			||||||
              );
 | 
					              );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          const status = res.status;
 | 
					          const status = res.status;
 | 
				
			||||||
          if ( !( status >= 200 && status < 300 || status === 304 ) ) {
 | 
					          if (!((status >= 200 && status < 300) || status === 304)) {
 | 
				
			||||||
            return textCb(
 | 
					            return textCb(
 | 
				
			||||||
              errorsLib.clarify(
 | 
					              errorsLib.clarify(
 | 
				
			||||||
                res,
 | 
					                res,
 | 
				
			||||||
                'Получен ответ с неудачным HTTP-кодом ' + status + '.'
 | 
					                `Получен ответ с неудачным HTTP-кодом ${status}.`
 | 
				
			||||||
              )
 | 
					              )
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          console.log('GETed with success:', url, Date.now() - start);
 | 
					          console.log('GETed with success:', url, Date.now() - start);
 | 
				
			||||||
          textCb();
 | 
					          return textCb();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        errorsLib.clarifyThen(checkCon, cb)
 | 
					        errorsLib.clarifyThen(checkCon, cb)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -65,36 +65,10 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const getDefaults = function getDefaults() {
 | 
					  const getDefaults = function getDefaults() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return Object.keys(configs).reduce((acc, key) => {
 | 
					    return Object.keys(configs).reduce((acc, key) =>
 | 
				
			||||||
 | 
					      Object.assign(acc, { [key]: configs[key].dflt }),
 | 
				
			||||||
      acc[key] = configs[key].dflt;
 | 
					      {}
 | 
				
			||||||
      return acc;
 | 
					    );
 | 
				
			||||||
 | 
					 | 
				
			||||||
    }, {});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const getCurrentConfigs = function getCurrentConfigs() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const mods = kitchenState(modsKey);
 | 
					 | 
				
			||||||
    return new PacModifiers(mods || {});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const getOrderedConfigsForUser = function getOrderedConfigs() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const pacMods = getCurrentConfigs();
 | 
					 | 
				
			||||||
    return Object.keys(configs).reduce((arr, key) => {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      const conf = configs[key];
 | 
					 | 
				
			||||||
      if(typeof(conf.index) === 'number') {
 | 
					 | 
				
			||||||
        arr[conf.index] = conf;
 | 
					 | 
				
			||||||
        conf.value = pacMods[key];
 | 
					 | 
				
			||||||
        conf.key = key;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return arr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }, []);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -110,17 +84,17 @@
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      Object.assign(this, defaults, mods);
 | 
					      Object.assign(this, defaults, mods);
 | 
				
			||||||
      this.ifNoMods = ifAllDefaults ? true : false;
 | 
					      this.ifNoMods = ifAllDefaults;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      let customProxyArray = [];
 | 
					      let customProxyArray = [];
 | 
				
			||||||
      if (this.customProxyStringRaw) {
 | 
					      if (this.customProxyStringRaw) {
 | 
				
			||||||
        customProxyArray = this.customProxyStringRaw
 | 
					        customProxyArray = this.customProxyStringRaw
 | 
				
			||||||
          .replace(/#.*$/mg, '') // Strip comments.
 | 
					          .replace(/#.*$/mg, '') // Strip comments.
 | 
				
			||||||
          .split( /(?:[^\S\r\n]*(?:;|\r?\n)+[^\S\r\n]*)+/g )
 | 
					          .split(/(?:[^\S\r\n]*(?:;|\r?\n)+[^\S\r\n]*)+/g)
 | 
				
			||||||
          .map( (p) => p.trim() )
 | 
					          .map((p) => p.trim())
 | 
				
			||||||
          .filter( (p) => p && /\s+/g.test(p) );
 | 
					          .filter((p) => p && /\s+/g.test(p));
 | 
				
			||||||
        if (this.ifUseSecureProxiesOnly) {
 | 
					        if (this.ifUseSecureProxiesOnly) {
 | 
				
			||||||
          customProxyArray = customProxyArray.filter( (p) => !p.startsWith('HTTP ') );
 | 
					          customProxyArray = customProxyArray.filter((p) => !p.startsWith('HTTP '));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (this.ifUseLocalTor) {
 | 
					      if (this.ifUseLocalTor) {
 | 
				
			||||||
| 
						 | 
					@ -142,13 +116,13 @@
 | 
				
			||||||
      if (this.ifMindExceptions && this.exceptions) {
 | 
					      if (this.ifMindExceptions && this.exceptions) {
 | 
				
			||||||
        this.included = [];
 | 
					        this.included = [];
 | 
				
			||||||
        this.excluded = [];
 | 
					        this.excluded = [];
 | 
				
			||||||
        for(const host of Object.keys(this.exceptions)) {
 | 
					        Object.keys(this.exceptions).forEach((host) => {
 | 
				
			||||||
          if (this.exceptions[host]) {
 | 
					          if (this.exceptions[host]) {
 | 
				
			||||||
            this.included.push(host);
 | 
					            this.included.push(host);
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            this.excluded.push(host);
 | 
					            this.excluded.push(host);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        });
 | 
				
			||||||
        if (this.included && !this.filteredCustomsString) {
 | 
					        if (this.included && !this.filteredCustomsString) {
 | 
				
			||||||
          throw new TypeError(
 | 
					          throw new TypeError(
 | 
				
			||||||
            'Проксировать свои сайты можно только через свои прокси. Нет ни одного своего прокси, удовлетворяющего вашим требованиям!'
 | 
					            'Проксировать свои сайты можно только через свои прокси. Нет ни одного своего прокси, удовлетворяющего вашим требованиям!'
 | 
				
			||||||
| 
						 | 
					@ -160,6 +134,73 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const getCurrentConfigs = function getCurrentConfigs() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const mods = kitchenState(modsKey);
 | 
				
			||||||
 | 
					    return new PacModifiers(mods || {});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const getOrderedConfigsForUser = function getOrderedConfigs() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const pacMods = getCurrentConfigs();
 | 
				
			||||||
 | 
					    return Object.keys(configs).reduce((arr, key) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const conf = configs[key];
 | 
				
			||||||
 | 
					      if (typeof conf.index === 'number') {
 | 
				
			||||||
 | 
					        Object.assign(arr, { [conf.index]: conf });
 | 
				
			||||||
 | 
					        conf.value = pacMods[key];
 | 
				
			||||||
 | 
					        conf.key = key;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return arr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const privates = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  privates.tryNowAsync = function tryNowAsync(maybeDetails, maybeCb = throwIfError) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let cb;
 | 
				
			||||||
 | 
					    let detailsOrUndefined;
 | 
				
			||||||
 | 
					    if (typeof maybeDetails === 'function') {
 | 
				
			||||||
 | 
					      detailsOrUndefined = undefined;
 | 
				
			||||||
 | 
					      cb = maybeDetails;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      detailsOrUndefined = maybeDetails;
 | 
				
			||||||
 | 
					      cb = maybeCb;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    new Promise((resolve) => (
 | 
				
			||||||
 | 
					      detailsOrUndefined
 | 
				
			||||||
 | 
					        ? resolve(detailsOrUndefined)
 | 
				
			||||||
 | 
					        : chrome.proxy.settings.get({}, timeouted(resolve))
 | 
				
			||||||
 | 
					    )).then((details) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (
 | 
				
			||||||
 | 
					        details.levelOfControl === 'controlled_by_this_extension'
 | 
				
			||||||
 | 
					      ) {
 | 
				
			||||||
 | 
					        const pac = window.utils.getProp(details, 'value.pacScript');
 | 
				
			||||||
 | 
					        if (pac && pac.data) {
 | 
				
			||||||
 | 
					          // Delete old kitchen modifications.
 | 
				
			||||||
 | 
					          pac.data = pac.data.replace(
 | 
				
			||||||
 | 
					            new RegExp(`${kitchenStartsMark}[\\s\\S]*$`, 'g'),
 | 
				
			||||||
 | 
					            ''
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          return chrome.proxy.settings.set(details, chromified(cb));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      kitchenState(ifIncontinence, true);
 | 
				
			||||||
 | 
					      return cb(null, null, new TypeError(
 | 
				
			||||||
 | 
					        'Не найдено активного PAC-скрипта! Изменения будут применены при возвращении контроля настроек прокси или установке нового PAC-скрипта.'
 | 
				
			||||||
 | 
					      ));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  window.apis.pacKitchen = {
 | 
					  window.apis.pacKitchen = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    getPacMods: getCurrentConfigs,
 | 
					    getPacMods: getCurrentConfigs,
 | 
				
			||||||
| 
						 | 
					@ -167,13 +208,13 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cook(pacData, pacMods = mandatory()) {
 | 
					    cook(pacData, pacMods = mandatory()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return pacMods.ifNoMods ? pacData : pacData + `${ kitchenStartsMark }
 | 
					      return pacMods.ifNoMods ? pacData : `${pacData}${kitchenStartsMark}
 | 
				
			||||||
;+function(global) {
 | 
					;+function(global) {
 | 
				
			||||||
  "use strict";
 | 
					  "use strict";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const originalFindProxyForURL = FindProxyForURL;
 | 
					  const originalFindProxyForURL = FindProxyForURL;
 | 
				
			||||||
  global.FindProxyForURL = function(url, host) {
 | 
					  global.FindProxyForURL = function(url, host) {
 | 
				
			||||||
    ${function() {
 | 
					    ${((function generateNewFindProxyForURL() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      let res = pacMods.ifProhibitDns ? `
 | 
					      let res = pacMods.ifProhibitDns ? `
 | 
				
			||||||
    global.dnsResolve = function(host) { return null; };
 | 
					    global.dnsResolve = function(host) { return null; };
 | 
				
			||||||
| 
						 | 
					@ -203,42 +244,42 @@
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if(
 | 
					      if (
 | 
				
			||||||
        !pacMods.ifUseSecureProxiesOnly &&
 | 
					        !pacMods.ifUseSecureProxiesOnly &&
 | 
				
			||||||
        !pacMods.filteredCustomsString &&
 | 
					        !pacMods.filteredCustomsString &&
 | 
				
			||||||
         pacMods.ifUsePacScriptProxies
 | 
					         pacMods.ifUsePacScriptProxies
 | 
				
			||||||
      ) {
 | 
					      ) {
 | 
				
			||||||
        return res + `
 | 
					        return `${res}
 | 
				
			||||||
    return originalFindProxyForURL(url, host);
 | 
					    return originalFindProxyForURL(url, host);
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return res + `
 | 
					      return `${res}
 | 
				
			||||||
    const originalProxyString = originalFindProxyForURL(url, host);
 | 
					    const originalProxyString = originalFindProxyForURL(url, host);
 | 
				
			||||||
    let originalProxyArray = originalProxyString.split(/(?:\\s*;\\s*)+/g).filter( (p) => p );
 | 
					    let originalProxyArray = originalProxyString.split(/(?:\\s*;\\s*)+/g).filter( (p) => p );
 | 
				
			||||||
    if (originalProxyArray.every( (p) => /^DIRECT$/i.test(p) )) {
 | 
					    if (originalProxyArray.every( (p) => /^DIRECT$/i.test(p) )) {
 | 
				
			||||||
      // Directs only or null, no proxies.
 | 
					      // Directs only or null, no proxies.
 | 
				
			||||||
      return originalProxyString;
 | 
					      return originalProxyString;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return ` +
 | 
					    return ${
 | 
				
			||||||
      function() {
 | 
					      ((function getProxies() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!pacMods.ifUsePacScriptProxies) {
 | 
					        if (!pacMods.ifUsePacScriptProxies) {
 | 
				
			||||||
          return '"' + pacMods.filteredCustomsString + '"';
 | 
					          return `"${pacMods.filteredCustomsString}"`;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let filteredOriginalsExp = 'originalProxyString';
 | 
					        let filteredOriginalsExp = 'originalProxyString';
 | 
				
			||||||
        if (pacMods.ifUseSecureProxiesOnly) {
 | 
					        if (pacMods.ifUseSecureProxiesOnly) {
 | 
				
			||||||
          filteredOriginalsExp =
 | 
					          filteredOriginalsExp =
 | 
				
			||||||
            'originalProxyArray.filter( (p) => !p.toUpperCase().startsWith("HTTP ") ).join("; ")';
 | 
					            'originalProxyArray.filter( (p) => !p.toUpperCase().startsWith("HTTP ") ).join("; ")';
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if ( !pacMods.filteredCustomsString ) {
 | 
					        if (!pacMods.filteredCustomsString) {
 | 
				
			||||||
          return filteredOriginalsExp;
 | 
					          return filteredOriginalsExp;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return '"' + pacMods.filteredCustomsString + '; " + ' + filteredOriginalsExp;
 | 
					        return `"${pacMods.filteredCustomsString}; " + ${filteredOriginalsExp}`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      }() + ' + "; DIRECT";'; // Without DIRECT you will get 'PROXY CONN FAILED' pac-error.
 | 
					      })())} + "; DIRECT";`; // Without DIRECT you will get 'PROXY CONN FAILED' pac-error.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }()}
 | 
					    })())}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -246,68 +287,33 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _tryNowAsync(details, cb = throwIfError) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (typeof(details) === 'function') {
 | 
					 | 
				
			||||||
        cb = details;
 | 
					 | 
				
			||||||
        details = undefined;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      new Promise((resolve) =>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        details
 | 
					 | 
				
			||||||
          ? resolve(details)
 | 
					 | 
				
			||||||
          : chrome.proxy.settings.get({}, timeouted(resolve) )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      ).then( (details) => {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (
 | 
					 | 
				
			||||||
          details.levelOfControl === 'controlled_by_this_extension'
 | 
					 | 
				
			||||||
        ) {
 | 
					 | 
				
			||||||
          const pac = window.utils.getProp(details, 'value.pacScript');
 | 
					 | 
				
			||||||
          if (pac && pac.data) {
 | 
					 | 
				
			||||||
            // Delete old kitchen modifications.
 | 
					 | 
				
			||||||
            pac.data = pac.data.replace(
 | 
					 | 
				
			||||||
              new RegExp(kitchenStartsMark + '[\\s\\S]*$', 'g'),
 | 
					 | 
				
			||||||
              ''
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            return chrome.proxy.settings.set(details, chromified(cb));
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        kitchenState(ifIncontinence, true);
 | 
					 | 
				
			||||||
        cb(null, null, new TypeError(
 | 
					 | 
				
			||||||
          'Не найдено активного PAC-скрипта! Изменения будут применены при возвращении контроля настроек прокси или установке нового PAC-скрипта.'
 | 
					 | 
				
			||||||
        ));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    checkIncontinence(details) {
 | 
					    checkIncontinence(details) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if ( kitchenState(ifIncontinence) ) {
 | 
					      if (kitchenState(ifIncontinence)) {
 | 
				
			||||||
        this._tryNowAsync(details, () => {/* Swallow. */});
 | 
					        privates.tryNowAsync(details, () => { /* Swallow. */ });
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    keepCookedNowAsync(pacMods = mandatory(), cb = throwIfError) {
 | 
					    keepCookedNowAsync(maybePacMods = mandatory(), maybeCb = throwIfError) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (typeof(pacMods) === 'function') {
 | 
					      let pacMods;
 | 
				
			||||||
        cb = pacMods;
 | 
					      let cb;
 | 
				
			||||||
 | 
					      if (typeof maybePacMods === 'function') {
 | 
				
			||||||
 | 
					        cb = maybePacMods;
 | 
				
			||||||
        pacMods = getCurrentConfigs();
 | 
					        pacMods = getCurrentConfigs();
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
          pacMods = new PacModifiers(pacMods);
 | 
					          pacMods = new PacModifiers(maybePacMods);
 | 
				
			||||||
        } catch(e) {
 | 
					        } catch (e) {
 | 
				
			||||||
          return cb(e);
 | 
					          return cb(e);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        kitchenState(modsKey, pacMods);
 | 
					        kitchenState(modsKey, pacMods);
 | 
				
			||||||
 | 
					        cb = maybeCb;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      console.log('Keep cooked now...', pacMods);
 | 
					      console.log('Keep cooked now...', pacMods);
 | 
				
			||||||
      this._tryNowAsync(
 | 
					      return privates.tryNowAsync(
 | 
				
			||||||
        (err, res, ...warns) => {
 | 
					        (err, res, ...warns) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          console.log('Try now err:', err);
 | 
					          console.log('Try now err:', err);
 | 
				
			||||||
| 
						 | 
					@ -320,8 +326,12 @@
 | 
				
			||||||
            return cb(null, res, ...warns);
 | 
					            return cb(null, res, ...warns);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          const hosts = par.map( (ps) => ps.split(/\s+/)[1] );
 | 
					          const hosts = par.map((ps) => ps.split(/\s+/)[1]);
 | 
				
			||||||
          window.utils.fireRequest('ip-to-host-replace-all', hosts, (err, res, ...moreWarns) => cb( err, res, ...warns.concat(moreWarns) ));
 | 
					          return window.utils.fireRequest(
 | 
				
			||||||
 | 
					            'ip-to-host-replace-all',
 | 
				
			||||||
 | 
					            hosts,
 | 
				
			||||||
 | 
					            (ipErr, ipRes, ...ipWarns) => cb(ipErr, ipRes, ...warns.concat(ipWarns))
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
| 
						 | 
					@ -340,20 +350,20 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const pacKitchen = window.apis.pacKitchen;
 | 
					  const pacKitchen = window.apis.pacKitchen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const originalSet = chrome.proxy.settings.set.bind( chrome.proxy.settings );
 | 
					  const originalSet = chrome.proxy.settings.set.bind(chrome.proxy.settings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  chrome.proxy.settings.set = function(details, cb) {
 | 
					  chrome.proxy.settings.set = function modifiedSet(details, cb = () => {}) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const pac = window.utils.getProp(details, 'value.pacScript');
 | 
					    const pac = window.utils.getProp(details, 'value.pacScript');
 | 
				
			||||||
    if (!(pac && pac.data)) {
 | 
					    if (!(pac && pac.data)) {
 | 
				
			||||||
      return originalSet(details, cb);
 | 
					      return originalSet(details, cb);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const pacMods = getCurrentConfigs();
 | 
					    const pacMods = getCurrentConfigs();
 | 
				
			||||||
    pac.data = pacKitchen.cook( pac.data, pacMods );
 | 
					    pac.data = pacKitchen.cook(pac.data, pacMods);
 | 
				
			||||||
    originalSet({value: details.value}, (/* No args. */) => {
 | 
					    return originalSet({ value: details.value }, (/* No args. */) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      kitchenState(ifIncontinence, null);
 | 
					      kitchenState(ifIncontinence, null);
 | 
				
			||||||
      cb && cb();
 | 
					      cb();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,11 +35,11 @@
 | 
				
			||||||
  const asyncLogGroup = function asyncLogGroup(...args) {
 | 
					  const asyncLogGroup = function asyncLogGroup(...args) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const cb = args.pop();
 | 
					    const cb = args.pop();
 | 
				
			||||||
    if(!(cb && typeof(cb) === 'function')) {
 | 
					    if (!cb || typeof cb !== 'function') {
 | 
				
			||||||
      throw new TypeError('cb must be a function, but got: ' + cb);
 | 
					      throw new TypeError(`cb must be a function, but got: ${cb}`);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    console.group(...args);
 | 
					    console.group(...args);
 | 
				
			||||||
    return function(...cbArgs) {
 | 
					    return function finishLogGroup(...cbArgs) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      console.groupEnd();
 | 
					      console.groupEnd();
 | 
				
			||||||
      console.log('Group finished.');
 | 
					      console.log('Group finished.');
 | 
				
			||||||
| 
						 | 
					@ -61,23 +61,23 @@
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    console.log('Setting chrome proxy settings...');
 | 
					    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) {
 | 
				
			||||||
        return cb(err);
 | 
					        return cb(err);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      handlers.updateControlState( () => {
 | 
					      return handlers.updateControlState(() => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ( !handlers.ifControlled ) {
 | 
					        if (!handlers.ifControlled) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          console.warn('Failed, other extension is in control.');
 | 
					          console.warn('Failed, other extension is in control.');
 | 
				
			||||||
          return cb(
 | 
					          return cb(
 | 
				
			||||||
            new Error( window.utils.messages.whichExtensionHtml() )
 | 
					            new Error(window.utils.messages.whichExtensionHtml())
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        console.log('Successfuly set PAC in proxy settings..');
 | 
					        console.log('Successfuly set PAC in proxy settings..');
 | 
				
			||||||
        cb();
 | 
					        return cb();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,25 +86,25 @@
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const updatePacProxyIps = function updatePacProxyIps(
 | 
					  const updatePacProxyIps = function updatePacProxyIps(
 | 
				
			||||||
    cb = throwIfError
 | 
					    originalCb = throwIfError
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cb = asyncLogGroup(
 | 
					    const cb = asyncLogGroup(
 | 
				
			||||||
      'Getting IPs for PAC hosts...',
 | 
					      'Getting IPs for PAC hosts...',
 | 
				
			||||||
      cb
 | 
					      originalCb
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    window.utils.fireRequest('ip-to-host-update-all', cb);
 | 
					    window.utils.fireRequest('ip-to-host-update-all', cb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const setPacScriptFromProviderAsync = function setPacScriptFromProviderAsync(
 | 
					  const setPacScriptFromProviderAsync = function setPacScriptFromProviderAsync(
 | 
				
			||||||
    provider, lastModified = mandatory(), cb = throwIfError
 | 
					    provider, lastModified = mandatory(), originalCb = throwIfError
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const pacUrl = provider.pacUrls[0];
 | 
					    const pacUrl = provider.pacUrls[0];
 | 
				
			||||||
    cb = asyncLogGroup(
 | 
					    const cb = asyncLogGroup(
 | 
				
			||||||
      'Getting PAC script from provider...', pacUrl,
 | 
					      'Getting PAC script from provider...', pacUrl,
 | 
				
			||||||
      cb
 | 
					      originalCb
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    httpLib.ifModifiedSince(pacUrl, lastModified, (err, newLastModified) => {
 | 
					    httpLib.ifModifiedSince(pacUrl, lastModified, (err, newLastModified) => {
 | 
				
			||||||
| 
						 | 
					@ -112,10 +112,9 @@
 | 
				
			||||||
      if (!newLastModified) {
 | 
					      if (!newLastModified) {
 | 
				
			||||||
        return cb(
 | 
					        return cb(
 | 
				
			||||||
          null,
 | 
					          null,
 | 
				
			||||||
          {lastModified},
 | 
					          { lastModified },
 | 
				
			||||||
          new Warning(
 | 
					          new Warning(
 | 
				
			||||||
            'Ваш PAC-скрипт не нуждается в обновлении. Его дата: ' +
 | 
					            `Ваш PAC-скрипт не нуждается в обновлении. Его дата: ${lastModified}.`
 | 
				
			||||||
              lastModified
 | 
					 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					@ -126,7 +125,7 @@
 | 
				
			||||||
          () => new Promise(
 | 
					          () => new Promise(
 | 
				
			||||||
            (resolve, reject) => httpLib.get(
 | 
					            (resolve, reject) => httpLib.get(
 | 
				
			||||||
              url,
 | 
					              url,
 | 
				
			||||||
              (newErr, pacData) => newErr ? reject(newErr) : resolve(pacData)
 | 
					              (newErr, pacData) => (newErr ? reject(newErr) : resolve(pacData))
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
| 
						 | 
					@ -139,29 +138,75 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          setPacAsync(
 | 
					          setPacAsync(
 | 
				
			||||||
            pacData,
 | 
					            pacData,
 | 
				
			||||||
            (err, res) => cb(
 | 
					            (pacErr, pacRes) => cb(
 | 
				
			||||||
              err,
 | 
					              pacErr,
 | 
				
			||||||
              Object.assign(res || {}, {lastModified: newLastModified})
 | 
					              Object.assign(pacRes || {}, { lastModified: newLastModified })
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        clarifyThen(
 | 
					        clarifyThen(
 | 
				
			||||||
          'Не удалось скачать PAC-скрипт с адресов: [ '
 | 
					          `Не удалось скачать PAC-скрипт с адресов: [ ${provider.pacUrls.join(' , ')} ].`,
 | 
				
			||||||
          + provider.pacUrls.join(' , ') + ' ].',
 | 
					 | 
				
			||||||
          cb
 | 
					          cb
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					      return undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  window.apis.antiCensorRu = {
 | 
					  const currentVersion = chrome.runtime.getManifest().version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    version: chrome.runtime.getManifest().version,
 | 
					  const privates = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pacUpdatePeriodInMinutes: 12 * 60,
 | 
				
			||||||
 | 
					    periodicUpdateAlarmReason: 'Периодичное обновление PAC-скрипта',
 | 
				
			||||||
 | 
					    state: window.utils.createStorage('anti-censor-ru-'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get version() {
 | 
				
			||||||
 | 
					      return this.state('version');
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    set version(newValue) {
 | 
				
			||||||
 | 
					      return this.state('version', newValue);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get ifFirstInstall() {
 | 
				
			||||||
 | 
					      return this.version === null;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    set ifFirstInstall(newValue) {
 | 
				
			||||||
 | 
					      if (newValue) {
 | 
				
			||||||
 | 
					        throw new TypeError('ifFirstInstall can\'t be set to true!');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      this.version = currentVersion;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get currentPacProviderKey() {
 | 
				
			||||||
 | 
					      return this.state('current-pac');
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    set currentPacProviderKey(newValue) {
 | 
				
			||||||
 | 
					      return this.state('current-pac', newValue);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get lastPacUpdateStamp() {
 | 
				
			||||||
 | 
					      return this.state('last-pac-update-stamp') || 0;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    set lastPacUpdateStamp(newValue) {
 | 
				
			||||||
 | 
					      return this.state('last-pac-update-stamp', newValue);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get currentPacProviderLastModified() {
 | 
				
			||||||
 | 
					      return this.state('current-pac-last-mod') || 0;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    set currentPacProviderLastModified(newValue) {
 | 
				
			||||||
 | 
					      return this.state('current-pac-last-mod', newValue);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  window.apis.antiCensorRu = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pacProviders: {
 | 
					    pacProviders: {
 | 
				
			||||||
      Антизапрет: {
 | 
					      Антизапрет: {
 | 
				
			||||||
| 
						 | 
					@ -199,20 +244,24 @@
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _currentPacProviderKey: 'Антизапрет',
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Is it the first time extension installed?
 | 
					    /* Is it the first time extension installed?
 | 
				
			||||||
       Do something, e.g. initiate PAC sync.
 | 
					       Do something, e.g. initiate PAC sync.
 | 
				
			||||||
    */
 | 
					    */
 | 
				
			||||||
    ifFirstInstall: false,
 | 
					    get ifFirstInstall() {
 | 
				
			||||||
    lastPacUpdateStamp: 0,
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _currentPacProviderLastModified: 0, // Not initialized.
 | 
					      return privates.ifFirstInstall;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    get lastPacUpdateStamp() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return privates.lastPacUpdateStamp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    getLastModifiedForKey(key = mandatory()) {
 | 
					    getLastModifiedForKey(key = mandatory()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (this._currentPacProviderKey === key) {
 | 
					      if (privates.currentPacProviderKey === key) {
 | 
				
			||||||
        return new Date(this._currentPacProviderLastModified).toUTCString();
 | 
					        return new Date(privates.currentPacProviderLastModified).toUTCString();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return new Date(0).toUTCString();
 | 
					      return new Date(0).toUTCString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -220,21 +269,21 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setLastModified(newValue = mandatory()) {
 | 
					    setLastModified(newValue = mandatory()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      this._currentPacProviderLastModified = newValue;
 | 
					      privates.currentPacProviderLastModified = newValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mustBeKey(key = mandatory()) {
 | 
					    mustBeKey(key = mandatory()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if ( !(key === null || this.pacProviders[key]) ) {
 | 
					      if (key !== null && !this.pacProviders[key]) {
 | 
				
			||||||
        throw new TypeError('No provider for key:' + key);
 | 
					        throw new TypeError(`No provider for key:${key}`);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    getCurrentPacProviderKey() {
 | 
					    getCurrentPacProviderKey() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return this._currentPacProviderKey;
 | 
					      return privates.currentPacProviderKey;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -244,15 +293,17 @@
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      this.mustBeKey(newKey);
 | 
					      this.mustBeKey(newKey);
 | 
				
			||||||
      this._currentPacProviderKey = newKey;
 | 
					      privates.currentPacProviderKey = newKey;
 | 
				
			||||||
      this._currentPacProviderLastModified = lastModified;
 | 
					      privates.currentPacProviderLastModified = lastModified;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    getPacProvider(key) {
 | 
					    getPacProvider(maybeKey) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if(key) {
 | 
					      let key;
 | 
				
			||||||
        this.mustBeKey(key);
 | 
					      if (maybeKey) {
 | 
				
			||||||
 | 
					        this.mustBeKey(maybeKey);
 | 
				
			||||||
 | 
					        key = maybeKey;
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        key = this.getCurrentPacProviderKey();
 | 
					        key = this.getCurrentPacProviderKey();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					@ -260,40 +311,18 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _periodicUpdateAlarmReason: 'Периодичное обновление PAC-скрипта',
 | 
					    syncWithPacProviderAsync(maybeKey = this.currentPacProvierKey, maybeCb = throwIfError) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pushToStorageAsync(cb = throwIfError) {
 | 
					      let key;
 | 
				
			||||||
 | 
					      let originalCb;
 | 
				
			||||||
      console.log('Pushing to storage...');
 | 
					      if (typeof maybeKey === 'function') {
 | 
				
			||||||
 | 
					 | 
				
			||||||
      // 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();
 | 
					        key = this.getCurrentPacProviderKey();
 | 
				
			||||||
 | 
					        originalCb = maybeKey;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        key = maybeKey;
 | 
				
			||||||
 | 
					        originalCb = maybeCb;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      cb = asyncLogGroup('Syncing with PAC provider ' + key + '...', cb);
 | 
					      const cb = asyncLogGroup(`Syncing with PAC provider ${key}...`, originalCb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (key === null) {
 | 
					      if (key === null) {
 | 
				
			||||||
        // No pac provider set.
 | 
					        // No pac provider set.
 | 
				
			||||||
| 
						 | 
					@ -303,15 +332,15 @@
 | 
				
			||||||
      const pacProvider = this.getPacProvider(key);
 | 
					      const pacProvider = this.getPacProvider(key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const pacSetPromise = new Promise(
 | 
					      const pacSetPromise = new Promise(
 | 
				
			||||||
        (resolve, reject) => setPacScriptFromProviderAsync(
 | 
					        (resolve) => setPacScriptFromProviderAsync(
 | 
				
			||||||
          pacProvider,
 | 
					          pacProvider,
 | 
				
			||||||
          this.getLastModifiedForKey(key),
 | 
					          this.getLastModifiedForKey(key),
 | 
				
			||||||
          (err, res, ...warns) => {
 | 
					          (err, res, ...warns) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!err) {
 | 
					            if (!err) {
 | 
				
			||||||
              this.setCurrentPacProviderKey(key, res.lastModified);
 | 
					              this.setCurrentPacProviderKey(key, res.lastModified);
 | 
				
			||||||
              this.lastPacUpdateStamp = Date.now();
 | 
					              privates.lastPacUpdateStamp = Date.now();
 | 
				
			||||||
              this.ifFirstInstall = false;
 | 
					              privates.ifFirstInstall = false;
 | 
				
			||||||
              this.setAlarms();
 | 
					              this.setAlarms();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -322,7 +351,7 @@
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const ipsErrorPromise = new Promise(
 | 
					      const ipsErrorPromise = new Promise(
 | 
				
			||||||
        (resolve, reject) => updatePacProxyIps(
 | 
					        (resolve) => updatePacProxyIps(
 | 
				
			||||||
          resolve
 | 
					          resolve
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
| 
						 | 
					@ -337,27 +366,25 @@
 | 
				
			||||||
          if (ipsErr) {
 | 
					          if (ipsErr) {
 | 
				
			||||||
            warns.push(ipsErr);
 | 
					            warns.push(ipsErr);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          this.pushToStorageAsync(
 | 
					          return cb(pacErr, null, ...warns);
 | 
				
			||||||
            (pushErr) => cb(pacErr || pushErr, null, ...warns)
 | 
					 | 
				
			||||||
          );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        cb
 | 
					        cb
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					      return undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _pacUpdatePeriodInMinutes: 12*60,
 | 
					 | 
				
			||||||
    get pacUpdatePeriodInMinutes() {
 | 
					    get pacUpdatePeriodInMinutes() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return this._pacUpdatePeriodInMinutes;
 | 
					      return privates.pacUpdatePeriodInMinutes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setAlarms() {
 | 
					    setAlarms() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      let nextUpdateMoment = this.lastPacUpdateStamp
 | 
					      let nextUpdateMoment = this.lastPacUpdateStamp
 | 
				
			||||||
        + this._pacUpdatePeriodInMinutes*60*1000;
 | 
					        + (privates.pacUpdatePeriodInMinutes * 60 * 1000);
 | 
				
			||||||
      const now = Date.now();
 | 
					      const now = Date.now();
 | 
				
			||||||
      if (nextUpdateMoment < now) {
 | 
					      if (nextUpdateMoment < now) {
 | 
				
			||||||
        nextUpdateMoment = now;
 | 
					        nextUpdateMoment = now;
 | 
				
			||||||
| 
						 | 
					@ -369,10 +396,10 @@
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      chrome.alarms.create(
 | 
					      chrome.alarms.create(
 | 
				
			||||||
        this._periodicUpdateAlarmReason,
 | 
					        privates.periodicUpdateAlarmReason,
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          when: nextUpdateMoment,
 | 
					          when: nextUpdateMoment,
 | 
				
			||||||
          periodInMinutes: this._pacUpdatePeriodInMinutes,
 | 
					          periodInMinutes: privates.pacUpdatePeriodInMinutes,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -390,14 +417,14 @@
 | 
				
			||||||
      if (this.currentProviderKey !== key) {
 | 
					      if (this.currentProviderKey !== key) {
 | 
				
			||||||
        return this.syncWithPacProviderAsync(key, cb);
 | 
					        return this.syncWithPacProviderAsync(key, cb);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      console.log(key + ' already installed.');
 | 
					      console.log(`${key} already installed.`);
 | 
				
			||||||
      cb();
 | 
					      return cb();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    clearPacAsync(cb = throwIfError) {
 | 
					    clearPacAsync(originalCb = throwIfError) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      cb = asyncLogGroup('Cearing alarms and PAC...', cb);
 | 
					      const cb = asyncLogGroup('Cearing alarms and PAC...', originalCb);
 | 
				
			||||||
      chrome.alarms.clearAll(
 | 
					      chrome.alarms.clearAll(
 | 
				
			||||||
        () => chrome.proxy.settings.clear(
 | 
					        () => chrome.proxy.settings.clear(
 | 
				
			||||||
          {},
 | 
					          {},
 | 
				
			||||||
| 
						 | 
					@ -407,9 +434,7 @@
 | 
				
			||||||
              return cb(err);
 | 
					              return cb(err);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            this.setCurrentPacProviderKey(null);
 | 
					            this.setCurrentPacProviderKey(null);
 | 
				
			||||||
            this.pushToStorageAsync(
 | 
					            return handlers.updateControlState(cb);
 | 
				
			||||||
              () => handlers.updateControlState(cb)
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          })
 | 
					          })
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
| 
						 | 
					@ -420,12 +445,7 @@
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // ON EACH LAUNCH, STARTUP, RELOAD, UPDATE, ENABLE
 | 
					  // ON EACH LAUNCH, STARTUP, RELOAD, UPDATE, ENABLE
 | 
				
			||||||
  chrome.storage.local.get(null, chromified( (err, oldStorage) => {
 | 
					  ((async function init() {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (err) {
 | 
					 | 
				
			||||||
      throw err;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
       Event handlers that ALWAYS work (even if installation is not done
 | 
					       Event handlers that ALWAYS work (even if installation is not done
 | 
				
			||||||
       or failed).
 | 
					       or failed).
 | 
				
			||||||
| 
						 | 
					@ -435,14 +455,14 @@
 | 
				
			||||||
    const antiCensorRu = window.apis.antiCensorRu;
 | 
					    const antiCensorRu = window.apis.antiCensorRu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    chrome.alarms.onAlarm.addListener(
 | 
					    chrome.alarms.onAlarm.addListener(
 | 
				
			||||||
      timeouted( (alarm) => {
 | 
					      timeouted((alarm) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (alarm.name === antiCensorRu._periodicUpdateAlarmReason) {
 | 
					        if (alarm.name === privates.periodicUpdateAlarmReason) {
 | 
				
			||||||
          console.log(
 | 
					          console.log(
 | 
				
			||||||
            'Periodic PAC update triggered:',
 | 
					            'Periodic PAC update triggered:',
 | 
				
			||||||
            new Date().toLocaleString('ru-RU')
 | 
					            new Date().toLocaleString('ru-RU')
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
          antiCensorRu.syncWithPacProviderAsync(() => {/* swallow */});
 | 
					          antiCensorRu.syncWithPacProviderAsync(() => { /* swallow */ });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
| 
						 | 
					@ -456,24 +476,14 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    console.log('Storage on init:', oldStorage);
 | 
					 | 
				
			||||||
    antiCensorRu.ifFirstInstall = Object.keys(oldStorage).length === 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (antiCensorRu.ifFirstInstall) {
 | 
					    if (antiCensorRu.ifFirstInstall) {
 | 
				
			||||||
      // INSTALL
 | 
					      // INSTALL
 | 
				
			||||||
      console.log('Installing...');
 | 
					      console.log('Installing...');
 | 
				
			||||||
 | 
					      privates.currentPacProviderKey = 'Антизапрет';
 | 
				
			||||||
      return chrome.runtime.openOptionsPage();
 | 
					      return chrome.runtime.openOptionsPage();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // LAUNCH, RELOAD, UPDATE
 | 
					    // 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(
 | 
					    console.log(
 | 
				
			||||||
      'Last PAC update was on',
 | 
					      'Last PAC update was on',
 | 
				
			||||||
      new Date(antiCensorRu.lastPacUpdateStamp).toLocaleString('ru-RU')
 | 
					      new Date(antiCensorRu.lastPacUpdateStamp).toLocaleString('ru-RU')
 | 
				
			||||||
| 
						 | 
					@ -487,44 +497,48 @@
 | 
				
			||||||
      2. We have to check storage for migration before using it.
 | 
					      2. We have to check storage for migration before using it.
 | 
				
			||||||
         Better on each launch then on each pull.
 | 
					         Better on each launch then on each pull.
 | 
				
			||||||
    */
 | 
					    */
 | 
				
			||||||
    const ifUpdating = antiCensorRu.version !== oldStorage.version;
 | 
					    const ifUpdating = currentVersion !== privates.version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!ifUpdating) {
 | 
					    if (!ifUpdating) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // LAUNCH, RELOAD, ENABLE
 | 
					      // LAUNCH, RELOAD, ENABLE
 | 
				
			||||||
      antiCensorRu.pacProviders = oldStorage.pacProviders;
 | 
					 | 
				
			||||||
      console.log('Extension launched, reloaded or enabled.');
 | 
					      console.log('Extension launched, reloaded or enabled.');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // UPDATE & MIGRATION
 | 
					      // UPDATE & MIGRATION
 | 
				
			||||||
      const key = antiCensorRu._currentPacProviderKey;
 | 
					      // Use old or migrate to defaults.
 | 
				
			||||||
      if (key !== null) {
 | 
					      const oldStorage = await new Promise((resolve) =>
 | 
				
			||||||
        const ifVeryOld = !Object.keys(antiCensorRu.pacProviders).includes(key);
 | 
					        chrome.storage.local.get(null, resolve)
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      if (Object.keys(oldStorage).length) {
 | 
				
			||||||
 | 
					        // eslint-disable-next-line no-underscore-dangle
 | 
				
			||||||
 | 
					        let oldKey = oldStorage._currentPacProviderKey;
 | 
				
			||||||
 | 
					        if (oldKey) {
 | 
				
			||||||
 | 
					          const ifVeryOld = !Object.keys(antiCensorRu.pacProviders).includes(oldKey);
 | 
				
			||||||
          const ifWasForced = localStorage.getItem('provider-backup');
 | 
					          const ifWasForced = localStorage.getItem('provider-backup');
 | 
				
			||||||
        if ( ifVeryOld || !ifWasForced ) {
 | 
					          if (ifVeryOld || !ifWasForced) {
 | 
				
			||||||
            if (!ifWasForced) {
 | 
					            if (!ifWasForced) {
 | 
				
			||||||
            localStorage.setItem('provider-backup', antiCensorRu._currentPacProviderKey);
 | 
					              localStorage.setItem('provider-backup', oldKey);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          antiCensorRu._currentPacProviderKey = 'Антизапрет';
 | 
					            oldKey = 'Антизапрет';
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        privates.currentPacProviderKey = oldKey || null;
 | 
				
			||||||
 | 
					        // eslint-disable-next-line no-underscore-dangle
 | 
				
			||||||
 | 
					        privates.currentPacProviderLastModified = oldStorage._currentPacProviderLastModified || 0;
 | 
				
			||||||
 | 
					        privates.lastPacUpdateStamp = oldStorage.lastPacUpdateStamp || 0;
 | 
				
			||||||
 | 
					        await new Promise((resolve) => chrome.storage.local.clear(resolve));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      privates.version = currentVersion;
 | 
				
			||||||
      console.log('Extension updated.');
 | 
					      console.log('Extension updated.');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (antiCensorRu.getPacProvider()) {
 | 
					    if (antiCensorRu.getPacProvider()) {
 | 
				
			||||||
 | 
					      antiCensorRu.setAlarms();
 | 
				
			||||||
      const ifAlarmTriggered = antiCensorRu.setAlarms();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (ifAlarmTriggered) {
 | 
					 | 
				
			||||||
        return; // Already pushed.
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if( ifUpdating ) {
 | 
					 | 
				
			||||||
      antiCensorRu.pushToStorageAsync();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    return undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
      History of Changes to Storage (Migration Guide)
 | 
					      History of Changes to Storage (Migration Guide)
 | 
				
			||||||
| 
						 | 
					@ -540,7 +554,6 @@
 | 
				
			||||||
        * Change storage.ifNotInstalled to storage.ifFirstInstall.
 | 
					        * Change storage.ifNotInstalled to storage.ifFirstInstall.
 | 
				
			||||||
        * Add storage.lastPacUpdateStamp.
 | 
					        * Add storage.lastPacUpdateStamp.
 | 
				
			||||||
    **/
 | 
					    **/
 | 
				
			||||||
 | 
					  })());
 | 
				
			||||||
  }));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,13 +12,13 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    chrome.runtime.onInstalled.addListener(
 | 
					    chrome.runtime.onInstalled.addListener(
 | 
				
			||||||
      () => chrome.contextMenus.create({
 | 
					      () => chrome.contextMenus.create({
 | 
				
			||||||
        id: id,
 | 
					        id,
 | 
				
			||||||
        title: title,
 | 
					        title,
 | 
				
			||||||
        contexts: ['browser_action'],
 | 
					        contexts: ['browser_action'],
 | 
				
			||||||
      }, timeouted(() => {
 | 
					      }, timeouted(() => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const err = chrome.runtime.lastError;
 | 
					        const err = chrome.runtime.lastError;
 | 
				
			||||||
        if(err) {
 | 
					        if (err) {
 | 
				
			||||||
          console.warn('Context menu error:', err);
 | 
					          console.warn('Context menu error:', err);
 | 
				
			||||||
          throw err;
 | 
					          throw err;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -28,9 +28,9 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    chrome.contextMenus.onClicked.addListener((info, tab) => {
 | 
					    chrome.contextMenus.onClicked.addListener((info, tab) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if(info.menuItemId === id) {
 | 
					      if (info.menuItemId === id) {
 | 
				
			||||||
        Promise.resolve( tab2url( tab ) )
 | 
					        Promise.resolve(tab2url(tab))
 | 
				
			||||||
          .then( (url) => chrome.tabs.create({url: url}) );
 | 
					          .then((url) => chrome.tabs.create({ url }));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
| 
						 | 
					@ -45,32 +45,32 @@
 | 
				
			||||||
            <input name='InstantCheckUrl' value='${new URL(tab.url).hostname}'
 | 
					            <input name='InstantCheckUrl' value='${new URL(tab.url).hostname}'
 | 
				
			||||||
              type='hidden'>
 | 
					              type='hidden'>
 | 
				
			||||||
            </form>
 | 
					            </form>
 | 
				
			||||||
            <script>document.querySelector('.tracker-form').submit()<\/script>`
 | 
					            <script>document.querySelector('.tracker-form').submit()</script>`
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  createMenuLinkEntry(
 | 
					  createMenuLinkEntry(
 | 
				
			||||||
    'Сайт в реестре блокировок?',
 | 
					    'Сайт в реестре блокировок?',
 | 
				
			||||||
    (tab) => 'https://antizapret.info/index.php?search=' + new URL(tab.url).hostname
 | 
					    (tab) => `https://antizapret.info/index.php?search=${new URL(tab.url).hostname}`
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  createMenuLinkEntry(
 | 
					  createMenuLinkEntry(
 | 
				
			||||||
    'Из архива archive.org',
 | 
					    'Из архива archive.org',
 | 
				
			||||||
    (tab) => 'https://web.archive.org/web/*/' + tab.url
 | 
					    (tab) => `https://web.archive.org/web/*/${tab.url}`
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  createMenuLinkEntry(
 | 
					  createMenuLinkEntry(
 | 
				
			||||||
    'Через Google Translate',
 | 
					    'Через Google Translate',
 | 
				
			||||||
    (tab) => 'https://translate.google.com/translate?hl=&sl=en&tl=ru&anno=2&sandbox=1&u=' + tab.url
 | 
					    (tab) => `https://translate.google.com/translate?hl=&sl=en&tl=ru&anno=2&sandbox=1&u=${tab.url}`
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  createMenuLinkEntry(
 | 
					  createMenuLinkEntry(
 | 
				
			||||||
    'Другие варианты разблокировки',
 | 
					    'Другие варианты разблокировки',
 | 
				
			||||||
    (tab) => 'https://rebrand.ly/ac-unblock#' + tab.url
 | 
					    (tab) => `https://rebrand.ly/ac-unblock#${tab.url}`
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  createMenuLinkEntry(
 | 
					  createMenuLinkEntry(
 | 
				
			||||||
    'У меня проблемы с расширением!',
 | 
					    'У меня проблемы с расширением!',
 | 
				
			||||||
    (tab) => 'https://rebrand.ly/ac-support'
 | 
					    () => 'https://rebrand.ly/ac-support'
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,100 +9,42 @@
 | 
				
			||||||
  // IP REGEX starts.
 | 
					  // IP REGEX starts.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const portOpt = '(:\\d+)?'; // The only capturing group, sic!
 | 
					  const portOpt = '(:\\d+)?'; // The only capturing group, sic!
 | 
				
			||||||
  const ipv4portOpt = '(?:[0-9]{1,3}\\.){3}[0-9]{1,3}' + portOpt;
 | 
					  const ipv4portOpt = `(?:[0-9]{1,3}\\.){3}[0-9]{1,3}${portOpt}`;
 | 
				
			||||||
  const ipv6nake = '(?:[0-9a-f]{0,4}:){2,7}[0-9a-f]{0,4}';
 | 
					  const ipv6nake = '(?:[0-9a-f]{0,4}:){2,7}[0-9a-f]{0,4}';
 | 
				
			||||||
  const ipv6portOpt = '(?:' + ipv6nake + '|' + '\\[' + ipv6nake + '\\]' + portOpt + ')';
 | 
					  const ipv6portOpt = `(?:${ipv6nake}|\\[${ipv6nake}\\]${portOpt})`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const ipv4Re = new RegExp('^' + ipv4portOpt + '$');
 | 
					  const ipv4Re = new RegExp(`^${ipv4portOpt}$`);
 | 
				
			||||||
  const ipv6Re = new RegExp('^' + ipv6portOpt + '$');
 | 
					  const ipv6Re = new RegExp(`^${ipv6portOpt}$`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const _match = function _match(ipRe, str) {
 | 
					  const reMatchIp = function reMatchIp(ipRe, str) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const m = (str.match(ipRe) || []).filter( (c) => c );
 | 
					    const m = (str.match(ipRe) || []).filter((c) => c);
 | 
				
			||||||
    const port = m.length > 1 ? m.pop() : false;
 | 
					    const port = m.length > 1 ? m.pop() : false;
 | 
				
			||||||
    return {ifMatched: m.length, port: port};
 | 
					    return { ifMatched: m.length, port };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const _test = {
 | 
					  const matchIpv4v6 = function matchIpv4v6(str) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ipv4: _match.bind(null, ipv4Re),
 | 
					    let mr = reMatchIp(ipv4Re, str);
 | 
				
			||||||
    ipv6: _match.bind(null, ipv6Re),
 | 
					 | 
				
			||||||
    ipv4v6: function(str) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      let mr = this.ipv4(str);
 | 
					 | 
				
			||||||
    if (mr.ifMatched) {
 | 
					    if (mr.ifMatched) {
 | 
				
			||||||
      mr.ifv4 = true;
 | 
					      mr.ifv4 = true;
 | 
				
			||||||
      mr.canonical = str.replace(mr.port, '');
 | 
					      mr.canonical = str.replace(mr.port, '');
 | 
				
			||||||
      return mr;
 | 
					      return mr;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
      mr = this.ipv6(str);
 | 
					    mr = reMatchIp(ipv6Re, str);
 | 
				
			||||||
    if (mr.ifMatched) {
 | 
					    if (mr.ifMatched) {
 | 
				
			||||||
      mr.ifv6 = true;
 | 
					      mr.ifv6 = true;
 | 
				
			||||||
        mr.canonical = str.replace(mr.port, '').replace(/[\[\]]/g, '');
 | 
					      mr.canonical = str.replace(mr.port, '').replace(/[[\]]/g, '');
 | 
				
			||||||
      return mr;
 | 
					      return mr;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return mr;
 | 
					    return mr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // IP REGEX ends.
 | 
					  // IP REGEX ends.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const _state = window.utils.createStorage('ip-to-host');
 | 
					  // GET IPS starts.
 | 
				
			||||||
  const ip2host = '';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const privates = {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const _createHostObj = function _addHostObj(hostStr) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return (privates._strToHostObj[hostStr] = {host: hostStr});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const _getHostObj = function _getHostObj(hostStr) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return privates._strToHostObj[hostStr] || _createHostObj(hostStr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const reinit = function reinit() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Defaults.
 | 
					 | 
				
			||||||
    const _antizapret = {
 | 
					 | 
				
			||||||
      /* Don't use directly, please.
 | 
					 | 
				
			||||||
         Encoded to counter abuse. */
 | 
					 | 
				
			||||||
      host: '\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',
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    privates._strToHostObj = {
 | 
					 | 
				
			||||||
      [_antizapret.host]: _antizapret,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    privates._ipToHostObj = {};
 | 
					 | 
				
			||||||
    for( const ip of [
 | 
					 | 
				
			||||||
      // IPs of Antizapret.
 | 
					 | 
				
			||||||
      '195.123.209.38',
 | 
					 | 
				
			||||||
      '137.74.171.91',
 | 
					 | 
				
			||||||
      '51.15.39.201',
 | 
					 | 
				
			||||||
      '2001:bc8:4700:2300::1:d07',
 | 
					 | 
				
			||||||
      '2a02:27ac::10',
 | 
					 | 
				
			||||||
    ] ) {
 | 
					 | 
				
			||||||
      privates._ipToHostObj[ip] = _antizapret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Persisted.
 | 
					 | 
				
			||||||
    const ipToHost = _state(ip2host);
 | 
					 | 
				
			||||||
    if (ipToHost) {
 | 
					 | 
				
			||||||
      for( const ip of Object.keys(ipToHost) ) {
 | 
					 | 
				
			||||||
        const host = ipToHost[ip];
 | 
					 | 
				
			||||||
        privates._ipToHostObj[ip] = _getHostObj(host);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  reinit();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const getIpsFor = function getIpsFor(host, cb = mandatory()) {
 | 
					  const getIpsFor = function getIpsFor(host, cb = mandatory()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -113,29 +55,32 @@
 | 
				
			||||||
    const promises = types.map(
 | 
					    const promises = types.map(
 | 
				
			||||||
      (type) => new Promise((resolve) =>
 | 
					      (type) => new Promise((resolve) =>
 | 
				
			||||||
        httpLib.get(
 | 
					        httpLib.get(
 | 
				
			||||||
          'https://dns.google.com/resolve?type=' + type + '&name=' + host,
 | 
					          `https://dns.google.com/resolve?type=${type}&name=${host}`,
 | 
				
			||||||
          (err, res) => {
 | 
					          (httpErr, httpRes) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (res) {
 | 
					            let res = httpRes;
 | 
				
			||||||
 | 
					            let err = httpErr;
 | 
				
			||||||
 | 
					            if (httpRes) {
 | 
				
			||||||
 | 
					              let jsonRes = {};
 | 
				
			||||||
              try {
 | 
					              try {
 | 
				
			||||||
                res = JSON.parse(res);
 | 
					                jsonRes = JSON.parse(httpRes);
 | 
				
			||||||
                console.log('JSON parsed.');
 | 
					                res = jsonRes;
 | 
				
			||||||
                if (err || res.Status) {
 | 
					                if (httpErr || jsonRes.Status) {
 | 
				
			||||||
                  const msg = ['Answer', 'Comment', 'Status']
 | 
					                  const msg = ['Answer', 'Comment', 'Status']
 | 
				
			||||||
                    .filter( (prop) => res[prop] )
 | 
					                    .filter((prop) => jsonRes[prop])
 | 
				
			||||||
                    .map( (prop) => prop + ': ' + JSON.stringify( res[prop] ) )
 | 
					                    .map((prop) => `${prop}: ${JSON.stringify(jsonRes[prop])}`)
 | 
				
			||||||
                    .join(', \n');
 | 
					                    .join(', \n');
 | 
				
			||||||
                  err = clarify(err || {}, 'Сервер (json): ' + msg, {data: res});
 | 
					                  err = clarify(httpErr || {}, `Сервер (json): ${msg}`, { data: jsonRes });
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                  res = res.Answer || [];
 | 
					                  res = (jsonRes.Answer || []).filter(
 | 
				
			||||||
                  res = res.filter(
 | 
					 | 
				
			||||||
                    (record) => types.includes(record.type)
 | 
					                    (record) => types.includes(record.type)
 | 
				
			||||||
                  ).map( (ans) => ans.data );
 | 
					                  ).map((ans) => ans.data);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              } catch(e) {
 | 
					              } catch (e) {
 | 
				
			||||||
                err = clarify(
 | 
					                err = clarify(
 | 
				
			||||||
                  e,
 | 
					                  e,
 | 
				
			||||||
                  'Сервер (текст): ' + res, err ? {data: err} : undefined
 | 
					                  `Сервер (текст): ${res}`,
 | 
				
			||||||
 | 
					                  httpErr ? { data: httpErr } : undefined
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -148,7 +93,7 @@
 | 
				
			||||||
    Promise.all(promises).then(
 | 
					    Promise.all(promises).then(
 | 
				
			||||||
      ([[v4err, v4res], [v6err, v6res]]) => {
 | 
					      ([[v4err, v4res], [v6err, v6res]]) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(v4err) {
 | 
					        if (v4err) {
 | 
				
			||||||
          return cb(v4err, v4res);
 | 
					          return cb(v4err, v4res);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        const ips = v4res;
 | 
					        const ips = v4res;
 | 
				
			||||||
| 
						 | 
					@ -158,77 +103,101 @@
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          warns = [v6err];
 | 
					          warns = [v6err];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        cb(null, ips, ...warns);
 | 
					        return cb(null, ips, ...warns);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					    return undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const _canonize = function canonize(addrArr) {
 | 
					  // GET IPS ends.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const ipSet = new Set();
 | 
					  const ipToHostKey = '';
 | 
				
			||||||
    const hostSet = new Set();
 | 
					  const privates = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for( const addr of addrArr ) {
 | 
					    state: window.utils.createStorage('ip-to-host'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const ipm = _test.ipv4v6(addr);
 | 
					    createHostObj(hostStr) {
 | 
				
			||||||
      if (ipm.ifMatched) {
 | 
					 | 
				
			||||||
        ipSet.add( ipm.canonical );
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        hostSet.add( addr.replace(/:\d+$/, '') );
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					      return (this.strToHostObj[hostStr] = { host: hostStr });
 | 
				
			||||||
 | 
					 | 
				
			||||||
    console.log('Canonized hosts/ips:', hostSet.size + '/' + ipSet.size);
 | 
					 | 
				
			||||||
    return [ipSet, hostSet];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const self = window.apis.ipToHost = {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    persistData() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      console.log('Persisting ipToHost...', privates);
 | 
					 | 
				
			||||||
      const ipToHost = {};
 | 
					 | 
				
			||||||
      for( const ip of Object.keys(privates._ipToHostObj) ) {
 | 
					 | 
				
			||||||
        ipToHost[ip] = privates._ipToHostObj[ip].host;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      _state(ip2host, ipToHost);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    getHostObj(hostStr) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return this.strToHostObj[hostStr] || this.createHostObj(hostStr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    reinit() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Defaults.
 | 
				
			||||||
 | 
					      const antizapret = {
 | 
				
			||||||
 | 
					        /* Don't use directly, please.
 | 
				
			||||||
 | 
					           Encoded to counter abuse. */
 | 
				
			||||||
 | 
					        host: '\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',
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      this.strToHostObj = {
 | 
				
			||||||
 | 
					        [antizapret.host]: antizapret,
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      this.ipToHostObj = {};
 | 
				
			||||||
 | 
					      [ // IPs of Antizapret.
 | 
				
			||||||
 | 
					        '195.123.209.38',
 | 
				
			||||||
 | 
					        '137.74.171.91',
 | 
				
			||||||
 | 
					        '51.15.39.201',
 | 
				
			||||||
 | 
					        '2001:bc8:4700:2300::1:d07',
 | 
				
			||||||
 | 
					        '2a02:27ac::10',
 | 
				
			||||||
 | 
					      ].forEach((ip) => {
 | 
				
			||||||
 | 
					        this.ipToHostObj[ip] = antizapret;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Persisted.
 | 
				
			||||||
 | 
					      const ipToHost = this.state(ipToHostKey);
 | 
				
			||||||
 | 
					      if (ipToHost) {
 | 
				
			||||||
 | 
					        Object.keys(ipToHost).forEach((ip) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          const host = ipToHost[ip];
 | 
				
			||||||
 | 
					          this.ipToHostObj[ip] = this.getHostObj(host);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // POST INIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    resetToDefaults() {
 | 
					    resetToDefaults() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      _state(ip2host, null);
 | 
					      this.state(ipToHostKey, null);
 | 
				
			||||||
      reinit();
 | 
					      this.reinit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _purgeOldIpsForSync(hostStr) {
 | 
					    purgeOldIpsForSync(hostStr) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      console.log('Purging old IPs for', hostStr);
 | 
					      console.log('Purging old IPs for', hostStr);
 | 
				
			||||||
      for(const ip of Object.keys(privates._ipToHostObj)) {
 | 
					      Object.keys(privates.ipToHostObj).forEach((ip) => {
 | 
				
			||||||
        if (hostStr === privates._ipToHostObj[ip].host) {
 | 
					        if (hostStr === this.ipToHostObj[ip].host) {
 | 
				
			||||||
          delete privates._ipToHostObj[ip];
 | 
					          delete this.ipToHostObj[ip];
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _addAsync(hostStr, cb = mandatory()) {
 | 
					    addAsync(hostStr, cb = mandatory()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      getIpsFor(hostStr, (err, ips, ...warns) => {
 | 
					      getIpsFor(hostStr, (err, ips, ...warns) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        console.log('Got IPs + err?:', ips, err);
 | 
					        console.log('Got IPs + err?:', ips, err);
 | 
				
			||||||
        if (!err) {
 | 
					        if (!err) {
 | 
				
			||||||
          this._purgeOldIpsForSync(hostStr);
 | 
					          this.purgeOldIpsForSync(hostStr);
 | 
				
			||||||
          // Object may be shared, string can't.
 | 
					          // Object may be shared, string can't.
 | 
				
			||||||
          const hostObj = _getHostObj(hostStr);
 | 
					          const hostObj = privates.getHostObj(hostStr);
 | 
				
			||||||
          for(const ip of ips) {
 | 
					          ips.forEach((ip) => {
 | 
				
			||||||
            privates._ipToHostObj[ip] = hostObj;
 | 
					            privates.ipToHostObj[ip] = hostObj;
 | 
				
			||||||
          }
 | 
					          });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return cb(err, null, ...warns);
 | 
					        return cb(err, null, ...warns);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -236,22 +205,22 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _updateAllAsync(cb = mandatory()) {
 | 
					    updateAllAsync(cb = mandatory()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const hostArr = Object.keys(privates._strToHostObj);
 | 
					      const hostArr = Object.keys(this.strToHostObj);
 | 
				
			||||||
      console.log('Update all:', hostArr);
 | 
					      console.log('Update all:', hostArr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const promises = hostArr.map(
 | 
					      const promises = hostArr.map(
 | 
				
			||||||
        (hostStr) => new Promise(
 | 
					        (hostStr) => new Promise(
 | 
				
			||||||
          (resolve) => this._addAsync(
 | 
					          (resolve) => this.addAsync(
 | 
				
			||||||
            hostStr,
 | 
					            hostStr,
 | 
				
			||||||
            (...args) => resolve(args)
 | 
					            (...args) => resolve(args)
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
      Promise.all( promises ).then( (cbsRes) => {
 | 
					      Promise.all(promises).then((cbsRes) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const errors = cbsRes.map( ([err]) => err ).filter( (err) => err );
 | 
					        const errors = cbsRes.map(([err]) => err).filter((err) => err);
 | 
				
			||||||
        let newError;
 | 
					        let newError;
 | 
				
			||||||
        const ifAllErrors = cbsRes.length === errors.length;
 | 
					        const ifAllErrors = cbsRes.length === errors.length;
 | 
				
			||||||
        if (errors.length) {
 | 
					        if (errors.length) {
 | 
				
			||||||
| 
						 | 
					@ -270,25 +239,71 @@
 | 
				
			||||||
            return cb(newError);
 | 
					            return cb(newError);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        cb(null, null, newError);
 | 
					        return cb(null, null, newError);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _replaceAllAsync(hostArr = mandatory(), cb) {
 | 
					    replaceAllAsync(maybeHostArr = mandatory(), maybeCb) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (typeof(hostArr) === 'function') {
 | 
					      let hostArr;
 | 
				
			||||||
        cb = hostArr;
 | 
					      let cb;
 | 
				
			||||||
        hostArr = Object.keys(privates._strToHostObj);
 | 
					      if (typeof maybeHostArr === 'function') {
 | 
				
			||||||
 | 
					        hostArr = Object.keys(this.strToHostObj);
 | 
				
			||||||
 | 
					        cb = maybeHostArr;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        hostArr = maybeHostArr;
 | 
				
			||||||
 | 
					        cb = maybeCb;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      this.resetToDefaults();
 | 
					      this.resetToDefaults();
 | 
				
			||||||
      for(const hostStr of hostArr) {
 | 
					      hostArr.forEach((hostStr) => this.createHostObj(hostStr));
 | 
				
			||||||
        _createHostObj(hostStr);
 | 
					
 | 
				
			||||||
 | 
					      this.updateAllAsync(cb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  privates.reinit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const canonize = function canonize(addrArr) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const ipSet = new Set();
 | 
				
			||||||
 | 
					    const hostSet = new Set();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    addrArr.forEach((addr) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const ipm = matchIpv4v6(addr);
 | 
				
			||||||
 | 
					      if (ipm.ifMatched) {
 | 
				
			||||||
 | 
					        ipSet.add(ipm.canonical);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        hostSet.add(addr.replace(/:\d+$/, ''));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      this._updateAllAsync(cb);
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    console.log(`Canonized hosts/ips: ${hostSet.size}/${ipSet.size}`);
 | 
				
			||||||
 | 
					    return [ipSet, hostSet];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const theApi = window.apis.ipToHost = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    persistData() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      console.log('Persisting ipToHost...', privates);
 | 
				
			||||||
 | 
					      const ipToHost = {};
 | 
				
			||||||
 | 
					      Object.keys(privates.ipToHostObj).forEach((ip) => {
 | 
				
			||||||
 | 
					        ipToHost[ip] = privates.ipToHostObj[ip].host;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      privates.state(ipToHostKey, ipToHost);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    resetToDefaults() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      privates.resetToDefaults();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -296,7 +311,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    updateAllAsync(cb = mandatory()) {
 | 
					    updateAllAsync(cb = mandatory()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      this._updateAllAsync((err, ...args) => {
 | 
					      privates.updateAllAsync((err, ...args) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!err) {
 | 
					        if (!err) {
 | 
				
			||||||
          this.persistData();
 | 
					          this.persistData();
 | 
				
			||||||
| 
						 | 
					@ -310,14 +325,15 @@
 | 
				
			||||||
    replaceAllAsync(addrArr, cb = mandatory()) {
 | 
					    replaceAllAsync(addrArr, cb = mandatory()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      console.log('Replacing...');
 | 
					      console.log('Replacing...');
 | 
				
			||||||
      const [ipSet, hostSet] = _canonize(addrArr);
 | 
					      const [ipSet, hostSet] = canonize(addrArr);
 | 
				
			||||||
      for( const ip of ipSet ) {
 | 
					      ipSet.forEach((ip) => {
 | 
				
			||||||
        const host = _getHostObj(ip);
 | 
					
 | 
				
			||||||
        privates._ipToHostObj[ip] = host;
 | 
					        privates.ipToHostObj[ip] = privates.getHostObj(ip);
 | 
				
			||||||
      }
 | 
					
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const hostArr = Array.from(hostSet);
 | 
					      const hostArr = Array.from(hostSet);
 | 
				
			||||||
      this._replaceAllAsync(hostArr, (allErr, ...args) => {
 | 
					      privates.replaceAllAsync(hostArr, (allErr, ...args) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!allErr) {
 | 
					        if (!allErr) {
 | 
				
			||||||
          this.persistData();
 | 
					          this.persistData();
 | 
				
			||||||
| 
						 | 
					@ -330,7 +346,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get(ip) {
 | 
					    get(ip) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const tmp = privates._ipToHostObj[ip];
 | 
					      const tmp = privates.ipToHostObj[ip];
 | 
				
			||||||
      return tmp && tmp.host;
 | 
					      return tmp && tmp.host;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
| 
						 | 
					@ -338,14 +354,14 @@
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  window.utils.addRequestResponder(
 | 
					  window.utils.addRequestResponder(
 | 
				
			||||||
    'ip-to-host-update-all', (...args) => self.updateAllAsync(...args)
 | 
					    'ip-to-host-update-all', (...args) => theApi.updateAllAsync(...args)
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
  window.utils.addRequestResponder(
 | 
					  window.utils.addRequestResponder(
 | 
				
			||||||
    'ip-to-host-replace-all', (...args) => self.replaceAllAsync(...args)
 | 
					    'ip-to-host-replace-all', (...args) => theApi.replaceAllAsync(...args)
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
  window.utils.addRequestResponder(
 | 
					  window.utils.addRequestResponder(
 | 
				
			||||||
    'ip-to-host-reset-to-defaults', (cb) => {
 | 
					    'ip-to-host-reset-to-defaults', (cb) => {
 | 
				
			||||||
      self.resetToDefaults();
 | 
					      theApi.resetToDefaults();
 | 
				
			||||||
      cb();
 | 
					      cb();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,47 +20,52 @@
 | 
				
			||||||
    color: '#db4b2f',
 | 
					    color: '#db4b2f',
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const _tabCallbacks = {};
 | 
					  const privates = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  privates.tabCallbacks = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const afterTabUpdated = function afterTabUpdated(tabId, cb) {
 | 
					  const afterTabUpdated = function afterTabUpdated(tabId, cb) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (_tabCallbacks[tabId]) {
 | 
					    if (privates.tabCallbacks[tabId]) {
 | 
				
			||||||
      _tabCallbacks[tabId].push(cb);
 | 
					      privates.tabCallbacks[tabId].push(cb);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      _tabCallbacks[tabId] = [cb];
 | 
					      privates.tabCallbacks[tabId] = [cb];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const onTabUpdate = function onTabUpdate(tabId) {
 | 
					  const onTabUpdate = function onTabUpdate(tabId) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (_tabCallbacks[tabId]) {
 | 
					    if (privates.tabCallbacks[tabId]) {
 | 
				
			||||||
      _tabCallbacks[tabId].map( (f) => f() );
 | 
					      privates.tabCallbacks[tabId].map((f) => f());
 | 
				
			||||||
      delete _tabCallbacks[tabId];
 | 
					      delete privates.tabCallbacks[tabId];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  chrome.tabs.onUpdated.addListener( onTabUpdate );
 | 
					  chrome.tabs.onUpdated.addListener(onTabUpdate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const updateTitle = function updateTitle(requestDetails, proxyHost, cb) {
 | 
					  const updateTitle = function updateTitle(requestDetails, proxyHost, cb) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    chrome.browserAction.getTitle(
 | 
					    chrome.browserAction.getTitle(
 | 
				
			||||||
      {tabId: requestDetails.tabId},
 | 
					      { tabId: requestDetails.tabId },
 | 
				
			||||||
      (title) => {
 | 
					      (title) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const ifTitleSetAlready = /\n/.test(title);
 | 
					        const ifTitleSetAlready = /\n/.test(title);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const hostname = new URL( requestDetails.url ).hostname;
 | 
					        const hostname = new URL(requestDetails.url).hostname;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let ifShouldUpdateTitle = false;
 | 
					        let ifShouldUpdateTitle = false;
 | 
				
			||||||
        const indent = '  ';
 | 
					        const indent = '  ';
 | 
				
			||||||
        const proxyTitle = 'Прокси:';
 | 
					        const proxyTitle = 'Прокси:';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let theLatestCb = cb;
 | 
				
			||||||
 | 
					        let newTitle = title;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!ifTitleSetAlready) {
 | 
					        if (!ifTitleSetAlready) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          title = 'Разблокированы:\n' + indent + hostname + '\n'
 | 
					          newTitle = `Разблокированы:\n${indent}${hostname}\n${proxyTitle}\n`
 | 
				
			||||||
            + proxyTitle + '\n' + indent + proxyHost;
 | 
					            + `${indent}${proxyHost}`;
 | 
				
			||||||
          ifShouldUpdateTitle = true;
 | 
					          ifShouldUpdateTitle = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          chrome.browserAction.setBadgeText({
 | 
					          chrome.browserAction.setBadgeText({
 | 
				
			||||||
| 
						 | 
					@ -70,37 +75,36 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          const hostsProxiesPair = title.split(proxyTitle);
 | 
					          const hostsProxiesPair = newTitle.split(proxyTitle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (hostsProxiesPair[1].indexOf(proxyHost) === -1) {
 | 
					          if (hostsProxiesPair[1].indexOf(proxyHost) === -1) {
 | 
				
			||||||
            title = title.replace(
 | 
					            newTitle = newTitle.replace(
 | 
				
			||||||
              hostsProxiesPair[1],
 | 
					              hostsProxiesPair[1],
 | 
				
			||||||
              hostsProxiesPair[1] + '\n' + indent + proxyHost
 | 
					              `${hostsProxiesPair[1]}\n${indent}${proxyHost}`
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            ifShouldUpdateTitle = true;
 | 
					            ifShouldUpdateTitle = true;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (hostsProxiesPair[0].indexOf(hostname) === -1) {
 | 
					          if (hostsProxiesPair[0].indexOf(hostname) === -1) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            title = title.replace(
 | 
					            newTitle = newTitle.replace(
 | 
				
			||||||
              proxyTitle,
 | 
					              proxyTitle,
 | 
				
			||||||
              indent + hostname + '\n' + proxyTitle
 | 
					              `${indent}${hostname}\n${proxyTitle}`
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            ifShouldUpdateTitle = true;
 | 
					            ifShouldUpdateTitle = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const _cb = cb;
 | 
					            theLatestCb = () => chrome.browserAction.getBadgeText(
 | 
				
			||||||
            cb = () => chrome.browserAction.getBadgeText(
 | 
					              { tabId: requestDetails.tabId },
 | 
				
			||||||
              {tabId: requestDetails.tabId},
 | 
					 | 
				
			||||||
              (result) => {
 | 
					              (result) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                const charPrefix = isNaN(result.charAt(0)) ? result.charAt(0) : '';
 | 
				
			||||||
                chrome.browserAction.setBadgeText(
 | 
					                chrome.browserAction.setBadgeText(
 | 
				
			||||||
                  {
 | 
					                  {
 | 
				
			||||||
                    tabId: requestDetails.tabId,
 | 
					                    tabId: requestDetails.tabId,
 | 
				
			||||||
                    text: (isNaN( result.charAt(0)) && result.charAt(0) || '')
 | 
					                    text: charPrefix + (hostsProxiesPair[0].split('\n').length - 1),
 | 
				
			||||||
                      + (hostsProxiesPair[0].split('\n').length - 1),
 | 
					 | 
				
			||||||
                  }
 | 
					                  }
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
                return _cb();
 | 
					                return cb();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
| 
						 | 
					@ -111,12 +115,12 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (ifShouldUpdateTitle) {
 | 
					        if (ifShouldUpdateTitle) {
 | 
				
			||||||
          chrome.browserAction.setTitle({
 | 
					          chrome.browserAction.setTitle({
 | 
				
			||||||
            title: title,
 | 
					            title: newTitle,
 | 
				
			||||||
            tabId: requestDetails.tabId,
 | 
					            tabId: requestDetails.tabId,
 | 
				
			||||||
          });
 | 
					          });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return cb();
 | 
					        return theLatestCb();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
| 
						 | 
					@ -127,7 +131,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const tryProxyAndInform = function tryProxyAndInform(requestDetails) {
 | 
					  const tryProxyAndInform = function tryProxyAndInform(requestDetails) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const host = window.apis.ipToHost.get( requestDetails.ip );
 | 
					    const host = window.apis.ipToHost.get(requestDetails.ip);
 | 
				
			||||||
    if (!host) {
 | 
					    if (!host) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -137,7 +141,7 @@
 | 
				
			||||||
    previousUpdateTitleFinished = previousUpdateTitleFinished.then(
 | 
					    previousUpdateTitleFinished = previousUpdateTitleFinished.then(
 | 
				
			||||||
      () => new Promise(
 | 
					      () => new Promise(
 | 
				
			||||||
        (resolve) => {
 | 
					        (resolve) => {
 | 
				
			||||||
          const cb = () => updateTitle( requestDetails, host, resolve );
 | 
					          const cb = () => updateTitle(requestDetails, host, resolve);
 | 
				
			||||||
          return ifMainFrame
 | 
					          return ifMainFrame
 | 
				
			||||||
            ? afterTabUpdated(requestDetails.tabId, cb) : cb();
 | 
					            ? afterTabUpdated(requestDetails.tabId, cb) : cb();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -155,11 +159,11 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for(const eventName of ['onResponseStarted', 'onErrorOccurred']) {
 | 
					  ['onResponseStarted', 'onErrorOccurred'].forEach((eventName) =>
 | 
				
			||||||
    chrome.webRequest[eventName].addListener(
 | 
					    chrome.webRequest[eventName].addListener(
 | 
				
			||||||
      onRequest,
 | 
					      onRequest,
 | 
				
			||||||
      {urls: ['<all_urls>']}
 | 
					      { urls: ['<all_urls>'] }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,5 @@
 | 
				
			||||||
'use strict';
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{
 | 
					window.apis.version.ifMini = true;
 | 
				
			||||||
 | 
					chrome.browserAction.setBadgeText({ text: 'M' });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  window.apis.version.ifMini = true;
 | 
					 | 
				
			||||||
  chrome.browserAction.setBadgeText({text: 'M'});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
'use strict';
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const commonContext = {
 | 
					const commonContext = {
 | 
				
			||||||
  version: '0.21',
 | 
					  version: '0.22',
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exports.contexts = {};
 | 
					exports.contexts = {};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user