From 7c169ce4a7b01d4ea92127e8be823ee0c7e60f4d Mon Sep 17 00:00:00 2001 From: Samuel Walker Date: Wed, 30 Oct 2024 17:16:10 -0600 Subject: [PATCH] finished auth --- fclauncher/InstanceManager.go | 7 +++- fclauncher/app.go | 1 + fclauncher/auth.go | 69 ++++++++++++++++++++++++++++++++++- fclauncher/minecraft.go | 10 ++--- 4 files changed, 80 insertions(+), 7 deletions(-) diff --git a/fclauncher/InstanceManager.go b/fclauncher/InstanceManager.go index 36cd5e5..92b8d7d 100644 --- a/fclauncher/InstanceManager.go +++ b/fclauncher/InstanceManager.go @@ -264,7 +264,12 @@ func (i *InstanceManager)LaunchInstance(instance string) { suffix = "win" } dir = filepath.Join(dir, "FCLauncher") - args, err := GetOfflineLaunchArgs(instanceObject.MinecraftVersion, filepath.Join(dir, "lib"), filepath.Join(dir, "bin"), filepath.Join(dir, "assets"), filepath.Join(dir, "instances", instance, "minecraft"), "Player") + auth, err := MicrosoftAuth(i.app.Auth) + if err != nil { + fmt.Printf("unable to authenticate: %s\n", err) + return + } + args, err := GetOnlineLaunchArgs(instanceObject.MinecraftVersion, filepath.Join(dir, "lib"), filepath.Join(dir, "bin"), filepath.Join(dir, "assets"), filepath.Join(dir, "instances", instance, "minecraft"), auth) if err != nil { fmt.Printf("unable to get launch args: %s\n", err) } diff --git a/fclauncher/app.go b/fclauncher/app.go index 0d9d9c5..9cbc181 100644 --- a/fclauncher/app.go +++ b/fclauncher/app.go @@ -69,6 +69,7 @@ func (a *App) CheckPrerequisites() { a.Java.InstallJavaVer(21) a.Status("Java 21 Installed") } + a.Status("Logging in with Microsoft") dir, _ := os.UserConfigDir() authenticated := false if _, err := os.Stat(filepath.Join(dir, "FCLauncher", "authentication.json")); err == nil { diff --git a/fclauncher/auth.go b/fclauncher/auth.go index 5ec10f3..aa952c5 100644 --- a/fclauncher/auth.go +++ b/fclauncher/auth.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "encoding/json" "fmt" "io" @@ -15,7 +16,7 @@ import ( type LauncherAuth struct { Id string Name string - token string + Token string } type McProfile struct { @@ -151,3 +152,69 @@ func TokenRefresh(app App, auth authenticationResp) (authenticationResp, error) json.Unmarshal(data, &authResp) return authResp, nil } + +func MicrosoftAuth(auth authenticationResp) (LauncherAuth, error) { + //Xbox Live Auth + req, _ := json.Marshal(xboxAuthRequest{Properties: xboxAuthProperties{AuthMethod: "RPS", SiteName: "user.auth.xboxlive.com", RpsTicket: "d="+auth.Access_token}, RelyingParty: "http://auth.xboxlive.com", TokenType: "JWT"}) + client := http.Client{} + httpreq, _ := http.NewRequest("POST", "https://user.auth.xboxlive.com/user/authenticate", bytes.NewBuffer(req)) + httpreq.Header.Add("x-xbl-contract-version", "1") + httpreq.Header.Add("Content-Type", "application/json") + httpreq.Header.Add("Accept", "application/json") + httpResp, err := client.Do(httpreq) + if err != nil { + return LauncherAuth{}, fmt.Errorf("unable to obtain xbox live token: %e\n", err) + } + defer httpResp.Body.Close() + if httpResp.StatusCode != 200 { + return LauncherAuth{}, fmt.Errorf("unable to obtain xbox live token: %s\n", httpResp.Status) + } + d,_ := io.ReadAll(httpResp.Body) + xblAuth := xboxAuthResponse{} + json.Unmarshal(d, &xblAuth) + xstsData, _ := json.Marshal(XSTSRequest{Properties: XSTSProperties{SandboxId: "RETAIL", UserTokens: []string{xblAuth.Token}}, RelyingParty: "rp://api.minecraftservices.com/", TokenType: "JWT"}) + httpXstsReq, _ := http.NewRequest("POST", "https://xsts.auth.xboxlive.com/xsts/authorize", bytes.NewBuffer(xstsData)) + httpXstsReq.Header.Add("Content-Type", "application/json") + httpResp, err = client.Do(httpXstsReq) + if err != nil { + return LauncherAuth{}, fmt.Errorf("unable to obtain minecraft sts token: %e\n", err) + } + defer httpResp.Body.Close() + if httpResp.StatusCode != 200 { + return LauncherAuth{}, fmt.Errorf("unable to obtain minecraft sts token: %s\n", httpResp.Status) + } + d, _ = io.ReadAll(httpResp.Body) + mcApi := xboxAuthResponse{} + json.Unmarshal(d, &mcApi) + mcAuthData, _ := json.Marshal(McAuthRequest{Xtoken: "XBL 3.0 x=" + mcApi.DisplayClaims.Xui[0].Uhs+ ";" + mcApi.Token, Platform: "PC_LAUNCHER"}) + httpReqMC, _ := http.NewRequest("POST", "https://api.minecraftservices.com/launcher/login", bytes.NewBuffer(mcAuthData)) + httpReqMC.Header.Add("Content-Type", "application/json") + httpReqMC.Header.Add("Accept", "application/json") + resp, err := client.Do(httpReqMC) + if err != nil { + return LauncherAuth{}, fmt.Errorf("unable to obtain mojang auth token: %e\n", err) + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + return LauncherAuth{}, fmt.Errorf("unable to obtain mojang auth token: %s\n", resp.Status) + } + d, _ = io.ReadAll(resp.Body) + mcAuth := McAuthResponse{} + json.Unmarshal(d, &mcAuth) + httpreq, err = http.NewRequest("GET", "https://api.minecraftservices.com/minecraft/profile", new(bytes.Buffer)) + httpreq.Header.Add("Content-Type", "application/json") + httpreq.Header.Add("Accept", "application/json") + httpreq.Header.Add("Authorization", "Bearer "+mcAuth.Access_token) + resp, _ = client.Do(httpreq) + if err != nil { + return LauncherAuth{}, fmt.Errorf("unable to get profile data: %e\n", err) + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + return LauncherAuth{}, fmt.Errorf("unable to get profile data: %s\n", resp.Status) + } + data, _ := io.ReadAll(resp.Body) + profile := McProfile{} + json.Unmarshal(data, &profile) + return LauncherAuth{Id: profile.Id, Name: profile.Name, Token: mcAuth.Access_token}, nil +} diff --git a/fclauncher/minecraft.go b/fclauncher/minecraft.go index 225ad47..595f6c5 100644 --- a/fclauncher/minecraft.go +++ b/fclauncher/minecraft.go @@ -599,7 +599,7 @@ func GetOfflineLaunchArgs(mcVersion string, libDir string, binDir string, assetD return args, nil } -func GetOnlineLaunchArgs(mcVersion string, libDir string, binDir string, assetDir string, gameDir string, playerName string) ([]string, error) { +func GetOnlineLaunchArgs(mcVersion string, libDir string, binDir string, assetDir string, gameDir string, auth LauncherAuth) ([]string, error) { args, err := GetBaseLaunchArgs(mcVersion, libDir, binDir, assetDir, gameDir) if err != nil { return []string{}, fmt.Errorf("GatOfflineLaunchArgs: %e\n", err) @@ -608,13 +608,13 @@ func GetOnlineLaunchArgs(mcVersion string, libDir string, binDir string, assetDi for ind, val := range args { switch val{ case "${auth_player_name}": - args[ind] = val + args[ind] = auth.Name case "${auth_uuid}": - args[ind] = val + args[ind] = auth.Id case "${auth_access_token}": - args[ind] = val + args[ind] = auth.Token case "${auth_xuid}": - args[ind] = val + args[ind] = auth.Id default: } }