package encoder import ( "encoding/base64" "os" "strings" "testing" ) func testKeyring(t *testing.T) string { t.Helper() path := t.TempDir() + "/pubring.mix" var content strings.Builder for i, name := range []string{"entry", "middle", "exit"} { keyID := strings.Repeat(string(rune('a'+i)), 32) publicKey := strings.Repeat(string(rune('d'+i)), 64) content.WriteString(name + " " + name + "@example.org " + keyID + " 4:0.2c E 2025-01-01 2099-12-31\n\n") content.WriteString("-----Begin Mix Key-----\n" + keyID + "\n" + publicKey + "\n-----End Mix Key-----\n") } if err := os.WriteFile(path, []byte(content.String()), 0600); err != nil { t.Fatal(err) } return path } func TestValidateEmail(t *testing.T) { r := Request{Kind: Email, PublicKeyring: "/tmp/pubring.mix", Entry: "entry", Chain: []string{"entry"}, To: "user@example.org", Body: "hello"} if err := Validate(r); err != nil { t.Fatal(err) } } func TestValidateRejectsPlainIncompleteRequest(t *testing.T) { r := Request{Kind: Email, PublicKeyring: "/tmp/pubring.mix", Entry: "entry", Chain: []string{"entry"}, To: "bad", Body: "hello"} if err := Validate(r); err == nil { t.Fatal("expected invalid recipient") } } func TestValidateUsenetRequiresGatewayRecipient(t *testing.T) { r := Request{Kind: Usenet, PublicKeyring: "/tmp/pubring.mix", Chain: []string{"entry"}, Newsgroup: "misc.test", Body: "hello"} if err := Validate(r); err == nil { t.Fatal("expected missing Usenet gateway recipient to be rejected") } r.To = "mail2news@example.org" if err := Validate(r); err != nil { t.Fatalf("expected valid Usenet request: %v", err) } } func TestComposeUsenetGatewayHeaders(t *testing.T) { plain, err := composeMessage(Request{ Kind: Usenet, To: "mail2news@example.org", Subject: "test", Newsgroup: "misc.test", Body: "hello", }) if err != nil { t.Fatal(err) } text := string(plain) if !strings.Contains(text, "To: mail2news@example.org\n") || !strings.Contains(text, "Newsgroups: misc.test\n") { t.Fatalf("missing Usenet delivery headers: %q", text) } } func TestEncodeProducesYAMNArmor(t *testing.T) { keyring := testKeyring(t) result, err := Encode(Request{ Kind: Email, PublicKeyring: keyring, Entry: "entry", Chain: []string{"entry"}, From: "Anonymous ", To: "user@example.org", Subject: "test", Body: "hello", }) if err != nil { t.Fatal(err) } if result.EntryAddress != "entry@example.org" { t.Fatalf("unexpected entry address: %q", result.EntryAddress) } text := string(result.Envelope) if !strings.Contains(text, "-----BEGIN REMAILER MESSAGE-----") || !strings.Contains(text, "-----END REMAILER MESSAGE-----") { t.Fatal("missing YAMN armor markers") } lines := strings.Split(text, "\n") start := 0 for i, line := range lines { if line == "-----BEGIN REMAILER MESSAGE-----" { start = i + 3 break } } var encoded strings.Builder for _, line := range lines[start:] { if line == "" || strings.HasPrefix(line, "-----END") { break } encoded.WriteString(line) } packet, err := base64.StdEncoding.DecodeString(encoded.String()) if err != nil { t.Fatal(err) } if len(packet) != messageBytes { t.Fatalf("unexpected packet size: got %d, want %d", len(packet), messageBytes) } } func TestEncodeMultiHop(t *testing.T) { result, err := Encode(Request{ Kind: Email, PublicKeyring: testKeyring(t), Entry: "entry", Chain: []string{"entry", "middle", "exit"}, To: "user@example.org", Body: "hello", }) if err != nil { t.Fatal(err) } if len(result.Envelope) == 0 || result.EntryAddress != "entry@example.org" { t.Fatal("multi-hop envelope was not produced") } }