feat(domains): 301-Weiterleitung Domain→Domain (redirect_to) — v1.2.108
Neue Domain kann per 301 auf eine andere Domain/URL umgeleitet werden, statt auf ein Backend zu routen (Use-Case: kvs.netcell-it.de → https://zkm.netcell-it.de, inkl. HTTPS). Variante (a): immer auf Ziel-Root (`redirect location`), pfad- unabhängig. - Migration 0043: domains.redirect_to text NOT NULL DEFAULT '' - Model + domains-Service (SELECT/INSERT/UPDATE/scan) - HAProxy-Generator: buildRedirectTo() sanitisiert (nur http(s), kein Whitespace/Quotes → sonst kein Redirect statt kaputter Config); Template emittiert `http-request redirect location <url> code 301 if hdr(host)`. Terminiert vor use_backend → Redirect-Domain routet auf kein Backend. http→https läuft über den vorhandenen :80-Redirect (zwei Hops, inkl. TLS). - UI: Feld „Weiterleitung (301) nach" im Domain-Formular (de/en) - Tests: Render-Zeile + buildRedirectTo-Sanitisierung Hinweis: Die Redirect-Domain braucht weiterhin ein eigenes TLS-Zert (ACME). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -170,6 +170,45 @@ func TestRender_WWWRedirectToWWW(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRender_RedirectTo(t *testing.T) {
|
||||
v := View{
|
||||
Domains: []DomainView{
|
||||
{
|
||||
Domain: models.Domain{
|
||||
ID: 1, Name: "kvs.netcell-it.de", Active: true,
|
||||
RedirectTo: "https://zkm.netcell-it.de",
|
||||
},
|
||||
RedirectTo: "https://zkm.netcell-it.de",
|
||||
},
|
||||
},
|
||||
}
|
||||
out := renderView(t, v)
|
||||
want := `http-request redirect location https://zkm.netcell-it.de code 301 if { hdr(host) -i kvs.netcell-it.de }`
|
||||
if !strings.Contains(out, want) {
|
||||
t.Errorf("missing domain→domain 301 redirect line:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildRedirectTo(t *testing.T) {
|
||||
cases := []struct{ in, want string }{
|
||||
{"https://zkm.netcell-it.de", "https://zkm.netcell-it.de"},
|
||||
{" https://zkm.netcell-it.de ", "https://zkm.netcell-it.de"}, // getrimmt
|
||||
{"http://x.de", "http://x.de"},
|
||||
{"", ""},
|
||||
{"zkm.netcell-it.de", ""}, // kein Schema
|
||||
{"ftp://x.de", ""}, // falsches Schema
|
||||
{"https://x .de", ""}, // Whitespace → unsafe
|
||||
{"https://x\"de", ""}, // Quote → unsafe
|
||||
{"javascript:alert(1)", ""}, // kein http(s)
|
||||
}
|
||||
for _, c := range cases {
|
||||
got := buildRedirectTo(models.Domain{RedirectTo: c.in})
|
||||
if got != c.want {
|
||||
t.Errorf("buildRedirectTo(%q) = %q, want %q", c.in, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildHSTSHeader(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
|
||||
Reference in New Issue
Block a user