summaryrefslogtreecommitdiffstats
path: root/internal/config/config_test.go
diff options
context:
space:
mode:
authorGab Virebent <gabriel1@virebent.art>2026-08-24 17:34:45 +0200
committerGab Virebent <gabriel1@virebent.art>2026-08-24 17:34:45 +0200
commite9fbbe3373eb66a345f5e3829e2563b94dc92051 (patch)
tree950d75fda88574afb46b4aeab36e96f3c089a3bb /internal/config/config_test.go
parentfb83c4d70616ec23d8a5397409a5d31c70b70d66 (diff)
downloadn2usenet-main.tar.gz
n2usenet-main.tar.xz
n2usenet-main.zip
Harden transport and preserve profile identitiesHEADmain
Diffstat (limited to 'internal/config/config_test.go')
-rw-r--r--internal/config/config_test.go151
1 files changed, 151 insertions, 0 deletions
diff --git a/internal/config/config_test.go b/internal/config/config_test.go
new file mode 100644
index 0000000..fdb02e4
--- /dev/null
+++ b/internal/config/config_test.go
@@ -0,0 +1,151 @@
+package config
+
+import (
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+ "time"
+)
+
+func validConfig() Config {
+ return Config{
+ Listen: "127.0.0.1:8095",
+ SMTP: SMTPConfig{
+ Host: "mail.virebent.art",
+ Port: 587,
+ Recipient: "mail2news@mail2news.tcpreset.net",
+ EnvelopeFrom: "n2usenet@virebent.art",
+ Sender: "n2usenet@virebent.art",
+ TLSServerName: "mail.virebent.art",
+ RequireTLS: true,
+ ProbeInterval: 15 * time.Minute,
+ },
+ Security: SecurityConfig{
+ MinHashcashBits: 20,
+ MinMessageBytes: 10,
+ MaxMessageBytes: 65536,
+ MaxNewsgroups: 3,
+ RateLimitCount: 10,
+ RateLimitWindow: time.Hour,
+ IdenticonsCLI: "/usr/local/bin/identicons-cli",
+ RequireFace: true,
+ },
+ }
+}
+
+func TestLoadAcceptsLegacyHeaderFromAsSender(t *testing.T) {
+ t.Setenv("N2U_SMTP_HEADER_FROM", "legacy-sender@virebent.art")
+
+ cfg, err := Load()
+ if err != nil {
+ t.Fatalf("Load returned error: %v", err)
+ }
+ if got, want := cfg.SMTP.Sender, "legacy-sender@virebent.art"; got != want {
+ t.Fatalf("Sender = %q, want %q", got, want)
+ }
+}
+
+func TestLoadPrefersSenderOverLegacyHeaderFrom(t *testing.T) {
+ t.Setenv("N2U_SMTP_SENDER", "sender@virebent.art")
+ t.Setenv("N2U_SMTP_HEADER_FROM", "legacy-sender@virebent.art")
+
+ cfg, err := Load()
+ if err != nil {
+ t.Fatalf("Load returned error: %v", err)
+ }
+ if got, want := cfg.SMTP.Sender, "sender@virebent.art"; got != want {
+ t.Fatalf("Sender = %q, want %q", got, want)
+ }
+}
+
+func TestValidateSMTPAuthentication(t *testing.T) {
+ tests := []struct {
+ name string
+ mutate func(*Config)
+ wantErr string
+ }{
+ {
+ name: "credentials with STARTTLS",
+ mutate: func(cfg *Config) {
+ cfg.SMTP.Username = "n2usenet@virebent.art"
+ cfg.SMTP.Password = "test-password"
+ },
+ },
+ {
+ name: "missing password",
+ mutate: func(cfg *Config) {
+ cfg.SMTP.Username = "n2usenet@virebent.art"
+ },
+ wantErr: "must be configured together",
+ },
+ {
+ name: "missing username",
+ mutate: func(cfg *Config) {
+ cfg.SMTP.Password = "test-password"
+ },
+ wantErr: "must be configured together",
+ },
+ {
+ name: "credentials without TLS",
+ mutate: func(cfg *Config) {
+ cfg.SMTP.Username = "n2usenet@virebent.art"
+ cfg.SMTP.Password = "test-password"
+ cfg.SMTP.RequireTLS = false
+ },
+ wantErr: "requires TLS",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ cfg := validConfig()
+ tt.mutate(&cfg)
+ err := cfg.Validate()
+ if tt.wantErr == "" {
+ if err != nil {
+ t.Fatalf("Validate returned error: %v", err)
+ }
+ return
+ }
+ if err == nil || !strings.Contains(err.Error(), tt.wantErr) {
+ t.Fatalf("Validate error = %v, want substring %q", err, tt.wantErr)
+ }
+ })
+ }
+}
+
+func TestLoadReadsSMTPPasswordFile(t *testing.T) {
+ passwordPath := filepath.Join(t.TempDir(), "smtp-password")
+ if err := os.WriteFile(passwordPath, []byte("test-password\n"), 0600); err != nil {
+ t.Fatalf("write password file: %v", err)
+ }
+ t.Setenv("N2U_SMTP_USERNAME", "n2usenet@virebent.art")
+ t.Setenv("N2U_SMTP_PASSWORD_FILE", passwordPath)
+ t.Setenv("N2U_SMTP_REQUIRE_TLS", "true")
+
+ cfg, err := Load()
+ if err != nil {
+ t.Fatalf("Load returned error: %v", err)
+ }
+ if got, want := cfg.SMTP.Password, "test-password"; got != want {
+ t.Fatalf("Password = %q, want %q", got, want)
+ }
+}
+
+func TestLoadReadsPersistentCSRFKey(t *testing.T) {
+ keyPath := filepath.Join(t.TempDir(), "csrf-key")
+ want := strings.Repeat("k", 32)
+ if err := os.WriteFile(keyPath, []byte(want+"\n"), 0600); err != nil {
+ t.Fatalf("write CSRF key file: %v", err)
+ }
+ t.Setenv("N2U_CSRF_KEY_FILE", keyPath)
+
+ cfg, err := Load()
+ if err != nil {
+ t.Fatalf("Load returned error: %v", err)
+ }
+ if got := string(cfg.Security.CSRFKey); got != want {
+ t.Fatalf("CSRFKey = %q, want %q", got, want)
+ }
+}