mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-21 23:22:34 +01:00
Replace all fmt.Printf/Println and log.Printf/Fatal with structured zap.Logger calls to eliminate inconsistent logging (anti-pattern #12). - network/crypt_conn: inject logger via NewCryptConn, replace 6 fmt calls - signserver/session: use existing s.logger for debug packet dumps - entranceserver: use s.logger for inbound/outbound debug logging - api/utils: accept logger param in verifyPath, replace fmt.Println - api/endpoints: use s.logger for screenshot path diagnostics - config: replace log.Fatal with error return in getOutboundIP4 - deltacomp: replace log.Printf with zap.L() global logger
446 lines
12 KiB
Go
446 lines
12 KiB
Go
package network
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
_config "erupe-ce/config"
|
|
"erupe-ce/network/crypto"
|
|
"io"
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// mockConn implements net.Conn for testing
|
|
type mockConn struct {
|
|
readData *bytes.Buffer
|
|
writeData *bytes.Buffer
|
|
closed bool
|
|
readErr error
|
|
writeErr error
|
|
}
|
|
|
|
func newMockConn(readData []byte) *mockConn {
|
|
return &mockConn{
|
|
readData: bytes.NewBuffer(readData),
|
|
writeData: bytes.NewBuffer(nil),
|
|
}
|
|
}
|
|
|
|
func (m *mockConn) Read(b []byte) (n int, err error) {
|
|
if m.readErr != nil {
|
|
return 0, m.readErr
|
|
}
|
|
return m.readData.Read(b)
|
|
}
|
|
|
|
func (m *mockConn) Write(b []byte) (n int, err error) {
|
|
if m.writeErr != nil {
|
|
return 0, m.writeErr
|
|
}
|
|
return m.writeData.Write(b)
|
|
}
|
|
|
|
func (m *mockConn) Close() error {
|
|
m.closed = true
|
|
return nil
|
|
}
|
|
|
|
func (m *mockConn) LocalAddr() net.Addr { return nil }
|
|
func (m *mockConn) RemoteAddr() net.Addr { return nil }
|
|
func (m *mockConn) SetDeadline(t time.Time) error { return nil }
|
|
func (m *mockConn) SetReadDeadline(t time.Time) error { return nil }
|
|
func (m *mockConn) SetWriteDeadline(t time.Time) error { return nil }
|
|
|
|
func TestNewCryptConn(t *testing.T) {
|
|
mockConn := newMockConn(nil)
|
|
cc := NewCryptConn(mockConn, _config.ZZ, nil)
|
|
|
|
if cc == nil {
|
|
t.Fatal("NewCryptConn() returned nil")
|
|
}
|
|
|
|
if cc.conn != mockConn {
|
|
t.Error("conn not set correctly")
|
|
}
|
|
|
|
if cc.readKeyRot != 995117 {
|
|
t.Errorf("readKeyRot = %d, want 995117", cc.readKeyRot)
|
|
}
|
|
|
|
if cc.sendKeyRot != 995117 {
|
|
t.Errorf("sendKeyRot = %d, want 995117", cc.sendKeyRot)
|
|
}
|
|
|
|
if cc.sentPackets != 0 {
|
|
t.Errorf("sentPackets = %d, want 0", cc.sentPackets)
|
|
}
|
|
|
|
if cc.prevRecvPacketCombinedCheck != 0 {
|
|
t.Errorf("prevRecvPacketCombinedCheck = %d, want 0", cc.prevRecvPacketCombinedCheck)
|
|
}
|
|
|
|
if cc.prevSendPacketCombinedCheck != 0 {
|
|
t.Errorf("prevSendPacketCombinedCheck = %d, want 0", cc.prevSendPacketCombinedCheck)
|
|
}
|
|
|
|
if cc.realClientMode != _config.ZZ {
|
|
t.Errorf("realClientMode = %d, want %d", cc.realClientMode, _config.ZZ)
|
|
}
|
|
}
|
|
|
|
func TestCryptConn_SendPacket(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
data []byte
|
|
}{
|
|
{
|
|
name: "small packet",
|
|
data: []byte{0x01, 0x02, 0x03, 0x04},
|
|
},
|
|
{
|
|
name: "empty packet",
|
|
data: []byte{},
|
|
},
|
|
{
|
|
name: "larger packet",
|
|
data: bytes.Repeat([]byte{0xAA}, 256),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
mockConn := newMockConn(nil)
|
|
cc := NewCryptConn(mockConn, _config.ZZ, nil)
|
|
|
|
err := cc.SendPacket(tt.data)
|
|
if err != nil {
|
|
t.Fatalf("SendPacket() error = %v, want nil", err)
|
|
}
|
|
|
|
written := mockConn.writeData.Bytes()
|
|
if len(written) < CryptPacketHeaderLength {
|
|
t.Fatalf("written data length = %d, want at least %d", len(written), CryptPacketHeaderLength)
|
|
}
|
|
|
|
// Verify header was written
|
|
headerData := written[:CryptPacketHeaderLength]
|
|
header, err := NewCryptPacketHeader(headerData)
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse header: %v", err)
|
|
}
|
|
|
|
// Verify packet counter incremented
|
|
if cc.sentPackets != 1 {
|
|
t.Errorf("sentPackets = %d, want 1", cc.sentPackets)
|
|
}
|
|
|
|
// Verify header fields
|
|
if header.KeyRotDelta != 3 {
|
|
t.Errorf("header.KeyRotDelta = %d, want 3", header.KeyRotDelta)
|
|
}
|
|
|
|
if header.PacketNum != 0 {
|
|
t.Errorf("header.PacketNum = %d, want 0", header.PacketNum)
|
|
}
|
|
|
|
// Verify encrypted data was written
|
|
encryptedData := written[CryptPacketHeaderLength:]
|
|
if len(encryptedData) != int(header.DataSize) {
|
|
t.Errorf("encrypted data length = %d, want %d", len(encryptedData), header.DataSize)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCryptConn_SendPacket_MultiplePackets(t *testing.T) {
|
|
mockConn := newMockConn(nil)
|
|
cc := NewCryptConn(mockConn, _config.ZZ, nil)
|
|
|
|
// Send first packet
|
|
err := cc.SendPacket([]byte{0x01, 0x02})
|
|
if err != nil {
|
|
t.Fatalf("SendPacket(1) error = %v", err)
|
|
}
|
|
|
|
if cc.sentPackets != 1 {
|
|
t.Errorf("After 1 packet: sentPackets = %d, want 1", cc.sentPackets)
|
|
}
|
|
|
|
// Send second packet
|
|
err = cc.SendPacket([]byte{0x03, 0x04})
|
|
if err != nil {
|
|
t.Fatalf("SendPacket(2) error = %v", err)
|
|
}
|
|
|
|
if cc.sentPackets != 2 {
|
|
t.Errorf("After 2 packets: sentPackets = %d, want 2", cc.sentPackets)
|
|
}
|
|
|
|
// Send third packet
|
|
err = cc.SendPacket([]byte{0x05, 0x06})
|
|
if err != nil {
|
|
t.Fatalf("SendPacket(3) error = %v", err)
|
|
}
|
|
|
|
if cc.sentPackets != 3 {
|
|
t.Errorf("After 3 packets: sentPackets = %d, want 3", cc.sentPackets)
|
|
}
|
|
}
|
|
|
|
func TestCryptConn_SendPacket_KeyRotation(t *testing.T) {
|
|
mockConn := newMockConn(nil)
|
|
cc := NewCryptConn(mockConn, _config.ZZ, nil)
|
|
|
|
initialKey := cc.sendKeyRot
|
|
|
|
err := cc.SendPacket([]byte{0x01, 0x02, 0x03})
|
|
if err != nil {
|
|
t.Fatalf("SendPacket() error = %v", err)
|
|
}
|
|
|
|
// Key should have been rotated (keyRotDelta=3, so new key = 3 * (oldKey + 1))
|
|
expectedKey := 3 * (initialKey + 1)
|
|
if cc.sendKeyRot != expectedKey {
|
|
t.Errorf("sendKeyRot = %d, want %d", cc.sendKeyRot, expectedKey)
|
|
}
|
|
}
|
|
|
|
func TestCryptConn_SendPacket_WriteError(t *testing.T) {
|
|
mockConn := newMockConn(nil)
|
|
mockConn.writeErr = errors.New("write error")
|
|
cc := NewCryptConn(mockConn, _config.ZZ, nil)
|
|
|
|
err := cc.SendPacket([]byte{0x01, 0x02, 0x03})
|
|
// Note: Current implementation doesn't return write error
|
|
// This test documents the behavior
|
|
if err != nil {
|
|
t.Logf("SendPacket() returned error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCryptConn_ReadPacket_Success(t *testing.T) {
|
|
testData := []byte{0x74, 0x65, 0x73, 0x74} // "test"
|
|
key := uint32(0)
|
|
|
|
// Encrypt the data
|
|
encryptedData, combinedCheck, check0, check1, check2 := crypto.Crypto(testData, key, true, nil)
|
|
|
|
// Build header
|
|
header := &CryptPacketHeader{
|
|
Pf0: 0x03,
|
|
KeyRotDelta: 0,
|
|
PacketNum: 0,
|
|
DataSize: uint16(len(encryptedData)),
|
|
PrevPacketCombinedCheck: 0,
|
|
Check0: check0,
|
|
Check1: check1,
|
|
Check2: check2,
|
|
}
|
|
|
|
headerBytes, _ := header.Encode()
|
|
|
|
// Combine header and encrypted data
|
|
packet := append(headerBytes, encryptedData...)
|
|
|
|
mockConn := newMockConn(packet)
|
|
cc := NewCryptConn(mockConn, _config.Z1, nil)
|
|
|
|
// Set the key to match what we used for encryption
|
|
cc.readKeyRot = key
|
|
|
|
result, err := cc.ReadPacket()
|
|
if err != nil {
|
|
t.Fatalf("ReadPacket() error = %v, want nil", err)
|
|
}
|
|
|
|
if !bytes.Equal(result, testData) {
|
|
t.Errorf("ReadPacket() = %v, want %v", result, testData)
|
|
}
|
|
|
|
if cc.prevRecvPacketCombinedCheck != combinedCheck {
|
|
t.Errorf("prevRecvPacketCombinedCheck = %d, want %d", cc.prevRecvPacketCombinedCheck, combinedCheck)
|
|
}
|
|
}
|
|
|
|
func TestCryptConn_ReadPacket_KeyRotation(t *testing.T) {
|
|
testData := []byte{0x01, 0x02, 0x03, 0x04}
|
|
key := uint32(995117)
|
|
keyRotDelta := byte(3)
|
|
|
|
// Calculate expected rotated key
|
|
rotatedKey := uint32(keyRotDelta) * (key + 1)
|
|
|
|
// Encrypt with the rotated key
|
|
encryptedData, _, check0, check1, check2 := crypto.Crypto(testData, rotatedKey, true, nil)
|
|
|
|
// Build header with key rotation
|
|
header := &CryptPacketHeader{
|
|
Pf0: 0x03,
|
|
KeyRotDelta: keyRotDelta,
|
|
PacketNum: 0,
|
|
DataSize: uint16(len(encryptedData)),
|
|
PrevPacketCombinedCheck: 0,
|
|
Check0: check0,
|
|
Check1: check1,
|
|
Check2: check2,
|
|
}
|
|
|
|
headerBytes, _ := header.Encode()
|
|
packet := append(headerBytes, encryptedData...)
|
|
|
|
mockConn := newMockConn(packet)
|
|
cc := NewCryptConn(mockConn, _config.Z1, nil)
|
|
cc.readKeyRot = key
|
|
|
|
result, err := cc.ReadPacket()
|
|
if err != nil {
|
|
t.Fatalf("ReadPacket() error = %v, want nil", err)
|
|
}
|
|
|
|
if !bytes.Equal(result, testData) {
|
|
t.Errorf("ReadPacket() = %v, want %v", result, testData)
|
|
}
|
|
|
|
// Verify key was rotated
|
|
if cc.readKeyRot != rotatedKey {
|
|
t.Errorf("readKeyRot = %d, want %d", cc.readKeyRot, rotatedKey)
|
|
}
|
|
}
|
|
|
|
func TestCryptConn_ReadPacket_NoKeyRotation(t *testing.T) {
|
|
testData := []byte{0x01, 0x02}
|
|
key := uint32(12345)
|
|
|
|
// Encrypt without key rotation
|
|
encryptedData, _, check0, check1, check2 := crypto.Crypto(testData, key, true, nil)
|
|
|
|
header := &CryptPacketHeader{
|
|
Pf0: 0x03,
|
|
KeyRotDelta: 0, // No rotation
|
|
PacketNum: 0,
|
|
DataSize: uint16(len(encryptedData)),
|
|
PrevPacketCombinedCheck: 0,
|
|
Check0: check0,
|
|
Check1: check1,
|
|
Check2: check2,
|
|
}
|
|
|
|
headerBytes, _ := header.Encode()
|
|
packet := append(headerBytes, encryptedData...)
|
|
|
|
mockConn := newMockConn(packet)
|
|
cc := NewCryptConn(mockConn, _config.Z1, nil)
|
|
cc.readKeyRot = key
|
|
|
|
originalKeyRot := cc.readKeyRot
|
|
|
|
result, err := cc.ReadPacket()
|
|
if err != nil {
|
|
t.Fatalf("ReadPacket() error = %v, want nil", err)
|
|
}
|
|
|
|
if !bytes.Equal(result, testData) {
|
|
t.Errorf("ReadPacket() = %v, want %v", result, testData)
|
|
}
|
|
|
|
// Verify key was NOT rotated
|
|
if cc.readKeyRot != originalKeyRot {
|
|
t.Errorf("readKeyRot = %d, want %d (should not have changed)", cc.readKeyRot, originalKeyRot)
|
|
}
|
|
}
|
|
|
|
func TestCryptConn_ReadPacket_HeaderReadError(t *testing.T) {
|
|
mockConn := newMockConn([]byte{0x01, 0x02}) // Only 2 bytes, header needs 14
|
|
cc := NewCryptConn(mockConn, _config.ZZ, nil)
|
|
|
|
_, err := cc.ReadPacket()
|
|
if err == nil {
|
|
t.Fatal("ReadPacket() error = nil, want error")
|
|
}
|
|
|
|
if err != io.EOF && err != io.ErrUnexpectedEOF {
|
|
t.Errorf("ReadPacket() error = %v, want io.EOF or io.ErrUnexpectedEOF", err)
|
|
}
|
|
}
|
|
|
|
func TestCryptConn_ReadPacket_InvalidHeader(t *testing.T) {
|
|
// Create invalid header data (wrong endianness or malformed)
|
|
invalidHeader := []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
|
|
mockConn := newMockConn(invalidHeader)
|
|
cc := NewCryptConn(mockConn, _config.ZZ, nil)
|
|
|
|
_, err := cc.ReadPacket()
|
|
if err == nil {
|
|
t.Fatal("ReadPacket() error = nil, want error")
|
|
}
|
|
}
|
|
|
|
func TestCryptConn_ReadPacket_BodyReadError(t *testing.T) {
|
|
// Create valid header but incomplete body
|
|
header := &CryptPacketHeader{
|
|
Pf0: 0x03,
|
|
KeyRotDelta: 0,
|
|
PacketNum: 0,
|
|
DataSize: 100, // Claim 100 bytes
|
|
PrevPacketCombinedCheck: 0,
|
|
Check0: 0x1234,
|
|
Check1: 0x5678,
|
|
Check2: 0x9ABC,
|
|
}
|
|
|
|
headerBytes, _ := header.Encode()
|
|
incompleteBody := []byte{0x01, 0x02, 0x03} // Only 3 bytes, not 100
|
|
|
|
packet := append(headerBytes, incompleteBody...)
|
|
|
|
mockConn := newMockConn(packet)
|
|
cc := NewCryptConn(mockConn, _config.Z1, nil)
|
|
|
|
_, err := cc.ReadPacket()
|
|
if err == nil {
|
|
t.Fatal("ReadPacket() error = nil, want error")
|
|
}
|
|
}
|
|
|
|
func TestCryptConn_ReadPacket_ChecksumMismatch(t *testing.T) {
|
|
testData := []byte{0x01, 0x02, 0x03, 0x04}
|
|
key := uint32(0)
|
|
|
|
encryptedData, _, _, _, _ := crypto.Crypto(testData, key, true, nil)
|
|
|
|
// Build header with WRONG checksums
|
|
header := &CryptPacketHeader{
|
|
Pf0: 0x03,
|
|
KeyRotDelta: 0,
|
|
PacketNum: 0,
|
|
DataSize: uint16(len(encryptedData)),
|
|
PrevPacketCombinedCheck: 0,
|
|
Check0: 0xFFFF, // Wrong checksum
|
|
Check1: 0xFFFF, // Wrong checksum
|
|
Check2: 0xFFFF, // Wrong checksum
|
|
}
|
|
|
|
headerBytes, _ := header.Encode()
|
|
packet := append(headerBytes, encryptedData...)
|
|
|
|
mockConn := newMockConn(packet)
|
|
cc := NewCryptConn(mockConn, _config.Z1, nil)
|
|
cc.readKeyRot = key
|
|
|
|
_, err := cc.ReadPacket()
|
|
if err == nil {
|
|
t.Fatal("ReadPacket() error = nil, want error for checksum mismatch")
|
|
}
|
|
|
|
expectedErr := "decrypted data checksum doesn't match header"
|
|
if err.Error() != expectedErr {
|
|
t.Errorf("ReadPacket() error = %q, want %q", err.Error(), expectedErr)
|
|
}
|
|
}
|
|
|
|
func TestCryptConn_Interface(t *testing.T) {
|
|
// Test that CryptConn implements Conn interface
|
|
var _ Conn = (*CryptConn)(nil)
|
|
}
|