2487681396
gofmt -w across the controller tree (46 files) so gofmt -l is empty — disarms the
formatting landmine where a targeted edit + accidental gofmt -w swept ~46 unrelated
files. Pure formatting: whitespace + gofmt's optional-semicolon removal in reflowed
inline closures. One doc comment reworded ('' -> 'the empty string') to avoid gofmt's
Go-1.19 doc-comment typographic substitition ('' -> curly quote) muddying its meaning.
No build/vet/test behavior change.
77 lines
2.9 KiB
Go
77 lines
2.9 KiB
Go
package web
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-controller/internal/stacks"
|
|
)
|
|
|
|
// R-53 / F7: app_export.html built the app's public URL as `<subdomain>.{{$.CSRFToken}}` — the
|
|
// session CSRF token substituted where the customer domain belongs. That is two defects in one
|
|
// token: the „open in browser" link is wrong for every app that has a subdomain, and a CSRF token
|
|
// lands in a URL (history, referrers, logs). The correct CSRF usage on this page is the csrfH()
|
|
// helper reading the meta tag, which is untouched.
|
|
|
|
const exportTestToken = "deadbeefcafebabedeadbeefcafebabedeadbeefcafebabedeadbeefcafebabe"
|
|
|
|
// exportScriptLine returns the `var domain = …` line, so an assertion cannot accidentally match the
|
|
// token where it legitimately appears (the meta tag) elsewhere on the page.
|
|
func exportScriptLine(t *testing.T, html string) string {
|
|
t.Helper()
|
|
for _, ln := range strings.Split(html, "\n") {
|
|
if strings.Contains(ln, "var domain =") {
|
|
return ln
|
|
}
|
|
}
|
|
t.Fatalf("no `var domain =` line in the rendered export page")
|
|
return ""
|
|
}
|
|
|
|
func renderExport(t *testing.T, subdomain string) string {
|
|
t.Helper()
|
|
return renderBackupPage(t, "app_export", map[string]interface{}{
|
|
"Stack": stacks.Stack{
|
|
Name: "immich", Deployed: true,
|
|
Meta: stacks.Metadata{Slug: "immich", DisplayName: "Immich", Subdomain: subdomain},
|
|
},
|
|
"Drives": nil,
|
|
"Domain": "demo-felhom.eu",
|
|
"CSRFToken": exportTestToken,
|
|
"CSRFField": "",
|
|
"Page": "apps",
|
|
"Title": "Export",
|
|
"ExportPage": true,
|
|
})
|
|
}
|
|
|
|
// Scenario C — the domain is joined from the CUSTOMER DOMAIN, and the CSRF token appears nowhere in
|
|
// that line. COMPANION red-proof: restore `{{$.CSRFToken}}` in app_export.html's `var domain` line
|
|
// → both assertions FAIL. Run → fail → revert (recorded in REPORT).
|
|
func TestAppExportDomainUsesCustomerDomainNotCSRFToken(t *testing.T) {
|
|
line := exportScriptLine(t, renderExport(t, "photos"))
|
|
|
|
if !strings.Contains(line, "'photos.demo-felhom.eu'") {
|
|
t.Errorf("export link must be built from the customer domain, got: %s", line)
|
|
}
|
|
if strings.Contains(line, exportTestToken) {
|
|
t.Errorf("the CSRF token must NEVER appear in the export URL, got: %s", line)
|
|
}
|
|
}
|
|
|
|
// The empty-subdomain branch still yields the empty string — an app without a subdomain must not get
|
|
// a link to a bare domain (the truthiness guard is what produces that, and the fix must not disturb it).
|
|
func TestAppExportDomainEmptyWithoutSubdomain(t *testing.T) {
|
|
line := exportScriptLine(t, renderExport(t, ""))
|
|
|
|
if !strings.Contains(line, "''") {
|
|
t.Errorf("no subdomain must yield an empty domain, got: %s", line)
|
|
}
|
|
if strings.Contains(line, "demo-felhom.eu'") && !strings.Contains(line, "'' ? ") {
|
|
t.Errorf("no subdomain must not produce a bare-domain link, got: %s", line)
|
|
}
|
|
if strings.Contains(line, exportTestToken) {
|
|
t.Errorf("the CSRF token must NEVER appear in the export URL, got: %s", line)
|
|
}
|
|
}
|