- Settings.BeforeValidate answers a cabana validation error on frontend_url, so the settings save is a 422 and the row is unchanged - sitemap:import-winter stops on a frontend_url that models.AllowedFrontendURL refuses, before the dry-run branch and before any database use; the value is printed quoted - errors.frontend_url phrase in en and pl - TestSettingsBeforeValidate, TestWinterSettingsFrontendURL and the save and import refusals in the Postgres smokes
93 lines
3.3 KiB
Go
93 lines
3.3 KiB
Go
package console
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.golem15.com/golem15/sm-sitemap-plugin/models"
|
|
"git.golem15.com/golem15/summercms/modules/bonfire"
|
|
)
|
|
|
|
// TestWinterSettingsFrontendURL pins the import check of T-17-15: a settings
|
|
// export whose frontend_url models.AllowedFrontendURL refuses stops
|
|
// sitemap:import-winter with an error naming the setting, with and without
|
|
// --dry-run and before the database is used (the test passes none). An
|
|
// accepted, empty, null or missing frontend_url is read as before.
|
|
func TestWinterSettingsFrontendURL(t *testing.T) {
|
|
dir := t.TempDir()
|
|
n := 0
|
|
settingsFile := func(fields map[string]any) string {
|
|
t.Helper()
|
|
// json.Marshal encodes the quotes of the attack value.
|
|
raw, err := json.Marshal(fields)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
n++
|
|
path := filepath.Join(dir, "settings-"+string(rune('a'+n))+".json")
|
|
if err := os.WriteFile(path, raw, 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return path
|
|
}
|
|
|
|
for _, value := range []string{
|
|
"javascript:alert(document.domain)//",
|
|
`https://x"/><y a="`,
|
|
"0",
|
|
" https://www.example.test",
|
|
} {
|
|
file := settingsFile(map[string]any{"frontend_url": value, "enable_priority_tiers": "1"})
|
|
var report WinterReport
|
|
if _, err := readWinterSettings(file, &report); err == nil || !strings.Contains(err.Error(), "setting frontend_url") {
|
|
t.Errorf("readWinterSettings(%q) = %v, want an error naming setting frontend_url", value, err)
|
|
}
|
|
for _, dry := range []bool{false, true} {
|
|
var buf bytes.Buffer
|
|
out := bonfire.NewOutput(strings.NewReader(""), &buf, &buf)
|
|
report, err := ImportWinterFiles(context.Background(), nil, nil, WinterOptions{SettingsFile: file, DryRun: dry}, out)
|
|
if err == nil || !strings.Contains(err.Error(), "setting frontend_url") {
|
|
t.Errorf("ImportWinterFiles(%q, dry run %v) = %v, want an error naming setting frontend_url", value, dry, err)
|
|
}
|
|
if report.Settings {
|
|
t.Errorf("ImportWinterFiles(%q, dry run %v) reports the settings as copied", value, dry)
|
|
}
|
|
if strings.Contains(buf.String(), "would be copied") || strings.Contains(buf.String(), "Settings copied") {
|
|
t.Errorf("ImportWinterFiles(%q, dry run %v) printed a copy line:\n%s", value, dry, buf.String())
|
|
}
|
|
}
|
|
}
|
|
|
|
// The error quotes the value, so a control character is not printed raw.
|
|
var report WinterReport
|
|
_, err := readWinterSettings(settingsFile(map[string]any{"frontend_url": "https://www.example.test\x1b[2J"}), &report)
|
|
if err == nil || strings.Contains(err.Error(), "\x1b") || !strings.Contains(err.Error(), `\x1b`) {
|
|
t.Errorf("a control character in frontend_url: %q", err)
|
|
}
|
|
|
|
for name, tc := range map[string]struct {
|
|
fields map[string]any
|
|
want string
|
|
}{
|
|
"valid": {map[string]any{"frontend_url": "https://www.example.test/"}, "https://www.example.test/"},
|
|
"empty": {map[string]any{"frontend_url": ""}, ""},
|
|
"null": {map[string]any{"frontend_url": nil}, ""},
|
|
"missing": {map[string]any{"enable_priority_tiers": "1"}, ""},
|
|
} {
|
|
var report WinterReport
|
|
s, err := readWinterSettings(settingsFile(tc.fields), &report)
|
|
if err != nil {
|
|
t.Errorf("%s: readWinterSettings = %v", name, err)
|
|
continue
|
|
}
|
|
if got := models.Text(s.FrontendURL); got != tc.want {
|
|
t.Errorf("%s: frontend_url = %q, want %q", name, got, tc.want)
|
|
}
|
|
}
|
|
}
|