package aviso_test import ( "errors" "testing" "amadan.net/rastrillo/aviso" ) func newService(t *testing.T) *aviso.Service { t.Helper() key, err := aviso.GenerateKey() if err != nil { t.Fatal(err) } s, err := aviso.New(aviso.Config{ DB: openDB(t), PrivateKey: key, Contact: "mailto:ops@example.test", Origin: "https://app.example.test", }) if err != nil { t.Fatal(err) } return s } func TestNewRefusesBadConfig(t *testing.T) { key, _ := aviso.GenerateKey() good := aviso.Config{DB: openDB(t), PrivateKey: key, Contact: "mailto:x@y", Origin: "https://a"} if _, err := aviso.New(good); err != nil { t.Fatalf("good config refused: %v", err) } c := good c.PrivateKey = "" if _, err := aviso.New(c); !errors.Is(err, aviso.ErrEmptyPrivateKey) { t.Errorf("empty key: %v", err) } c = good c.PrivateKey = "not-a-key" if _, err := aviso.New(c); !errors.Is(err, aviso.ErrInvalidPrivateKey) { t.Errorf("bad key: %v", err) } c = good c.DB = nil if _, err := aviso.New(c); err == nil { t.Error("nil DB accepted") } for _, contact := range []string{"ops@example.test", "mailto:", "mailto:nobody", "https://", "https://bad host", "http://example.test", "https://u:p@example.test"} { c = good c.Contact = contact if _, err := aviso.New(c); err == nil { t.Errorf("Contact %q accepted", contact) } } for _, contact := range []string{"mailto:ops@example.test", "https://example.test/abuse"} { c = good c.Contact = contact if _, err := aviso.New(c); err != nil { t.Errorf("Contact %q refused: %v", contact, err) } } // csrf.SameOrigin compares the Origin header to this string exactly, // so anything beyond scheme://host[:port] would refuse every POST. for _, origin := range []string{"app.example.test", "https://", "https://app.example.test/", "https://app.example.test/path", "https://app.example.test?x=1", "https://u:p@app.example.test", "ftp://app.example.test"} { c = good c.Origin = origin if _, err := aviso.New(c); err == nil { t.Errorf("Origin %q accepted", origin) } } for _, origin := range []string{"https://app.example.test", "http://localhost:8080"} { c = good c.Origin = origin if _, err := aviso.New(c); err != nil { t.Errorf("Origin %q refused: %v", origin, err) } } } // The same private key must give the same public key across a // restart: browsers compare it on every load, and a key that drifted // would make every one of them re-enrol. func TestPublicKeyStringIsStableAcrossRestart(t *testing.T) { key, _ := aviso.GenerateKey() mk := func() *aviso.Service { s, err := aviso.New(aviso.Config{DB: openDB(t), PrivateKey: key, Contact: "mailto:x@y", Origin: "https://a"}) if err != nil { t.Fatal(err) } return s } a, b := mk(), mk() if a.PublicKeyString() == "" || a.PublicKeyString() != b.PublicKeyString() { t.Fatalf("public key not stable: %q vs %q", a.PublicKeyString(), b.PublicKeyString()) } }