mtproto-checker 0.1.2 โ†’ 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +177 -126
  2. package/check.js +113 -19
  3. package/package.json +1 -1
  4. package/urls.txt +0 -4
package/README.md CHANGED
@@ -1,198 +1,249 @@
1
- # MTProto Checker
1
+ # ๐Ÿ” mtproto-checker
2
2
 
3
- Telegram MTProto proxy checker powered by TDLib. It runs a real `testProxy`
4
- handshake through each proxy, so a successful result is closer to "works in
5
- Telegram" than a plain TCP/TLS port check.
3
+ Telegram MTProto proxy health checker powered by **TDLib**. Performs a real `testProxy` handshake through each proxy โ€” the same protocol path tdesktop uses. If it says โœ…, the proxy **actually works** in Telegram.
6
4
 
7
- ## Features
5
+ ## โšก Features
8
6
 
9
- - Parses `tg://proxy` and `https://t.me/proxy` links.
10
- - Loads proxies from direct links, remote lists, local files, or `stdin`.
11
- - De-duplicates by `server:port:secret`.
12
- - Supports hex and base64url secrets, including Fake-TLS SNI extraction.
13
- - Checks proxies concurrently and can re-check only successful proxies across
14
- multiple iterations.
15
- - Works as a CLI, HTTP API server, or CommonJS library.
7
+ - ๐Ÿค Real MTProto handshake (not just a port scan)
8
+ - ๐Ÿ“ก Check from remote URLs, local files, or single proxy links
9
+ - ๐Ÿ”„ Multi-iteration filtering โ€” only survivors advance
10
+ - ๐ŸŒ Built-in HTTP API server with Basic Auth
11
+ - ๐Ÿงน Auto de-duplication by `server:port:secret`
12
+ - ๐Ÿ“Š Sorted output: working first, fastest on top
13
+ - ๐Ÿ” Fake-TLS SNI extraction from `ee`-prefixed secrets
16
14
 
17
- ## Requirements
18
-
19
- - Node.js 18+
20
- - Telegram API credentials: `TG_API_ID` and `TG_API_HASH`
21
-
22
- Get credentials from [my.telegram.org](https://my.telegram.org). No Telegram
23
- login or phone number is required; credentials are only used to initialize TDLib.
24
-
25
- ## Install
15
+ ## ๐Ÿ“ฆ Install
26
16
 
27
17
  ```bash
28
18
  npm install mtproto-checker
29
19
  ```
30
20
 
31
- For local development:
21
+ Or clone locally:
32
22
 
33
23
  ```bash
34
- git clone git@github.com:Tar4s/mtproto-checker.git
24
+ git clone https://github.com/Tar4s/mtproto-checker.git
35
25
  cd mtproto-checker
36
26
  npm install
37
27
  ```
38
28
 
39
- GitHub Packages users can install the scoped package:
29
+ GitHub Packages (scoped):
40
30
 
41
31
  ```bash
42
32
  npm config set @tar4s:registry https://npm.pkg.github.com
43
33
  npm install @tar4s/mtproto-checker
44
34
  ```
45
35
 
46
- Private GitHub Packages require a token with `read:packages`.
36
+ > **Requirements:** Node.js โ‰ฅ 18 ยท `TG_API_ID` + `TG_API_HASH` from [my.telegram.org](https://my.telegram.org)
37
+ > No phone login needed โ€” credentials only initialize TDLib.
47
38
 
48
- ## CLI
39
+ ## ๐Ÿ”‘ Environment Variables
40
+
41
+ | Variable | Required | Description |
42
+ |----------|:--------:|-------------|
43
+ | `TG_API_ID` | โœ… | Telegram API ID |
44
+ | `TG_API_HASH` | โœ… | Telegram API Hash |
45
+ | `CHECK_AUTH_USER` | ๐ŸŒ | HTTP Basic Auth username (server mode) |
46
+ | `CHECK_AUTH_PASSWORD` | ๐ŸŒ | HTTP Basic Auth password (server mode) |
47
+ | `PORT` | โŒ | Server port (default `3080`) |
48
+
49
+ ## ๐Ÿš€ CLI Usage
49
50
 
50
51
  ```bash
51
- TG_API_ID=12345 TG_API_HASH=abcdef npx mtproto-checker --sources urls.txt
52
+ TG_API_ID=12345 TG_API_HASH=abcdef node check.js [sources] [options]
52
53
  ```
53
54
 
54
- Common inputs:
55
+ ### Input Methods
55
56
 
56
57
  ```bash
57
- # One direct proxy link
58
- TG_API_ID=12345 TG_API_HASH=abcdef node check.js \
59
- --proxy 'tg://proxy?server=1.2.3.4&port=443&secret=...'
58
+ # Single proxy link
59
+ node check.js --proxy "tg://proxy?server=1.2.3.4&port=443&secret=ee..."
60
+
61
+ # Remote URLs (positional or --url flag, repeatable)
62
+ node check.js https://example.com/proxies.txt
63
+ node check.js --url URL1 --url URL2
60
64
 
61
- # One or more remote proxy-list URLs
62
- TG_API_ID=12345 TG_API_HASH=abcdef node check.js \
63
- --url https://example.com/proxies.txt \
64
- --url https://example.com/more.txt
65
+ # File with source URLs (one per line, # comments ok)
66
+ node check.js --sources urls.txt
65
67
 
66
- # Source URL file, local proxy file, or stdin
67
- TG_API_ID=12345 TG_API_HASH=abcdef node check.js --sources urls.txt
68
- TG_API_ID=12345 TG_API_HASH=abcdef node check.js proxies.txt
69
- cat proxies.txt | TG_API_ID=12345 TG_API_HASH=abcdef node check.js
68
+ # Local proxy file
69
+ node check.js ./my-proxies.txt
70
+
71
+ # Stdin
72
+ cat proxies.txt | node check.js
70
73
  ```
71
74
 
72
- Options:
75
+ ### โš™๏ธ Options
76
+
77
+ | Flag | Default | Description |
78
+ |------|:-------:|-------------|
79
+ | `--proxy <link>` | โ€” | Check one proxy link directly |
80
+ | `--url <url>` | โ€” | Add a source URL (repeatable) |
81
+ | `--sources <file>` | โ€” | File of source URLs |
82
+ | `--dc <1-5>` | `2` | Data center for `testProxy` |
83
+ | `--timeout <sec>` | `10` | Per-proxy timeout |
84
+ | `--concurrency <n>` | `30` | Parallel checks (lower = more accurate ms) |
85
+ | `--iterations <n>` | `1` | Re-check rounds; only working proxies advance |
86
+ | `--out <prefix>` | `result` | Output prefix โ†’ `.json` + `.txt` |
73
87
 
74
- | Option | Default | Description |
75
- | --- | ---: | --- |
76
- | `--proxy <link>` | none | Check one `tg://proxy` or `https://t.me/proxy` link directly. |
77
- | `--url <url>` | none | Add a remote proxy-list URL. Repeatable. |
78
- | `--sources <file>` | none | Read remote source URLs from a file. |
79
- | `--dc <1-5>` | `2` | Telegram data center used for `testProxy`. |
80
- | `--timeout <sec>` | `10` | Per-proxy TDLib timeout. |
81
- | `--concurrency <n>` | `30` | Parallel proxy checks. |
82
- | `--iterations <n>` | `1` | Re-check only successful proxies for `n` rounds. |
83
- | `--out <prefix>` | `result` | Writes `<prefix>.json` and `<prefix>.txt`. |
88
+ ### ๐Ÿ“„ Output Files
84
89
 
85
- Input files may contain blank lines and `#` comments. Only MTProto proxy links
86
- are checked; `tg://socks` links are ignored.
90
+ | File | Content |
91
+ |------|---------|
92
+ | `result.json` | Full report: server, port, SNI, latency, error, link |
93
+ | `result.txt` | Working proxy links only, fastest first |
87
94
 
88
- ## HTTP API
95
+ ## ๐ŸŒ HTTP API Server
89
96
 
90
- Running `node check.js` without arguments starts the server on `PORT` or `3080`.
91
- Basic auth is required.
97
+ Start with **no arguments**:
92
98
 
93
99
  ```bash
94
- TG_API_ID=12345 \
95
- TG_API_HASH=abcdef \
96
- CHECK_AUTH_USER=admin \
97
- CHECK_AUTH_PASSWORD=secret \
100
+ TG_API_ID=12345 TG_API_HASH=abcdef \
101
+ CHECK_AUTH_USER=admin CHECK_AUTH_PASSWORD=secret \
98
102
  node check.js
99
103
  ```
100
104
 
101
- Endpoint:
102
-
103
- ```http
104
- POST /check
105
- Content-Type: application/json
106
- Authorization: Basic ...
107
-
108
- {
109
- "url": "https://example.com/proxies.txt",
110
- "iterations": 3,
111
- "concurrency": 10
112
- }
105
+ ```
106
+ [mtproto-checker] โšก HTTP server listening on http://localhost:3080
107
+ [mtproto-checker] POST /check (Basic auth: admin:***)
113
108
  ```
114
109
 
115
- `url` accepts either a remote `http(s)` proxy list or one direct `tg://proxy` /
116
- `https://t.me/proxy` link. `iterations` defaults to `1`; `concurrency` defaults
117
- to `30`.
118
-
119
- Example:
110
+ ### `POST /check`
120
111
 
121
112
  ```bash
122
- curl -u admin:secret \
123
- -H 'content-type: application/json' \
124
- -d '{"url":"tg://proxy?server=1.2.3.4&port=443&secret=...","iterations":3,"concurrency":10}' \
125
- http://127.0.0.1:3080/check
113
+ curl -u admin:secret http://localhost:3080/check \
114
+ -H "Content-Type: application/json" \
115
+ -d '{"url": "https://example.com/proxies.txt", "iterations": 2, "concurrency": 20}'
126
116
  ```
127
117
 
128
- Response shape:
118
+ **Request body:**
119
+
120
+ | Field | Type | Default | Description |
121
+ |-------|------|:-------:|-------------|
122
+ | `url` | string | โ€” | Proxy list URL or single `tg://proxy` link |
123
+ | `iterations` | int | `1` | Check rounds |
124
+ | `concurrency` | int | `30` | Parallel checks |
125
+
126
+ **Response:**
129
127
 
130
128
  ```json
131
129
  {
132
130
  "url": "https://example.com/proxies.txt",
133
- "iterations": 3,
134
- "concurrency": 10,
135
- "count": 1,
136
- "working": 1,
131
+ "iterations": 2,
132
+ "concurrency": 20,
133
+ "count": 150,
134
+ "working": 42,
137
135
  "results": [
138
- {
139
- "server": "1.2.3.4",
140
- "port": 443,
141
- "sni": "example.com",
142
- "ok": true,
143
- "ms": 841,
144
- "error": null,
145
- "link": "tg://proxy?server=1.2.3.4&port=443&secret=..."
146
- }
136
+ { "server": "1.2.3.4", "port": 443, "sni": "example.com", "ok": true, "ms": 312, "error": null, "link": "tg://proxy?..." }
147
137
  ]
148
138
  }
149
139
  ```
150
140
 
151
- ## Library Usage
141
+ **Error codes:** `400` bad request ยท `401` unauthorized ยท `404` wrong endpoint ยท `405` wrong method ยท `502` upstream fetch failed
142
+
143
+ ## ๐Ÿ“š Library API
152
144
 
153
145
  ```js
154
- const { checkRequestUrl, checkProxiesFromUrls } = require('mtproto-checker')
146
+ const { checkProxyLink, checkProxiesFromURIs, startServer } = require('mtproto-checker')
147
+ ```
155
148
 
156
- const opts = {
157
- apiId: Number(process.env.TG_API_ID),
158
- apiHash: process.env.TG_API_HASH,
159
- concurrency: 30,
160
- iterations: 2
161
- }
149
+ ### `checkProxyLink(link, opts)` โ†’ `Promise<Array>`
162
150
 
163
- const direct = await checkRequestUrl('tg://proxy?server=1.2.3.4&port=443&secret=...', opts)
164
- const fromLists = await checkProxiesFromUrls(['https://example.com/proxies.txt'], opts)
151
+ Check a single `tg://proxy` or `https://t.me/proxy` link.
165
152
 
166
- console.log(direct, fromLists)
153
+ ```js
154
+ const results = await checkProxyLink(
155
+ 'tg://proxy?server=1.2.3.4&port=443&secret=ee...',
156
+ { apiId: 12345, apiHash: 'abcdef' }
157
+ )
167
158
  ```
168
159
 
169
- Main exports:
160
+ ```
161
+ [mtproto-checker] Checking 1.2.3.4:443 [example.com]...
162
+ [mtproto-checker] โœ“ 312ms
163
+ ```
164
+
165
+ ### `checkProxiesFromURIs(uris, opts)` โ†’ `Promise<Array>`
166
+
167
+ Check proxies from remote URLs, local files, or both. Auto-detects type per entry.
168
+
169
+ ```js
170
+ // Remote
171
+ const results = await checkProxiesFromURIs(
172
+ 'https://example.com/proxies.txt',
173
+ { apiId: 12345, apiHash: 'abcdef' }
174
+ )
175
+
176
+ // Local
177
+ const results = await checkProxiesFromURIs('./proxies.txt', opts)
178
+
179
+ // Mix
180
+ const results = await checkProxiesFromURIs([
181
+ 'https://example.com/list1.txt',
182
+ './local-list.txt',
183
+ 'https://example.com/list2.txt'
184
+ ], { apiId: 12345, apiHash: 'abcdef', iterations: 2, concurrency: 20 })
185
+ ```
186
+
187
+ ```
188
+ [mtproto-checker] Loading 3 source(s)...
189
+ โ†“ https://example.com/list1.txt
190
+ โ—ˆ ./local-list.txt
191
+ โ†“ https://example.com/list2.txt
192
+ [mtproto-checker] Checking 150 proxies (dc=2, timeout=10s, concurrency=30, iterations=2)...
193
+
194
+ [ 1/150] โœ“ 312ms 1.2.3.4:443 [example.com]
195
+ [ 2/150] โœ— Timeout 5.6.7.8:443
196
+ ...
170
197
 
171
- - `checkRequestUrl(url, opts)`
172
- - `checkProxiesFromUrls(urls, opts)`
173
- - `loadProxiesFromUrls(urls)`
174
- - `checkProxies(proxies, opts)`
175
- - `mergeProxies(texts)`
176
- - `parseLink(line)`
177
- - `normalizeSecret(secret)`
178
- - `faketlsSni(hexSecret)`
198
+ [mtproto-checker] Done: 42/150 working.
199
+ ```
200
+
201
+ ### `startServer(opts)` โ†’ `Promise<http.Server>`
202
+
203
+ Start the HTTP API server programmatically.
204
+
205
+ ```js
206
+ const server = await startServer({
207
+ apiId: 12345,
208
+ apiHash: 'abcdef',
209
+ user: 'admin',
210
+ password: 'secret',
211
+ port: 8080
212
+ })
213
+ ```
214
+
215
+ All fields are optional โ€” falls back to env vars if omitted.
216
+
217
+ ### `opts` Reference
179
218
 
180
- ## Output
219
+ | Key | Type | Default | Description |
220
+ |-----|------|:-------:|-------------|
221
+ | `apiId` | number | โ€” | Telegram API ID |
222
+ | `apiHash` | string | โ€” | Telegram API Hash |
223
+ | `dc` | number | `2` | Data center (1โ€“5) |
224
+ | `timeout` | number | `10` | Timeout in seconds |
225
+ | `concurrency` | number | `30` | Parallel checks |
226
+ | `iterations` | number | `1` | Check rounds |
227
+ | `onProgress` | function | โ€” | `(proxy, res, index, total) => void` |
181
228
 
182
- CLI runs write:
229
+ ## ๐Ÿงฉ Proxy Link Formats
183
230
 
184
- - `result.json` or `<out>.json`: full report for the final completed round.
185
- - `result.txt` or `<out>.txt`: working proxy links, fastest first.
231
+ ```
232
+ tg://proxy?server=1.2.3.4&port=443&secret=ee...
233
+ https://t.me/proxy?server=1.2.3.4&port=443&secret=ee...
234
+ ```
186
235
 
187
- Use `--out fresh` to write `fresh.json` and `fresh.txt`.
236
+ Secrets: hex (`ee...`, `dd...`), plain hex, or base64url โ€” auto-detected. `tg://socks` links are ignored.
188
237
 
189
- ## Troubleshooting
238
+ ## ๐Ÿ›  Troubleshooting
190
239
 
191
- - `Set TG_API_ID and TG_API_HASH`: export both credentials or prefix the command.
192
- - Noisy latency: reduce `--concurrency`.
193
- - Need only stable proxies: increase `--iterations`.
194
- - Temporary TDLib files are created in `.proxy-checker-td/` and removed after the run.
240
+ | Problem | Fix |
241
+ |---------|-----|
242
+ | `Set TG_API_ID and TG_API_HASH` | Export both env vars |
243
+ | Noisy latency | Reduce `--concurrency` |
244
+ | Need stable proxies only | Increase `--iterations` |
245
+ | TDLib leftover files | `.proxy-checker-td/` is auto-cleaned after each run |
195
246
 
196
- ## License
247
+ ## ๐Ÿ“œ License
197
248
 
198
- No license file is currently included.
249
+ ISC
package/check.js CHANGED
@@ -415,6 +415,92 @@ async function checkSingleUrl(url, opts) {
415
415
  return checker(proxies, opts)
416
416
  }
417
417
 
418
+ /**
419
+ * Load proxies from a local file path.
420
+ * @param {string} filePath - path to a text file with proxy links (one per line)
421
+ * @returns {Array} de-duplicated parsed proxies
422
+ */
423
+ function loadProxiesFromFile(filePath) {
424
+ const text = fs.readFileSync(filePath, 'utf8')
425
+ return mergeProxies([text])
426
+ }
427
+
428
+ /**
429
+ * Check proxies from URIs โ€” supports both remote URLs (http/https) and local
430
+ * file paths. Detects type automatically per entry.
431
+ * @param {string|string[]} uris - URL(s) or file path(s) with proxy links
432
+ * @param {{apiId: number, apiHash: string, dc?: number, timeout?: number, concurrency?: number, iterations?: number, onProgress?: Function}} opts
433
+ * @returns {Promise<Array<{proxy: object, ok: boolean, ms: number, error: string|null}>>}
434
+ */
435
+ async function checkProxiesFromURIs(uris, opts) {
436
+ const list = Array.isArray(uris) ? uris : [uris]
437
+ console.error(`[mtproto-checker] Loading ${list.length} source(s)...`)
438
+ const directProxies = []
439
+ const texts = await Promise.all(list.map(uri => {
440
+ const parsed = parseLink(uri)
441
+ if (parsed) {
442
+ console.error(` โšก ${parsed.server}:${parsed.port}`)
443
+ directProxies.push(parsed)
444
+ return Promise.resolve('')
445
+ }
446
+ if (/^https?:\/\//i.test(uri)) {
447
+ console.error(` โ†“ ${uri}`)
448
+ return fetchText(uri).catch(err => { console.error(` โœ— Skipping ${uri}: ${err.message}`); return '' })
449
+ }
450
+ console.error(` โ—ˆ ${uri}`)
451
+ return Promise.resolve(fs.readFileSync(uri, 'utf8'))
452
+ }))
453
+ const fromTexts = mergeProxies(texts)
454
+ const seen = new Set(fromTexts.map(p => `${p.server}:${p.port}:${p.secret}`))
455
+ const proxies = [...fromTexts]
456
+ for (const p of directProxies) {
457
+ const key = `${p.server}:${p.port}:${p.secret}`
458
+ if (seen.has(key)) continue
459
+ seen.add(key)
460
+ proxies.push(p)
461
+ }
462
+ if (proxies.length === 0) {
463
+ console.error('[mtproto-checker] No valid proxy links found.')
464
+ return []
465
+ }
466
+ const iterations = opts.iterations ?? 1
467
+ console.error(`[mtproto-checker] Checking ${proxies.length} proxies (dc=${opts.dc ?? 2}, timeout=${opts.timeout ?? 10}s, concurrency=${opts.concurrency ?? 30}, iterations=${iterations})...\n`)
468
+ const results = await runIterativeChecks(proxies, iterations, (batch, iteration) => {
469
+ if (iterations > 1) console.error(`[mtproto-checker] Iteration ${iteration}/${iterations}: ${batch.length} proxies\n`)
470
+ return checkProxies(batch, {
471
+ ...opts,
472
+ onProgress: (proxy, res, index, total) => {
473
+ const tag = res.ok ? `โœ“ ${String(res.ms).padStart(5)}ms` : `โœ— ${res.error}`
474
+ const sni = proxy.sni ? ` [${proxy.sni}]` : ''
475
+ console.error(` [${String(index + 1).padStart(3)}/${total}] ${tag} ${proxy.server}:${proxy.port}${sni}`)
476
+ if (opts.onProgress) opts.onProgress(proxy, res, index, total)
477
+ }
478
+ })
479
+ })
480
+ const working = results.filter(c => c.ok).length
481
+ console.error(`\n[mtproto-checker] Done: ${working}/${proxies.length} working.`)
482
+ return results
483
+ }
484
+
485
+ /**
486
+ * Check a single tg://proxy or t.me/proxy link via real MTProto handshake.
487
+ * @param {string} link - proxy link (tg://proxy?... or https://t.me/proxy?...)
488
+ * @param {{apiId: number, apiHash: string, dc?: number, timeout?: number, iterations?: number, onProgress?: Function}} opts
489
+ * @returns {Promise<Array<{proxy: object, ok: boolean, ms: number, error: string|null}>>}
490
+ * @throws if the link is not a valid MTProto proxy link
491
+ */
492
+ async function checkProxyLink(link, opts) {
493
+ const proxy = parseLink(link)
494
+ if (!proxy) throw new Error('Invalid proxy link. Expected tg://proxy?... or https://t.me/proxy?...')
495
+ const sni = proxy.sni ? ` [${proxy.sni}]` : ''
496
+ console.error(`[mtproto-checker] Checking ${proxy.server}:${proxy.port}${sni}...`)
497
+ const results = await runIterativeChecks([proxy], opts.iterations ?? 1, batch => checkProxies(batch, opts))
498
+ const r = results[0]
499
+ if (r)
500
+ console.error(`[mtproto-checker] ${r.ok ? `โœ“ ${r.ms}ms` : `โœ— ${r.error}`}`)
501
+ return results
502
+ }
503
+
418
504
  async function loadSingleUrlProxies(url, opts = {}) {
419
505
  const directProxy = parseLink(url)
420
506
  if (directProxy) return [directProxy]
@@ -574,9 +660,10 @@ function createServer({ auth, checkUrl, logger = console.error }) {
574
660
  }
575
661
 
576
662
  const body = await readJsonBody(req)
577
- if (!body || typeof body.url !== 'string' || body.url.trim() === '') {
663
+ const uris = body.url || body.urls || body.uri || body.uris
664
+ if (!uris || (typeof uris === 'string' && uris.trim() === '') || (Array.isArray(uris) && uris.length === 0)) {
578
665
  statusCode = 400
579
- jsonResponse(res, statusCode, { error: 'Request body must include url' })
666
+ jsonResponse(res, statusCode, { error: 'Request body must include url (string or array)' })
580
667
  return
581
668
  }
582
669
  const iterations = body.iterations === undefined ? 1 : body.iterations
@@ -592,10 +679,10 @@ function createServer({ auth, checkUrl, logger = console.error }) {
592
679
  return
593
680
  }
594
681
 
595
- const url = body.url.trim()
682
+ const input = Array.isArray(uris) ? uris.map(u => u.trim()) : [uris.trim()]
596
683
  let results
597
684
  try {
598
- results = await checkUrl(url, { iterations, concurrency })
685
+ results = await checkUrl(input, { iterations, concurrency })
599
686
  } catch (err) {
600
687
  statusCode = 502
601
688
  jsonResponse(res, statusCode, {
@@ -604,15 +691,14 @@ function createServer({ auth, checkUrl, logger = console.error }) {
604
691
  })
605
692
  return
606
693
  }
607
- const report = toReport(results)
608
694
  statusCode = 200
609
695
  jsonResponse(res, statusCode, {
610
- url,
696
+ uris: input,
611
697
  iterations,
612
698
  concurrency,
613
- count: report.length,
614
- working: report.filter(item => item.ok).length,
615
- results: report
699
+ count: results.length,
700
+ working: results.filter(item => item.ok).length,
701
+ results
616
702
  })
617
703
  } catch (err) {
618
704
  statusCode = err.statusCode || 500
@@ -629,20 +715,26 @@ function shouldStartServer(argv) {
629
715
  return argv.length === 0
630
716
  }
631
717
 
632
- async function startServer(env = process.env) {
633
- const apiId = parseInt(env.TG_API_ID, 10)
634
- const apiHash = env.TG_API_HASH
635
- const user = env.CHECK_AUTH_USER
636
- const password = env.CHECK_AUTH_PASSWORD
637
- const port = parseInt(env.PORT || '3080', 10)
718
+ /**
719
+ * Start the HTTP API server for proxy checking.
720
+ * @param {{apiId?: number, apiHash?: string, user?: string, password?: string, port?: number}} opts
721
+ * All fields fall back to environment variables if omitted.
722
+ * @returns {Promise<http.Server>} the listening server instance
723
+ */
724
+ async function startServer(opts = {}) {
725
+ const apiId = opts.apiId ?? parseInt(process.env.TG_API_ID, 10)
726
+ const apiHash = opts.apiHash ?? process.env.TG_API_HASH
727
+ const user = opts.user ?? process.env.CHECK_AUTH_USER
728
+ const password = opts.password ?? process.env.CHECK_AUTH_PASSWORD
729
+ const port = opts.port ?? parseInt(process.env.PORT || '3080', 10)
638
730
 
639
731
  if (!apiId || !apiHash) throw new Error('Set TG_API_ID and TG_API_HASH (get them at https://my.telegram.org).')
640
732
  if (!user || !password) throw new Error('Set CHECK_AUTH_USER and CHECK_AUTH_PASSWORD for HTTP Basic auth.')
641
- if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error('PORT must be a valid TCP port.')
733
+ if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error('port must be a valid TCP port (1-65535).')
642
734
 
643
735
  const server = createServer({
644
736
  auth: { user, password },
645
- checkUrl: async (url, requestOpts) => checkRequestUrl(url, {
737
+ checkUrl: async (url, requestOpts) => checkProxiesFromURIs(url, {
646
738
  apiId,
647
739
  apiHash,
648
740
  iterations: requestOpts.iterations,
@@ -658,7 +750,8 @@ async function startServer(env = process.env) {
658
750
  })
659
751
  })
660
752
 
661
- console.error(`MTProto checker HTTP server listening on :${port}`)
753
+ console.error(`[mtproto-checker] โšก HTTP server listening on http://localhost:${port}`)
754
+ console.error(`[mtproto-checker] POST /check (Basic auth: ${user}:***)`)
662
755
  return server
663
756
  }
664
757
 
@@ -725,7 +818,8 @@ async function main() {
725
818
  process.exit(0)
726
819
  }
727
820
 
728
- module.exports = { checkRequestUrl, checkSingleUrl, configureTdlibOnce, createServer, parseArgs, resolveInputProxies, checkProxiesFromUrls, loadProxiesFromUrls, checkProxies, runIterativeChecks, mergeProxies, parseLink, normalizeSecret, faketlsSni, shouldStartServer, startServer }
821
+ module.exports = { checkProxyLink, checkProxiesFromURIs, startServer }
822
+ module.exports._internals = { checkRequestUrl, checkSingleUrl, configureTdlibOnce, createServer, parseArgs, resolveInputProxies, runIterativeChecks, shouldStartServer, parseLink, normalizeSecret, faketlsSni, mergeProxies, loadProxiesFromFile }
729
823
 
730
824
  if (require.main === module) (shouldStartServer(process.argv.slice(2)) ? startServer() : main()).catch(err => {
731
825
  console.error(err)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mtproto-checker",
3
- "version": "0.1.2",
3
+ "version": "0.3.0",
4
4
  "description": "Check Telegram MTProto proxies via a real TDLib handshake (testProxy), like tdesktop does",
5
5
  "main": "check.js",
6
6
  "exports": {
package/urls.txt DELETED
@@ -1,4 +0,0 @@
1
- https://raw.githubusercontent.com/SoliSpirit/mtproto/refs/heads/master/all_proxies.txt
2
- https://raw.githubusercontent.com/kort0881/telegram-proxy-collector/refs/heads/main/proxy_all.txt
3
- https://raw.githubusercontent.com/Surfboardv2ray/TGProto/refs/heads/main/proxies.txt
4
- https://raw.githubusercontent.com/Therealwh/MTPproxyLIST/refs/heads/main/verified/proxy_all_tme_verified.txt