From c1decadb590c4d79d92bcc4df7772119a5c91244 Mon Sep 17 00:00:00 2001 From: Gab Virebent Date: Sat, 22 Aug 2026 20:36:56 +0200 Subject: Initial Aegis Usenet client release --- internal/config/config_test.go | 113 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 internal/config/config_test.go (limited to 'internal/config/config_test.go') diff --git a/internal/config/config_test.go b/internal/config/config_test.go new file mode 100644 index 0000000..c35ee61 --- /dev/null +++ b/internal/config/config_test.go @@ -0,0 +1,113 @@ +package config + +import ( + "os" + "path/filepath" + "reflect" + "strings" + "testing" +) + +func TestSaveLoadRoundTrip(t *testing.T) { + path := filepath.Join(t.TempDir(), "nested", "config.json") + want := Settings{ + Host: "news.example.org", + Port: "563", + UseTLS: true, + SMTPHost: "qee4i7sags6phsvb2yodwecfj7noimfhhalsjktsvikrwotxzis3raad.onion", + SMTPPort: "25", + SMTPRecipient: "mail2news@mail2news.tcpreset.net", + Username: "reader", + ProxyType: "SOCKS5", + ProxyAddress: "127.0.0.1:9050", + DisplayName: "Aegis User", + Email: "reader@example.org", + Subscriptions: []string{"comp.lang.go", "sci.crypt"}, + } + if err := Save(path, want); err != nil { + t.Fatalf("Save() error = %v", err) + } + info, err := os.Stat(path) + if err != nil { + t.Fatal(err) + } + if got := info.Mode().Perm(); got != 0o600 { + t.Fatalf("mode = %o, want 600", got) + } + got, err := Load(path) + if err != nil { + t.Fatalf("Load() error = %v", err) + } + if !reflect.DeepEqual(got, want) { + t.Fatalf("Load() = %#v, want %#v", got, want) + } +} + +func TestPasswordCannotBePersisted(t *testing.T) { + settingsType := reflect.TypeOf(Settings{}) + if _, ok := settingsType.FieldByName("Password"); ok { + t.Fatal("Settings must not contain a persistent Password field") + } + path := filepath.Join(t.TempDir(), "config.json") + if err := Save(path, Default()); err != nil { + t.Fatal(err) + } + data, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + if strings.Contains(strings.ToLower(string(data)), "password") { + t.Fatal("saved settings unexpectedly mention a password") + } +} + +func TestValidateRejectsProtocolInjection(t *testing.T) { + settings := Default() + settings.Username = "user\r\nQUIT" + if err := settings.Validate(); err == nil { + t.Fatal("Validate() accepted a username with protocol injection") + } + if err := ValidateGroupName("comp.lang.go\r\nPOST"); err == nil { + t.Fatal("ValidateGroupName() accepted protocol injection") + } +} + +func TestValidateRejectsAuthenticationWithoutTLS(t *testing.T) { + settings := Default() + settings.UseTLS = false + settings.Username = "reader" + if err := settings.Validate(); err == nil { + t.Fatal("Validate() accepted authentication without TLS") + } +} + +func TestValidateRejectsCompressionWithTLS(t *testing.T) { + settings := Default() + settings.UseCompression = true + if err := settings.Validate(); err == nil { + t.Fatal("Validate() accepted compression over TLS") + } +} + +func TestValidateRequiresProxyForOnionSMTP(t *testing.T) { + settings := Default() + settings.SMTPHost = "mail.example.onion" + settings.SMTPPort = "465" + settings.SMTPMode = "" + settings.ProxyType = "DIRECT" + if err := settings.Validate(); err == nil { + t.Fatal("Validate() accepted direct .onion SMTP") + } +} + +func TestValidateAllowsCleartextOnionSMTPThroughSharedProxy(t *testing.T) { + settings := Default() + settings.SMTPHost = "mail.example.onion" + settings.SMTPPort = "25" + settings.SMTPMode = "" + settings.ProxyType = "SOCKS5" + settings.ProxyAddress = "127.0.0.1:9050" + if err := settings.Validate(); err != nil { + t.Fatalf("Validate() rejected cleartext onion SMTP through SOCKS5: %v", err) + } +} -- cgit v1.2.3