Share CSRF headers across guest uploads
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled

This commit is contained in:
Codex Agent
2026-01-30 13:10:19 +01:00
parent 96aaea23e4
commit 3ba784154b
4 changed files with 93 additions and 46 deletions

View File

@@ -1,5 +1,6 @@
// @ts-nocheck
import { getDeviceId } from '../lib/device';
import { buildCsrfHeaders } from '../lib/csrf';
export type UploadError = Error & {
code?: string;
@@ -7,51 +8,8 @@ export type UploadError = Error & {
meta?: Record<string, unknown>;
};
function getCsrfToken(): string | null {
// Method 1: Meta tag (preferred for SPA)
const metaToken = document.querySelector('meta[name="csrf-token"]');
if (metaToken) {
return (metaToken as HTMLMetaElement).getAttribute('content') || null;
}
// Method 2: XSRF-TOKEN cookie (Sanctum fallback)
const name = 'XSRF-TOKEN=';
const decodedCookie = decodeURIComponent(document.cookie);
const ca = decodedCookie.split(';');
for (let i = 0; i < ca.length; i++) {
const c = ca[i].trimStart();
if (c.startsWith(name)) {
const token = c.substring(name.length);
try {
// Decode base64 if needed
return decodeURIComponent(atob(token));
} catch {
return token;
}
}
}
console.warn('No CSRF token found - API requests may fail');
return null;
}
function getCsrfHeaders(): Record<string, string> {
const token = getCsrfToken();
const headers: Record<string, string> = {
'X-Device-Id': getDeviceId(),
'Accept': 'application/json',
};
if (token) {
headers['X-CSRF-TOKEN'] = token;
headers['X-XSRF-TOKEN'] = token;
}
return headers;
}
export async function likePhoto(id: number): Promise<number> {
const headers = getCsrfHeaders();
const headers = buildCsrfHeaders();
const res = await fetch(`/api/v1/photos/${id}/like`, {
method: 'POST',
@@ -122,7 +80,7 @@ export async function uploadPhoto(
const maxRetries = options.maxRetries ?? 2;
const url = `/api/v1/events/${encodeURIComponent(eventToken)}/upload`;
const headers = getCsrfHeaders();
const headers = buildCsrfHeaders();
const attemptUpload = (): Promise<Record<string, unknown>> =>
new Promise((resolve, reject) => {