From 69ffeefd3d0af651ed24bf8e0819d74d0c8c9f6e Mon Sep 17 00:00:00 2001 From: HF Date: Thu, 18 Aug 2022 14:13:15 +0200 Subject: [PATCH] better handle proxycheck key createStore without combine --- src/core/isAllowed.js | 11 ++++-- src/store/store.js | 25 ++++++------ src/store/storeWin.js | 11 ++---- src/utils/proxycheck.js | 85 ++++++++++++++++++++++++++++++++++++++--- 4 files changed, 102 insertions(+), 30 deletions(-) diff --git a/src/core/isAllowed.js b/src/core/isAllowed.js index fee68ea..720913a 100644 --- a/src/core/isAllowed.js +++ b/src/core/isAllowed.js @@ -20,7 +20,11 @@ import { USE_PROXYCHECK } from './config'; * dummy function to include if you don't want any proxycheck */ async function dummy() { - return [false, 'dummy']; + return { + allowed: true, + status: 0, + pcheck: 'dummy', + }; } /* @@ -83,10 +87,11 @@ async function withoutCache(f, ip) { } /* - * execute proxycheck without caching results for 3 days - * do not check more than 3 at a time, do not check ip double + * execute proxycheck with caching results + * do not check ip double * @param f function for checking if proxy * @param ip IP to check + * @return Object as in checkIfAllowed * @return true if proxy or blacklisted, false if not or whitelisted */ const checking = []; diff --git a/src/store/store.js b/src/store/store.js index 566e9c4..c566adb 100644 --- a/src/store/store.js +++ b/src/store/store.js @@ -3,7 +3,7 @@ */ import { - applyMiddleware, createStore, compose, combineReducers, + applyMiddleware, createStore, combineReducers, } from 'redux'; import thunk from 'redux-thunk'; import { persistStore, persistReducer } from 'redux-persist'; @@ -55,19 +55,16 @@ const reducers = combineReducers({ const store = createStore( reducers, - undefined, - compose( - applyMiddleware( - thunk, - promise, - array, - audio, - notifications, - title, - socketClientHook, - rendererHook, - extensions, - ), + applyMiddleware( + thunk, + promise, + array, + audio, + notifications, + title, + socketClientHook, + rendererHook, + extensions, ), ); diff --git a/src/store/storeWin.js b/src/store/storeWin.js index 022e2a6..5f41fd8 100644 --- a/src/store/storeWin.js +++ b/src/store/storeWin.js @@ -5,7 +5,7 @@ /* eslint-disable no-console */ import { - applyMiddleware, createStore, compose, combineReducers, + applyMiddleware, createStore, combineReducers, } from 'redux'; import thunk from 'redux-thunk'; import { persistStore } from 'redux-persist'; @@ -30,12 +30,9 @@ const reducers = combineReducers({ const store = createStore( reducers, - undefined, - compose( - applyMiddleware( - thunk, - promise, - ), + applyMiddleware( + thunk, + promise, ), ); diff --git a/src/utils/proxycheck.js b/src/utils/proxycheck.js index 99a33cc..cca16b0 100644 --- a/src/utils/proxycheck.js +++ b/src/utils/proxycheck.js @@ -1,12 +1,77 @@ /* * check if an ip is a proxy via proxycheck.io */ +import http from 'http'; + import { proxyLogger as logger } from '../core/logger'; import { PROXYCHECK_KEY } from '../core/config'; +import { HOUR } from '../core/constants'; -const http = require('http'); -const pcKeys = PROXYCHECK_KEY.split(','); +/* + * class to serve proxyckec.io key + * One paid account is allowed to have one additional free account, + * which is good for fallback, if something goes wrong + */ +class PcKeyProvider { + /* + * @param pcKeys comma seperated list of keys + */ + constructor(pcKeys) { + let keys = (pcKeys) + ? pcKeys.split(',') + : []; + keys = keys.map((k) => k.trim()); + if (keys.length) { + logger.info(`Loaded pc Keys: ${keys}`); + } else { + logger.info(`You have to define PROXYCHECK_KEY to use proxycheck.io`); + } + this.availableKeys = keys; + this.deniedKeys = []; + this.retryDeniedKeys = this.retryDeniedKeys.bind(this); + setInterval(this.retryDeniedKeys, HOUR); + } + + /* + * @return random available pcKey + */ + getKey() { + const { availableKeys: keys } = this; + if (!keys.length) { + return null; + } + return keys[Math.floor(Math.random() * keys.length)]; + } + + /* + * report denied key (over daily quota, rate limited, blocked,...) + * @param key + */ + denyKey(key) { + const { availableKeys: keys } = this; + const pos = keys.indexOf(key); + if (~pos) { + keys.splice(pos, 1); + this.deniedKeys.push(key); + } + } + + /* + * allow all denied keys again + */ + retryDeniedKeys() { + const { deniedKeys } = this; + if (!deniedKeys.length) { + return; + } + logger.info(`Retry denied Keys ${deniedKeys}`); + this.availableKeys = this.availableKeys.concat(deniedKeys); + this.deniedKeys = []; + } +} + +const pcKeyProvider = new PcKeyProvider(PROXYCHECK_KEY); /* * queue of ip-checking tasks @@ -18,13 +83,18 @@ let fetching = false; function reqProxyCheck(ips) { return new Promise((resolve, reject) => { + const key = pcKeyProvider.getKey(); + if (!key) { + setTimeout( + () => reject(new Error('No pc key available')), + 5000, + ); + return; + } const postData = `ips=${ips.join(',')}`; + const path = `/v2/?vpn=1&asn=1&key=${key}`; logger.info(`Request for ${postData}`); - let path = '/v2/?vpn=1&asn=1'; - const key = pcKeys[Math.floor(Math.random() * pcKeys.length)]; - if (key) path += `&key=${key}`; - const options = { hostname: 'proxycheck.io', port: 80, @@ -66,6 +136,9 @@ function reqProxyCheck(ips) { }); return; } + if (result.status === 'denied') { + pcKeyProvider.denyKey(key); + } if (result.status !== 'warning') { throw new Error(`${key}: ${result.message}`); } else {