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 `.{{$.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 '' — 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) } }