ONLINE MODE
This commit is contained in:
@@ -0,0 +1,139 @@
|
|||||||
|
package strom
|
||||||
|
|
||||||
|
// https://github.com/Tnze/go-mc/blob/master/net/CFB8/cfb8.go
|
||||||
|
// Package CFB8 implements CFB8 block cipher mode of operation used by Minecraft protocol.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/subtle"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CFB8 struct {
|
||||||
|
c cipher.Block
|
||||||
|
blockSize int
|
||||||
|
ivPos int
|
||||||
|
iv []byte
|
||||||
|
de bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCFB8Decrypt(c cipher.Block, iv []byte) *CFB8 {
|
||||||
|
return newCFB8(c, iv, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCFB8Encrypt(c cipher.Block, iv []byte) *CFB8 {
|
||||||
|
return newCFB8(c, iv, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCFB8(c cipher.Block, iv []byte, de bool) *CFB8 {
|
||||||
|
cp := make([]byte, len(iv)*3)
|
||||||
|
copy(cp, iv)
|
||||||
|
return &CFB8{
|
||||||
|
c: c,
|
||||||
|
blockSize: c.BlockSize(),
|
||||||
|
iv: cp,
|
||||||
|
de: de,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cf *CFB8) XORKeyStream(dst, src []byte) {
|
||||||
|
if len(src) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(dst) < len(src) {
|
||||||
|
panic("cfb8: output smaller than input")
|
||||||
|
}
|
||||||
|
|
||||||
|
// If dst and src does not overlap in first block size,
|
||||||
|
// and the length of src is greater than 2*blockSize,
|
||||||
|
// we can use an optimized implementation.
|
||||||
|
if len(src) > cf.blockSize<<1 &&
|
||||||
|
(uintptr(unsafe.Pointer(&dst[0]))+uintptr(cf.blockSize) <= uintptr(unsafe.Pointer(&src[0])) ||
|
||||||
|
uintptr(unsafe.Pointer(&src[0]))+uintptr(len(src)) <= uintptr(unsafe.Pointer(&dst[0]))) {
|
||||||
|
// encrypt/decrypt first blockSize bytes
|
||||||
|
// After this, the IV will come to the same as
|
||||||
|
// the last blockSize of ciphertext, so
|
||||||
|
// we can reuse them without copy.
|
||||||
|
cf.xorKeyStream(dst, src[:cf.blockSize])
|
||||||
|
var ciphertext []byte
|
||||||
|
if cf.de {
|
||||||
|
ciphertext = src
|
||||||
|
} else {
|
||||||
|
ciphertext = dst
|
||||||
|
}
|
||||||
|
dst = dst[cf.blockSize:]
|
||||||
|
src = src[cf.blockSize:]
|
||||||
|
iv := cf.iv
|
||||||
|
_ = iv[0] // bounds check hint to compiler; see golang.org/issue/14808
|
||||||
|
var (
|
||||||
|
i int
|
||||||
|
val byte
|
||||||
|
)
|
||||||
|
dst = dst[:len(src)]
|
||||||
|
if cf.de && // and requires to be non-overlapping at all
|
||||||
|
uintptr(unsafe.Pointer(&dst[0])) <= uintptr(unsafe.Pointer(&src[len(src)-1])) &&
|
||||||
|
uintptr(unsafe.Pointer(&src[0])) <= uintptr(unsafe.Pointer(&dst[len(dst)-1])) {
|
||||||
|
for i = 0; i < len(src)-cf.blockSize; i += 1 {
|
||||||
|
cf.c.Encrypt(dst[i:], ciphertext[i:])
|
||||||
|
}
|
||||||
|
subtle.XORBytes(dst, src[:i], dst)
|
||||||
|
for ; i < len(src); i += 1 {
|
||||||
|
cf.c.Encrypt(iv, ciphertext[i:])
|
||||||
|
dst[i] = src[i] ^ iv[0]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_ = ciphertext[len(src)]
|
||||||
|
for i, val = range src {
|
||||||
|
cf.c.Encrypt(iv, ciphertext[i:])
|
||||||
|
dst[i] = val ^ iv[0]
|
||||||
|
}
|
||||||
|
// for-range does not increase i in the last loop,
|
||||||
|
// compared to the classic for clause
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
// copy the current IV for next operation
|
||||||
|
copy(iv, ciphertext[i:i+cf.blockSize])
|
||||||
|
cf.ivPos = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cf.xorKeyStream(dst, src)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cf *CFB8) xorKeyStream(dst, src []byte) {
|
||||||
|
dst = dst[:len(src)] // remove bounds check in loop
|
||||||
|
for i, val := range src {
|
||||||
|
posPlusBlockSize := cf.ivPos + cf.blockSize
|
||||||
|
// fast mod; 2*blockSize must be a non-negative integer power of 2
|
||||||
|
tempPos := posPlusBlockSize & (cf.blockSize<<1 - 1)
|
||||||
|
// reuse space to store encrypted block
|
||||||
|
cf.c.Encrypt(cf.iv[tempPos:], cf.iv[cf.ivPos:])
|
||||||
|
// Only the first byte of the encrypted block is used
|
||||||
|
// for encryption/decryption, other bytes are ignored.
|
||||||
|
val ^= cf.iv[tempPos]
|
||||||
|
|
||||||
|
if cf.ivPos == cf.blockSize<<1 {
|
||||||
|
// bound reached; move to next round for next operation
|
||||||
|
// copy next block to the start of the ring buffer
|
||||||
|
copy(cf.iv, cf.iv[cf.ivPos+1:])
|
||||||
|
// insert the encrypted byte to the end of IV
|
||||||
|
if cf.de {
|
||||||
|
cf.iv[cf.blockSize-1] = src[i]
|
||||||
|
} else {
|
||||||
|
cf.iv[cf.blockSize-1] = val
|
||||||
|
}
|
||||||
|
cf.ivPos = 0
|
||||||
|
} else {
|
||||||
|
// insert the encrypted byte to the end of IV
|
||||||
|
if cf.de {
|
||||||
|
cf.iv[posPlusBlockSize] = src[i]
|
||||||
|
} else {
|
||||||
|
cf.iv[posPlusBlockSize] = val
|
||||||
|
}
|
||||||
|
// move to next block
|
||||||
|
cf.ivPos += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
dst[i] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-15
@@ -44,6 +44,8 @@ func (a Actor) ReceiveDirection() queser.Direction {
|
|||||||
|
|
||||||
type Connection struct {
|
type Connection struct {
|
||||||
net.Conn
|
net.Conn
|
||||||
|
R io.Reader
|
||||||
|
W io.Writer
|
||||||
CompressionThreshold int32
|
CompressionThreshold int32
|
||||||
State queser.State
|
State queser.State
|
||||||
Actor Actor
|
Actor Actor
|
||||||
@@ -69,7 +71,7 @@ func (c *Connection) Send(packet any) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = zlib.NewWriter(packetBuffer).Write(packetBytes)
|
_, err = zlib.NewWriter(packetBuffer).Write(rawPacketBuffer.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -78,29 +80,30 @@ func (c *Connection) Send(packet any) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = packetBuffer.Write(packetBytes)
|
_, err = packetBuffer.Write(rawPacketBuffer.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
packetBytes = packetBuffer.Bytes()
|
||||||
} else {
|
} else {
|
||||||
packetBytes = rawPacketBuffer.Bytes()
|
packetBytes = rawPacketBuffer.Bytes()
|
||||||
}
|
}
|
||||||
err = queser.VarInt(len(packetBytes)).Encode(c)
|
err = queser.VarInt(len(packetBytes)).Encode(c.W)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = c.Write(packetBytes)
|
_, err = c.W.Write(packetBytes)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Connection) Receive() (packet any, err error) {
|
func (c *Connection) Receive() (packet any, err error) {
|
||||||
var rawPacketLen queser.VarInt
|
var rawPacketLen queser.VarInt
|
||||||
rawPacketLen, err = rawPacketLen.Decode(c)
|
rawPacketLen, err = rawPacketLen.Decode(c.R)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rawPacketBytes, err := io.ReadAll(io.LimitReader(c, int64(rawPacketLen)))
|
rawPacketBytes, err := io.ReadAll(io.LimitReader(c.R, int64(rawPacketLen)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -143,14 +146,7 @@ func ClientConnect(addr string) (ret *Connection, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
ret.R = ret.Conn
|
||||||
}
|
ret.W = ret.Conn
|
||||||
|
|
||||||
func ConnectAndStart(addr string, inst HandlerInst) (ret *Connection, err error) {
|
|
||||||
ret, err = ClientConnect(addr)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = ret.Start(inst)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"strom"
|
"strom"
|
||||||
"strom/modules"
|
"strom/modules/loginclient"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
@@ -16,11 +16,11 @@ func must(err error) {
|
|||||||
func main() {
|
func main() {
|
||||||
c, err := strom.ClientConnect("127.0.0.1:25566")
|
c, err := strom.ClientConnect("127.0.0.1:25566")
|
||||||
must(err)
|
must(err)
|
||||||
err = c.Start(&modules.LoginClient{
|
err = c.Start(&loginclient.LoginClient{
|
||||||
Account: modules.Account{
|
Account: loginclient.Account{
|
||||||
Username: "Admin_rizz",
|
Username: "449stan_Ytb",
|
||||||
UUID: uuid.UUID{},
|
Uuid: uuid.MustParse("caec076c80c34637a31b44874ffa009d"),
|
||||||
Token: "",
|
Token: "eyJraWQiOiIwNDkxODEiLCJhbGciOiJSUzI1NiJ9.eyJ4dWlkIjoiMjUzNTQwOTA1OTUxMzgxOSIsImFnZyI6IkFkdWx0Iiwic3ViIjoiMjY4OGQ0ZTktZmZiZi00N2FkLTlkYWYtZDU3ZWY5Yzg5YWE0IiwiYXV0aCI6IlhCT1giLCJucyI6ImRlZmF1bHQiLCJyb2xlcyI6W10sImlzcyI6ImF1dGhlbnRpY2F0aW9uIiwiZmxhZ3MiOlsib3JkZXJzXzIwMjIiLCJtdWx0aXBsYXllciIsInR3b2ZhY3RvcmF1dGgiLCJtc2FtaWdyYXRpb25fc3RhZ2U0Il0sInByb2ZpbGVzIjp7Im1jIjoiY2FlYzA3NmMtODBjMy00NjM3LWEzMWItNDQ4NzRmZmEwMDlkIn0sInBsYXRmb3JtIjoiUENfTEFVTkNIRVIiLCJwZmQiOlt7InR5cGUiOiJtYyIsImlkIjoiY2FlYzA3NmMtODBjMy00NjM3LWEzMWItNDQ4NzRmZmEwMDlkIiwibmFtZSI6IjQ0OXN0YW5fWXRiIn1dLCJuYmYiOjE3NjI4NDc4OTgsImV4cCI6MTc2MjkzNDI5OCwiaWF0IjoxNzYyODQ3ODk4LCJhaWQiOiJjMzZhOWZiNi00ZjJhLTQxZmYtOTBiZC1hZTdjYzkyMDMxZWIifQ.bcyq-FrP4XXESyKBr4TFstsjw8tgjY5cz_p7ansohPV_VfbKqBeLV-E1XYySwKj6BRuc0dAuW6nGdwE9qlv94tRtapVb1q1W__-GguVWOD16TaEi6dmzDyw8--lpI6eL657lPkzFaVeNrSHNPCPn0ltGcZzlOv1XYJwZM8D1yj57x7aXaOMmJqLY8R5zCgfWp_TnGPjJrbd_gV-N5wP9z_vL6jQKj5bvaTkYqItLq5tTFWbX1wAoeSV47D3mtZfx2N4rGgeUSQ1bYanUZ_eMuH6hSwrwxzqn_-HwN2PA7j0VFVUOu54FRqJbw8D4H6tAf3SY1xIjFC5GUu22IbVP3Q",
|
||||||
},
|
},
|
||||||
Connection: c,
|
Connection: c,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
package modules
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"strom"
|
|
||||||
|
|
||||||
"github.com/admin-else/queser"
|
|
||||||
"github.com/admin-else/queser/data"
|
|
||||||
"github.com/admin-else/queser/generated/v1_21_8"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Account struct {
|
|
||||||
Username string
|
|
||||||
UUID uuid.UUID
|
|
||||||
Token string
|
|
||||||
}
|
|
||||||
type LoginClient struct {
|
|
||||||
*strom.Connection
|
|
||||||
Account Account
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *LoginClient) Default(event any) (err error) {
|
|
||||||
err = fmt.Errorf("unexpected event: %T%v", event, event)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *LoginClient) OnStart(_ strom.OnStart) (err error) {
|
|
||||||
parts := strings.Split(s.RemoteAddr().String(), ":")
|
|
||||||
versionData, err := data.LookUpProtocolVersionByName(s.Version)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
port, err := strconv.Atoi(parts[1])
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = s.Send(v1_21_8.HandshakingToServerPacketSetProtocol{
|
|
||||||
ProtocolVersion: queser.VarInt(versionData.Version),
|
|
||||||
ServerHost: parts[0],
|
|
||||||
ServerPort: uint16(port),
|
|
||||||
NextState: queser.VarInt(queser.Login),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.State = queser.Login
|
|
||||||
err = s.Send(v1_21_8.LoginToServerPacketLoginStart{Username: s.Account.Username, PlayerUUID: s.Account.UUID})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *LoginClient) OnCompress(compress v1_21_8.LoginToClientPacketCompress) (err error) {
|
|
||||||
s.CompressionThreshold = int32(compress.Threshold)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *LoginClient) OnSuccess(success v1_21_8.LoginToClientPacketSuccess) (err error) {
|
|
||||||
err = s.Send(v1_21_8.LoginToServerPacketLoginAcknowledged{})
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.State = queser.Configuration
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,197 @@
|
|||||||
|
package loginclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/sha1"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"strom"
|
||||||
|
|
||||||
|
"github.com/admin-else/queser"
|
||||||
|
"github.com/admin-else/queser/data"
|
||||||
|
"github.com/admin-else/queser/generated/v1_21_8"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Account struct {
|
||||||
|
Username string
|
||||||
|
Uuid uuid.UUID
|
||||||
|
Token string
|
||||||
|
}
|
||||||
|
type LoginClient struct {
|
||||||
|
*strom.Connection
|
||||||
|
Account Account
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LoginClient) Default(event any) (err error) {
|
||||||
|
err = fmt.Errorf("unexpected event: %T%v", event, event)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LoginClient) OnStart(_ strom.OnStart) (err error) {
|
||||||
|
parts := strings.Split(s.RemoteAddr().String(), ":")
|
||||||
|
versionData, err := data.LookUpProtocolVersionByName(s.Version)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
port, err := strconv.Atoi(parts[1])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = s.Send(v1_21_8.HandshakingToServerPacketSetProtocol{
|
||||||
|
ProtocolVersion: queser.VarInt(versionData.Version),
|
||||||
|
ServerHost: parts[0],
|
||||||
|
ServerPort: uint16(port),
|
||||||
|
NextState: queser.VarInt(queser.Login),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.State = queser.Login
|
||||||
|
err = s.Send(v1_21_8.LoginToServerPacketLoginStart{Username: s.Account.Username, PlayerUUID: s.Account.Uuid})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LoginClient) OnCompress(compress v1_21_8.LoginToClientPacketCompress) (err error) {
|
||||||
|
s.CompressionThreshold = int32(compress.Threshold)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func twosComplement(p []byte) []byte {
|
||||||
|
carry := true
|
||||||
|
for i := len(p) - 1; i >= 0; i-- {
|
||||||
|
p[i] = byte(^p[i])
|
||||||
|
if carry {
|
||||||
|
carry = p[i] == 0xff
|
||||||
|
p[i]++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthDigest stolen from https://gist.github.com/toqueteos/5372776
|
||||||
|
func AuthDigest(elems ...[]byte) string {
|
||||||
|
h := sha1.New()
|
||||||
|
for _, elem := range elems {
|
||||||
|
h.Write(elem)
|
||||||
|
}
|
||||||
|
hash := h.Sum(nil)
|
||||||
|
|
||||||
|
negative := (hash[0] & 0x80) == 0x80
|
||||||
|
if negative {
|
||||||
|
hash = twosComplement(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := strings.TrimLeft(hex.EncodeToString(hash), "0")
|
||||||
|
if negative {
|
||||||
|
res = "-" + res
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func JoinServerAPI(a Account, serverId string) (err error) {
|
||||||
|
var body []byte
|
||||||
|
body, err = json.Marshal(struct {
|
||||||
|
AccessToken string `json:"accessToken"`
|
||||||
|
SelectedProfile string `json:"selectedProfile"`
|
||||||
|
ServerId string `json:"serverId"`
|
||||||
|
}{
|
||||||
|
AccessToken: a.Token,
|
||||||
|
SelectedProfile: strings.ReplaceAll(a.Uuid.String(), "-", ""),
|
||||||
|
ServerId: serverId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var resp *http.Response
|
||||||
|
resp, err = http.Post("https://sessionserver.mojang.com/session/minecraft/join", "application/json", bytes.NewReader(body))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if resp.StatusCode != 204 {
|
||||||
|
body, err = io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = fmt.Errorf("bad status code %v body %v", resp.StatusCode, string(body))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LoginClient) OnEncrypt(packet v1_21_8.LoginToClientPacketEncryptionBegin) (err error) {
|
||||||
|
sharedSecret := make([]byte, 16)
|
||||||
|
_, _ = rand.Read(sharedSecret) //never fails
|
||||||
|
|
||||||
|
if packet.ShouldAuthenticate {
|
||||||
|
if s.Account.Token == "" {
|
||||||
|
err = fmt.Errorf("the account has no token so we cant join online servers")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
serverId := AuthDigest([]byte(packet.ServerId), sharedSecret, packet.PublicKey)
|
||||||
|
err = JoinServerAPI(s.Account, serverId)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pubAny, err := x509.ParsePKIXPublicKey(packet.PublicKey)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pub, ok := pubAny.(*rsa.PublicKey)
|
||||||
|
if !ok {
|
||||||
|
err = fmt.Errorf("public key is not rsa")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
verifyTokenEnc, err := rsa.EncryptPKCS1v15(rand.Reader, pub, packet.VerifyToken)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sharedSecretEnc, err := rsa.EncryptPKCS1v15(rand.Reader, pub, sharedSecret)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = s.Send(v1_21_8.LoginToServerPacketEncryptionBegin{SharedSecret: sharedSecretEnc, VerifyToken: verifyTokenEnc})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var b cipher.Block
|
||||||
|
b, err = aes.NewCipher(sharedSecret)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.R = cipher.StreamReader{
|
||||||
|
S: strom.NewCFB8Decrypt(b, sharedSecret),
|
||||||
|
R: s.Conn,
|
||||||
|
}
|
||||||
|
s.W = cipher.StreamWriter{
|
||||||
|
S: strom.NewCFB8Encrypt(b, sharedSecret),
|
||||||
|
W: s.Conn,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LoginClient) OnSuccess(success v1_21_8.LoginToClientPacketSuccess) (err error) {
|
||||||
|
fmt.Println("login success", success)
|
||||||
|
err = s.Send(v1_21_8.LoginToServerPacketLoginAcknowledged{})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.State = queser.Configuration
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package modules
|
package statusclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
Reference in New Issue
Block a user