From ca1418fc0135d52a009ab218d6e24187fb355a3c Mon Sep 17 00:00:00 2001 From: Adam Mathes Date: Sat, 14 Feb 2026 09:09:10 -0800 Subject: security: implement CSRF protection and improve session cookie security (fixing NK-gfh33y) --- frontend/src/utils.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 frontend/src/utils.ts (limited to 'frontend/src/utils.ts') diff --git a/frontend/src/utils.ts b/frontend/src/utils.ts new file mode 100644 index 0000000..129ebbb --- /dev/null +++ b/frontend/src/utils.ts @@ -0,0 +1,31 @@ +export function getCookie(name: string): string | undefined { + const value = `; ${document.cookie}`; + const parts = value.split(`; ${name}=`); + if (parts.length === 2) return parts.pop()?.split(';').shift(); +} + +/** + * A wrapper around fetch that automatically includes the CSRF token + * for state-changing requests (POST, PUT, DELETE). + */ +export async function apiFetch(input: RequestInfo | URL, init?: RequestInit): Promise { + const method = init?.method?.toUpperCase() || 'GET'; + const isStateChanging = ['POST', 'PUT', 'DELETE'].includes(method); + + const headers = new Headers(init?.headers || {}); + + if (isStateChanging) { + const token = getCookie('csrf_token'); + if (token) { + headers.set('X-CSRF-Token', token); + } + } + + // Ensure requests are treated as coming from our own origin if needed, + // but for a same-origin API, standard fetch defaults are usually fine. + + return fetch(input, { + ...init, + headers, + }); +} -- cgit v1.2.3