Skip to content

Commit 4399c89

Browse files
committed
support new auth
1 parent ffd7fcf commit 4399c89

File tree

8 files changed

+136
-72
lines changed

8 files changed

+136
-72
lines changed

handlers/worlds/packets.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package worlds
33
import (
44
"fmt"
55
"maps"
6+
"strings"
67
"time"
78

89
"github.com/bedrock-tool/bedrocktool/handlers/worlds/entity"
@@ -104,6 +105,13 @@ func (w *worldsHandler) packetHandlerPreLogin(_pk packet.Packet, timeReceived ti
104105
case *packet.BiomeDefinitionList:
105106
for _, biome := range pk.BiomeDefinitions {
106107
biomeName := pk.StringList[biome.NameIndex]
108+
sp := strings.SplitN(biomeName, ":", 2)
109+
if len(sp) > 1 {
110+
ns := sp[0]
111+
if ns == "minecraft" {
112+
biomeName = sp[1]
113+
}
114+
}
107115
_, ok := w.serverState.biomes.BiomeByName(biomeName)
108116
if !ok {
109117
w.serverState.biomes.Register(&customBiome{name: biomeName, biome: biome, pk: pk})

utils/auth/account.go

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"crypto/ecdsa"
66
"crypto/elliptic"
77
"crypto/rand"
8+
"crypto/x509"
89
"errors"
910
"fmt"
1011
"os"
@@ -27,11 +28,19 @@ type Account struct {
2728
gatherings *discovery.GatheringsService
2829
}
2930

31+
type accountTokenSource struct {
32+
account *Account
33+
}
34+
35+
func (a *accountTokenSource) Token() (t *oauth2.Token, err error) {
36+
return a.account.Token(context.Background())
37+
}
38+
3039
func (a *Account) Name() string {
3140
return a.name
3241
}
3342

34-
func (a *Account) Token() (t *oauth2.Token, err error) {
43+
func (a *Account) Token(ctx context.Context) (t *oauth2.Token, err error) {
3544
if a.token == nil {
3645
return nil, ErrNotLoggedIn
3746
}
@@ -60,11 +69,11 @@ func (a *Account) Discovery() (d *discovery.Discovery, err error) {
6069
}
6170

6271
func (a *Account) PlayfabXblToken(ctx context.Context) (*xbox.XBLToken, error) {
63-
liveToken, err := a.Token()
72+
liveToken, err := a.Token(ctx)
6473
if err != nil {
6574
return nil, err
6675
}
67-
return xbox.RequestXBLToken(ctx, liveToken, "rp://[playfabapi.com/](https://playfabapi.com/)", a.token.XboxDeviceType())
76+
return xbox.RequestXBLToken(ctx, liveToken, "rp://playfabapi.com/", a.token.XboxDeviceType())
6877
}
6978

7079
func (a *Account) MCToken(ctx context.Context) (*discovery.MCToken, error) {
@@ -115,7 +124,7 @@ func (a *Account) Gatherings(ctx context.Context) (*discovery.GatheringsService,
115124

116125
func (a *Account) Realms() *realms.Client {
117126
if a.realms == nil {
118-
a.realms = realms.NewClient(a, nil, "")
127+
a.realms = realms.NewClient(&accountTokenSource{account: a}, nil, "")
119128
}
120129
return a.realms
121130
}
@@ -148,18 +157,44 @@ func (a *Account) Chain(ctx context.Context) (ChainKey *ecdsa.PrivateKey, ChainD
148157
return ch.ChainKey, ch.ChainData, nil
149158
}
150159

151-
func (a *Account) authChain(ctx context.Context) (key *ecdsa.PrivateKey, chain string, err error) {
152-
key, _ = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
153-
liveToken, err := a.Token()
160+
func (a *Account) PfToken(ctx context.Context, publicKey *ecdsa.PublicKey) (string, error) {
161+
discovery, err := a.Discovery()
154162
if err != nil {
155-
return nil, "", fmt.Errorf("request Live Connect token: %w", err)
163+
return "", err
164+
}
165+
authService, err := discovery.AuthService()
166+
if err != nil {
167+
return "", err
168+
}
169+
mcToken, err := a.MCToken(ctx)
170+
if err != nil {
171+
return "", err
172+
}
173+
174+
keyData, _ := x509.MarshalPKIXPublicKey(publicKey)
175+
signedToken, _, err := authService.MultiplayerSessionStart(ctx, keyData, mcToken)
176+
return signedToken, err
177+
}
178+
179+
func (a *Account) XBLToken(ctx context.Context) (*auth.XBLToken, error) {
180+
liveToken, err := a.Token(ctx)
181+
if err != nil {
182+
return nil, fmt.Errorf("request Live Connect token: %w", err)
156183
}
157184
xsts, err := xbox.RequestXBLToken(ctx, liveToken, "https://multiplayer.minecraft.net/", a.token.XboxDeviceType())
158185
if err != nil {
159-
return nil, "", fmt.Errorf("request XBOX Live token: %w", err)
186+
return nil, fmt.Errorf("request XBOX Live token: %w", err)
160187
}
161-
xstsa := &auth.XBLToken{
188+
return &auth.XBLToken{
162189
AuthorizationToken: xsts.AuthorizationToken,
190+
}, nil
191+
}
192+
193+
func (a *Account) authChain(ctx context.Context) (key *ecdsa.PrivateKey, chain string, err error) {
194+
key, _ = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
195+
xstsa, err := a.XBLToken(ctx)
196+
if err != nil {
197+
return nil, "", err
163198
}
164199
chain, err = auth.RequestMinecraftChain(ctx, xstsa, key)
165200
if err != nil {

utils/auth/auth.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,6 @@ func (a *authSrv) Logout() {
8585
os.Remove(chainFileName(acc.name))
8686
}
8787

88-
func (a *authSrv) setAccount(acc *Account) {
89-
a.account.Store(acc)
90-
}
91-
9288
func (a *authSrv) Account() *Account {
9389
return a.account.Load()
9490
}

utils/discovery/authservice.go

Lines changed: 20 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
package discovery
22

33
import (
4-
"bytes"
54
"context"
6-
"encoding/json"
5+
"encoding/base64"
76
"fmt"
8-
"io"
97
"net/http"
108
"strings"
119
"time"
@@ -88,50 +86,26 @@ func (a *AuthService) StartSession(ctx context.Context, xblToken, titleid string
8886
return &resp.Result, nil
8987
}
9088

91-
func doRequest[T any](ctx context.Context, client *http.Client, method, url string, payload any, extraHeaders func(*http.Request)) (*T, error) {
92-
body, err := json.Marshal(payload)
93-
if err != nil {
94-
return nil, err
95-
}
96-
req, err := http.NewRequestWithContext(ctx, method, url, bytes.NewReader(body))
97-
if err != nil {
98-
return nil, err
99-
}
100-
req.Header.Set("Accept", "*/*")
101-
req.Header.Set("Content-Type", "application/json")
102-
req.Header.Set("User-Agent", minecraftUserAgent)
103-
req.Header.Set("Accept-Language", "en-US,en;q=0.5")
104-
req.Header.Set("Cache-Control", "no-cache")
105-
if extraHeaders != nil {
106-
extraHeaders(req)
107-
}
108-
109-
res, err := client.Do(req)
110-
if err != nil {
111-
return nil, err
112-
}
113-
defer res.Body.Close()
114-
115-
if res.StatusCode >= 400 {
116-
bodyResp, err := io.ReadAll(res.Body)
117-
if err != nil {
118-
return nil, err
119-
}
120-
var resp map[string]any
121-
err = json.Unmarshal(bodyResp, &resp)
122-
if err != nil {
123-
return nil, err
124-
}
125-
return nil, &JsonResponseError{
126-
Status: res.Status,
127-
Data: resp,
128-
}
129-
}
89+
type multiplayerSessionStartResponse struct {
90+
Result struct {
91+
IssuedAt time.Time `json:"issuedAt"`
92+
SignedToken string `json:"signedToken"`
93+
ValidUntil time.Time `json:"validUntil"`
94+
} `json:"result"`
95+
}
13096

131-
var resp T
132-
err = json.NewDecoder(res.Body).Decode(&resp)
97+
func (a *AuthService) MultiplayerSessionStart(ctx context.Context, publicKey []byte, mcToken *MCToken) (signedToken string, validUntil time.Time, err error) {
98+
resp, err := doRequest[multiplayerSessionStartResponse](ctx, http.DefaultClient, "POST",
99+
fmt.Sprintf("%s/api/v1.0/multiplayer/session/start", a.ServiceURI),
100+
map[string]any{
101+
"publicKey": base64.RawStdEncoding.EncodeToString(publicKey),
102+
},
103+
func(req *http.Request) {
104+
req.Header.Set("Authorization", mcToken.AuthorizationHeader)
105+
},
106+
)
133107
if err != nil {
134-
return nil, err
108+
return "", time.Time{}, err
135109
}
136-
return &resp, nil
110+
return resp.Result.SignedToken, resp.Result.ValidUntil, nil
137111
}

utils/discovery/request.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package discovery
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"io"
8+
"net/http"
9+
)
10+
11+
func doRequest[T any](ctx context.Context, client *http.Client, method, url string, payload any, extraHeaders func(*http.Request)) (*T, error) {
12+
body, err := json.Marshal(payload)
13+
if err != nil {
14+
return nil, err
15+
}
16+
req, err := http.NewRequestWithContext(ctx, method, url, bytes.NewReader(body))
17+
if err != nil {
18+
return nil, err
19+
}
20+
req.Header.Set("Accept", "*/*")
21+
req.Header.Set("Content-Type", "application/json")
22+
req.Header.Set("User-Agent", minecraftUserAgent)
23+
req.Header.Set("Accept-Language", "en-US,en;q=0.5")
24+
req.Header.Set("Cache-Control", "no-cache")
25+
if extraHeaders != nil {
26+
extraHeaders(req)
27+
}
28+
29+
res, err := client.Do(req)
30+
if err != nil {
31+
return nil, err
32+
}
33+
defer res.Body.Close()
34+
35+
if res.StatusCode >= 400 {
36+
bodyResp, err := io.ReadAll(res.Body)
37+
if err != nil {
38+
return nil, err
39+
}
40+
var resp map[string]any
41+
err = json.Unmarshal(bodyResp, &resp)
42+
if err != nil {
43+
return nil, err
44+
}
45+
return nil, &JsonResponseError{
46+
Status: res.Status,
47+
Data: resp,
48+
}
49+
}
50+
51+
var resp T
52+
err = json.NewDecoder(res.Body).Decode(&resp)
53+
if err != nil {
54+
return nil, err
55+
}
56+
return &resp, nil
57+
}

utils/proxy/packet_logger.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ func (p *packetLogger) logPacket(pk packet.Packet, t time.Time, toServer bool) e
8484
utils.DumpStruct(p.packetLogWriter, pk)
8585
p.packetLogWriter.Write([]byte("\n\n\n"))
8686
p.packetLogWriter.Flush()
87+
//switch pk := pk.(type) {
88+
//case *packet.Login:
89+
// fmt.Fprintf(p.packetLogWriter, "%s\n", hex.EncodeToString(pk.ConnectionRequest))
90+
//}
8791
}
8892

8993
var dir string = dirS2C

utils/proxy/session.go

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ func (s *Session) connectServer(ctx context.Context, rpHandler *resourcepacks.Re
378378

379379
logrus.Info(locale.Loc("connecting", locale.Strmap{"Address": address}))
380380
dialer := minecraft.Dialer{
381-
TokenSource: s.connectInfo.Account,
381+
AuthSource: s.connectInfo.Account,
382382
DisconnectOnUnknownPackets: false,
383383
ErrorLog: slog.Default(),
384384
PacketFunc: s.packetFunc,
@@ -399,16 +399,6 @@ func (s *Session) connectServer(ctx context.Context, rpHandler *resourcepacks.Re
399399
conn.SetPrePlayPacketHandler(s.serverPrePlayHandler)
400400
},
401401
}
402-
for range 3 {
403-
dialer.ChainKey, dialer.ChainData, err = s.connectInfo.Account.Chain(s.ctx)
404-
if err != nil {
405-
continue
406-
}
407-
break
408-
}
409-
if err != nil {
410-
return err
411-
}
412402

413403
_, err = dialer.DialContext(ctx, "raknet", address, 20*time.Second)
414404
if err != nil {

0 commit comments

Comments
 (0)