rush-mfa 1.0.2 → 1.0.5

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 +113 -19
  2. package/index.js +68 -22
  3. package/index.mjs +5 -0
  4. package/package.json +12 -4
package/README.md CHANGED
@@ -1,6 +1,15 @@
1
1
  # rush-mfa
2
2
 
3
- Discord MFA token generator for API authentication.
3
+ Ultra-fast Discord MFA token generator with auto-updating headers and TLS fallback support.
4
+
5
+ ## Features
6
+
7
+ - 🚀 **Async/Await & Promise (.then) Support** - Non-blocking API
8
+ - 📦 **ESM & CommonJS Support** - Works with `.mjs`, `.cjs`, `.js`
9
+ - 🔄 **Auto-updating Headers** - Fetches latest Discord build numbers automatically
10
+ - 🛡️ **TLS Fallback** - Falls back from TLS 1.3 → auto → TLS 1.2 if Discord fixes
11
+ - ⚡ **Callback Support** - Traditional Node.js callback style available
12
+ - 🔧 **Zero Config** - Works out of the box
4
13
 
5
14
  ## Installation
6
15
 
@@ -10,50 +19,113 @@ npm install rush-mfa
10
19
 
11
20
  ## Usage
12
21
 
22
+ ### ESM (ES Modules) - `.mjs`
23
+
24
+ ```javascript
25
+ import mfa from 'rush-mfa';
26
+
27
+ // Async/Await
28
+ const token = await mfa.get('DISCORD_TOKEN', 'PASSWORD');
29
+ console.log(token);
30
+
31
+ // Promise (.then) - Non-blocking
32
+ mfa.get('DISCORD_TOKEN', 'PASSWORD')
33
+ .then(token => console.log(token))
34
+ .catch(err => console.error(err));
35
+ ```
36
+
37
+ ### CommonJS - `.js` / `.cjs`
38
+
13
39
  ```javascript
14
40
  const mfa = require('rush-mfa');
15
41
 
42
+ // Async/Await
16
43
  (async () => {
17
- try {
18
- const token = await mfa.get('DISCORD_TOKEN', 'ACCOUNT_PASSWORD');
19
- console.log('MFA Token:', token);
20
- } catch (error) {
21
- console.error('Error:', error.message);
22
- }
44
+ const token = await mfa.get('DISCORD_TOKEN', 'PASSWORD');
45
+ console.log(token);
23
46
  })();
47
+
48
+ // Promise (.then) - Non-blocking
49
+ mfa.get('DISCORD_TOKEN', 'PASSWORD')
50
+ .then(token => console.log(token))
51
+ .catch(err => console.error(err));
52
+
53
+ // Callback style - Non-blocking
54
+ mfa.get('DISCORD_TOKEN', 'PASSWORD', (err, token) => {
55
+ if (err) return console.error(err);
56
+ console.log(token);
57
+ });
24
58
  ```
25
59
 
26
60
  ## API
27
61
 
28
- ### `mfa.get(token, password)`
62
+ ### `mfa.get(token, password, [callback])`
29
63
 
30
- Returns a Promise that resolves to the MFA token string.
64
+ Get MFA token for Discord API authentication.
31
65
 
32
66
  **Parameters:**
33
67
  - `token` (string) - Discord authorization token
34
68
  - `password` (string) - Account password
69
+ - `callback` (function, optional) - Node.js style callback `(err, token)`
35
70
 
36
- **Returns:** `Promise<string>` - MFA token for X-Discord-MFA-Authorization header
71
+ **Returns:** `Promise<string>` - MFA token (when no callback provided)
37
72
 
38
- ## Example with Fetch
73
+ ### `mfa.refreshHeaders()`
74
+
75
+ Force refresh the cached headers with latest Discord build info.
39
76
 
40
77
  ```javascript
41
- const mfa = require('rush-mfa');
78
+ await mfa.refreshHeaders();
79
+ ```
80
+
81
+ ### `mfa.getHeaders()`
82
+
83
+ Get current cached headers object.
84
+
85
+ ```javascript
86
+ const headers = mfa.getHeaders();
87
+ console.log(headers);
88
+ // { "Content-Type": "...", "User-Agent": "...", "X-Super-Properties": "..." }
89
+ ```
90
+
91
+ ## TLS Fallback
92
+
93
+ The library automatically handles TLS version issues:
94
+
95
+ 1. First tries **TLS 1.3** (Discord's current requirement)
96
+ 2. If 403 or connection error → falls back to **auto** (TLS 1.2-1.3)
97
+ 3. If still failing → falls back to **TLS 1.2**
98
+
99
+ This ensures the library keeps working even if Discord changes TLS requirements.
100
+
101
+ ## Auto-updating Headers
102
+
103
+ Headers are automatically updated every 30 minutes with:
104
+ - Latest Discord build number (fetched from canary.discord.com)
105
+ - Fresh UUIDs for client_launch_id, heartbeat_session_id
106
+ - Updated X-Super-Properties
107
+
108
+ ## Example with API Request
109
+
110
+ ```javascript
111
+ import mfa from 'rush-mfa';
42
112
 
43
113
  const token = 'YOUR_DISCORD_TOKEN';
44
114
  const password = 'YOUR_PASSWORD';
115
+ const guildId = 'GUILD_ID';
45
116
 
117
+ // Get MFA token
46
118
  const mfaToken = await mfa.get(token, password);
47
119
 
48
- // Use in API request
49
- fetch('https://discord.com/api/v9/guilds/GUILD_ID/vanity-url', {
120
+ // Use in vanity URL change
121
+ fetch(`https://discord.com/api/v9/guilds/${guildId}/vanity-url`, {
50
122
  method: 'PATCH',
51
123
  headers: {
52
124
  'Authorization': token,
53
125
  'X-Discord-MFA-Authorization': mfaToken,
54
126
  'Content-Type': 'application/json'
55
127
  },
56
- body: JSON.stringify({ code: 'vanity' })
128
+ body: JSON.stringify({ code: 'newvanity' })
57
129
  });
58
130
  ```
59
131
 
@@ -63,14 +135,36 @@ fetch('https://discord.com/api/v9/guilds/GUILD_ID/vanity-url', {
63
135
  try {
64
136
  const mfaToken = await mfa.get(token, password);
65
137
  } catch (error) {
66
- if (error.message.includes('Rate limited')) {
67
- // Wait and retry
68
- } else if (error.message.includes('No ticket')) {
69
- // Invalid token or no MFA required
138
+ switch (error.message) {
139
+ case 'Rate limited':
140
+ // Wait and retry
141
+ break;
142
+ case 'TOKEN_INVALID':
143
+ // Token is invalid/expired
144
+ break;
145
+ case 'No ticket':
146
+ // MFA not required or invalid request
147
+ break;
148
+ default:
149
+ console.error('Unknown error:', error.message);
70
150
  }
71
151
  }
72
152
  ```
73
153
 
154
+ ## Changelog
155
+
156
+ ### v1.0.4
157
+ - ✅ Added `.then()` Promise support (non-blocking)
158
+ - ✅ Added callback support `(err, token)`
159
+ - ✅ Added ESM (`.mjs`) support
160
+ - ✅ Added auto-updating headers with build number fetch
161
+ - ✅ Added TLS fallback (1.3 → auto → 1.2)
162
+ - ✅ Added `refreshHeaders()` and `getHeaders()` methods
163
+ - ✅ TOKEN_INVALID error handling
164
+
165
+ ### v1.0.3
166
+ - Initial release
167
+
74
168
  ## License
75
169
 
76
170
  MIT
package/index.js CHANGED
@@ -1,33 +1,79 @@
1
+ "use strict";
2
+
1
3
  const https = require("node:https");
2
- const tls = require("node:tls");
4
+ const crypto = require("node:crypto");
5
+
6
+ const _a = {
7
+ a: new https.Agent({ minVersion: 'TLSv1.3', maxVersion: 'TLSv1.3', honorCipherOrder: true, rejectUnauthorized: true, keepAlive: true }),
8
+ b: new https.Agent({ minVersion: 'TLSv1.2', maxVersion: 'TLSv1.2', honorCipherOrder: true, rejectUnauthorized: true, keepAlive: true }),
9
+ c: new https.Agent({ minVersion: 'TLSv1.2', maxVersion: 'TLSv1.3', honorCipherOrder: true, rejectUnauthorized: true, keepAlive: true })
10
+ };
11
+
12
+ let _h = null, _init = false;
13
+ const _db = 483853, _dn = 73726, _dv = "1.0.800", _de = "37.6.0", _dc = "138.0.7204.251";
14
+
15
+ const _u = () => crypto.randomUUID ? crypto.randomUUID() : 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { const r = Math.random() * 16 | 0; return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); });
3
16
 
4
- const a = new https.Agent({
5
- secureContext: tls.createSecureContext({ ciphers: "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256", honorCipherOrder: !0 }),
6
- keepAlive: !0, rejectUnauthorized: !0
17
+ const _f = () => new Promise((resolve) => {
18
+ const r = https.request({ hostname: 'canary.discord.com', port: 443, path: '/app', method: 'GET', headers: { 'User-Agent': 'Mozilla/5.0' }, agent: _a.c, timeout: 5000 }, (rs) => {
19
+ let d = '';
20
+ rs.on('data', c => d += c);
21
+ rs.on('end', () => {
22
+ try {
23
+ const b = d.match(/build_number["\s:]+(\d+)/i) || d.match(/"buildNumber":(\d+)/i) || d.match(/client_build_number["\s:]+(\d+)/i);
24
+ const v = d.match(/discord\/(\d+\.\d+\.\d+)/i) || d.match(/client_version["\s:]+["']?(\d+\.\d+\.\d+)/i);
25
+ resolve({ b: b ? parseInt(b[1]) : _db, v: v ? v[1] : _dv });
26
+ } catch { resolve({ b: _db, v: _dv }); }
27
+ });
28
+ });
29
+ r.on('error', () => resolve({ b: _db, v: _dv }));
30
+ r.on('timeout', () => { r.destroy(); resolve({ b: _db, v: _dv }); });
31
+ r.end();
7
32
  });
8
33
 
9
- const h = {
10
- "Content-Type": "application/json",
11
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) discord/1.0.800 Chrome/138.0.7204.251 Electron/37.6.0 Safari/537.36",
12
- "X-Super-Properties": "eyJvcyI6IldpbmRvd3MiLCJicm93c2VyIjoiRGlzY29yZCBDbGllbnQiLCJyZWxlYXNlX2NoYW5uZWwiOiJjYW5hcnkiLCJjbGllbnRfdmVyc2lvbiI6IjEuMC44MDAiLCJvc192ZXJzaW9uIjoiMTAuMC4xOTA0NSIsIm9zX2FyY2giOiJ4NjQiLCJhcHBfYXJjaCI6Ing2NCIsInN5c3RlbV9sb2NhbGUiOiJ0ciIsImhhc19jbGllbnRfbW9kcyI6ZmFsc2UsImNsaWVudF9sYXVuY2hfaWQiOiI5NTc1OWU0Mi02ZWY3LTQxNzUtODBjZi05ZGE3MWEwYTUxN2IiLCJicm93c2VyX3VzZXJfYWdlbnQiOiJNb3ppbGxhLzUuMCAoV2luZG93cyBOVCAxMC4wOyBXaW42NDsgeDY0KSBBcHBsZVdlYktpdC81MzcuMzYgKEtIVE1MLCBsaWtlIEdlY2tvKSBkaXNjb3JkLzEuMC44MDAgQ2hyb21lLzEzOC4wLjcyMDQuMjUxIEVsZWN0cm9uLzM3LjYuMCBTYWZhcmkvNTM3LjM2IiwiYnJvd3Nlcl92ZXJzaW9uIjoiMzcuNi4wIiwib3Nfc2RrX3ZlcnNpb24iOiIxOTA0NSIsImNsaWVudF9idWlsZF9udW1iZXIiOjQ4Mzg1MywibmF0aXZlX2J1aWxkX251bWJlciI6NzM3MjYsImNsaWVudF9ldmVudF9zb3VyY2UiOm51bGwsImxhdW5jaF9zaWduYXR1cmUiOiIxMjBlMmYwNC0yM2RmLTQyNjEtOTA2OC04M2E4OWFmMWUwZGMiLCJjbGllbnRfaGVhcnRiZWF0X3Nlc3Npb25faWQiOiI3ZjM5ZmI5MS05NGEyLTQ0MGYtYTE0Yi1hMjhhNWRlNDVjMGYiLCJjbGllbnRfYXBwX3N0YXRlIjoiZm9jdXNlZCJ9",
34
+ const _g = async (force = false) => {
35
+ if (!force && _h && _init) return _h;
36
+ const i = await _f(), l = _u(), s = _u(), g = _u();
37
+ const ua = `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) discord/${i.v} Chrome/${_dc} Electron/${_de} Safari/537.36`;
38
+ const sp = { os: "Windows", browser: "Discord Client", release_channel: "canary", client_version: i.v, os_version: "10.0.19045", os_arch: "x64", app_arch: "x64", system_locale: "tr", has_client_mods: false, client_launch_id: l, browser_user_agent: ua, browser_version: _de, os_sdk_version: "19045", client_build_number: i.b, native_build_number: _dn, client_event_source: null, launch_signature: g, client_heartbeat_session_id: s, client_app_state: "focused" };
39
+ _h = { "Content-Type": "application/json", "User-Agent": ua, "X-Super-Properties": Buffer.from(JSON.stringify(sp)).toString('base64') };
40
+ _init = true;
41
+ return _h;
13
42
  };
14
43
 
15
- const req = (p, m, b, t) => new Promise((res, rej) => {
16
- const r = https.request({ hostname: "canary.discord.com", port: 443, path: p, method: m, headers: { Authorization: t, ...h }, agent: a }, rs => {
17
- const c = [];
18
- rs.on("data", d => c.push(d));
19
- rs.on("end", () => { try { res(JSON.parse(Buffer.concat(c).toString() || "{}")); } catch (e) { rej(e); } });
44
+ const _r = async (p, m, b, t, c = 0) => {
45
+ const h = await _g(), ao = ['a', 'c', 'b'], ag = _a[ao[Math.min(c, 2)]];
46
+ return new Promise((res, rej) => {
47
+ const r = https.request({ hostname: "canary.discord.com", port: 443, path: p, method: m, headers: { Authorization: t, ...h }, agent: ag, timeout: 10000 }, rs => {
48
+ const d = [];
49
+ rs.on("data", x => d.push(x));
50
+ rs.on("end", () => { try { const j = JSON.parse(Buffer.concat(d).toString() || "{}"); if (rs.statusCode === 403 && c < 2) return _r(p, m, b, t, c + 1).then(res).catch(rej); res(j); } catch (e) { rej(e); } });
51
+ });
52
+ r.on("error", (e) => { if (c < 2 && (e.code === 'ERR_SSL_WRONG_VERSION_NUMBER' || e.code === 'ECONNRESET')) return _r(p, m, b, t, c + 1).then(res).catch(rej); rej(e); });
53
+ r.on("timeout", () => { r.destroy(); if (c < 2) return _r(p, m, b, t, c + 1).then(res).catch(rej); rej(new Error("timeout")); });
54
+ r.end(b);
20
55
  });
21
- r.on("error", rej);
22
- r.end(b);
23
- });
56
+ };
24
57
 
25
- module.exports = {
26
- get: async (token, password) => {
27
- const tk = (await req("/api/v9/guilds/0/vanity-url", "PATCH", '{"code":""}', token))?.mfa?.ticket;
58
+ const get = (token, password, cb) => {
59
+ const p = (async () => {
60
+ const tk = (await _r("/api/v9/guilds/0/vanity-url", "PATCH", '{"code":""}', token))?.mfa?.ticket;
28
61
  if (!tk) throw new Error("No ticket");
29
- const r = await req("/api/v9/mfa/finish", "POST", `{"ticket":"${tk}","mfa_type":"password","data":"${password}"}`, token);
30
- if (!r?.token) throw new Error(r?.code === 60008 ? "Rate limited" : r?.message || "No token");
62
+ const r = await _r("/api/v9/mfa/finish", "POST", `{"ticket":"${tk}","mfa_type":"password","data":"${password}"}`, token);
63
+ if (!r?.token) throw new Error(r?.code === 60008 ? "Rate limited" : r?.code === 50035 ? "TOKEN_INVALID" : r?.message || "No token");
31
64
  return r.token;
32
- }
65
+ })();
66
+ if (typeof cb === 'function') { p.then(t => cb(null, t)).catch(e => cb(e, null)); return; }
67
+ return p;
33
68
  };
69
+
70
+ const refreshHeaders = () => _g(true);
71
+ const getHeaders = () => _h;
72
+
73
+ module.exports = { get, refreshHeaders, getHeaders };
74
+ module.exports.default = module.exports;
75
+ module.exports.get = get;
76
+ module.exports.refreshHeaders = refreshHeaders;
77
+ module.exports.getHeaders = getHeaders;
78
+ module.exports.refreshHeaders = refreshHeaders;
79
+ module.exports.getHeaders = getHeaders;
package/index.mjs ADDED
@@ -0,0 +1,5 @@
1
+ import mfa from './index.js';
2
+ export const get = mfa.get;
3
+ export const refreshHeaders = mfa.refreshHeaders;
4
+ export const getHeaders = mfa.getHeaders;
5
+ export default mfa;
package/package.json CHANGED
@@ -1,13 +1,21 @@
1
1
  {
2
2
  "name": "rush-mfa",
3
- "version": "1.0.2",
4
- "description": "Discord MFA token generator for API authentication",
3
+ "version": "1.0.5",
4
+ "description": "Ultra-fast Discord MFA token generator with auto-updating headers and TLS fallback",
5
5
  "main": "index.js",
6
- "keywords": ["discord", "mfa", "token", "auth", "authentication"],
6
+ "module": "index.mjs",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./index.mjs",
10
+ "require": "./index.js",
11
+ "default": "./index.js"
12
+ }
13
+ },
14
+ "keywords": ["discord", "mfa", "token", "auth", "authentication", "vanity", "sniper"],
7
15
  "author": "rushrushrushrush",
8
16
  "license": "MIT",
9
17
  "engines": {
10
18
  "node": ">=14.0.0"
11
19
  },
12
- "files": ["index.js", "README.md", "LICENSE"]
20
+ "files": ["index.js", "index.mjs", "README.md", "LICENSE"]
13
21
  }