Renamed `allowedPublicKeyMu` to `allowedPublicKeyMutex` in PeerRegistry. `Mu` is an abbreviation that violates AX Principle 1 (predictable names over short names) — the full word `Mutex` removes any ambiguity about what the field represents. Co-Authored-By: Charon <charon@lethean.io>
208 lines
6.7 KiB
Go
208 lines
6.7 KiB
Go
package ueps
|
|
|
|
import (
|
|
"bytes"
|
|
"testing"
|
|
)
|
|
|
|
// TestPacket_NewBuilder_Good verifies NewBuilder returns a PacketBuilder with correct defaults.
|
|
// builder := NewBuilder(0x01, []byte("hello"))
|
|
// // builder.Header.Version == 0x09; builder.Header.CurrentLayer == 5
|
|
func TestPacket_NewBuilder_Good(t *testing.T) {
|
|
intentID := uint8(0x01)
|
|
payload := []byte("hello")
|
|
|
|
builder := NewBuilder(intentID, payload)
|
|
|
|
if builder == nil {
|
|
t.Fatal("NewBuilder returned nil")
|
|
}
|
|
if builder.Header.Version != 0x09 {
|
|
t.Errorf("expected Version 0x09, got 0x%02x", builder.Header.Version)
|
|
}
|
|
if builder.Header.CurrentLayer != 5 {
|
|
t.Errorf("expected CurrentLayer 5, got %d", builder.Header.CurrentLayer)
|
|
}
|
|
if builder.Header.TargetLayer != 5 {
|
|
t.Errorf("expected TargetLayer 5, got %d", builder.Header.TargetLayer)
|
|
}
|
|
if builder.Header.IntentID != intentID {
|
|
t.Errorf("expected IntentID 0x%02x, got 0x%02x", intentID, builder.Header.IntentID)
|
|
}
|
|
if builder.Header.ThreatScore != 0 {
|
|
t.Errorf("expected ThreatScore 0, got %d", builder.Header.ThreatScore)
|
|
}
|
|
if !bytes.Equal(builder.Payload, payload) {
|
|
t.Errorf("expected Payload %q, got %q", payload, builder.Payload)
|
|
}
|
|
}
|
|
|
|
// TestPacket_NewBuilder_Bad verifies NewBuilder with an empty payload still returns a valid builder.
|
|
// builder := NewBuilder(0x04, nil)
|
|
// frame, err := builder.MarshalAndSign(secret) // succeeds with zero-length payload
|
|
func TestPacket_NewBuilder_Bad(t *testing.T) {
|
|
builder := NewBuilder(0x04, nil)
|
|
|
|
if builder == nil {
|
|
t.Fatal("NewBuilder returned nil for nil payload")
|
|
}
|
|
if builder.Payload != nil {
|
|
t.Errorf("expected nil Payload, got %v", builder.Payload)
|
|
}
|
|
|
|
frame, err := builder.MarshalAndSign([]byte("secret"))
|
|
if err != nil {
|
|
t.Fatalf("MarshalAndSign with nil payload failed: %v", err)
|
|
}
|
|
if len(frame) == 0 {
|
|
t.Error("expected non-empty frame for nil payload")
|
|
}
|
|
}
|
|
|
|
// TestPacket_NewBuilder_Ugly verifies NewBuilder with a zero-byte intentID and large payload.
|
|
// builder := NewBuilder(0x00, largePayload)
|
|
// frame, err := builder.MarshalAndSign(secret) // succeeds; 0xFF tag appended without length prefix
|
|
func TestPacket_NewBuilder_Ugly(t *testing.T) {
|
|
largePayload := bytes.Repeat([]byte("x"), 300)
|
|
builder := NewBuilder(0x00, largePayload)
|
|
|
|
if builder.Header.IntentID != 0x00 {
|
|
t.Errorf("expected IntentID 0x00, got 0x%02x", builder.Header.IntentID)
|
|
}
|
|
|
|
frame, err := builder.MarshalAndSign([]byte("secret"))
|
|
if err != nil {
|
|
t.Fatalf("MarshalAndSign with 300-byte payload failed: %v", err)
|
|
}
|
|
if !bytes.Contains(frame, largePayload) {
|
|
t.Error("frame does not contain the large payload")
|
|
}
|
|
}
|
|
|
|
// TestPacket_MarshalAndSign_Good verifies a signed frame contains all expected TLV tags.
|
|
// builder := NewBuilder(0x01, []byte("ping"))
|
|
// frame, err := builder.MarshalAndSign([]byte("my-shared-secret"))
|
|
func TestPacket_MarshalAndSign_Good(t *testing.T) {
|
|
builder := NewBuilder(0x01, []byte("ping"))
|
|
sharedSecret := []byte("my-shared-secret")
|
|
|
|
frame, err := builder.MarshalAndSign(sharedSecret)
|
|
|
|
if err != nil {
|
|
t.Fatalf("MarshalAndSign failed: %v", err)
|
|
}
|
|
if len(frame) == 0 {
|
|
t.Fatal("expected non-empty frame")
|
|
}
|
|
|
|
// Verify each expected tag is present in the frame
|
|
for _, expectedTag := range []byte{TagVersion, TagCurrentLayer, TagTargetLayer, TagIntent, TagThreatScore, TagHMAC, TagPayload} {
|
|
if !bytes.Contains(frame, []byte{expectedTag}) {
|
|
t.Errorf("frame missing tag 0x%02x", expectedTag)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestPacket_MarshalAndSign_Bad verifies that different secrets produce different signatures.
|
|
// frame1, _ := builder.MarshalAndSign([]byte("secret-a"))
|
|
// frame2, _ := builder.MarshalAndSign([]byte("secret-b"))
|
|
// // frame1 != frame2 (HMAC tag differs)
|
|
func TestPacket_MarshalAndSign_Bad(t *testing.T) {
|
|
builder := NewBuilder(0x02, []byte("data"))
|
|
|
|
frame1, err1 := builder.MarshalAndSign([]byte("secret-a"))
|
|
frame2, err2 := builder.MarshalAndSign([]byte("secret-b"))
|
|
|
|
if err1 != nil || err2 != nil {
|
|
t.Fatalf("MarshalAndSign errors: %v, %v", err1, err2)
|
|
}
|
|
if bytes.Equal(frame1, frame2) {
|
|
t.Error("expected different frames for different secrets, got identical frames")
|
|
}
|
|
}
|
|
|
|
// TestPacket_MarshalAndSign_Ugly verifies that altering the payload after signing does not match
|
|
// the HMAC stored in the frame (the frame is immutable once signed).
|
|
// frame, _ := builder.MarshalAndSign(secret)
|
|
// // modifying frame[len(frame)-1] breaks HMAC verification
|
|
func TestPacket_MarshalAndSign_Ugly(t *testing.T) {
|
|
builder := NewBuilder(0x03, []byte("sensitive"))
|
|
sharedSecret := []byte("my-secret")
|
|
|
|
frame, err := builder.MarshalAndSign(sharedSecret)
|
|
if err != nil {
|
|
t.Fatalf("MarshalAndSign failed: %v", err)
|
|
}
|
|
|
|
// Corrupt the last byte of the frame (part of the payload)
|
|
corrupted := make([]byte, len(frame))
|
|
copy(corrupted, frame)
|
|
corrupted[len(corrupted)-1] ^= 0xFF
|
|
|
|
if bytes.Equal(frame, corrupted) {
|
|
t.Error("expected corrupted frame to differ from original")
|
|
}
|
|
}
|
|
|
|
// TestPacket_writeTLV_Good verifies writeTLV writes tag, length, and value correctly.
|
|
// writeTLV(buf, TagVersion, []byte{0x09})
|
|
// // buf contains: [0x01, 0x01, 0x09]
|
|
func TestPacket_writeTLV_Good(t *testing.T) {
|
|
buffer := new(bytes.Buffer)
|
|
|
|
err := writeTLV(buffer, TagVersion, []byte{0x09})
|
|
|
|
if err != nil {
|
|
t.Fatalf("writeTLV failed: %v", err)
|
|
}
|
|
result := buffer.Bytes()
|
|
if len(result) != 3 {
|
|
t.Fatalf("expected 3 bytes, got %d", len(result))
|
|
}
|
|
if result[0] != TagVersion {
|
|
t.Errorf("expected tag 0x%02x, got 0x%02x", TagVersion, result[0])
|
|
}
|
|
if result[1] != 0x01 {
|
|
t.Errorf("expected length 1, got %d", result[1])
|
|
}
|
|
if result[2] != 0x09 {
|
|
t.Errorf("expected value 0x09, got 0x%02x", result[2])
|
|
}
|
|
}
|
|
|
|
// TestPacket_writeTLV_Bad verifies writeTLV rejects values exceeding 255 bytes.
|
|
// writeTLV(buf, TagPayload, bytes.Repeat([]byte("x"), 256))
|
|
// // returns error: "TLV value too large for 1-byte length header"
|
|
func TestPacket_writeTLV_Bad(t *testing.T) {
|
|
buffer := new(bytes.Buffer)
|
|
oversizedValue := bytes.Repeat([]byte("x"), 256)
|
|
|
|
err := writeTLV(buffer, TagPayload, oversizedValue)
|
|
|
|
if err == nil {
|
|
t.Fatal("expected error for oversized TLV value, got nil")
|
|
}
|
|
}
|
|
|
|
// TestPacket_writeTLV_Ugly verifies writeTLV handles an empty value slice correctly.
|
|
// writeTLV(buf, TagIntent, []byte{})
|
|
// // buf contains: [0x04, 0x00] (tag + zero length, no value bytes)
|
|
func TestPacket_writeTLV_Ugly(t *testing.T) {
|
|
buffer := new(bytes.Buffer)
|
|
|
|
err := writeTLV(buffer, TagIntent, []byte{})
|
|
|
|
if err != nil {
|
|
t.Fatalf("writeTLV with empty value failed: %v", err)
|
|
}
|
|
result := buffer.Bytes()
|
|
if len(result) != 2 {
|
|
t.Fatalf("expected 2 bytes for empty value, got %d", len(result))
|
|
}
|
|
if result[0] != TagIntent {
|
|
t.Errorf("expected tag 0x%02x, got 0x%02x", TagIntent, result[0])
|
|
}
|
|
if result[1] != 0x00 {
|
|
t.Errorf("expected length 0, got %d", result[1])
|
|
}
|
|
}
|