├── proxies.txt ├── .gitignore ├── readme.md ├── config.js ├── package.json └── index.js /proxies.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.DS_Store 2 | /node_modules 3 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## Install 2 | `npm install` 3 | 4 | 5 | ## Configure 6 | Add proxies one per line in format ip:port:user:pass to `proxies.txt` 7 | 8 | Modify domain, delay, threshold, and timeout settings in `config.js` 9 | 10 | 11 | ## Run 12 | `npm start` 13 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | delay: 50, // delay in ms between sending requests 3 | domain: 'sixflags.com', 4 | timeout: 50000, 5 | thresholds: { // times in ms 6 | good: 1000, // less than this is good 7 | bad: 5000 // greater than this is bad 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "proxy-tester", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "jetty": "^0.2.1", 14 | "request": "^2.88.0", 15 | "request-promise-native": "^1.0.7" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const request = require('request'); 3 | const rp = require('request-promise-native'); 4 | 5 | const Jetty = require('jetty'); 6 | const tty = new Jetty(process.stdout); 7 | tty.reset().clear().moveTo([0, 0]); 8 | 9 | const { 10 | delay, 11 | domain, 12 | thresholds, 13 | timeout 14 | } = require('./config'); 15 | 16 | let completed = 0; 17 | const limit = process.stdout.rows - 1; 18 | let proxies = []; 19 | let chunks = []; 20 | let chunksCompleted = 0; 21 | const times = {}; 22 | 23 | // Jetty Colors 24 | const colors = { 25 | white: [5,5,5], 26 | blue: [0,0,5], 27 | red: [5,0,0], 28 | green: [0,3,0], 29 | black: [0,0,0], 30 | gray: [2,2,2] 31 | }; 32 | 33 | // Jetty Styles 34 | const styles = { 35 | index: function (str) { 36 | this 37 | .bold() 38 | .rgb(colors.black, 1) 39 | .rgb(colors.white) 40 | .text(str) 41 | .reset(); 42 | }, 43 | good: function (str) { 44 | this 45 | .rgb(colors.green, 1) 46 | .rgb(colors.white) 47 | .text(str) 48 | .reset(); 49 | }, 50 | bad: function (str) { 51 | this 52 | .bold() 53 | .rgb(colors.red, 1) 54 | .rgb(colors.white) 55 | .text(str) 56 | .reset(); 57 | }, 58 | neutral: function (str) { 59 | this 60 | .rgb(colors.gray, 1) 61 | .rgb(colors.white) 62 | .text(str) 63 | .reset(); 64 | }, 65 | }; 66 | 67 | // Headers for request 68 | const headers = { 69 | Host: domain, 70 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Safari/605.1.15', 71 | 'Cache-Control': 'no-cache', 72 | Pragma: 'no-cache', 73 | Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 74 | 'Accept-Language': 'en-US', 75 | 'Accept-Encoding': 'br, gzip, deflate', 76 | Connection: 'keep-alive', 77 | }; 78 | 79 | // Options for request 80 | const getOptions = () => ({ 81 | url: `http://${domain}`, 82 | headers, 83 | method: 'get', 84 | gzip: true, 85 | resolveWithFullResponse: true, 86 | timeout, 87 | jar: request.jar() 88 | }); 89 | 90 | const getTimeStyle = (time) => { 91 | if (time < thresholds.good) return styles.good; 92 | if (time < thresholds.bad) return styles.neutral; 93 | return styles.bad; 94 | }; 95 | 96 | const getMessageStyle = (message) => { 97 | if (message.includes('200')) return styles.good; 98 | return styles.bad; 99 | }; 100 | 101 | const updateLine = (index, proxy, message, time = false) => { 102 | let p = proxy.replace('http://', ''); 103 | if (p.includes('@')) [, p] = p.split('@'); 104 | const i = `000${chunksCompleted * limit + index}`.slice(-4); 105 | 106 | if (time) { 107 | const timeStyle = getTimeStyle(time); 108 | const messageStyle = getMessageStyle(message); 109 | 110 | tty 111 | .moveTo([index - 1, 0]) 112 | .text(`${i} - ${p} `, styles.index) 113 | .text(' ') 114 | .text(` ${(time / 1000).toFixed(3)}s `, timeStyle) 115 | .text(' ') 116 | .text(` ${message} `, messageStyle) 117 | .text('\n'); 118 | } else { 119 | tty 120 | .moveTo([index - 1, 0]) 121 | .text(`${i} - ${p} `, styles.index) 122 | .text(' ') 123 | .text(` ${message} `) 124 | .text('\n'); 125 | } 126 | }; 127 | 128 | // Proxy file to proxy object 129 | const formatProxies = () => { 130 | const rawProxies = fs.readFileSync('./proxies.txt', 'utf-8'); 131 | const split = rawProxies.trim().split('\n'); 132 | 133 | for (const p of split) { 134 | const parts = p.trim().split(':'); 135 | const [ip, port, user, pass] = parts; 136 | proxies.push({ 137 | ip, port, user, pass 138 | }); 139 | } 140 | }; 141 | 142 | // Groups proxies into chunks 143 | const blowChunks = () => { 144 | const fullChunks = Math.floor(proxies.length / limit); 145 | const lastChunk = proxies.length % limit; 146 | 147 | for (let i = 0; i < fullChunks; i += 1) { 148 | chunks.push(proxies.slice(i * limit, i * limit + limit)); 149 | } 150 | 151 | chunks.push(proxies.slice(fullChunks * limit, fullChunks * limit + lastChunk)); 152 | }; 153 | 154 | // Test a proxy 155 | const test = async (index, proxy) => { 156 | updateLine(index, proxy, 'Running...'); 157 | times[index] = new Date().getTime(); 158 | 159 | try { 160 | const response = await rp(Object.assign({ proxy }, getOptions())); 161 | 162 | completed += 1; 163 | 164 | const now = new Date().getTime(); 165 | const time = now - times[index]; 166 | 167 | updateLine(index, proxy, response.statusCode.toString(), time); 168 | } catch (e) { 169 | completed += 1; 170 | 171 | const now = new Date().getTime(); 172 | const time = ((now - times[index]) / 1000).toFixed(3); 173 | updateLine(index, proxy, e.statusCode || e.message, time); 174 | } 175 | }; 176 | 177 | // Run em all 178 | const run = async () => { 179 | proxies = chunks.shift(); 180 | 181 | for (let i = 0; i < proxies.length; i += 1) { 182 | const p = proxies[i]; 183 | let proxy = `${p.ip}:${p.port}`; 184 | if (p.user) proxy = `${p.user}:${p.pass}@${proxy}`; 185 | proxy = `http://${proxy}`; 186 | 187 | const index = i + 1; 188 | 189 | setTimeout(() => { // eslint-disable-line 190 | test(index, proxy); 191 | }, index * delay); 192 | } 193 | }; 194 | 195 | const start = async () => { 196 | formatProxies(); 197 | blowChunks(); 198 | 199 | run(); 200 | } 201 | 202 | start(); 203 | 204 | // Have to do this so the process doesn't exit before all requests have completed 205 | const interval = setInterval(() => { 206 | if (completed >= proxies.length) { 207 | completed = 0; 208 | chunksCompleted += 1; 209 | 210 | if (chunks.length > 0) { 211 | tty.reset().clear().moveTo([0, 0]); 212 | return run(); 213 | } 214 | 215 | tty.moveTo([proxies.length + 1, 0]); 216 | console.log('============ DONE! ============'); 217 | clearInterval(interval); 218 | } else { 219 | // console.log('not done'); 220 | } 221 | }, 1 * 1000); 222 | --------------------------------------------------------------------------------