Files
Ananta-ps/internal/logingate/server_test.go
T

125 lines
3.2 KiB
Go

package logingate
import (
"crypto/aes"
"crypto/cipher"
"net"
"testing"
"time"
"ananta-ps/internal/config"
"ananta-ps/pkg/crypto/chacha8"
"ananta-ps/pkg/protocol"
)
func TestLoginGateServer(t *testing.T) {
cfg := &config.Config{
Client: config.ClientConfig{
ServerID: 801,
Aid: 5944,
},
Network: config.NetworkConfig{
BindHost: "127.0.0.1",
AdvertisedHost: "127.0.0.1",
LoginPorts: []int{15200},
GamePort: 15202,
},
Player: config.PlayerConfig{
Pid: 100,
AccountId: "test_acc",
UserName: "test_user",
},
}
srv := New(cfg)
if err := srv.Start(); err != nil {
t.Fatalf("failed to start login gate: %v", err)
}
defer srv.Stop()
// Connect client
conn, err := net.DialTimeout("tcp", "127.0.0.1:15200", 2*time.Second)
if err != nil {
t.Fatalf("failed to connect: %v", err)
}
defer conn.Close()
// 1. Send client handshake (mode 0x01 plaintext)
clientHandshake := make([]byte, 260)
clientHandshake[0] = 0xAA
clientHandshake[1] = 0xBB
clientHandshake[2] = 0xCC
clientHandshake[3] = 0xDD
aesKey := []byte("0123456789abcdef") // 16 bytes
copy(clientHandshake[4:20], aesKey)
if err := protocol.WriteFrame(conn, 0x01, clientHandshake, nil); err != nil {
t.Fatalf("failed to write client handshake: %v", err)
}
// 2. Read server handshake reply
serverReplyFrame, err := protocol.ReadFrame(conn, nil)
if err != nil {
t.Fatalf("failed to read server handshake reply: %v", err)
}
if len(serverReplyFrame.Payload) < 112 {
t.Fatalf("server reply too short: %d", len(serverReplyFrame.Payload))
}
aesNonce := serverReplyFrame.Payload[8:20]
encryptedHead := serverReplyFrame.Payload[20:96]
tag := serverReplyFrame.Payload[96:112]
cipherBlock, err := aes.NewCipher(aesKey)
if err != nil {
t.Fatalf("failed to create aes cipher: %v", err)
}
aesGcm, err := cipher.NewGCM(cipherBlock)
if err != nil {
t.Fatalf("failed to create aes gcm: %v", err)
}
fullCipher := append(encryptedHead, tag...)
chaChaHead, err := aesGcm.Open(nil, aesNonce, fullCipher, nil)
if err != nil {
t.Fatalf("failed to decrypt chacha head: %v", err)
}
clientWriteKey := chaChaHead[0:32]
clientReadKey := chaChaHead[32:64]
streamNonce := chaChaHead[64:76]
clientSendCipher, err := chacha8.New(clientWriteKey, streamNonce)
if err != nil {
t.Fatalf("failed to create client send cipher: %v", err)
}
clientReadCipher, err := chacha8.New(clientReadKey, streamNonce)
if err != nil {
t.Fatalf("failed to create client read cipher: %v", err)
}
// 3. Send CheckVersion Invoke
invokePayload := protocol.BuildInvoke(protocol.MethodCheckVersion, 1, nil)
if err := protocol.WriteFrame(conn, 0x09, invokePayload, clientSendCipher); err != nil {
t.Fatalf("failed to write invoke frame: %v", err)
}
// 4. Read Return frame
respFrame, err := protocol.ReadFrame(conn, clientReadCipher)
if err != nil {
t.Fatalf("failed to read response frame: %v", err)
}
pkt := protocol.ParseRpcPacket(respFrame.Payload)
if pkt.Kind != protocol.PacketKindReturn {
t.Fatalf("expected Return packet, got %v", pkt.Kind)
}
if pkt.InvokeID != 1 {
t.Fatalf("expected InvokeID 1, got %d", pkt.InvokeID)
}
if pkt.Error != 0 {
t.Fatalf("expected Error 0, got %d", pkt.Error)
}
}