2024-10-25 06:23:15 -06:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2024-10-25 09:06:54 -06:00
|
|
|
"bytes"
|
2024-10-29 12:01:22 -06:00
|
|
|
"crypto/sha1"
|
|
|
|
"encoding/hex"
|
2024-10-25 08:05:21 -06:00
|
|
|
"encoding/json"
|
2024-10-25 06:23:15 -06:00
|
|
|
"fmt"
|
2024-10-25 08:05:21 -06:00
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
2024-10-26 22:49:24 -06:00
|
|
|
"os"
|
2024-10-29 16:54:31 -06:00
|
|
|
"os/exec"
|
2024-10-26 22:49:24 -06:00
|
|
|
"path/filepath"
|
2024-10-29 16:54:31 -06:00
|
|
|
"runtime"
|
2024-10-29 12:01:22 -06:00
|
|
|
"strings"
|
2024-10-25 08:05:21 -06:00
|
|
|
"time"
|
2024-10-29 16:54:31 -06:00
|
|
|
|
2024-10-25 06:23:15 -06:00
|
|
|
)
|
|
|
|
|
2024-10-25 08:05:21 -06:00
|
|
|
const client_id string = "9305aeb8-5ecb-4e7a-b28f-c33aefcfbd8d"
|
|
|
|
|
2024-10-29 16:54:31 -06:00
|
|
|
type McProfile struct {
|
|
|
|
Id string
|
|
|
|
Name string
|
|
|
|
}
|
|
|
|
|
2024-10-25 12:27:29 -06:00
|
|
|
type Authentication struct {
|
|
|
|
Access authenticationResp
|
|
|
|
XboxAuth xboxAuthResponse
|
|
|
|
XboxAPI xboxAuthResponse
|
|
|
|
McAPI xboxAuthResponse
|
2024-10-29 12:01:22 -06:00
|
|
|
McAuth McAuthResponse
|
2024-10-29 16:54:31 -06:00
|
|
|
Profile McProfile
|
2024-10-25 12:27:29 -06:00
|
|
|
}
|
|
|
|
|
2024-10-25 08:05:21 -06:00
|
|
|
type devCodeResp struct {
|
|
|
|
User_code string
|
|
|
|
Device_code string
|
|
|
|
Verification_uri string
|
|
|
|
Expires_in string
|
|
|
|
Interval int
|
|
|
|
Message string
|
|
|
|
}
|
|
|
|
|
|
|
|
type authenticationResp struct {
|
|
|
|
Access_token string
|
|
|
|
Token_type string
|
|
|
|
Refresh_token string
|
|
|
|
Expires_in string
|
|
|
|
Error string
|
|
|
|
Error_description string
|
|
|
|
}
|
|
|
|
|
2024-10-25 09:06:54 -06:00
|
|
|
type xboxAuthProperties struct {
|
|
|
|
AuthMethod string
|
|
|
|
SiteName string
|
|
|
|
RpsTicket string
|
|
|
|
}
|
|
|
|
|
|
|
|
type xboxAuthRequest struct {
|
|
|
|
Properties xboxAuthProperties
|
|
|
|
RelyingParty string
|
|
|
|
TokenType string
|
|
|
|
}
|
|
|
|
|
|
|
|
type xboxDisplayClaim struct {
|
|
|
|
Uhs string
|
2024-10-25 12:27:29 -06:00
|
|
|
Gtg string
|
|
|
|
Xid string
|
|
|
|
Agg string
|
|
|
|
Usr string
|
|
|
|
Utr string
|
|
|
|
Prv string
|
2024-10-25 09:06:54 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
type xboxDisplayClaims struct {
|
|
|
|
Xui []xboxDisplayClaim
|
|
|
|
}
|
|
|
|
|
|
|
|
type xboxAuthResponse struct {
|
|
|
|
IssueInstant time.Time
|
|
|
|
NotAfter time.Time
|
|
|
|
Token string
|
|
|
|
DisplayClaims xboxDisplayClaims
|
|
|
|
}
|
|
|
|
|
|
|
|
type XSTSProperties struct {
|
|
|
|
SandboxId string
|
|
|
|
UserTokens []string
|
|
|
|
}
|
|
|
|
|
|
|
|
type XSTSRequest struct {
|
|
|
|
Properties XSTSProperties
|
|
|
|
RelyingParty string
|
|
|
|
TokenType string
|
|
|
|
}
|
|
|
|
|
2024-10-25 12:27:29 -06:00
|
|
|
type McAuthRequest struct {
|
|
|
|
Xtoken string `json:"xtoken"`
|
|
|
|
Platform string `json:"platform"`
|
|
|
|
}
|
|
|
|
|
2024-10-29 12:01:22 -06:00
|
|
|
type McAuthResponse struct {
|
|
|
|
Username string
|
|
|
|
Access_token string
|
|
|
|
Expires_in int
|
|
|
|
token_type string
|
2024-10-25 12:27:29 -06:00
|
|
|
}
|
|
|
|
|
2024-10-29 12:01:22 -06:00
|
|
|
type McVersionManifestEntry struct {
|
|
|
|
Id string
|
|
|
|
Type string
|
|
|
|
Url string
|
|
|
|
Time time.Time
|
|
|
|
ReleaseTime time.Time
|
|
|
|
Sha1 string
|
|
|
|
ComplianceLevel int
|
|
|
|
}
|
|
|
|
|
|
|
|
type McLatestEntry struct {
|
|
|
|
Release string
|
|
|
|
Snapshot string
|
|
|
|
}
|
|
|
|
|
|
|
|
type McVersionManifest struct {
|
|
|
|
Latest McLatestEntry
|
|
|
|
Versions []McVersionManifestEntry
|
|
|
|
}
|
|
|
|
|
|
|
|
type McArguments struct {
|
2024-10-29 16:54:31 -06:00
|
|
|
Game []string
|
|
|
|
Jvm []string
|
2024-10-29 12:01:22 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
type McAssetIndex struct {
|
|
|
|
Id string
|
|
|
|
Sha1 string
|
|
|
|
Size int
|
|
|
|
TotalSize int
|
|
|
|
Url string
|
|
|
|
}
|
|
|
|
|
|
|
|
type McDownload struct {
|
|
|
|
Sha1 string
|
|
|
|
Size int
|
|
|
|
Url string
|
|
|
|
}
|
|
|
|
|
|
|
|
type McDownloads struct {
|
2024-10-29 16:54:31 -06:00
|
|
|
Client McDownload
|
|
|
|
Client_mappings McDownload
|
|
|
|
Server McDownload
|
|
|
|
Server_mappings McDownload
|
2024-10-29 12:01:22 -06:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
type McJavaVersion struct {
|
|
|
|
Component string
|
|
|
|
MajorVersion int
|
|
|
|
}
|
|
|
|
|
|
|
|
type McLibraryArtifact struct {
|
|
|
|
Path string
|
|
|
|
Sha1 string
|
|
|
|
Size int
|
|
|
|
Url string
|
|
|
|
}
|
|
|
|
|
|
|
|
type McLibraryDownload struct {
|
|
|
|
Artifact McLibraryArtifact
|
|
|
|
}
|
|
|
|
|
2024-10-29 16:54:31 -06:00
|
|
|
type McRuleOs struct {
|
|
|
|
Name string
|
|
|
|
Version string
|
|
|
|
Arch string
|
|
|
|
}
|
|
|
|
|
|
|
|
type McRule struct {
|
|
|
|
Action string
|
|
|
|
Features map[string]bool
|
|
|
|
Os McRuleOs
|
|
|
|
}
|
|
|
|
|
2024-10-29 12:01:22 -06:00
|
|
|
type McLibrary struct {
|
|
|
|
Downloads McLibraryDownload
|
|
|
|
Name string
|
2024-10-29 16:54:31 -06:00
|
|
|
Rules []McRule
|
2024-10-29 12:01:22 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
type McMetadata struct {
|
|
|
|
Arguments McArguments
|
|
|
|
AssetIndex McAssetIndex
|
|
|
|
Assets string
|
|
|
|
complianceLevel int
|
|
|
|
Downloads McDownloads
|
|
|
|
Id string
|
|
|
|
JavaVersion McJavaVersion
|
|
|
|
Libraries []McLibrary
|
|
|
|
Logging interface{}
|
|
|
|
MainClass string
|
|
|
|
MinimumLauncherVersion int
|
|
|
|
ReleaseTime time.Time
|
|
|
|
Time time.Time
|
|
|
|
Type string
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-10-25 06:23:15 -06:00
|
|
|
func main() {
|
2024-10-26 22:49:24 -06:00
|
|
|
|
|
|
|
auth := Authentication{}
|
|
|
|
dir, _ := os.UserConfigDir()
|
|
|
|
if _, err := os.Stat(filepath.Join(dir, "minecraft_test", "authentication.json")); err != nil {
|
|
|
|
resp, err := http.PostForm("https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode", url.Values{
|
|
|
|
"client_id": {client_id},
|
|
|
|
"scope": {"XboxLive.SignIn XboxLive.offline_access"},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Device Auth Step: %s\n", err)
|
2024-10-25 06:23:15 -06:00
|
|
|
return
|
|
|
|
}
|
2024-10-25 08:05:21 -06:00
|
|
|
defer resp.Body.Close()
|
2024-10-26 22:49:24 -06:00
|
|
|
if resp.StatusCode != 200 {
|
|
|
|
fmt.Printf("Device Auth Step: %v\n", resp.Status)
|
|
|
|
return
|
2024-10-25 08:05:21 -06:00
|
|
|
}
|
2024-10-26 22:49:24 -06:00
|
|
|
data, _ := io.ReadAll(resp.Body)
|
|
|
|
codeResp := devCodeResp{}
|
|
|
|
json.Unmarshal(data, &codeResp)
|
|
|
|
fmt.Println(codeResp.Message)
|
|
|
|
ticker := time.NewTicker(time.Second * time.Duration(codeResp.Interval))
|
|
|
|
defer ticker.Stop()
|
|
|
|
for range ticker.C {
|
|
|
|
resp, err := http.PostForm("https://login.microsoftonline.com/consumers/oauth2/v2.0/token", url.Values{
|
|
|
|
"client_id": {client_id},
|
|
|
|
"grant_type": {"urn:ietf:params:oauth:grant-type:device_code"},
|
|
|
|
"device_code": {codeResp.Device_code},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Authentication Request Error: %s\n", err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
//if resp.StatusCode != 200 {
|
|
|
|
// fmt.Printf("Authentication Request Error: %s\n", resp.Status)
|
|
|
|
//}
|
|
|
|
data, _ := io.ReadAll(resp.Body)
|
|
|
|
authResp := authenticationResp{}
|
|
|
|
json.Unmarshal(data, &authResp)
|
|
|
|
if authResp.Error == "" {
|
|
|
|
fmt.Printf("Authenticated!\n")
|
|
|
|
auth.Access = authResp
|
|
|
|
break
|
|
|
|
}
|
2024-10-25 08:05:21 -06:00
|
|
|
|
2024-10-26 22:49:24 -06:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
f, _ := os.OpenFile(filepath.Join(dir, "minecraft_test", "authentication.json"), os.O_CREATE|os.O_RDWR, 0755)
|
|
|
|
data, _ := io.ReadAll(f)
|
|
|
|
json.Unmarshal(data, &auth.Access)
|
2024-10-29 05:55:36 -06:00
|
|
|
resp, err := http.PostForm("https://login.microsoftonline.com/consumers/oauth2/v2.0/token", url.Values{
|
|
|
|
"client_id": {client_id},
|
|
|
|
"grant_type": {"refresh_token"},
|
|
|
|
"refresh_token": {auth.Access.Refresh_token},
|
|
|
|
"scope": {"XboxLive.SignIn XboxLive.offline_access"},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Authentication Request Error: %s\n", err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
//if resp.StatusCode != 200 {
|
|
|
|
// fmt.Printf("Authentication Request Error: %s\n", resp.Status)
|
|
|
|
//}
|
|
|
|
data, _ = io.ReadAll(resp.Body)
|
|
|
|
authResp := authenticationResp{}
|
|
|
|
json.Unmarshal(data, &authResp)
|
|
|
|
if authResp.Error == "" {
|
|
|
|
fmt.Printf("Authenticated!\n")
|
|
|
|
auth.Access = authResp
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-10-25 06:23:15 -06:00
|
|
|
}
|
2024-10-29 05:55:36 -06:00
|
|
|
os.MkdirAll(filepath.Join(dir, "minecraft_test"), 0755)
|
|
|
|
f, _ := os.OpenFile(filepath.Join(dir, "minecraft_test", "authentication.json"), os.O_CREATE|os.O_RDWR, 0755)
|
|
|
|
defer f.Close()
|
|
|
|
data, _ := json.Marshal(auth.Access)
|
|
|
|
f.Write(data)
|
|
|
|
|
2024-10-25 12:27:29 -06:00
|
|
|
req, _ := json.Marshal(xboxAuthRequest{Properties: xboxAuthProperties{AuthMethod: "RPS", SiteName: "user.auth.xboxlive.com", RpsTicket: "d=" + auth.Access.Access_token}, RelyingParty: "http://auth.xboxlive.com", TokenType: "JWT"})
|
2024-10-25 09:06:54 -06:00
|
|
|
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 {
|
|
|
|
fmt.Printf("XboxLive Error: %s\n", err)
|
|
|
|
}
|
|
|
|
defer httpResp.Body.Close()
|
|
|
|
if httpResp.StatusCode != 200 {
|
|
|
|
fmt.Printf("XboxLive Error: %s\n", httpResp.Status)
|
|
|
|
}
|
|
|
|
d, _ := io.ReadAll(httpResp.Body)
|
2024-10-25 12:27:29 -06:00
|
|
|
json.Unmarshal(d, &auth.XboxAuth)
|
|
|
|
xstsData, _ := json.Marshal(XSTSRequest{Properties: XSTSProperties{SandboxId: "RETAIL", UserTokens: []string{auth.XboxAuth.Token}}, RelyingParty: "http://xboxlive.com", TokenType: "JWT"})
|
2024-10-25 09:06:54 -06:00
|
|
|
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 {
|
|
|
|
fmt.Printf("XboxLive STS error: %s\n", err)
|
|
|
|
}
|
|
|
|
defer httpResp.Body.Close()
|
|
|
|
if httpResp.StatusCode != 200 {
|
|
|
|
fmt.Printf("XboxLive STS error: %s\n", httpResp.Status)
|
|
|
|
}
|
|
|
|
d, _ = io.ReadAll(httpResp.Body)
|
2024-10-25 12:27:29 -06:00
|
|
|
json.Unmarshal(d, &auth.XboxAPI)
|
|
|
|
|
|
|
|
xstsData, _ = json.Marshal(XSTSRequest{Properties: XSTSProperties{SandboxId: "RETAIL", UserTokens: []string{auth.XboxAuth.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 {
|
|
|
|
fmt.Printf("Minecraft STS error: %s\n", err)
|
|
|
|
}
|
|
|
|
defer httpResp.Body.Close()
|
|
|
|
if httpResp.StatusCode != 200 {
|
|
|
|
fmt.Printf("Minecraft STS error: %s\n", httpResp.Status)
|
|
|
|
}
|
|
|
|
d, _ = io.ReadAll(httpResp.Body)
|
|
|
|
json.Unmarshal(d, &auth.McAPI)
|
|
|
|
if auth.McAPI.DisplayClaims.Xui[0].Uhs != auth.XboxAPI.DisplayClaims.Xui[0].Uhs {
|
|
|
|
fmt.Printf("Warning: Inconsistant user hash!")
|
|
|
|
}
|
2024-10-29 12:01:22 -06:00
|
|
|
mcAuthData, _ := json.Marshal(McAuthRequest{Xtoken: "XBL3.0 x=" + auth.McAPI.DisplayClaims.Xui[0].Uhs + ";" + auth.McAPI.Token, Platform: "PC_LAUNCHER"})
|
|
|
|
httpReqMC, _ := http.NewRequest("POST", "https://api.minecraftservices.com/launcher/login", bytes.NewBuffer(mcAuthData))
|
2024-10-25 12:27:29 -06:00
|
|
|
httpReqMC.Header.Add("Content-Type", "application/json")
|
|
|
|
httpReqMC.Header.Add("Accept", "application/json")
|
2024-10-26 22:49:24 -06:00
|
|
|
resp, err := client.Do(httpReqMC)
|
2024-10-25 12:27:29 -06:00
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("MC Auth Error: %s\n", err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != 200 {
|
|
|
|
fmt.Printf("MC Auth Error: %s\n", resp.Status)
|
|
|
|
}
|
|
|
|
d, _ = io.ReadAll(resp.Body)
|
2024-10-29 12:01:22 -06:00
|
|
|
json.Unmarshal(d, &auth.McAuth)
|
2024-10-29 16:54:31 -06:00
|
|
|
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 "+auth.McAuth.Access_token)
|
|
|
|
resp, _ = client.Do(httpReq)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Error obtaining mc profile information: %s\n", err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
data, _ = io.ReadAll(resp.Body)
|
|
|
|
json.Unmarshal(data, &auth.Profile)
|
2024-10-29 12:01:22 -06:00
|
|
|
resp, err = http.Get("https://piston-meta.mojang.com/mc/game/version_manifest_v2.json")
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("manifest error")
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
data, _ = io.ReadAll(resp.Body)
|
|
|
|
versionManifest := McVersionManifest{}
|
|
|
|
json.Unmarshal(data, &versionManifest)
|
|
|
|
resp, err = http.Get(versionManifest.Versions[0].Url)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("metadata error")
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
data, _ = io.ReadAll(resp.Body)
|
|
|
|
var metadata McMetadata
|
|
|
|
json.Unmarshal(data, &metadata)
|
2024-10-29 16:54:31 -06:00
|
|
|
os.MkdirAll(filepath.Join(dir, "minecraft_test", "assets", "indexes"), 0755)
|
|
|
|
os.MkdirAll(filepath.Join(dir, "minecraft_test", "assets", "objects"), 0755)
|
|
|
|
download_index := false
|
|
|
|
if _, err := os.Stat(filepath.Join(dir, "minecraft_test", "assets", "indexes", metadata.Assets+".json")); err == nil {
|
|
|
|
f, _ := os.OpenFile(filepath.Join(dir, "minecraft_test", "assets", "indexes", metadata.Assets+".json"), os.O_RDONLY, 0755)
|
|
|
|
defer f.Close()
|
|
|
|
data, _ = io.ReadAll(f)
|
|
|
|
sha := sha1.Sum(data)
|
|
|
|
if hex.EncodeToString(sha[:20]) != metadata.AssetIndex.Sha1 {
|
|
|
|
download_index = true
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
download_index = true
|
2024-10-29 12:01:22 -06:00
|
|
|
}
|
2024-10-29 16:54:31 -06:00
|
|
|
if download_index {
|
|
|
|
resp, err = http.Get(metadata.AssetIndex.Url)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("asset index error")
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
data, _ = io.ReadAll(resp.Body)
|
|
|
|
sha := sha1.Sum(data)
|
|
|
|
if hex.EncodeToString(sha[:20]) != metadata.AssetIndex.Sha1 {
|
|
|
|
fmt.Printf("Error downloading asset index")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
f, _ = os.OpenFile(filepath.Join(dir, "minecraft_test", "assets", "indexes", metadata.Assets + ".json"), os.O_CREATE|os.O_RDWR, 0755)
|
|
|
|
defer f.Close()
|
|
|
|
f.Write(data)
|
2024-10-29 12:01:22 -06:00
|
|
|
}
|
|
|
|
var index map[string]interface{}
|
|
|
|
json.Unmarshal(data, &index)
|
|
|
|
index = index["objects"].(map[string]interface{})
|
2024-10-29 16:54:31 -06:00
|
|
|
for name, asset := range index {
|
2024-10-29 12:01:22 -06:00
|
|
|
asset_map := asset.(map[string]interface{})
|
2024-10-29 16:54:31 -06:00
|
|
|
path := asset_map["hash"].(string)[:2] + "/" + asset_map["hash"].(string)
|
|
|
|
if _, err = os.Stat(filepath.Join(dir, "minecraft_test", "assets", "objects", path)); err == nil {
|
|
|
|
f, _ := os.OpenFile(filepath.Join(dir, "minecraft_test", "assets", "objects", path), os.O_RDONLY, 0755)
|
2024-10-29 12:01:22 -06:00
|
|
|
data, _ := io.ReadAll(f)
|
|
|
|
sha := sha1.Sum(data)
|
|
|
|
if hex.EncodeToString(sha[:20]) == asset_map["hash"].(string) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fmt.Printf("Downloading %s: ", name)
|
|
|
|
resp, err = http.Get(fmt.Sprintf("https://resources.download.minecraft.net/%s/%s", asset_map["hash"].(string)[:2], asset_map["hash"].(string)))
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Error\n")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
data, _ = io.ReadAll(resp.Body)
|
2024-10-29 16:54:31 -06:00
|
|
|
sha := sha1.Sum(data)
|
2024-10-29 12:01:22 -06:00
|
|
|
if hex.EncodeToString(sha[:20]) != asset_map["hash"].(string) {
|
|
|
|
fmt.Printf("Sha1 Mismatch\n")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
fmt.Printf("Ok\n")
|
2024-10-29 16:54:31 -06:00
|
|
|
os.MkdirAll(filepath.Join(dir, "minecraft_test", "assets", "objects", asset_map["hash"].(string)[:2]), 0755)
|
|
|
|
f, _ := os.OpenFile(filepath.Join(dir, "minecraft_test", "assets", "objects", path), os.O_CREATE|os.O_RDWR, 0755)
|
2024-10-29 12:01:22 -06:00
|
|
|
defer f.Close()
|
|
|
|
f.Write(data)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, lib := range metadata.Libraries {
|
2024-10-29 16:54:31 -06:00
|
|
|
if _, err = os.Stat(filepath.Join(dir, "minecraft_test", "lib", lib.Downloads.Artifact.Path)); err == nil {
|
|
|
|
f, _ := os.OpenFile(filepath.Join(dir, "minecraft_test", "lib", lib.Downloads.Artifact.Path), os.O_RDONLY, 0755)
|
|
|
|
defer f.Close()
|
|
|
|
data, _ := io.ReadAll(f)
|
|
|
|
sha := sha1.Sum(data)
|
|
|
|
if hex.EncodeToString(sha[:20]) == lib.Downloads.Artifact.Sha1 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
2024-10-29 12:01:22 -06:00
|
|
|
fmt.Printf("Downloading %s: ", lib.Name)
|
|
|
|
resp, err = http.Get(lib.Downloads.Artifact.Url)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Error\n")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
data, _ = io.ReadAll(resp.Body)
|
2024-10-29 16:54:31 -06:00
|
|
|
sha := sha1.Sum(data)
|
2024-10-29 12:01:22 -06:00
|
|
|
if hex.EncodeToString(sha[:20]) != lib.Downloads.Artifact.Sha1 {
|
|
|
|
fmt.Printf("Sha1 Mismatch\n")
|
|
|
|
return
|
|
|
|
}
|
2024-10-29 16:54:31 -06:00
|
|
|
path := ""
|
|
|
|
tokens := strings.Split(lib.Downloads.Artifact.Path, "/")
|
|
|
|
for ind, token := range tokens {
|
|
|
|
if ind != len(tokens)-1 {
|
|
|
|
path = filepath.Join(path, token)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
os.MkdirAll(filepath.Join(dir, "minecraft_test", "lib", path), 0755)
|
|
|
|
f, _ := os.OpenFile(filepath.Join(dir, "minecraft_test", "lib", lib.Downloads.Artifact.Path), os.O_CREATE|os.O_RDWR, 0755)
|
|
|
|
defer f.Close()
|
|
|
|
f.Write(data)
|
|
|
|
fmt.Printf("OK\n")
|
|
|
|
}
|
|
|
|
download := false
|
|
|
|
if os.Stat(filepath.Join(dir, "minecraft_test", "bin", metadata.Id, "client.jar")); err == nil {
|
|
|
|
f, _ := os.OpenFile(filepath.Join(dir, "minecraft_test", "bin", metadata.Id, "client.jar"), os.O_RDONLY, 0755)
|
|
|
|
defer f.Close()
|
|
|
|
data, _ := io.ReadAll(f)
|
|
|
|
sha := sha1.Sum(data)
|
|
|
|
if hex.EncodeToString(sha[:20]) != metadata.Downloads.Client.Sha1 {
|
|
|
|
download = true
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
download = true
|
|
|
|
}
|
|
|
|
|
|
|
|
if download {
|
|
|
|
fmt.Printf("Downloading minecraft.jar: ")
|
|
|
|
req, err := http.Get(metadata.Downloads.Client.Url)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("ERROR\n")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer req.Body.Close()
|
|
|
|
data, _ := io.ReadAll(req.Body)
|
|
|
|
sha := sha1.Sum(data)
|
|
|
|
if hex.EncodeToString(sha[:20]) != metadata.Downloads.Client.Sha1 {
|
|
|
|
fmt.Printf("Sha Mismatch\n")
|
|
|
|
return
|
|
|
|
}
|
2024-10-29 12:01:22 -06:00
|
|
|
fmt.Printf("OK\n")
|
2024-10-29 16:54:31 -06:00
|
|
|
os.MkdirAll(filepath.Join(dir, "minecraft_test", "bin", metadata.Id), 0755)
|
|
|
|
f, _ := os.OpenFile(filepath.Join(dir, "minecraft_test", "bin", metadata.Id, "client.jar"), os.O_CREATE|os.O_RDWR, 0755)
|
|
|
|
defer f.Close()
|
|
|
|
f.Write(data)
|
|
|
|
}
|
|
|
|
os.MkdirAll(filepath.Join(dir, "minecraft_test", "minecraft"), 0755)
|
|
|
|
args := []string{}
|
|
|
|
args = append(args, "-Xms512m")
|
|
|
|
args = append(args, "-Xmx1024m")
|
|
|
|
for _, val := range metadata.Arguments.Jvm {
|
|
|
|
val = strings.ReplaceAll(val, "${natives_directory}", filepath.Join(dir, "minecraft_test", "minecraft", "natives"))
|
|
|
|
switch val {
|
|
|
|
case "-cp":
|
|
|
|
args = append(args, val)
|
|
|
|
case "${classpath}":
|
|
|
|
arg := ""
|
|
|
|
for _, lib := range metadata.Libraries {
|
|
|
|
if lib.Rules != nil && lib.Rules[0].Os.Name != runtime.GOOS {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
arg += filepath.Join(dir, "minecraft_test", "lib", lib.Downloads.Artifact.Path) + ":"
|
|
|
|
}
|
|
|
|
arg += filepath.Join(dir, "minecraft_test", "bin", metadata.Id, "client.jar")
|
|
|
|
args = append(args, arg)
|
|
|
|
default:
|
|
|
|
//args = append(args, val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
args = append(args, "net.minecraft.client.main.Main")
|
|
|
|
|
|
|
|
for _, val := range metadata.Arguments.Game {
|
|
|
|
switch val{
|
|
|
|
case "${auth_player_name}":
|
|
|
|
args = append(args, auth.Profile.Name)
|
|
|
|
case "${version_name}":
|
|
|
|
args = append(args, metadata.Id)
|
|
|
|
case "${game_directory}":
|
|
|
|
args = append(args, filepath.Join(dir, "minecraft_test", "minecraft"))
|
|
|
|
case "${assets_root}":
|
|
|
|
args = append(args, filepath.Join(dir, "minecraft_test", "assets"))
|
|
|
|
case "${auth_uuid}":
|
|
|
|
args = append(args, auth.Profile.Id)
|
|
|
|
case "${auth_access_token}":
|
|
|
|
args = append(args, auth.McAuth.Access_token)
|
|
|
|
case "${clientid}":
|
|
|
|
args = append(args, client_id)
|
|
|
|
case "${auth_xuid}":
|
|
|
|
args = append(args, auth.Profile.Id)
|
|
|
|
case "${version_type}":
|
|
|
|
args = append(args, "release")
|
|
|
|
case "${user_type}":
|
|
|
|
args = append(args, "mojang")
|
|
|
|
case "${assets_index_name}":
|
|
|
|
args = append(args, metadata.Assets)
|
|
|
|
|
|
|
|
default:
|
|
|
|
args = append(args, val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Printf("Args: %+v", args)
|
|
|
|
|
|
|
|
cmd := exec.Command("/usr/lib/jvm/java-21-openjdk/bin/java", args...)
|
|
|
|
out, err := cmd.CombinedOutput()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Error: %s\n", err)
|
2024-10-29 12:01:22 -06:00
|
|
|
}
|
2024-10-29 16:54:31 -06:00
|
|
|
fmt.Printf("Output: %s\n", out)
|
2024-10-29 12:01:22 -06:00
|
|
|
|
2024-10-25 08:05:21 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
fmt.Println("Requesting Oauth")
|
|
|
|
token, err := auth.RequestLiveToken()
|
2024-10-25 06:23:15 -06:00
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return
|
2024-10-25 08:05:21 -06:00
|
|
|
} else {
|
|
|
|
ts := auth.RefreshTokenSource(token)
|
|
|
|
fmt.Println("Generating Key")
|
|
|
|
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
fmt.Println("Requesting XBL Token")
|
|
|
|
token, err = ts.Token()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
xbl, err := auth.RequestXBLToken(ctx, token, "rp://api.minecraftservices.com/")
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
fmt.Println("Requesting Minecraft Chain")
|
|
|
|
ctx = context.Background()
|
|
|
|
_, err = auth.RequestMinecraftChain(ctx, xbl, key)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}*/
|
2024-10-25 06:23:15 -06:00
|
|
|
}
|