UNPKG

@xmcl/user

Version:

Minecraft user related functions, including Yggdrasil authenticator, player skin fetcher, and Mojang security API

5 lines 59.1 kB
{ "version": 3, "sources": ["../offline.ts", "../../user-offline-uuid/index.browser.ts", "../../undici-shim/index.ts", "../mojang.ts", "../yggdrasil.ts", "../microsoft.ts"], "sourcesContent": ["import { v4 } from 'uuid'\nimport { getOfflineUUID } from 'user-offline-uuid'\n\n/**\n * Random generate a new token by uuid v4. It can be client or auth token.\n * @returns a new token\n */\nexport function newToken() {\n return v4().replace(/-/g, '')\n}\n\nexport { getOfflineUUID }\n\n/**\n * Create an offline auth. It'll ensure the user game profile's `uuid` is the same for the same `username`.\n *\n * @param username The username you want to have in-game.\n */\nexport function offline(username: string, uuid?: string) {\n const id = (uuid || getOfflineUUID(username))\n const prof = {\n id,\n name: username,\n }\n return {\n accessToken: newToken(),\n clientToken: newToken(),\n selectedProfile: prof,\n availableProfiles: [prof],\n user: {\n id,\n username,\n },\n }\n}\n", "/* eslint-disable camelcase */\nconst md5 = (s: string) => {\n function md5cycle(x: Int32Array, k: any[]) {\n let a = x[0]; let b = x[1]; let c = x[2]; let d = x[3]\n\n a = ff(a, b, c, d, k[0], 7, -680876936)\n d = ff(d, a, b, c, k[1], 12, -389564586)\n c = ff(c, d, a, b, k[2], 17, 606105819)\n b = ff(b, c, d, a, k[3], 22, -1044525330)\n a = ff(a, b, c, d, k[4], 7, -176418897)\n d = ff(d, a, b, c, k[5], 12, 1200080426)\n c = ff(c, d, a, b, k[6], 17, -1473231341)\n b = ff(b, c, d, a, k[7], 22, -45705983)\n a = ff(a, b, c, d, k[8], 7, 1770035416)\n d = ff(d, a, b, c, k[9], 12, -1958414417)\n c = ff(c, d, a, b, k[10], 17, -42063)\n b = ff(b, c, d, a, k[11], 22, -1990404162)\n a = ff(a, b, c, d, k[12], 7, 1804603682)\n d = ff(d, a, b, c, k[13], 12, -40341101)\n c = ff(c, d, a, b, k[14], 17, -1502002290)\n b = ff(b, c, d, a, k[15], 22, 1236535329)\n\n a = gg(a, b, c, d, k[1], 5, -165796510)\n d = gg(d, a, b, c, k[6], 9, -1069501632)\n c = gg(c, d, a, b, k[11], 14, 643717713)\n b = gg(b, c, d, a, k[0], 20, -373897302)\n a = gg(a, b, c, d, k[5], 5, -701558691)\n d = gg(d, a, b, c, k[10], 9, 38016083)\n c = gg(c, d, a, b, k[15], 14, -660478335)\n b = gg(b, c, d, a, k[4], 20, -405537848)\n a = gg(a, b, c, d, k[9], 5, 568446438)\n d = gg(d, a, b, c, k[14], 9, -1019803690)\n c = gg(c, d, a, b, k[3], 14, -187363961)\n b = gg(b, c, d, a, k[8], 20, 1163531501)\n a = gg(a, b, c, d, k[13], 5, -1444681467)\n d = gg(d, a, b, c, k[2], 9, -51403784)\n c = gg(c, d, a, b, k[7], 14, 1735328473)\n b = gg(b, c, d, a, k[12], 20, -1926607734)\n\n a = hh(a, b, c, d, k[5], 4, -378558)\n d = hh(d, a, b, c, k[8], 11, -2022574463)\n c = hh(c, d, a, b, k[11], 16, 1839030562)\n b = hh(b, c, d, a, k[14], 23, -35309556)\n a = hh(a, b, c, d, k[1], 4, -1530992060)\n d = hh(d, a, b, c, k[4], 11, 1272893353)\n c = hh(c, d, a, b, k[7], 16, -155497632)\n b = hh(b, c, d, a, k[10], 23, -1094730640)\n a = hh(a, b, c, d, k[13], 4, 681279174)\n d = hh(d, a, b, c, k[0], 11, -358537222)\n c = hh(c, d, a, b, k[3], 16, -722521979)\n b = hh(b, c, d, a, k[6], 23, 76029189)\n a = hh(a, b, c, d, k[9], 4, -640364487)\n d = hh(d, a, b, c, k[12], 11, -421815835)\n c = hh(c, d, a, b, k[15], 16, 530742520)\n b = hh(b, c, d, a, k[2], 23, -995338651)\n\n a = ii(a, b, c, d, k[0], 6, -198630844)\n d = ii(d, a, b, c, k[7], 10, 1126891415)\n c = ii(c, d, a, b, k[14], 15, -1416354905)\n b = ii(b, c, d, a, k[5], 21, -57434055)\n a = ii(a, b, c, d, k[12], 6, 1700485571)\n d = ii(d, a, b, c, k[3], 10, -1894986606)\n c = ii(c, d, a, b, k[10], 15, -1051523)\n b = ii(b, c, d, a, k[1], 21, -2054922799)\n a = ii(a, b, c, d, k[8], 6, 1873313359)\n d = ii(d, a, b, c, k[15], 10, -30611744)\n c = ii(c, d, a, b, k[6], 15, -1560198380)\n b = ii(b, c, d, a, k[13], 21, 1309151649)\n a = ii(a, b, c, d, k[4], 6, -145523070)\n d = ii(d, a, b, c, k[11], 10, -1120210379)\n c = ii(c, d, a, b, k[2], 15, 718787259)\n b = ii(b, c, d, a, k[9], 21, -343485551)\n\n x[0] = add32(a, x[0])\n x[1] = add32(b, x[1])\n x[2] = add32(c, x[2])\n x[3] = add32(d, x[3])\n }\n\n function cmn(q: number, a: number, b: any, x: any, s: number, t: any) {\n a = add32(add32(a, q), add32(x, t))\n return add32((a << s) | (a >>> (32 - s)), b)\n }\n\n function ff(a: any, b: number, c: number, d: number, x: any, s: number, t: number) {\n return cmn((b & c) | ((~b) & d), a, b, x, s, t)\n }\n\n function gg(a: any, b: number, c: number, d: number, x: any, s: number, t: number) {\n return cmn((b & d) | (c & (~d)), a, b, x, s, t)\n }\n\n function hh(a: any, b: number, c: number, d: number, x: any, s: number, t: number) {\n return cmn(b ^ c ^ d, a, b, x, s, t)\n }\n\n function ii(a: any, b: number, c: number, d: number, x: any, s: number, t: number) {\n return cmn(c ^ (b | (~d)), a, b, x, s, t)\n }\n\n function md51(s: string) {\n const n = s.length\n const state = new Int32Array([1732584193, -271733879, -1732584194, 271733878]); let i\n for (i = 64; i <= s.length; i += 64) {\n md5cycle(state, md5blk(s.substring(i - 64, i)))\n }\n s = s.substring(i - 64)\n const tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n for (i = 0; i < s.length; i++) { tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3) }\n tail[i >> 2] |= 0x80 << ((i % 4) << 3)\n if (i > 55) {\n md5cycle(state, tail)\n for (i = 0; i < 16; i++) tail[i] = 0\n }\n tail[14] = n * 8\n md5cycle(state, tail)\n return state\n }\n\n /* there needs to be support for Unicode here,\n * unless we pretend that we can redefine the MD-5\n * algorithm for multi-byte characters (perhaps\n * by adding every four 16-bit characters and\n * shortening the sum to 32 bits). Otherwise\n * I suggest performing MD-5 as if every character\n * was two bytes--e.g., 0040 0025 = @%--but then\n * how will an ordinary MD-5 sum be matched?\n * There is no way to standardize text to something\n * like UTF-8 before transformation; speed cost is\n * utterly prohibitive. The JavaScript standard\n * itself needs to look at this: it should start\n * providing access to strings as preformed UTF-8\n * 8-bit unsigned value arrays.\n */\n function md5blk(s: string) { /* I figured global was faster. */\n const md5blks = [] as number[]; let i /* Andy King said do it this way. */\n for (i = 0; i < 64; i += 4) {\n md5blks[i >> 2] = s.charCodeAt(i) +\n (s.charCodeAt(i + 1) << 8) +\n (s.charCodeAt(i + 2) << 16) +\n (s.charCodeAt(i + 3) << 24)\n }\n return md5blks\n }\n\n /* this function is much faster,\n so if possible we use it. Some IEs\n are the only ones I know of that\n need the idiotic second function,\n generated by an if clause. */\n\n function add32(a: number, b: number) {\n return (a + b) & 0xFFFFFFFF\n }\n\n return md51(s)\n}\n\nexport function getOfflineUUID(username: string) {\n const md5Bytes = md5(`OfflinePlayer:${username}`)\n md5Bytes[6] &= 0x0f /* clear version */\n md5Bytes[6] |= 0x30 /* set to version 3 */\n md5Bytes[8] &= 0x3f /* clear variant */\n md5Bytes[8] |= 0x80 /* set to IETF variant */\n\n const hex_chr = '0123456789abcdef'.split('')\n\n function rhex(n: number) {\n let s = ''; let j = 0\n for (; j < 4; j++) {\n s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] +\n hex_chr[(n >> (j * 8)) & 0x0F]\n }\n return s\n }\n\n function hex(x: Int32Array) {\n const reuslt = new Array(4) as string[]\n for (let i = 0; i < x.length; i++) { reuslt[i] = rhex(x[i]) }\n return reuslt.join('')\n }\n\n return hex(md5Bytes).replace(/(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})/, '$1-$2-$3-$4-$5')\n}\n", "// eslint-disable-next-line @typescript-eslint/no-redeclare, n/no-unsupported-features/node-builtins\nexport const fetch = globalThis.fetch\n// eslint-disable-next-line n/no-unsupported-features/node-builtins, @typescript-eslint/no-redeclare\nexport const File = globalThis.File\n// eslint-disable-next-line n/no-unsupported-features/node-builtins, @typescript-eslint/no-redeclare\nexport const FormData = globalThis.FormData\n", "/* eslint-disable @typescript-eslint/no-redeclare */\nimport { fetch, FormData } from 'undici'\n\n/**\n * Users defined question when they register this account\n *\n * The question id, content mapping is:\n *\n * 1. What is your favorite pet's name?\n * 2. What is your favorite movie?\n * 3. What is your favorite author's last name?\n * 4. What is your favorite artist's last name?\n * 5. What is your favorite actor's last name?\n * 6. What is your favorite activity?\n * 7. What is your favorite restaurant?\n * 8. What is the name of your favorite cartoon?\n * 9. What is the name of the first school you attended?\n * 10. What is the last name of your favorite teacher?\n * 11. What is your best friend's first name?\n * 12. What is your favorite cousin's name?\n * 13. What was the first name of your first girl/boyfriend?\n * 14. What was the name of your first stuffed animal?\n * 15. What is your mother's middle name?\n * 16. What is your father's middle name?\n * 17. What is your oldest sibling's middle name?\n * 18. In what city did your parents meet?\n * 19. In what hospital were you born?\n * 20. What is your favorite team?\n * 21. How old were you when you got your first computer?\n * 22. How old were you when you got your first gaming console?\n * 23. What was your first video game?\n * 24. What is your favorite card game?\n * 25. What is your favorite board game?\n * 26. What was your first gaming console?\n * 27. What was the first book you ever read?\n * 28. Where did you go on your first holiday?\n * 29. In what city does your grandmother live?\n * 30. In what city does your grandfather live?\n * 31. What is your grandmother's first name?\n * 32. What is your grandfather's first name?\n * 33. What is your least favorite food?\n * 34. What is your favorite ice cream flavor?\n * 35. What is your favorite ice cream flavor?\n * 36. What is your favorite place to visit?\n * 37. What is your dream job?\n * 38. What color was your first pet?\n * 39. What is your lucky number?s\n *\n */\nexport interface MojangChallenge {\n readonly answer: { id: number }\n readonly question: { id: number; question: string }\n}\n\nexport interface MojangChallengeResponse {\n id: number\n answer: string\n}\nexport interface MinecraftProfileResponse {\n id: string // the real uuid of the account, woo\n name: string // the mc user name of the account\n skins: [{\n id: string\n state: 'ACTIVE' | 'string'\n url: string\n variant: 'CLASSIC' | string\n alias: 'STEVE' | string\n }]\n capes: [{\n id: string\n state: 'ACTIVE' | string\n url: string\n }]\n}\n\nexport interface MinecraftOwnershipResponse {\n /**\n * If the account doesn't own the game, the items array will be empty.\n */\n items: Array<{\n name: 'product_minecraft' | 'game_minecraft'\n /**\n * jwt signature\n */\n signature: string\n }>\n /**\n * jwt signature\n */\n signature: string\n keyId: string\n}\n\nexport interface MinecraftProfileErrorResponse {\n path: '/minecraft/profile'\n errorType: 'NOT_FOUND' | string\n error: string | 'NOT_FOUND'\n errorMessage: string\n developerMessage: string\n}\nexport interface MojangSkin {\n id: string\n state: 'ACTIVE' | 'INACTIVE'\n url: string\n variant: 'SLIM' | 'CLASSIC'\n}\nexport interface MojangCape {\n id: string\n state: 'ACTIVE' | 'INACTIVE'\n url: string\n /**\n * Capes name\n */\n alias: string\n}\n\nexport interface MicrosoftMinecraftProfile {\n id: string\n name: string\n skins: MojangSkin[]\n capes: MojangCape[]\n}\n\nexport interface NameChangeInformation {\n changedAt: string\n createdAt: string\n nameChangeAllowed: boolean\n}\n\nexport enum NameAvailability {\n DUPLICATE = 'DUPLICATE',\n AVAILABLE = 'AVAILABLE',\n NOT_ALLOWED = 'NOT_ALLOWED',\n}\n\nexport class SetNameError extends Error {\n public path: string\n public errorType: string\n public error: string\n public details: object\n public errorMessage: string\n public developerMessage: string\n\n constructor(message: string, err: any) {\n super(message)\n this.name = 'SetNameError'\n this.path = err.path\n this.errorType = err.errorType\n this.error = err.error\n this.details = err.details\n this.errorMessage = err.errorMessage\n this.developerMessage = err.developerMessage\n }\n}\n\nexport class SetSkinError extends Error {\n public path: string\n public errorType: string\n public error: string\n public details: object\n public errorMessage: string\n public developerMessage: string\n\n constructor(message: string, err: any) {\n super(message)\n this.name = 'SetSkinError'\n this.path = err.path\n this.errorType = err.errorType\n this.error = err.error\n this.details = err.details\n this.errorMessage = err.errorMessage\n this.developerMessage = err.developerMessage\n }\n}\n\nexport class MojangError extends Error {\n public path: string\n public errorMessage: string\n public developerMessage: string\n\n constructor(err: any) {\n super(err.errorMessage)\n this.path = err.path\n this.errorMessage = err.errorMessage\n this.developerMessage = err.developerMessage\n Object.assign(this, err)\n }\n}\n\nexport class UnauthorizedError extends MojangError {\n name = 'UnauthorizedError'\n constructor(err: any) {\n super(err)\n }\n}\n\nexport class ProfileNotFoundError extends MojangError {\n name = 'ProfileNotFoundError'\n\n constructor(err: any) {\n super(err)\n }\n}\n\nexport interface MojangClientOptions {\n fetch?: typeof fetch\n}\n\n/**\n * The mojang api client. Please referece https://wiki.vg/Mojang_API.\n *\n * All the apis need user to authenticate the access token from microsoft.\n * @see {@link MicrosoftAuthenticator}\n */\nexport class MojangClient {\n private fetch: typeof fetch\n\n constructor(options?: MojangClientOptions) {\n this.fetch = options?.fetch || fetch\n }\n\n async setName(name: string, token: string, signal?: AbortSignal) {\n const resp = await this.fetch(`https://api.minecraftservices.com/minecraft/profile/name/${name}`, {\n method: 'PUT',\n headers: {\n Authorization: `Bearer ${token}`,\n },\n signal,\n })\n switch (resp.status) {\n case 200: return await resp.json() as MicrosoftMinecraftProfile\n case 400: throw new SetNameError('Name is unavailable (Either taken or has not become available)', await resp.json())\n case 403: throw new SetNameError('Name is unavailable (Either taken or has not become available)', await resp.json())\n case 401: throw new SetNameError('Unauthorized (Bearer token expired or is not correct)', await resp.json())\n case 429: throw new SetNameError('Too many requests sent', await resp.json())\n case 500: throw new SetNameError('Timed out (API lagged out and could not respond)', await resp.json())\n }\n throw new SetNameError('Unknown error', await resp.json())\n }\n\n async getNameChangeInformation(token: string) {\n const resp = await this.fetch('https://api.minecraftservices.com/minecraft/profile/namechange', {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${token}`,\n },\n })\n return await resp.json() as NameChangeInformation\n }\n\n async checkNameAvailability(name: string, token: string, signal?: AbortSignal): Promise<NameAvailability> {\n const resp = await this.fetch(`https://api.minecraftservices.com/minecraft/profile/name/${name}/available`, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${token}`,\n },\n signal,\n })\n const result = await resp.json() as any\n return result.status\n }\n\n async getProfile(token: string, signal?: AbortSignal): Promise<MicrosoftMinecraftProfile> {\n const resp = await this.fetch('https://api.minecraftservices.com/minecraft/profile', {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${token}`,\n },\n signal,\n })\n if (resp.headers.get('content-type')?.toLocaleLowerCase() !== 'application/json') {\n throw new Error(await resp.text())\n }\n const json = await resp.json() as any\n if (resp.ok) {\n return json as MicrosoftMinecraftProfile\n } else if (json.error === 'NOT_FOUND') {\n throw new ProfileNotFoundError(json)\n } else if (resp.status === 401) {\n throw new UnauthorizedError(json)\n }\n throw Object.assign(new Error('Unknown Error'), json)\n }\n\n async setSkin(fileName: string, skin: string | Buffer, variant: 'slim' | 'classic', token: string, signal?: AbortSignal) {\n const body = typeof skin === 'string' ? JSON.stringify({ url: skin, variant }) : getSkinFormData(skin, fileName, variant)\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n }\n\n if (typeof body === 'string') {\n headers['Content-Type'] = 'application/json'\n }\n\n const resp = await this.fetch('https://api.minecraftservices.com/minecraft/profile/skins', {\n method: 'POST',\n headers,\n body,\n signal,\n })\n\n const profileResponse: MinecraftProfileResponse | MinecraftProfileErrorResponse = await resp.json() as any\n\n if (resp.status === 401) {\n throw new UnauthorizedError(await resp.json())\n }\n\n if ('error' in profileResponse || 'errorMessage' in profileResponse) {\n throw new SetSkinError(`Fail to set skin ${profileResponse.errorMessage}`, profileResponse)\n }\n\n return profileResponse\n }\n\n async resetSkin(token: string, signal?: AbortSignal) {\n const resp = await this.fetch('https://api.minecraftservices.com/minecraft/profile/skins/active', {\n method: 'DELETE',\n headers: {\n Authorization: `Bearer ${token}`,\n },\n signal,\n })\n if (resp.status === 401) {\n throw new UnauthorizedError(await resp.json())\n }\n }\n\n async hideCape(token: string, signal?: AbortSignal) {\n const resp = await this.fetch('https://api.minecraftservices.com/minecraft/profile/capes/active', {\n method: 'DELETE',\n headers: {\n Authorization: `Bearer ${token}`,\n },\n signal,\n })\n if (resp.status === 401) {\n throw new UnauthorizedError(await resp.json())\n }\n }\n\n async showCape(capeId: string, token: string, signal?: AbortSignal) {\n const resp = await this.fetch('https://api.minecraftservices.com/minecraft/profile/capes/active', {\n method: 'PUT',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ capeId }),\n signal,\n })\n if (resp.status === 401) {\n throw new UnauthorizedError(await resp.json())\n }\n if (resp.status === 400) {\n throw new Error()\n }\n const profile = await resp.json() as MicrosoftMinecraftProfile\n return profile\n }\n\n async verifySecurityLocation(token: string, signal?: AbortSignal) {\n const resp = await this.fetch('https://api.mojang.com/user/security/location', {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${token}`,\n },\n signal,\n })\n\n if (resp.status === 204) {\n return true\n }\n return false\n }\n\n async getSecurityChallenges(token: string) {\n const resp = await this.fetch('https://api.mojang.com/user/security/challenges', {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${token}`,\n },\n })\n\n if (resp.status === 401) {\n throw new UnauthorizedError(await resp.json())\n }\n return await resp.json() as MojangChallenge[]\n }\n\n async submitSecurityChallenges(answers: MojangChallengeResponse[], token: string) {\n const resp = await this.fetch('https://api.mojang.com/user/security/location', {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(answers),\n })\n\n if (resp.status === 204) {\n return\n }\n if (resp.status === 401) {\n throw new UnauthorizedError(await resp.json())\n }\n throw new Error()\n }\n\n /**\n * Return the owner ship list of the player with those token.\n */\n async checkGameOwnership(token: string, signal?: AbortSignal) {\n const mcResponse = await this.fetch('https://api.minecraftservices.com/entitlements/mcstore', {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n signal,\n })\n\n if (mcResponse.status === 401) {\n throw new UnauthorizedError(await mcResponse.text())\n }\n\n if (!mcResponse.ok || mcResponse.headers.get('content-type')?.toLocaleLowerCase() !== 'application/json') {\n throw new Error(await mcResponse.text())\n }\n\n const result = await mcResponse.json() as MinecraftOwnershipResponse\n\n return result\n }\n}\n\nfunction getSkinFormData(buf: Buffer, fileName: string, variant: 'slim' | 'classic') {\n const form = new FormData()\n form.append('variant', variant)\n const file = new File([buf], fileName, { type: 'image/png' })\n form.append('file', file)\n return form\n}\n", "/* eslint-disable n/no-unsupported-features/node-builtins */\nimport { GameProfile, GameProfileWithProperties } from './gameProfile'\n\n/**\n * The auth response format.\n *\n * Please refer https://wiki.vg/Authentication\n */\nexport interface YggrasilAuthentication {\n /**\n * hexadecimal or JSON-Web-Token (unconfirmed) [The normal accessToken can be found in the payload of the JWT (second by '.' separated part as Base64 encoded JSON object), in key \"yggt\"]\n */\n accessToken: string\n /**\n * identical to the one received\n */\n clientToken: string\n /**\n * only present if the agent field was received\n */\n availableProfiles: GameProfile[]\n /**\n * only present if the agent field was received\n */\n selectedProfile: GameProfile\n /**\n * only present if requestUser was true in the request payload\n */\n user?: {\n id: string\n username: string\n email?: string\n registerIp?: string\n migratedFrom?: string\n migratedAt?: number\n registeredAt?: number\n passwordChangedAt?: number\n dateOfBirth?: number\n suspended?: boolean\n blocked?: boolean\n secured?: boolean\n migrated?: boolean\n emailVerified?: boolean\n legacyUser?: boolean\n verifiedByParent?: boolean\n properties?: object[]\n }\n}\n\nexport interface YggdrasilClientOptions {\n headers?: Record<string, string>\n fetch?: typeof fetch\n FormData?: typeof FormData\n File?: typeof File\n}\n\nexport interface ProfileLookupException {\n /**\n * - statusCode=204 -> error=\"NoPlayerFound\"\n * - statusCode=400 -> error=\"IllegalArgumentException\" (parsed from body)\n * - statusCode=other -> error=statusCode.toString()\n */\n error: 'NoPlayerFoundException' | 'IllegalArgumentException' | 'GeneralException'\n errorMessage?: string | 'Invalid timestamp.'\n statusCode?: number\n statusMessage?: string\n}\n\nexport interface SetTextureOption {\n accessToken: string\n uuid: string\n type: 'skin' | 'cape' | 'elytra'\n texture?: {\n url: string\n metadata?: { model?: 'slim' | 'steve';[key: string]: any }\n } | {\n data: Uint8Array\n metadata?: { model?: 'slim' | 'steve';[key: string]: any }\n }\n}\n\nexport class YggdrasilError extends Error {\n error: string\n errorMessage: string\n cause?: string\n\n constructor(readonly statusCode: number, message: string, o?: any) {\n super(message)\n this.name = 'YggdrasilError'\n this.error = o?.error\n this.errorMessage = o?.errorMessage\n this.cause = o?.cause\n }\n}\n\nexport class YggdrasilClient {\n protected headers: Record<string, string>\n protected fetch: typeof fetch\n protected FormData: typeof FormData\n protected File: typeof File\n\n /**\n * Create client for official-like api endpoint\n * @param api The official-like api endpoint\n */\n constructor(public api: string, options?: YggdrasilClientOptions) {\n this.headers = options?.headers ?? {}\n this.fetch = options?.fetch || fetch\n this.FormData = options?.FormData || FormData\n this.File = options?.File || File\n }\n\n async validate(accessToken: string, clientToken: string, signal?: AbortSignal) {\n const response = await this.fetch(this.api + '/validate', {\n method: 'POST',\n body: JSON.stringify({ accessToken, clientToken }),\n headers: {\n ...this.headers,\n 'content-type': 'application/json; charset=utf-8',\n },\n signal,\n })\n return response.ok\n }\n\n async invalidate(accessToken: string, clientToken: string, signal?: AbortSignal) {\n return await this.fetch(this.api + '/invalidate', {\n method: 'POST',\n body: JSON.stringify({ accessToken, clientToken }),\n headers: {\n ...this.headers,\n 'content-type': 'application/json; charset=utf-8',\n },\n signal,\n }).then((s) => s.ok)\n }\n\n async login({ username, password, clientToken, requestUser }: { username: string; password: string; clientToken: string; requestUser?: boolean }, signal?: AbortSignal) {\n const response = await this.fetch(this.api + '/authenticate', {\n method: 'POST',\n body: JSON.stringify({\n agent: { name: 'Minecraft', version: 1 },\n requestUser: typeof requestUser === 'boolean' ? requestUser : false,\n username,\n password,\n clientToken,\n }),\n headers: {\n ...this.headers,\n 'content-type': 'application/json; charset=utf-8',\n },\n signal,\n })\n\n if (response.status >= 400) {\n const body = await response.text()\n throw new YggdrasilError(response.status, response.status + ':' + body, response.headers.get('content-type')?.startsWith('application/json') ? JSON.parse(body) : undefined)\n }\n\n const authentication: YggrasilAuthentication = await response.json() as YggrasilAuthentication\n return authentication\n }\n\n async refresh({ accessToken, requestUser, clientToken }: { accessToken: string; clientToken: string; requestUser?: boolean }, signal?: AbortSignal) {\n const response = await this.fetch(this.api + '/refresh', {\n method: 'POST',\n body: JSON.stringify({\n accessToken,\n clientToken,\n requestUser: typeof requestUser === 'boolean' ? requestUser : false,\n }),\n headers: {\n ...this.headers,\n 'content-type': 'application/json; charset=utf-8',\n },\n signal,\n })\n\n if (response.status >= 400) {\n const body = await response.text()\n throw new YggdrasilError(response.status, response.status + ':' + body, response.headers.get('content-type')?.startsWith('application/json') ? JSON.parse(body) : undefined)\n }\n\n const authentication = await response.json() as YggrasilAuthentication\n return authentication\n }\n}\n\n/**\n * The texture structure for yggdrasil API\n */\nexport interface YggdrasilTexturesInfo {\n /**\n * java time in ms\n */\n timestamp: number\n /**\n * player name\n */\n profileName: string\n /**\n * player id\n */\n profileId: string\n textures: {\n SKIN?: YggdrasilTexture\n CAPE?: YggdrasilTexture\n ELYTRA?: YggdrasilTexture\n }\n}\n\n/**\n * The data structure that hold the texture\n */\nexport interface YggdrasilTexture {\n url: string\n metadata?: { model?: 'slim' | 'steve';[key: string]: any }\n}\n\nexport function isTextureSlim(o: YggdrasilTexture) {\n return o.metadata ? o.metadata.model === 'slim' : false\n}\n\nexport function getTextureType(o: YggdrasilTexture) {\n return isTextureSlim(o) ? 'slim' : 'steve'\n}\n\nexport class YggdrasilThirdPartyClient extends YggdrasilClient {\n public profileApi: string\n public textureApi: string\n /**\n * Create thirdparty (authlib-injector) style client\n * @param api The api url following https://github.com/yushijinhun/authlib-injector/wiki/Yggdrasil-%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%8A%80%E6%9C%AF%E8%A7%84%E8%8C%83\n * @param clientToken\n * @param dispatcher\n */\n constructor(\n api: string,\n options?: YggdrasilClientOptions,\n ) {\n super(api + '/authserver', options)\n // eslint-disable-next-line no-template-curly-in-string\n this.profileApi = api + '/sessionserver/session/minecraft/profile/${uuid}'\n // this.profileApi = api + '/yggdrasil/sessionserver/session/minecraft/profile/${uuid}'\n // eslint-disable-next-line no-template-curly-in-string\n this.textureApi = api + '/api/user/profile/${uuid}/${type}'\n }\n\n async lookup(uuid: string, unsigned = true, signal?: AbortSignal) {\n // eslint-disable-next-line no-template-curly-in-string\n const url = new URL(this.profileApi.replace('${uuid}', uuid))\n url.searchParams.append('unsigned', unsigned ? 'true' : 'false')\n const response = await this.fetch(url.toString(), {\n method: 'GET',\n headers: this.headers,\n signal,\n })\n if (response.status !== 200) {\n const body = await response.text()\n throw new YggdrasilError(response.status, response.status + ':' + body, response.headers.get('content-type')?.startsWith('application/json') ? JSON.parse(body) : undefined)\n }\n const o = await response.json() as any\n if (o.properties && o.properties instanceof Array) {\n const properties = o.properties as Array<{ name: string; value: string; signature: string }>\n const to: { [key: string]: string } = {}\n for (const prop of properties) {\n // if (prop.signature && api.publicKey && !await verify(prop.value, prop.signature, api.publicKey)) {\n // console.warn(`Discard corrupted prop ${prop.name}: ${prop.value} as the signature mismatched!`)\n // } else {\n to[prop.name] = prop.value\n // }\n }\n o.properties = to\n }\n return o as GameProfileWithProperties\n }\n\n async setTexture(options: SetTextureOption, signal?: AbortSignal) {\n // eslint-disable-next-line no-template-curly-in-string\n const url = new URL(this.textureApi.replace('${uuid}', options.uuid).replace('${type}', options.type))\n\n // eslint-disable-next-line no-undef\n const requestOptions: RequestInit = {\n headers: {\n ...this.headers,\n Authorization: `Bearer ${options.accessToken}`,\n },\n signal,\n }\n if (!options.texture) {\n // delete texture\n requestOptions.method = 'DELETE'\n } else if ('data' in options.texture) {\n requestOptions.method = 'PUT'\n // upload texture\n const form = new this.FormData()\n form.append('model', options.texture.metadata?.model || 'steve')\n form.append('file', new this.File([options.texture.data], 'Steve.png', { type: 'image/png' }))\n requestOptions.body = form\n } else if ('url' in options.texture) {\n // set texture\n requestOptions.method = 'POST'\n url.searchParams.append('model', options.texture.metadata?.model || '')\n url.searchParams.append('url', options.texture.url)\n } else {\n throw new TypeError('Illegal Option Format!')\n }\n\n const response = await this.fetch(url.toString(), requestOptions)\n if (response.status === 401) {\n if (response.headers.get('content-type') === 'application/json') {\n const body = await response.json() as any\n throw new YggdrasilError(response.status, response.status.toString(), {\n error: body.error ?? 'Unauthorized',\n errorMessage: body.errorMessage ?? 'Unauthorized',\n })\n } else {\n const body = await response.text()\n throw new YggdrasilError(response.status, response.status + ':' + body, {\n error: 'Unauthorized',\n errorMessage: 'Unauthorized: ' + body,\n })\n }\n }\n if (response.status >= 400) {\n const body = await response.text()\n throw new YggdrasilError(response.status, response.status + ':' + body, {\n error: 'SetSkinFailed',\n errorMessage: 'Fail to set skin ' + body,\n })\n }\n }\n}\n", "/* eslint-disable n/no-unsupported-features/node-builtins */\n/* eslint-disable camelcase */\nexport interface XBoxResponse {\n IssueInstant: string\n NotAfter: string\n Token: string\n DisplayClaims: {\n xui: [\n {\n /**\n * gamer tag\n */\n gtg: string\n /**\n * user id\n */\n xid: string\n uhs: string\n },\n ]\n }\n}\n\nexport interface XBoxGameProfileResponse {\n profileUsers: [{\n id: string\n hostId: string | null\n settings: [{\n 'id': 'Gamertag'\n 'value': string\n }, {\n 'id': 'PublicGamerpic'\n 'value': string\n }]\n isSponsoredUser: boolean\n }]\n}\n\nexport interface MinecraftAuthResponse {\n username: string // this is not the uuid of the account\n roles: []\n access_token: string // jwt, your good old minecraft access token\n token_type: 'Bearer'\n expires_in: number\n}\n\nexport interface MicrosoftAuthenticatorOptions {\n fetch?: typeof fetch\n}\n\n/**\n * The microsoft authenticator for Minecraft (Xbox) account.\n */\nexport class MicrosoftAuthenticator {\n fetch: typeof fetch\n\n constructor(options: MicrosoftAuthenticatorOptions) {\n this.fetch = options.fetch || fetch\n }\n\n /**\n * Authenticate with xbox live by ms oauth access token\n * @param oauthAccessToken The oauth access token\n */\n async authenticateXboxLive(oauthAccessToken: string, signal?: AbortSignal) {\n const xblResponse = await this.fetch('https://user.auth.xboxlive.com/user/authenticate', {\n method: 'POST',\n body: JSON.stringify({\n Properties: {\n AuthMethod: 'RPS',\n SiteName: 'user.auth.xboxlive.com',\n RpsTicket: `d=${oauthAccessToken}`,\n },\n RelyingParty: 'http://auth.xboxlive.com',\n TokenType: 'JWT',\n }),\n headers: {\n 'Content-Type': 'application/json',\n },\n signal,\n })\n\n if (xblResponse.status !== 200) {\n throw new Error(`Failed to authenticate with xbox live, status code: ${xblResponse.status}: ${await xblResponse.text()}}`)\n }\n\n const result = await xblResponse.json() as XBoxResponse\n\n return result\n }\n\n /**\n * Authorize the xbox live. It will get the xsts token in response.\n * @param xblResponseToken The {@link XBoxResponse.Token}\n */\n async authorizeXboxLive(xblResponseToken: string, relyingParty: 'rp://api.minecraftservices.com/' | 'http://xboxlive.com' = 'rp://api.minecraftservices.com/', signal?: AbortSignal) {\n const xstsResponse = await this.fetch('https://xsts.auth.xboxlive.com/xsts/authorize', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n Properties: {\n SandboxId: 'RETAIL',\n UserTokens: [xblResponseToken],\n },\n RelyingParty: relyingParty,\n TokenType: 'JWT',\n }),\n signal,\n })\n\n if (xstsResponse.status !== 200) {\n const errText = await xstsResponse.text()\n let errObj = {} as any\n try {\n errObj = JSON.parse(errText)\n } catch (e) {}\n throw Object.assign(new Error(`Failed to authorize with xbox live, status code: ${xstsResponse.status}: ${errText}}`), errObj)\n }\n\n const result = await xstsResponse.json() as XBoxResponse\n\n return result\n }\n\n /**\n * Get xbox user profile, including **username** and **avatar**.\n *\n * You can find the parameters from the {@link XBoxResponse}.\n *\n * @param xuid The `xuid` in a {@link XBoxResponse.DisplayClaims}\n * @param uhs The `uhs` in a {@link XBoxResponse.DisplayClaims}\n * @param xstsToken The {@link XBoxResponse.Token}\n * @returns The user game profile.\n */\n async getXboxGameProfile(xuid: string, uhs: string, xstsToken: string, signal?: AbortSignal) {\n const url = new URL(`https://profile.xboxlive.com/users/xuid(${xuid})/profile/settings`)\n url.searchParams.append('settings', ['PublicGamerpic', 'Gamertag'].join(','))\n const response = await this.fetch(url.toString(), {\n headers: {\n 'x-xbl-contract-version': '2',\n 'content-type': 'application/json',\n Authorization: `XBL3.0 x=${uhs};${xstsToken}`,\n },\n signal,\n })\n\n if (response.status !== 200) {\n throw new Error(`Failed to get xbox game profile, status code: ${response.status}: ${await response.text()}}`)\n }\n\n const result = await response.json() as XBoxGameProfileResponse\n return result\n }\n\n /**\n * Acquire both Minecraft and xbox token and xbox game profile.\n * You can use the xbox token to login Minecraft by {@link loginMinecraftWithXBox}.\n *\n * This method is the composition of calling\n * - {@link authenticateXboxLive}\n * - {@link authorizeXboxLive} to `rp://api.minecraftservices.com/`\n * - {@link authorizeXboxLive} to `http://xboxlive.com`\n * - {@link getXboxGameProfile}\n *\n * You can call them individually if you want a more detailed control.\n *\n * @param oauthAccessToken The microsoft access token\n * @param signal The abort signal\n * @returns The object contain xstsResponse (minecraft xbox token) and xbox game profile\n */\n async acquireXBoxToken(oauthAccessToken: string, signal?: AbortSignal) {\n const xblResponse: XBoxResponse = await this.authenticateXboxLive(oauthAccessToken, signal)\n const minecraftXstsResponse: XBoxResponse = await this.authorizeXboxLive(xblResponse.Token, 'rp://api.minecraftservices.com/', signal)\n const xstsResponse: XBoxResponse = await this.authorizeXboxLive(xblResponse.Token, 'http://xboxlive.com', signal)\n\n return { minecraftXstsResponse, liveXstsResponse: xstsResponse }\n }\n\n /**\n * This will return the response with Minecraft access token!\n *\n * This access token allows us to launch the game, but, we haven't actually checked if the account owns the game. Everything until here works with a normal Microsoft account!\n *\n * @param uhs uhs from {@link XBoxResponse} of {@link acquireXBoxToken}\n * @param xstsToken You need to get this token from {@link acquireXBoxToken}\n */\n async loginMinecraftWithXBox(uhs: string, xstsToken: string, signal?: AbortSignal) {\n const mcResponse = await this.fetch('https://api.minecraftservices.com/authentication/login_with_xbox', {\n method: 'POST',\n body: JSON.stringify({\n identityToken: `XBL3.0 x=${uhs};${xstsToken}`,\n }),\n headers: {\n 'content-type': 'application/json',\n },\n signal,\n })\n\n if (mcResponse.status !== 200) {\n throw new Error(`Failed to login minecraft with xbox, status code: ${mcResponse.status}: ${await mcResponse.text()}}`)\n }\n\n const result = await mcResponse.json() as MinecraftAuthResponse\n\n return result\n }\n}\n"], "mappings": "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