Add CSRF protection to state-changing POST endpoints

Add gorilla/csrf middleware to protect all HTML-serving routes against
cross-site request forgery attacks. The webhook endpoint is excluded
since it uses secret-based authentication.

Changes:
- Add gorilla/csrf v1.7.3 dependency
- Add CSRF() middleware method using session secret as key
- Apply CSRF middleware to all HTML route groups in routes.go
- Pass CSRF token to all templates via addGlobals helper
- Add {{ .CSRFField }} / {{ $.CSRFField }} hidden inputs to all forms

Closes #11
This commit is contained in:
clawbot
2026-02-15 14:17:55 -08:00
parent d4eae284b5
commit b1dc8fcc4e
17 changed files with 77 additions and 30 deletions

View File

@@ -29,8 +29,8 @@ const (
func (h *Handlers) HandleAppNew() http.HandlerFunc {
tmpl := templates.GetParsed()
return func(writer http.ResponseWriter, _ *http.Request) {
data := h.addGlobals(map[string]any{})
return func(writer http.ResponseWriter, request *http.Request) {
data := h.addGlobals(map[string]any{}, request)
err := tmpl.ExecuteTemplate(writer, "app_new.html", data)
if err != nil {
@@ -57,12 +57,12 @@ func (h *Handlers) HandleAppCreate() http.HandlerFunc {
branch := request.FormValue("branch")
dockerfilePath := request.FormValue("dockerfile_path")
data := map[string]any{
data := h.addGlobals(map[string]any{
"Name": name,
"RepoURL": repoURL,
"Branch": branch,
"DockerfilePath": dockerfilePath,
}
}, request)
if name == "" || repoURL == "" {
data["Error"] = "Name and repository URL are required"
@@ -150,7 +150,7 @@ func (h *Handlers) HandleAppDetail() http.HandlerFunc {
"WebhookURL": webhookURL,
"DeployKey": deployKey,
"Success": request.URL.Query().Get("success"),
})
}, request)
err := tmpl.ExecuteTemplate(writer, "app_detail.html", data)
if err != nil {
@@ -183,7 +183,7 @@ func (h *Handlers) HandleAppEdit() http.HandlerFunc {
data := h.addGlobals(map[string]any{
"App": application,
})
}, request)
err := tmpl.ExecuteTemplate(writer, "app_edit.html", data)
if err != nil {
@@ -241,10 +241,10 @@ func (h *Handlers) HandleAppUpdate() http.HandlerFunc {
if saveErr != nil {
h.log.Error("failed to update app", "error", saveErr)
data := map[string]any{
data := h.addGlobals(map[string]any{
"App": application,
"Error": "Failed to update app",
}
}, request)
_ = tmpl.ExecuteTemplate(writer, "app_edit.html", data)
return
@@ -337,7 +337,7 @@ func (h *Handlers) HandleAppDeployments() http.HandlerFunc {
data := h.addGlobals(map[string]any{
"App": application,
"Deployments": deployments,
})
}, request)
err := tmpl.ExecuteTemplate(writer, "deployments.html", data)
if err != nil {