summaryrefslogtreecommitdiffstats
path: root/internal/submit/validation_test.go
diff options
context:
space:
mode:
authorGab Virebent <gabriel1@virebent.art>2026-08-03 17:13:50 +0200
committerGab Virebent <gabriel1@virebent.art>2026-08-03 17:13:50 +0200
commitcd58d593789c6facb1d05b7f255bc2c5f2e46010 (patch)
tree87a226313e49e2c6f7b7028d77d4957db416d1c1 /internal/submit/validation_test.go
downloadn2usenet-cd58d593789c6facb1d05b7f255bc2c5f2e46010.tar.gz
n2usenet-cd58d593789c6facb1d05b7f255bc2c5f2e46010.tar.xz
n2usenet-cd58d593789c6facb1d05b7f255bc2c5f2e46010.zip
Initial import: n2usenet HTTPS/Nym Usenet gateway
Diffstat (limited to 'internal/submit/validation_test.go')
-rw-r--r--internal/submit/validation_test.go111
1 files changed, 111 insertions, 0 deletions
diff --git a/internal/submit/validation_test.go b/internal/submit/validation_test.go
new file mode 100644
index 0000000..630b647
--- /dev/null
+++ b/internal/submit/validation_test.go
@@ -0,0 +1,111 @@
+package submit
+
+import (
+ "crypto/ed25519"
+ "crypto/rand"
+ "crypto/sha1"
+ "encoding/base64"
+ "fmt"
+ "net/url"
+ "strings"
+ "testing"
+ "time"
+
+ "n2usenet/internal/config"
+)
+
+func TestParseAndValidateSignedSubmission(t *testing.T) {
+ pub, priv, err := ed25519.GenerateKey(rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ body := "This is a valid signed test message."
+ sig := ed25519.Sign(priv, []byte(body))
+ sigB64 := base64.StdEncoding.EncodeToString(sig)
+ pubB64 := base64.StdEncoding.EncodeToString(pub)
+
+ form := url.Values{}
+ form.Set("from", "Tester <tester@example.net>")
+ form.Set("newsgroups", "alt.test")
+ form.Set("subject", "Test")
+ form.Set("xhashcash", mineTestHashcash(t, "tester@example.net", 8))
+ form.Set("message", body+"\n\n--- Digital Signature ---\n"+sigB64)
+ form.Set("x-ed25519-pub", pubB64)
+ form.Set("x-ed25519-sig", sigB64)
+
+ sub, err := ParseAndValidate(form, config.SecurityConfig{
+ MinHashcashBits: 8,
+ MinMessageBytes: 10,
+ MaxMessageBytes: 1024,
+ MaxNewsgroups: 3,
+ })
+ if err != nil {
+ t.Fatalf("ParseAndValidate returned error: %v", err)
+ }
+ if sub.SignedText != body {
+ t.Fatalf("signed payload mismatch: %q", sub.SignedText)
+ }
+}
+
+func TestParseAndValidateRejectsBadSignature(t *testing.T) {
+ pub, _, err := ed25519.GenerateKey(rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, otherPriv, err := ed25519.GenerateKey(rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ body := "This is a valid sized test message."
+ sig := ed25519.Sign(otherPriv, []byte("different"))
+ form := url.Values{}
+ form.Set("from", "Tester <tester@example.net>")
+ form.Set("newsgroups", "alt.test")
+ form.Set("subject", "Test")
+ form.Set("xhashcash", mineTestHashcash(t, "tester@example.net", 8))
+ form.Set("message", body+"\n\n--- Digital Signature ---\n"+base64.StdEncoding.EncodeToString(sig))
+ form.Set("x-ed25519-pub", base64.StdEncoding.EncodeToString(pub))
+ form.Set("x-ed25519-sig", base64.StdEncoding.EncodeToString(sig))
+
+ _, err = ParseAndValidate(form, config.SecurityConfig{
+ MinHashcashBits: 8,
+ MinMessageBytes: 10,
+ MaxMessageBytes: 1024,
+ MaxNewsgroups: 3,
+ })
+ if err == nil {
+ t.Fatal("expected bad signature to be rejected")
+ }
+}
+
+func TestBuildMessageRequiresFaceWhenConfigured(t *testing.T) {
+ sub := Submission{
+ From: "Tester <tester@example.net>",
+ FromAddress: "tester@example.net",
+ Newsgroups: []string{"alt.test"},
+ Subject: "Test",
+ Message: "This is a body.",
+ PublicKeyB64: base64.StdEncoding.EncodeToString(make([]byte, ed25519.PublicKeySize)),
+ SignatureB64: base64.StdEncoding.EncodeToString(make([]byte, ed25519.SignatureSize)),
+ }
+ _, _, err := BuildMessage(sub, "mail2news@mail2news.tcpreset.net", "example.net", "/missing/identicons-cli", true)
+ if err == nil {
+ t.Fatal("expected missing Face generator to reject message")
+ }
+}
+
+func mineTestHashcash(t *testing.T, resource string, bits int) string {
+ t.Helper()
+ date := time.Now().UTC().Format("060102150405")
+ prefix := fmt.Sprintf("1:%d:%s:%s::test:", bits, date, resource)
+ target := bits / 4
+ for i := 0; i < 1_000_000; i++ {
+ token := fmt.Sprintf("%s%d", prefix, i)
+ sum := sha1.Sum([]byte(token))
+ if strings.HasPrefix(fmt.Sprintf("%x", sum[:]), strings.Repeat("0", target)) {
+ return token
+ }
+ }
+ t.Fatal("failed to mine test hashcash")
+ return ""
+}