fix: switch to form-encoded POST + CSRF as query param + form field

This commit is contained in:
Claus Lohmar 2026-07-24 10:54:45 +00:00
parent 78cae8dea4
commit 76e7fc3d5c
2 changed files with 28 additions and 18 deletions

View file

@ -246,12 +246,15 @@ func handleListLeases(w http.ResponseWriter, r *http.Request) {
}
func handlePinLease(w http.ResponseWriter, r *http.Request) {
var req PinRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeJSON(w, http.StatusBadRequest, ErrorResponse{Error: "invalid JSON: " + err.Error()})
if err := r.ParseForm(); err != nil {
writeJSON(w, http.StatusBadRequest, ErrorResponse{Error: "invalid form data: " + err.Error()})
return
}
defer r.Body.Close()
req := PinRequest{
MAC: r.FormValue("mac"),
IP: r.FormValue("ip"),
Hostname: r.FormValue("hostname"),
}
if req.MAC == "" || req.IP == "" {
writeJSON(w, http.StatusBadRequest, ErrorResponse{Error: "mac and ip are required"})
@ -280,12 +283,15 @@ func handlePinLease(w http.ResponseWriter, r *http.Request) {
}
func handleUnpinLease(w http.ResponseWriter, r *http.Request) {
var req PinRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeJSON(w, http.StatusBadRequest, ErrorResponse{Error: "invalid JSON: " + err.Error()})
if err := r.ParseForm(); err != nil {
writeJSON(w, http.StatusBadRequest, ErrorResponse{Error: "invalid form data: " + err.Error()})
return
}
defer r.Body.Close()
req := PinRequest{
MAC: r.FormValue("mac"),
IP: r.FormValue("ip"),
Hostname: r.FormValue("hostname"),
}
if req.MAC == "" {
writeJSON(w, http.StatusBadRequest, ErrorResponse{Error: "mac is required"})

View file

@ -26,20 +26,24 @@ async function apiFetch(path, opts) {
var method = (opts.method || 'GET').toUpperCase();
var isPost = (method === 'POST' || method === 'PUT' || method === 'PATCH');
// Attach CSRF token as query param (Zoraxy may validate it there)
if (csrfToken && csrfToken !== '{{.csrfToken}}') {
var sep = path.indexOf('?') >= 0 ? '&' : '?';
path = path + sep + 'csrfToken=' + encodeURIComponent(csrfToken);
opts.headers['X-Zoraxy-Csrf'] = csrfToken;
// For POST requests, include token in body (Zoraxy validates via form field)
if (isPost) {
if (opts.body && typeof opts.body === 'object') {
opts.body.csrfToken = csrfToken;
} else {
opts.body = { csrfToken: csrfToken };
}
if (isPost && opts.body && typeof opts.body === 'object') {
// Send as URL-encoded form data (Zoraxy's CSRF middleware parses forms, not JSON)
var formBody = new URLSearchParams();
for (var key in opts.body) {
if (opts.body.hasOwnProperty(key)) {
formBody.append(key, opts.body[key]);
}
}
}
if (opts.body && typeof opts.body === 'object') {
opts.body = JSON.stringify(opts.body);
opts.headers['Content-Type'] = 'application/json';
formBody.append('csrfToken', csrfToken || '');
opts.body = formBody.toString();
opts.headers['Content-Type'] = 'application/x-www-form-urlencoded';
}
var res = await fetch(API_BASE + path, opts);
var text = await res.text();