mtproto-checker 0.2.0 โ†’ 0.3.1

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 (3) hide show
  1. package/README.md +75 -34
  2. package/check.js +29 -14
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -5,7 +5,7 @@ Telegram MTProto proxy health checker powered by **TDLib**. Performs a real `tes
5
5
  ## โšก Features
6
6
 
7
7
  - ๐Ÿค Real MTProto handshake (not just a port scan)
8
- - ๐Ÿ“ก Check from remote URLs, local files, or single proxy links
8
+ - ๐Ÿ“ก Check from remote URLs, local files, direct proxy links, or any mix
9
9
  - ๐Ÿ”„ Multi-iteration filtering โ€” only survivors advance
10
10
  - ๐ŸŒ Built-in HTTP API server with Basic Auth
11
11
  - ๐Ÿงน Auto de-duplication by `server:port:secret`
@@ -15,10 +15,14 @@ Telegram MTProto proxy health checker powered by **TDLib**. Performs a real `tes
15
15
  ## ๐Ÿ“ฆ Install
16
16
 
17
17
  ```bash
18
+ # Global โ€” gives you the `mtproto-checker` command
19
+ npm install -g mtproto-checker
20
+
21
+ # Local dependency
18
22
  npm install mtproto-checker
19
23
  ```
20
24
 
21
- Or clone locally:
25
+ Or clone:
22
26
 
23
27
  ```bash
24
28
  git clone https://github.com/Tar4s/mtproto-checker.git
@@ -44,32 +48,46 @@ npm install @tar4s/mtproto-checker
44
48
  | `TG_API_HASH` | โœ… | Telegram API Hash |
45
49
  | `CHECK_AUTH_USER` | ๐ŸŒ | HTTP Basic Auth username (server mode) |
46
50
  | `CHECK_AUTH_PASSWORD` | ๐ŸŒ | HTTP Basic Auth password (server mode) |
47
- | `PORT` | โŒ | Server port (default `3080`) |
51
+ | `PORT` | โŒ | Server port (default `8080`) |
52
+
53
+ ## ๐Ÿš€ Quick Start (Global)
54
+
55
+ After `npm i -g mtproto-checker`:
56
+
57
+ ```bash
58
+ # Start HTTP server (no arguments)
59
+ TG_API_ID=12345 TG_API_HASH=abcdef \
60
+ CHECK_AUTH_USER=admin CHECK_AUTH_PASSWORD=secret \
61
+ check-proxies
62
+
63
+ # CLI mode (with arguments)
64
+ TG_API_ID=12345 TG_API_HASH=abcdef check-proxies --sources urls.txt
65
+ ```
48
66
 
49
- ## ๐Ÿš€ CLI Usage
67
+ ## ๐Ÿ–ฅ CLI Usage
50
68
 
51
69
  ```bash
52
- TG_API_ID=12345 TG_API_HASH=abcdef node check.js [sources] [options]
70
+ TG_API_ID=12345 TG_API_HASH=abcdef check-proxies [sources] [options]
53
71
  ```
54
72
 
55
73
  ### Input Methods
56
74
 
57
75
  ```bash
58
76
  # Single proxy link
59
- node check.js --proxy "tg://proxy?server=1.2.3.4&port=443&secret=ee..."
77
+ check-proxies --proxy "tg://proxy?server=1.2.3.4&port=443&secret=ee..."
60
78
 
61
79
  # Remote URLs (positional or --url flag, repeatable)
62
- node check.js https://example.com/proxies.txt
63
- node check.js --url URL1 --url URL2
80
+ check-proxies https://example.com/proxies.txt
81
+ check-proxies --url URL1 --url URL2
64
82
 
65
83
  # File with source URLs (one per line, # comments ok)
66
- node check.js --sources urls.txt
84
+ check-proxies --sources urls.txt
67
85
 
68
86
  # Local proxy file
69
- node check.js ./my-proxies.txt
87
+ check-proxies ./my-proxies.txt
70
88
 
71
89
  # Stdin
72
- cat proxies.txt | node check.js
90
+ cat proxies.txt | check-proxies
73
91
  ```
74
92
 
75
93
  ### โš™๏ธ Options
@@ -94,23 +112,29 @@ cat proxies.txt | node check.js
94
112
 
95
113
  ## ๐ŸŒ HTTP API Server
96
114
 
97
- Start with **no arguments**:
115
+ Start with **no arguments** โ€” works both globally and locally:
98
116
 
99
117
  ```bash
118
+ # Global
119
+ TG_API_ID=12345 TG_API_HASH=abcdef \
120
+ CHECK_AUTH_USER=admin CHECK_AUTH_PASSWORD=secret \
121
+ check-proxies
122
+
123
+ # Local
100
124
  TG_API_ID=12345 TG_API_HASH=abcdef \
101
125
  CHECK_AUTH_USER=admin CHECK_AUTH_PASSWORD=secret \
102
126
  node check.js
103
127
  ```
104
128
 
105
129
  ```
106
- [mtproto-checker] โšก HTTP server listening on http://localhost:3080
130
+ [mtproto-checker] โšก HTTP server listening on http://localhost:8080
107
131
  [mtproto-checker] POST /check (Basic auth: admin:***)
108
132
  ```
109
133
 
110
134
  ### `POST /check`
111
135
 
112
136
  ```bash
113
- curl -u admin:secret http://localhost:3080/check \
137
+ curl -u admin:secret http://localhost:8080/check \
114
138
  -H "Content-Type: application/json" \
115
139
  -d '{"url": "https://example.com/proxies.txt", "iterations": 2, "concurrency": 20}'
116
140
  ```
@@ -119,21 +143,39 @@ curl -u admin:secret http://localhost:3080/check \
119
143
 
120
144
  | Field | Type | Default | Description |
121
145
  |-------|------|:-------:|-------------|
122
- | `url` | string | โ€” | Proxy list URL or single `tg://proxy` link |
146
+ | `url` / `urls` / `uri` / `uris` | string \| string[] | โ€” | Proxy link(s), list URL(s), or any mix |
123
147
  | `iterations` | int | `1` | Check rounds |
124
148
  | `concurrency` | int | `30` | Parallel checks |
125
149
 
150
+ All input formats work:
151
+
152
+ ```json
153
+ // Single proxy link
154
+ { "url": "tg://proxy?server=1.2.3.4&port=443&secret=ee..." }
155
+
156
+ // Single list URL
157
+ { "url": "https://example.com/proxies.txt" }
158
+
159
+ // Array โ€” mix of direct links and list URLs
160
+ { "urls": [
161
+ "tg://proxy?server=1.2.3.4&port=443&secret=ee...",
162
+ "https://t.me/proxy?server=5.6.7.8&port=443&secret=dd...",
163
+ "https://example.com/list.txt"
164
+ ]
165
+ }
166
+ ```
167
+
126
168
  **Response:**
127
169
 
128
170
  ```json
129
171
  {
130
- "url": "https://example.com/proxies.txt",
172
+ "uris": ["https://example.com/proxies.txt"],
131
173
  "iterations": 2,
132
174
  "concurrency": 20,
133
175
  "count": 150,
134
176
  "working": 42,
135
177
  "results": [
136
- { "server": "1.2.3.4", "port": 443, "sni": "example.com", "ok": true, "ms": 312, "error": null, "link": "tg://proxy?..." }
178
+ { "proxy": { "raw": "tg://proxy?...", "server": "1.2.3.4", "port": 443, "secret": "ee...", "sni": "example.com" }, "ok": true, "ms": 312, "error": null }
137
179
  ]
138
180
  }
139
181
  ```
@@ -164,32 +206,31 @@ const results = await checkProxyLink(
164
206
 
165
207
  ### `checkProxiesFromURIs(uris, opts)` โ†’ `Promise<Array>`
166
208
 
167
- Check proxies from remote URLs, local files, or both. Auto-detects type per entry.
209
+ Check proxies from remote URLs, local files, direct proxy links, or any mix. Auto-detects type per entry, de-duplicates automatically.
168
210
 
169
211
  ```js
170
- // Remote
171
- const results = await checkProxiesFromURIs(
172
- 'https://example.com/proxies.txt',
173
- { apiId: 12345, apiHash: 'abcdef' }
174
- )
212
+ // Single source
213
+ await checkProxiesFromURIs('https://example.com/proxies.txt', opts)
175
214
 
176
- // Local
177
- const results = await checkProxiesFromURIs('./proxies.txt', opts)
215
+ // Direct proxy link
216
+ await checkProxiesFromURIs('tg://proxy?server=1.2.3.4&port=443&secret=ee...', opts)
178
217
 
179
- // Mix
180
- const results = await checkProxiesFromURIs([
181
- 'https://example.com/list1.txt',
182
- './local-list.txt',
183
- 'https://example.com/list2.txt'
218
+ // Mix of everything
219
+ await checkProxiesFromURIs([
220
+ 'tg://proxy?server=1.2.3.4&port=443&secret=ee...',
221
+ 'https://t.me/proxy?server=5.6.7.8&port=443&secret=dd...',
222
+ 'https://example.com/list.txt',
223
+ './local-list.txt'
184
224
  ], { apiId: 12345, apiHash: 'abcdef', iterations: 2, concurrency: 20 })
185
225
  ```
186
226
 
187
227
  ```
188
- [mtproto-checker] Loading 3 source(s)...
189
- โ†“ https://example.com/list1.txt
228
+ [mtproto-checker] Loading 4 source(s)...
229
+ โšก 1.2.3.4:443
230
+ โšก 5.6.7.8:443
231
+ โ†“ https://example.com/list.txt
190
232
  โ—ˆ ./local-list.txt
191
- โ†“ https://example.com/list2.txt
192
- [mtproto-checker] Checking 150 proxies (dc=2, timeout=10s, concurrency=30, iterations=2)...
233
+ [mtproto-checker] Checking 150 proxies (dc=2, timeout=10s, concurrency=20, iterations=2)...
193
234
 
194
235
  [ 1/150] โœ“ 312ms 1.2.3.4:443 [example.com]
195
236
  [ 2/150] โœ— Timeout 5.6.7.8:443
package/check.js CHANGED
@@ -19,7 +19,7 @@
19
19
  *
20
20
  * CLI usage:
21
21
  * TG_API_ID=12345 TG_API_HASH=abcdef CHECK_AUTH_USER=admin CHECK_AUTH_PASSWORD=secret node check.js
22
- * # starts the HTTP API server on PORT (default 3080)
22
+ * # starts the HTTP API server on PORT (default 8080)
23
23
  * TG_API_ID=12345 TG_API_HASH=abcdef... node check.js [sources] [options]
24
24
  * # sources: any positional http(s) URL, a local file path, or stdin
25
25
  * node check.js https://raw.githubusercontent.com/u/r/main/list.txt
@@ -435,7 +435,14 @@ function loadProxiesFromFile(filePath) {
435
435
  async function checkProxiesFromURIs(uris, opts) {
436
436
  const list = Array.isArray(uris) ? uris : [uris]
437
437
  console.error(`[mtproto-checker] Loading ${list.length} source(s)...`)
438
+ const directProxies = []
438
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
+ }
439
446
  if (/^https?:\/\//i.test(uri)) {
440
447
  console.error(` โ†“ ${uri}`)
441
448
  return fetchText(uri).catch(err => { console.error(` โœ— Skipping ${uri}: ${err.message}`); return '' })
@@ -443,7 +450,15 @@ async function checkProxiesFromURIs(uris, opts) {
443
450
  console.error(` โ—ˆ ${uri}`)
444
451
  return Promise.resolve(fs.readFileSync(uri, 'utf8'))
445
452
  }))
446
- const proxies = mergeProxies(texts)
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
+ }
447
462
  if (proxies.length === 0) {
448
463
  console.error('[mtproto-checker] No valid proxy links found.')
449
464
  return []
@@ -645,9 +660,10 @@ function createServer({ auth, checkUrl, logger = console.error }) {
645
660
  }
646
661
 
647
662
  const body = await readJsonBody(req)
648
- 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)) {
649
665
  statusCode = 400
650
- jsonResponse(res, statusCode, { error: 'Request body must include url' })
666
+ jsonResponse(res, statusCode, { error: 'Request body must include url (string or array)' })
651
667
  return
652
668
  }
653
669
  const iterations = body.iterations === undefined ? 1 : body.iterations
@@ -663,10 +679,10 @@ function createServer({ auth, checkUrl, logger = console.error }) {
663
679
  return
664
680
  }
665
681
 
666
- const url = body.url.trim()
682
+ const input = Array.isArray(uris) ? uris.map(u => u.trim()) : [uris.trim()]
667
683
  let results
668
684
  try {
669
- results = await checkUrl(url, { iterations, concurrency })
685
+ results = await checkUrl(input, { iterations, concurrency })
670
686
  } catch (err) {
671
687
  statusCode = 502
672
688
  jsonResponse(res, statusCode, {
@@ -675,15 +691,14 @@ function createServer({ auth, checkUrl, logger = console.error }) {
675
691
  })
676
692
  return
677
693
  }
678
- const report = toReport(results)
679
694
  statusCode = 200
680
695
  jsonResponse(res, statusCode, {
681
- url,
696
+ uris: input,
682
697
  iterations,
683
698
  concurrency,
684
- count: report.length,
685
- working: report.filter(item => item.ok).length,
686
- results: report
699
+ count: results.length,
700
+ working: results.filter(item => item.ok).length,
701
+ results
687
702
  })
688
703
  } catch (err) {
689
704
  statusCode = err.statusCode || 500
@@ -711,7 +726,7 @@ async function startServer(opts = {}) {
711
726
  const apiHash = opts.apiHash ?? process.env.TG_API_HASH
712
727
  const user = opts.user ?? process.env.CHECK_AUTH_USER
713
728
  const password = opts.password ?? process.env.CHECK_AUTH_PASSWORD
714
- const port = opts.port ?? parseInt(process.env.PORT || '3080', 10)
729
+ const port = opts.port ?? parseInt(process.env.PORT || '8080', 10)
715
730
 
716
731
  if (!apiId || !apiHash) throw new Error('Set TG_API_ID and TG_API_HASH (get them at https://my.telegram.org).')
717
732
  if (!user || !password) throw new Error('Set CHECK_AUTH_USER and CHECK_AUTH_PASSWORD for HTTP Basic auth.')
@@ -719,7 +734,7 @@ async function startServer(opts = {}) {
719
734
 
720
735
  const server = createServer({
721
736
  auth: { user, password },
722
- checkUrl: async (url, requestOpts) => checkRequestUrl(url, {
737
+ checkUrl: async (url, requestOpts) => checkProxiesFromURIs(url, {
723
738
  apiId,
724
739
  apiHash,
725
740
  iterations: requestOpts.iterations,
@@ -804,7 +819,7 @@ async function main() {
804
819
  }
805
820
 
806
821
  module.exports = { checkProxyLink, checkProxiesFromURIs, startServer }
807
- module.exports._internals = { checkRequestUrl, checkSingleUrl, configureTdlibOnce, createServer, parseArgs, resolveInputProxies, runIterativeChecks, shouldStartServer }
822
+ module.exports._internals = { checkRequestUrl, checkSingleUrl, configureTdlibOnce, createServer, parseArgs, resolveInputProxies, runIterativeChecks, shouldStartServer, parseLink, normalizeSecret, faketlsSni, mergeProxies, loadProxiesFromFile }
808
823
 
809
824
  if (require.main === module) (shouldStartServer(process.argv.slice(2)) ? startServer() : main()).catch(err => {
810
825
  console.error(err)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mtproto-checker",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Check Telegram MTProto proxies via a real TDLib handshake (testProxy), like tdesktop does",
5
5
  "main": "check.js",
6
6
  "exports": {
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "homepage": "https://github.com/Tar4s/mtproto-checker#readme",
17
17
  "bin": {
18
- "check-proxies": "check.js"
18
+ "mtproto-checker": "check.js"
19
19
  },
20
20
  "files": [
21
21
  "check.js",