package models_test import ( "errors" "reflect" "testing" "git.golem15.com/golem15/sm-sitemap-plugin/models" "git.golem15.com/golem15/summercms/modules/cabana" "git.golem15.com/golem15/summercms/modules/lagoon" ) // TestAllowedFrontendURL pins the one definition of a frontend_url that may // be saved, imported and applied (T-17-15): empty, or an absolute http(s) // URL with a host and without whitespace, control characters, a double // quote, <, > or &. func TestAllowedFrontendURL(t *testing.T) { for _, u := range []string{ "", "https://www.ex.pl", "https://www.ex.pl/", "https://www.ex.pl///", "http://localhost:3000", "HTTPS://WWW.EX.PL", "https://www.ex.pl/app", "https://www.ex.pl:8443/base/", "https://[::1]:3000", // The frontend URLs of the golden inputs. "https://api.example.test", "https://www.example.test/", } { if !models.AllowedFrontendURL(u) { t.Errorf("AllowedFrontendURL(%q) = false, want true", u) } } for _, u := range []string{ "0", "javascript:alert(document.domain)//", "JavaScript://www.ex.pl/%0aalert(1)", `https://x"/>", " https://www.ex.pl", "https://www.ex.pl\n", "https://www.ex.pl\t", "https://www.ex.plĀ ", "https://www.ex.pl\x7f", "https://www.ex.pl\xff", "//www.ex.pl", "www.ex.pl", "/path", "https:///x", "https://:8080", "https:www.ex.pl", "http://", "https://", "https://%zz", "data:text/html,x", "ftp://www.ex.pl", } { if models.AllowedFrontendURL(u) { t.Errorf("AllowedFrontendURL(%q) = true, want false", u) } } } // TestSettingsValidate pins the save checks of the settings singleton // (UI-SPEC C26, T-33-12): the check the controller runs before a save passes // a null, empty or accepted site_url, a file size from 1 to 50 000 and // additional addresses that are paths or http(s) URLs, and answers a // validation error keyed by the field for any other value. func TestSettingsValidate(t *testing.T) { text := func(s string) *string { return &s } ok := func(s models.Settings) models.Settings { if s.FileSize == 0 { s.FileSize = 1000 } if s.HTMLPageSize == 0 { s.HTMLPageSize = models.DefaultHTMLPageSize } return s } extra := func(urls ...string) lagoon.Jsonable[[]models.ExtraURL] { rows := []models.ExtraURL{} for _, u := range urls { rows = append(rows, models.ExtraURL{URL: u}) } return lagoon.Jsonable[[]models.ExtraURL]{Data: rows, Valid: true} } for name, s := range map[string]models.Settings{ "null site_url": ok(models.Settings{}), "empty site_url": ok(models.Settings{SiteURL: text("")}), "site_url": ok(models.Settings{SiteURL: text("https://www.ex.pl/")}), "file size 1": ok(models.Settings{FileSize: 1}), "file size 50 000": ok(models.Settings{FileSize: 50000}), "extra addresses": ok(models.Settings{ExtraURLs: extra("/", "/o-nas?x=1&y=2", "https://www.ex.pl/kontakt")}), } { if err := s.Validate(); err != nil { t.Errorf("%s: Validate = %v, want nil", name, err) } } for name, c := range map[string]struct { s models.Settings want map[string]any }{ "javascript site_url": {ok(models.Settings{SiteURL: text("javascript:alert(document.domain)//")}), map[string]any{"site_url": []string{"golem15.sitemap::lang.errors.frontend_url"}}}, "attribute site_url": {ok(models.Settings{SiteURL: text(`https://x"/>