Skip to content

Commit

Permalink
Added missing feature
Browse files Browse the repository at this point in the history
Thanks to Miate (On the discord)
  • Loading branch information
Hanro50 committed Mar 21, 2023
1 parent 8863f28 commit ba80a60
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 23 deletions.
Binary file added MSMC.zip
Binary file not shown.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "msmc",
"version": "4.0.3",
"version": "4.0.5",
"description": "A bare bones login library for Minecraft based projects to authenticate individuals with a Microsoft account.",
"license": "MIT",
"exports": {
Expand Down
9 changes: 6 additions & 3 deletions src/assets.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { readFileSync } from "fs";
import type { Response } from "node-fetch"
import { join } from "path";
import { mcToken } from "./auth/minecraft";
/**
* A copy of the user object mclc uses
*/
Expand All @@ -10,7 +11,9 @@ export type mclcUser = {
uuid: string;

name?: string;
meta?: { type: "mojang" | "msa" | "legacy", xuid?: string, demo?: boolean };
meta?: {
refresh: string; exp?: number, type: "mojang" | "msa" | "legacy", xuid?: string, demo?: boolean
};
user_properties?: Partial<any>;
}

Expand Down Expand Up @@ -119,15 +122,15 @@ export interface windowProperties {
export interface mcProfile {
id: string,
name: string,
skins: Array<
skins?: Array<
{
id: string,
state: 'ACTIVE',
url: string,
variant: 'SLIM' | 'CLASSIC'
}
>,
capes: Array<
capes?: Array<
{
id: string,
state: 'ACTIVE',
Expand Down
87 changes: 79 additions & 8 deletions src/auth/minecraft.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,85 @@
import fetch from "node-fetch";
import { errResponse, gmllUser, mclcUser, mcProfile } from "../assets.js";
import xbox from "./xbox.js";
import { auth } from "./auth.js"
export interface mcJWTDecoded { xuid: string, agg: string, sub: string, nbf: number, auth: string, roles: [], iss: string, exp: number, iat: number, platform: string, yuid: string }
export type entitlements = "game_minecraft" | "game_minecraft_bedrock" | "game_dungeons" | "product_minecraft" | "product_minecraft_bedrock" | "product_dungeons"
export interface mcToken {
refresh?: string;
mcToken: string;
profile: mcProfile;
xuid: string;
exp: number;
}
/**Validates MC tokens to check if they're valid. */
export function validate(token: mcToken | minecraft | mclcUser) {
if ("exp" in token)
return (typeof token.exp == "number" && token.exp > Date.now());
else if ("meta" in token && "exp" in token.meta)
return (typeof token.meta.exp == "number" && token.meta.exp > Date.now());
return false;
}

/**
* Gets a minecraft token from a saved mcToken.
* @param auth A new instance of the auth object
* @param token The mcToken
* @param refresh Set to true if we should try refreshing the token
* @returns A newly serialized minecraft Token.
*
* @warning The xbox object may not be restored using this method!
*/
export function fromToken(auth: auth, token: mcToken): null | minecraft
export function fromToken(auth: auth, token: mcToken, refresh?: boolean): Promise<minecraft>
export function fromToken(auth: auth, token: mcToken, refresh?: boolean): null | minecraft | Promise<minecraft> {
if (validate(token) && refresh)
return new Promise(async done => {
const xbl = await auth.refresh(token.refresh);
done(await xbl.getMinecraft())
})
let mc = new minecraft(token.mcToken, token.profile, auth, token.refresh, token.exp );
return mc;
}

/**
* Gets a minecraft token from a saved mcToken.
* @param auth A new instance of the auth object
* @param token The mcToken
* @returns A newly serialized minecraft Token.
*
* @warning The xbox object may not be restored using this method!
*/
export function fromMclcToken(auth: auth, token: mclcUser, refresh?: boolean): null | minecraft | Promise<minecraft> {
return fromToken(auth, { mcToken: token.access_token, refresh: token.meta?.refresh, exp: token.meta?.exp, profile: { id: token.uuid, name: token.name }, xuid: token.meta?.xuid }, refresh)
}

export default class minecraft {

readonly mcToken: string;
readonly profile: mcProfile;
readonly parent: xbox;
readonly profile: mcProfile | undefined;
readonly parent: xbox | auth;
readonly xuid: string;
readonly exp: number;
refreshTkn: string;
getToken(full: boolean): mcToken {
return {
refresh: (this.parent instanceof auth) ? this.refreshTkn : this.parent?.msToken?.refresh_token,
mcToken: this.mcToken,
profile: full ? this.profile : { name: this.profile.name, id: this.profile.id, demo: this.profile.demo },
xuid: this.xuid,
exp: this.exp
}

constructor(parent: xbox, mcToken: string, profile: mcProfile) {
}
constructor(mcToken: string, profile: mcProfile, parent: xbox)
constructor(mcToken: string, profile: mcProfile, parent: auth, refreshTkn: string, exp: number)
constructor(mcToken: string, profile: mcProfile, parent: xbox | auth, refreshTkn?: string, exp = new Date().getTime() + (1000 * 60 * 60 * 23)) {
this.parent = parent;
this.mcToken = mcToken;
this.profile = profile;
this.xuid = this._parseLoginToken().xuid;
this.exp = new Date().getTime() + (1000 * 60 * 60 * 23);
this.exp = exp;
this.refreshTkn = refreshTkn;
}
async entitlements() {
var r998 = await fetch("https://api.minecraftservices.com/minecraft/profile", {
Expand All @@ -38,7 +100,13 @@ export default class minecraft {
isDemo() {
return this.profile.demo;
}
mclc() {
/**
* A MCLC user object for launching minecraft
* @param refreshable Should we embed some metadata for refreshable tokens?
* @returns returns an MCLC user token
*
*/
mclc(refreshable?: boolean) {
return {
access_token: this.mcToken,
client_token: getUUID(),
Expand All @@ -47,7 +115,9 @@ export default class minecraft {
meta: {
xuid: this.xuid,
type: "msa",
demo: this.profile.demo
demo: this.profile.demo,
exp: this.exp,
refresh: refreshable ? ((this.parent instanceof auth) ? this.refreshTkn : this.parent.msToken.refresh_token) : undefined
},
user_properties: {}
} as mclcUser
Expand All @@ -65,8 +135,9 @@ export default class minecraft {
}
}
async refresh(force?: boolean) {

//@ts-ignore
this.parent = await this.parent.refresh(force);
this.parent = (this.parent instanceof auth) ? await this.parent.refresh(this.refreshTkn) : await this.parent.refresh(force);
if (this.validate() && !force) return this
let tkn = await this.parent.getMinecraft();
//Copy back objects
Expand All @@ -76,7 +147,7 @@ export default class minecraft {
return this;
}
validate() {
return this.exp > Date.now();
return validate(this);
}
_parseLoginToken() {
var base64Url = this.mcToken.split('.')[1];
Expand Down
12 changes: 5 additions & 7 deletions src/auth/xbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,12 @@ export interface mcAuthToken {
expires_in: number
}
export interface xblAuthToken {
IssueInstant: string
NotAfter: string
IssueInstant?: string
NotAfter?: string
Token: string
DisplayClaims: { xui: [{ uhs: string }] }
DisplayClaims?: { xui: [{ uhs: string }] }
}



export default class xbox {
readonly parent: auth;
readonly msToken: msAuthToken;
Expand Down Expand Up @@ -107,13 +105,13 @@ export default class xbox {
errResponse(r998, "error.auth.minecraft.profile")
var MCprofile = await r998.json() as mcProfile & { error?: string };
const profile = MCprofile.error ? { id: MCauth.username, capes: [], skins: [], name: "player", demo: true } : MCprofile;
let mc = new minecraft(this, MCauth.access_token, profile);
let mc = new minecraft(MCauth.access_token, profile, this);
if (mc.isDemo()) {
this.load('load.auth.minecraft.gamepass');
const entitlements = await mc.entitlements()
if (entitlements.includes("game_minecraft") || entitlements.includes("product_minecraft")) {
const social = await (await this.getSocial()).getProfile();
mc = new minecraft(this, MCauth.access_token, { id: MCauth.username, capes: [], skins: [], name: social.gamerTag });
mc = new minecraft(MCauth.access_token, { id: MCauth.username, capes: [], skins: [], name: social.gamerTag }, this);
}
}
return mc
Expand Down
5 changes: 3 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { wrapError, lst } from "./assets.js";
import social from "./auth/social";
import type xbox from "./auth/xbox.js";
import type minecraft from "./auth/minecraft.js";

import { fromToken, fromMclcToken, validate, mcToken } from "./auth/minecraft.js";

export { social, auth, assets, wrapError, lst };
export type { xbox, minecraft };
export const mcTokenToolbox = {fromToken, fromMclcToken, validate}
export type { xbox, minecraft, mcToken };
6 changes: 4 additions & 2 deletions tests/raw/test2.js → tests/raw/test2.mjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Client } from "minecraft-launcher-core";
const launcher = new Client();
//Import the auth class
import { auth } from "msmc";
import msmc from "msmc";
//Create a new auth manager
const authManager = new auth("select_account");
const authManager = new msmc.auth("select_account");
//Launch using the 'raw' gui framework (can be 'electron' or 'nwjs')
const xboxManager = await authManager.launch("raw")
//Generate the minecraft login token
Expand All @@ -23,6 +23,8 @@ let opts = {
min: "4G"
}
};
console.log(JSON.stringify(msmc.mcTokenToolbox.fromMclcToken(authManager,token.mclc()).validate()))
//mcTokenToolkit.fromToken(authManager,token.mclc()).mclc()
console.log("Starting!");
launcher.launch(opts);

Expand Down

0 comments on commit ba80a60

Please sign in to comment.