├── .gitignore
├── README.md
├── bin
└── proxy-checker-cli
├── package-lock.json
├── package.json
├── request.js
└── sample-input.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # proxy-checker-cli
2 | Simple utility which is designed to accept a file of ip:port lines and to produce beautiful table of check results in terminal and to write the file with proxies which passed the checks successfully. Processes proxies concurrently (20 threads are running at the same time by default) so can be used for quite large files without overloading the server resources.
3 |
4 | ## Installation
5 | ```
6 | npm i -g proxy-checker-cli
7 | ```
8 |
9 | ## Example usage:
10 |
11 | ```proxy-checker-cli listofproxies.txt --code=20. -o goodproxies.txt --url=https://google.com```
12 |
13 | Which will get proxies from `listofproxies.txt` file, try to request https://google.com and check that reply http code is 20x
14 |
15 |
16 | ## Proxy tests included out of the box:
17 | - Expected http code ( --code=200 ) - regex supported
18 | - Expected text in body ( --text=sometext )
19 | - Expected no specified text in body ( --notext=error )
20 |
21 |
22 | ## Arguments list:
23 | ```
24 | --input file The input file to process. The file is expected to contain ip:port lines
25 | without protocol specified. This is a default argument.
26 | -o, --output file Output good ips to txt file.
27 | -v, --verbose Turn on debug output.
28 | -s, --silent Do not output visual table, only write result to files.
29 | -h, --help Print this usage guide.
30 | -t, --timeout number Number of seconds to wait for connection to proxy and for the whole request.
31 | -p, --protocol string Protocol to append to proxy ip (the file is expected to contain ip:port lines
32 | without protocol specified).
33 | -u, --url string Url to connect to validate proxy.
34 | --text string Text expected in body to validate proxy.
35 | --notext string Text expected to not exist in body to validate proxy.
36 | --code string Http code expected for test to succeed.
37 | -c, --concurrency integer Maximum Concurrency threads (default: 20)
38 | --user-agent string User agent to use for http(s) connections to tested websites.
39 | --header headername: headervalue Header to attach to request for http(s) connections to tested websites.
40 | Accepts multiple args.
41 | -l, --limit integer Limit number of proxies to check. Can be negative to trim trailing proxies
42 | from file (like arr.slice(0, -100) in js)
43 | ```
44 |
45 | ## Sample output to terminal:
46 |
47 |
--------------------------------------------------------------------------------
/bin/proxy-checker-cli:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict';
3 |
4 | const fs = require('fs')
5 | const colors = require('colors')
6 | const singleRequestExecute = require('../request.js')
7 | const commandLineArgs = require('command-line-args')
8 | const commandLineUsage = require('command-line-usage')
9 | const cliProgress = require('cli-progress')
10 | const Bottleneck = require('bottleneck')
11 |
12 | const allowedProtocols = ['http', 'https', 'socks5', 'socks', 'socks4', 'socks4a']
13 |
14 | const urlPresets = {
15 | instagram: 'https://www.instagram.com/graphql/query/?query_hash=e769aa130647d2354c40ea6a439bfc08&variables=%7B%22id%22%3A%221226157729%22%2C%22first%22%3A%221%22%2C%22after%22%3A%22%22%7D',
16 | avito: 'https://www.avito.ru/samara?q=%D0%B4%D0%B8%D0%B2%D0%B0%D0%BD',
17 | ifconfig: 'https://ifconfig.me/'
18 | }
19 |
20 | const optionDefinitions = [
21 | {
22 | name: 'input',
23 | type: String,
24 | defaultOption: true,
25 | typeLabel: '{underline file}',
26 | description: 'The input file to process. The file is expected to contain ip:port lines without protocol specified. This is a default argument.'
27 | },
28 | {
29 | name: 'output',
30 | alias: 'o',
31 | type: String,
32 | typeLabel: '{underline file}',
33 | description: 'Output good ips to txt file.'
34 | },
35 | {
36 | name: 'verbose',
37 | alias: 'v',
38 | type: Boolean,
39 | description: 'Turn on debug output.'
40 | },
41 | {
42 | name: 'silent',
43 | alias: 's',
44 | type: Boolean,
45 | defaultValue: false,
46 | description: 'Do not output visual table, only write result to files.'
47 | },
48 | {
49 | name: 'help',
50 | alias: 'h',
51 | type: Boolean,
52 | description: 'Print this usage guide.'
53 | },
54 |
55 | {
56 | name: 'timeout',
57 | alias: 't',
58 | type: Number,
59 | defaultValue: 5,
60 | description: 'Number of seconds to wait for connection to proxy and for the whole request.'
61 | },
62 | {
63 | name: 'protocol',
64 | alias: 'p', type: String,
65 | defaultValue: allowedProtocols[1],
66 | description: 'Protocol to append to proxy ip (the file is expected to contain ip:port lines without protocol specified).'
67 | },
68 | {
69 | name: 'url',
70 | alias: 'u',
71 | type: String,
72 | defaultValue: urlPresets.ifconfig,
73 | description: 'Url to connect to validate proxy.'
74 | },
75 | {
76 | name: 'text',
77 | type: String,
78 | description: 'Text expected in body to validate proxy.'
79 | },
80 | {
81 | name: 'notext',
82 | type: String,
83 | description: 'Text expected to not exist in body to validate proxy.'
84 | },
85 | {
86 | name: 'code',
87 | type: String,
88 | description: 'Http code expected for test to succeed.'
89 | },
90 | {
91 | name: 'concurrency',
92 | alias: 'c',
93 | type: Number,
94 | defaultValue: 20,
95 | description: 'Maximum Concurrency threads (default: 20)',
96 | typeLabel: '{underline integer}'
97 | },
98 | {
99 | name: 'user-agent',
100 | type: String,
101 | description: 'User agent to use for http(s) connections to tested websites.'
102 | },
103 | {
104 | name: 'header',
105 | type: String,
106 | multiple: true,
107 | description: 'Header to attach to request for http(s) connections to tested websites. Accepts multiple args.',
108 | typeLabel: '{underline headername: headervalue}'
109 | },
110 | {
111 | name: 'limit',
112 | alias: 'l',
113 | type: Number,
114 | description: 'Limit number of proxies to check. Can be negative to trim trailing proxies from file (like arr.slice(0, -100) in js)',
115 | typeLabel: '{underline integer}'
116 | },
117 | {
118 | name: 'notable',
119 | type: Boolean,
120 | description: 'Hide results table. Useful for big proxy lists when progressbar is needed but final table is too big.'
121 | }
122 | ]
123 |
124 |
125 | const options = commandLineArgs(optionDefinitions)
126 |
127 | const sections = [
128 | {
129 | header: 'Simple & fast proxy checker',
130 | content: 'Gets proxy list from file and tests them via set of checks, logging time and response result.\n Usage: `proxy-checker-cli ips.txt -t 10`'
131 | },
132 | {
133 | header: 'Options',
134 | optionList: optionDefinitions
135 | }
136 | ]
137 |
138 | let r = new RegExp(options.code);
139 |
140 |
141 | if (options.help) {
142 | const usage = commandLineUsage(sections)
143 | console.log(usage)
144 | process.exit(0)
145 | }
146 |
147 | if (!options.input) {
148 | console.error('Input file with ips is required. Try --help')
149 | process.exit(1)
150 | }
151 |
152 | if (!allowedProtocols.includes(options.protocol)) {
153 | console.error('Allowed protocols: ', allowedProtocols)
154 | process.exit(1)
155 | }
156 |
157 | if (!fs.existsSync(options.input)) {
158 | console.error('Input file does not exist!')
159 | process.exit(1)
160 | }
161 |
162 | if (options.silent) {
163 | options.verbose = false;
164 | }
165 |
166 | const limiter = new Bottleneck({
167 | maxConcurrent: options.concurrency,
168 | minTime: 0
169 | })
170 |
171 |
172 |
173 | const url = urlPresets[options.url] ? urlPresets[options.url] : options.url
174 | const lines = fs.readFileSync(options.input, 'utf8').split('\n').filter(String).slice(0, options.limit)
175 |
176 | const startMs = Date.now();
177 |
178 |
179 | options.mainLog = (...vars) => {
180 | vars[0] = '\n' + vars[0]
181 | options.silent ? false : console.log(...vars)
182 | }
183 | options.verboseLog = (...vars) => {
184 | vars[0] = '\n' + vars[0]
185 | options.verbose ? console.log(...vars) : false
186 | }
187 |
188 |
189 |
190 | var goodProxyCount = 0;
191 | if (!options.silent) {
192 | var bar1 = new cliProgress.SingleBar({
193 | stopOnComplete: true,
194 | format: '{bar} {percentage}% | ETA: {eta}s | {value}/{total} | Good: {goodProxyCount}'
195 | }, cliProgress.Presets.shades_classic)
196 |
197 | bar1.start(lines.length, 0, { goodProxyCount })
198 | }
199 |
200 | let singleRequestExecuteLimited = limiter.wrap(singleRequestExecute)
201 |
202 |
203 | let promises = lines.map((proxyAddr) =>
204 | singleRequestExecuteLimited(url, proxyAddr, options).then((result) => {
205 | if (!options.silent) {
206 | goodProxyCount += result.success ? 1 : 0
207 | bar1.increment({ goodProxyCount })
208 | }
209 |
210 | return result
211 | })
212 | )
213 |
214 |
215 | Promise.all(promises).then((results) => {
216 |
217 | if (!options.silent) {
218 | bar1.stop()
219 |
220 | if (!options.notable) {
221 | const Table = require('cli-table3')
222 |
223 | let table = new Table({style: {head: ['cyan']}, head: [
224 | 'Proxy', 'Result', 'Time', 'Response'
225 | ]});
226 | results.map((item) => {
227 | table.push([
228 | item.name,
229 | item.success ? colors.green('TRUE') : colors.red('FALSE'),
230 | item.time,
231 | item.success ? item.response : colors.red(item.error)
232 | ]);
233 | })
234 | options.mainLog(table.toString())
235 |
236 | }
237 |
238 | }
239 |
240 | let good = results.reduce((a,c) => a + (c.success ? 1 : 0), 0)
241 |
242 | if (options.output) {
243 | let file = fs.createWriteStream(options.output)
244 | file.on('error', function(err) { /* error handling */ })
245 | results.forEach(function(v) {
246 | if (v.success) {
247 | file.write(v.name + '\n')
248 | }
249 | })
250 | file.end()
251 | options.verboseLog('Results put to %s', options.output)
252 | }
253 |
254 | options.verboseLog('Finished in %s', (Date.now() - startMs)/1000 + 's')
255 | options.mainLog('Found %d good proxies out of %d', good, results.length)
256 |
257 |
258 | });
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "proxy-checker-cli",
3 | "version": "2.0.10",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "ansi-regex": {
8 | "version": "5.0.0",
9 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
10 | "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
11 | },
12 | "ansi-styles": {
13 | "version": "3.2.1",
14 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
15 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
16 | "requires": {
17 | "color-convert": "^1.9.0"
18 | }
19 | },
20 | "array-back": {
21 | "version": "3.1.0",
22 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz",
23 | "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q=="
24 | },
25 | "bottleneck": {
26 | "version": "2.19.5",
27 | "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
28 | "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="
29 | },
30 | "chalk": {
31 | "version": "2.4.2",
32 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
33 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
34 | "requires": {
35 | "ansi-styles": "^3.2.1",
36 | "escape-string-regexp": "^1.0.5",
37 | "supports-color": "^5.3.0"
38 | }
39 | },
40 | "cli-progress": {
41 | "version": "3.8.2",
42 | "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.8.2.tgz",
43 | "integrity": "sha512-qRwBxLldMSfxB+YGFgNRaj5vyyHe1yMpVeDL79c+7puGujdKJHQHydgqXDcrkvQgJ5U/d3lpf6vffSoVVUftVQ==",
44 | "requires": {
45 | "colors": "^1.1.2",
46 | "string-width": "^4.2.0"
47 | }
48 | },
49 | "cli-table3": {
50 | "version": "0.6.0",
51 | "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.0.tgz",
52 | "integrity": "sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==",
53 | "requires": {
54 | "colors": "^1.1.2",
55 | "object-assign": "^4.1.0",
56 | "string-width": "^4.2.0"
57 | }
58 | },
59 | "color-convert": {
60 | "version": "1.9.3",
61 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
62 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
63 | "requires": {
64 | "color-name": "1.1.3"
65 | }
66 | },
67 | "color-name": {
68 | "version": "1.1.3",
69 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
70 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
71 | },
72 | "colors": {
73 | "version": "1.4.0",
74 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
75 | "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA=="
76 | },
77 | "command-line-args": {
78 | "version": "5.1.1",
79 | "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.1.1.tgz",
80 | "integrity": "sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==",
81 | "requires": {
82 | "array-back": "^3.0.1",
83 | "find-replace": "^3.0.0",
84 | "lodash.camelcase": "^4.3.0",
85 | "typical": "^4.0.0"
86 | }
87 | },
88 | "command-line-usage": {
89 | "version": "6.1.0",
90 | "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.0.tgz",
91 | "integrity": "sha512-Ew1clU4pkUeo6AFVDFxCbnN7GIZfXl48HIOQeFQnkO3oOqvpI7wdqtLRwv9iOCZ/7A+z4csVZeiDdEcj8g6Wiw==",
92 | "requires": {
93 | "array-back": "^4.0.0",
94 | "chalk": "^2.4.2",
95 | "table-layout": "^1.0.0",
96 | "typical": "^5.2.0"
97 | },
98 | "dependencies": {
99 | "array-back": {
100 | "version": "4.0.1",
101 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz",
102 | "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg=="
103 | },
104 | "typical": {
105 | "version": "5.2.0",
106 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz",
107 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg=="
108 | }
109 | }
110 | },
111 | "deep-extend": {
112 | "version": "0.6.0",
113 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
114 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
115 | },
116 | "detect-indent": {
117 | "version": "6.0.0",
118 | "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz",
119 | "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA=="
120 | },
121 | "docopt": {
122 | "version": "0.6.2",
123 | "resolved": "https://registry.npmjs.org/docopt/-/docopt-0.6.2.tgz",
124 | "integrity": "sha1-so6eIiDaXsSffqW7JKR3h0Be6xE="
125 | },
126 | "dot-json": {
127 | "version": "1.2.1",
128 | "resolved": "https://registry.npmjs.org/dot-json/-/dot-json-1.2.1.tgz",
129 | "integrity": "sha512-sHtCsDBBzhTUFhS12cAvUbP9JTr59LLNxnpNr6dlgbjZlN+nrWFs+uHXgsJvFmc5HoMFR4e60rdqd+GdSUlM3w==",
130 | "requires": {
131 | "detect-indent": "~6.0.0",
132 | "docopt": "~0.6.2",
133 | "underscore-keypath": "~0.0.22"
134 | }
135 | },
136 | "emoji-regex": {
137 | "version": "8.0.0",
138 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
139 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
140 | },
141 | "escape-string-regexp": {
142 | "version": "1.0.5",
143 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
144 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
145 | },
146 | "find-replace": {
147 | "version": "3.0.0",
148 | "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz",
149 | "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==",
150 | "requires": {
151 | "array-back": "^3.0.1"
152 | }
153 | },
154 | "has-flag": {
155 | "version": "3.0.0",
156 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
157 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
158 | },
159 | "ip": {
160 | "version": "1.1.5",
161 | "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
162 | "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
163 | },
164 | "is-fullwidth-code-point": {
165 | "version": "3.0.0",
166 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
167 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
168 | },
169 | "lodash.camelcase": {
170 | "version": "4.3.0",
171 | "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
172 | "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
173 | },
174 | "lodash.clonedeep": {
175 | "version": "4.5.0",
176 | "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
177 | "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
178 | },
179 | "node-fetch": {
180 | "version": "2.6.1",
181 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
182 | "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
183 | },
184 | "object-assign": {
185 | "version": "4.1.1",
186 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
187 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
188 | },
189 | "reduce-flatten": {
190 | "version": "2.0.0",
191 | "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz",
192 | "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w=="
193 | },
194 | "simple-proxy-agent": {
195 | "version": "1.1.0",
196 | "resolved": "https://registry.npmjs.org/simple-proxy-agent/-/simple-proxy-agent-1.1.0.tgz",
197 | "integrity": "sha512-amJaLagzNELaNNB2UXdXiORVbbU/RC4yRwtGvF4cttJheTm4JvL2fZ1SfuLU952XC7TLamYdgzzJtWUbGM6Jcw==",
198 | "requires": {
199 | "socks": "^2.3.2"
200 | }
201 | },
202 | "smart-buffer": {
203 | "version": "4.1.0",
204 | "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz",
205 | "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw=="
206 | },
207 | "socks": {
208 | "version": "2.4.4",
209 | "resolved": "https://registry.npmjs.org/socks/-/socks-2.4.4.tgz",
210 | "integrity": "sha512-7LmHN4IHj1Vpd/k8D872VGCHJ6yIVyeFkfIBExRmGPYQ/kdUkpdg9eKh9oOzYYYKQhuxavayJHTnmBG+EzluUA==",
211 | "requires": {
212 | "ip": "^1.1.5",
213 | "smart-buffer": "^4.1.0"
214 | }
215 | },
216 | "string-width": {
217 | "version": "4.2.0",
218 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
219 | "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
220 | "requires": {
221 | "emoji-regex": "^8.0.0",
222 | "is-fullwidth-code-point": "^3.0.0",
223 | "strip-ansi": "^6.0.0"
224 | }
225 | },
226 | "strip-ansi": {
227 | "version": "6.0.0",
228 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
229 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
230 | "requires": {
231 | "ansi-regex": "^5.0.0"
232 | }
233 | },
234 | "supports-color": {
235 | "version": "5.5.0",
236 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
237 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
238 | "requires": {
239 | "has-flag": "^3.0.0"
240 | }
241 | },
242 | "table-layout": {
243 | "version": "1.0.1",
244 | "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.1.tgz",
245 | "integrity": "sha512-dEquqYNJiGwY7iPfZ3wbXDI944iqanTSchrACLL2nOB+1r+h1Nzu2eH+DuPPvWvm5Ry7iAPeFlgEtP5bIp5U7Q==",
246 | "requires": {
247 | "array-back": "^4.0.1",
248 | "deep-extend": "~0.6.0",
249 | "typical": "^5.2.0",
250 | "wordwrapjs": "^4.0.0"
251 | },
252 | "dependencies": {
253 | "array-back": {
254 | "version": "4.0.1",
255 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz",
256 | "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg=="
257 | },
258 | "typical": {
259 | "version": "5.2.0",
260 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz",
261 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg=="
262 | }
263 | }
264 | },
265 | "typical": {
266 | "version": "4.0.0",
267 | "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz",
268 | "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw=="
269 | },
270 | "underscore": {
271 | "version": "1.11.0",
272 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.11.0.tgz",
273 | "integrity": "sha512-xY96SsN3NA461qIRKZ/+qox37YXPtSBswMGfiNptr+wrt6ds4HaMw23TP612fEyGekRE6LNRiLYr/aqbHXNedw=="
274 | },
275 | "underscore-keypath": {
276 | "version": "0.0.22",
277 | "resolved": "https://registry.npmjs.org/underscore-keypath/-/underscore-keypath-0.0.22.tgz",
278 | "integrity": "sha1-SKUoOSu278QkvhyqVtpLX6zPJk0=",
279 | "requires": {
280 | "underscore": "*"
281 | }
282 | },
283 | "user-agents": {
284 | "version": "1.0.559",
285 | "resolved": "https://registry.npmjs.org/user-agents/-/user-agents-1.0.559.tgz",
286 | "integrity": "sha512-HdAlNS3vDxOGMRwmv8or05xL96MV3CEwQhUSFTCRoOvTOEnWhTEBPAHRry/xZpVTTOtx77UHMal8YKcx6fs7Lg==",
287 | "requires": {
288 | "dot-json": "^1.2.0",
289 | "lodash.clonedeep": "^4.5.0"
290 | }
291 | },
292 | "wordwrapjs": {
293 | "version": "4.0.0",
294 | "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.0.tgz",
295 | "integrity": "sha512-Svqw723a3R34KvsMgpjFBYCgNOSdcW3mQFK4wIfhGQhtaFVOJmdYoXgi63ne3dTlWgatVcUc7t4HtQ/+bUVIzQ==",
296 | "requires": {
297 | "reduce-flatten": "^2.0.0",
298 | "typical": "^5.0.0"
299 | },
300 | "dependencies": {
301 | "typical": {
302 | "version": "5.2.0",
303 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz",
304 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg=="
305 | }
306 | }
307 | }
308 | }
309 | }
310 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "bottleneck": "^2.19.5",
4 | "cli-progress": "^3.8.2",
5 | "cli-table3": "^0.6.0",
6 | "colors": "^1.4.0",
7 | "command-line-args": "^5.1.1",
8 | "command-line-usage": "^6.1.0",
9 | "node-fetch": "^2.6.1",
10 | "simple-proxy-agent": "^1.1.0",
11 | "user-agents": "^1.0.559"
12 | },
13 | "name": "proxy-checker-cli",
14 | "description": "Simple utility which is designed to accept a file of ip:port lines and to produce beautiful table of check results in terminal and to write the file with proxies which passed the checks successfully.",
15 | "version": "2.0.10",
16 | "main": "test.js",
17 | "devDependencies": {},
18 | "bin": {
19 | "proxy-checker-cli": "./bin/proxy-checker-cli"
20 | },
21 | "scripts": {
22 | "test": "echo \"Error: no test specified\" && exit 1"
23 | },
24 | "repository": {
25 | "type": "git",
26 | "url": "git+https://github.com/restyler/proxy-checker-cli.git"
27 | },
28 | "keywords": [
29 | "proxy-checker",
30 | "proxy",
31 | "cli"
32 | ],
33 | "author": "restyler (https://pixeljets.com)",
34 | "license": "ISC",
35 | "bugs": {
36 | "url": "https://github.com/restyler/proxy-checker-cli/issues"
37 | },
38 | "homepage": "https://github.com/restyler/proxy-checker-cli#readme"
39 | }
40 |
--------------------------------------------------------------------------------
/request.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fetch = require('node-fetch')
4 | const ProxyAgent = require('simple-proxy-agent')
5 | const UserAgent = require('user-agents')
6 |
7 | async function request(url, options, timeout = 5) {
8 | try {
9 | const res = await fetch(url, {
10 | ...options,
11 | timeout: timeout * 1000
12 | })
13 | if(!res.ok) {
14 | throw new Error('Invalid Response');
15 | }
16 | return res;
17 | } catch (err) {
18 | throw err;
19 | }
20 | }
21 |
22 | async function singleRequestExecute(url, proxyAddr, options) {
23 | return new Promise((resolve) => {
24 | let res = {};
25 | res.name = proxyAddr;
26 | res.startMs = Date.now();
27 |
28 | options.verboseLog('Queueing %s', proxyAddr)
29 |
30 | let agent = ProxyAgent(options.protocol + '://' + proxyAddr, {
31 | timeout: options.timeout * 1000,
32 | tunnel: true
33 | })
34 |
35 | let headers = {}
36 | if (typeof options['user-agent'] == 'undefined') {
37 | headers['user-agent'] = new UserAgent().toString()
38 | } else {
39 | headers['user-agent'] = options['user-agent']
40 | }
41 |
42 | if (typeof options.header !== 'undefined' && options.header.length) {
43 | options.header.forEach(elem => {
44 | let el = elem.split(':').map(e => e.trim())
45 | headers[el[0]] = el[1]
46 | });
47 | }
48 |
49 | request(url, {agent, timeout: options.timeout, headers }, options.timeout)
50 | .then(async (resp) => {
51 | res = await requestProcess(res, resp, options)
52 | })
53 | .catch(err => {
54 | res.success = false;
55 | res.error = err.message.substring(0, 30).trim();
56 | options.verboseLog('Failed response from %s', proxyAddr)
57 | }).finally(() => {
58 | res.time = ((Date.now() - res.startMs)/1000).toFixed(1);
59 | resolve(res);
60 | })
61 | })
62 | }
63 |
64 | async function requestProcess(res, response, options) {
65 | res.success = true;
66 | let responseText = (await response.text());
67 | options.verboseLog('Received response from %s, http code: %d', res.name, response.status)
68 |
69 |
70 | if (options.code) {
71 |
72 | let r = new RegExp(options.code);
73 | if (r.test(response.status)) {
74 | options.verboseLog('Code check for %s: success, http code: %d', res.name, response.status)
75 | } else {
76 | res.success = false;
77 | res.error = 'Bad code:' + response.status;
78 | options.verboseLog('Code check for %s: fail, http code: %d', res.name, response.status)
79 | }
80 |
81 |
82 | }
83 |
84 | if (options.text) {
85 | if (!responseText.includes(options.text)) {
86 | res.success = false;
87 | res.error = 'Expected text not found';
88 | options.verboseLog('Text check for %s: fail', res.name)
89 | } else {
90 | options.verboseLog('Text check for %s: success', res.name)
91 | }
92 | }
93 |
94 | if (options.notext) {
95 | if (responseText.includes(options.notext)) {
96 | res.success = false;
97 | res.error = 'Not expected text found'
98 | options.verboseLog('Notext check for %s: fail', res.name)
99 | } else {
100 | options.verboseLog('Notext check for %s: success', res.name)
101 | }
102 | }
103 | res.response = responseText.substring(0, 30).trim();
104 |
105 | return res;
106 | }
107 |
108 | module.exports = singleRequestExecute;
--------------------------------------------------------------------------------
/sample-input.txt:
--------------------------------------------------------------------------------
1 | 127.0.0.1:2314
2 | 127.0.0.1:3522
--------------------------------------------------------------------------------