diff --git a/pkg/webui/accounts.go b/pkg/webui/accounts.go index dfc4439..ad0dbca 100644 --- a/pkg/webui/accounts.go +++ b/pkg/webui/accounts.go @@ -1,6 +1,7 @@ package webui import ( + "fmt" "html/template" "net/http" "path" @@ -36,6 +37,14 @@ func handleAccountsGET(db *database.DB) http.Handler { func handleAccountsPOST(db *database.DB) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if err := r.ParseForm(); err != nil { + errorResponse(w, r, http.StatusBadRequest, + fmt.Errorf("failed to parse form: %w", err)) + return + } + if !verifyCSRFToken(w, r) { + return + } accounts, err := db.LoadAccounts() if err != nil { errorResponse(w, r, http.StatusInternalServerError, err) diff --git a/pkg/webui/accountsIdResetPassword.go b/pkg/webui/accountsIdResetPassword.go index a39d287..9c5b6f5 100644 --- a/pkg/webui/accountsIdResetPassword.go +++ b/pkg/webui/accountsIdResetPassword.go @@ -1,6 +1,7 @@ package webui import ( + "fmt" "html/template" "net/http" @@ -66,6 +67,14 @@ func handleAccountsIdResetPasswordPOST(db *database.DB) http.Handler { if account == nil { return } + if err := r.ParseForm(); err != nil { + errorResponse(w, r, http.StatusBadRequest, + fmt.Errorf("failed to parse form: %w", err)) + return + } + if !verifyCSRFToken(w, r) { + return + } password := r.FormValue("password") if len(password) < 8 { errorResponse(w, r, http.StatusBadRequest, nil) diff --git a/pkg/webui/csrf.go b/pkg/webui/csrf.go new file mode 100644 index 0000000..7261f84 --- /dev/null +++ b/pkg/webui/csrf.go @@ -0,0 +1,30 @@ +package webui + +import ( + "fmt" + "net/http" + + "git.adyxax.org/adyxax/tfstated/pkg/model" + "go.n16f.net/uuid" +) + +func verifyCSRFToken(w http.ResponseWriter, r *http.Request) bool { + session := r.Context().Value(model.SessionContextKey{}).(*model.Session) + tokenStr := r.FormValue("csrf_token") + if tokenStr == "" { + tokenStr = r.Header.Get("X-XSRF-Token") + } + var token uuid.UUID + if err := token.Parse(tokenStr); err != nil { + errorResponse(w, r, http.StatusBadRequest, + fmt.Errorf("failed to parse csrf token: %w", err)) + return false + } + + if !token.Equal(session.Data.CsrfToken) { + errorResponse(w, r, http.StatusForbidden, + fmt.Errorf("invalid csrf token")) + return false + } + return true +} diff --git a/pkg/webui/html/accounts.html b/pkg/webui/html/accounts.html index ff3670a..227585e 100644 --- a/pkg/webui/html/accounts.html +++ b/pkg/webui/html/accounts.html @@ -9,6 +9,7 @@ {{ if .Page.Session.Data.Account.IsAdmin }}