Files
Erupe/network/crypt_conn_test.go
Houmgaor 06cb3afa57 refactor: standardize logging on zap across all packages
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
2026-02-20 18:59:12 +01:00

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)
}