From cc9b50a765bcd5529364339f4fa39ba54305a041 Mon Sep 17 00:00:00 2001 From: tristan Date: Wed, 24 Jun 2026 10:25:50 +0200 Subject: [PATCH] =?UTF-8?q?feat(audit)=20:=20envoie=20un=20device=20id=20p?= =?UTF-8?q?ersistant=20sur=20les=20requ=C3=AAtes=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/composables/useApi.ts | 8 ++++++++ frontend/composables/useDeviceId.ts | 28 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 frontend/composables/useDeviceId.ts diff --git a/frontend/composables/useApi.ts b/frontend/composables/useApi.ts index ec296b4..5d9b6dc 100644 --- a/frontend/composables/useApi.ts +++ b/frontend/composables/useApi.ts @@ -80,6 +80,14 @@ export const useApi = (): ApiClient => { baseURL, retry: 0, credentials: 'include', + onRequest({ options }) { + const deviceId = useDeviceId() + if (deviceId) { + const headers = new Headers(options.headers as HeadersInit | undefined) + headers.set('X-Device-Id', deviceId) + options.headers = headers + } + }, onResponse({ options, response }) { const apiOptions = options as ApiFetchOptions<'json'> if (apiOptions?.toast === false) { diff --git a/frontend/composables/useDeviceId.ts b/frontend/composables/useDeviceId.ts new file mode 100644 index 0000000..b8d9879 --- /dev/null +++ b/frontend/composables/useDeviceId.ts @@ -0,0 +1,28 @@ +// Stable per-device identifier used to add forensic context to audit logs. +// Persisted in localStorage so the same browser/device reuses it across sessions. +// NOTE: this identifies a device/browser, not a human — on a shared kiosk every +// user of the same browser shares one id (intended: it distinguishes devices). + +const STORAGE_KEY = 'sirh-device-id' +let cached: string | null = null + +export const useDeviceId = (): string | null => { + if (!import.meta.client) { + return null + } + if (cached) { + return cached + } + try { + let id = localStorage.getItem(STORAGE_KEY) + if (!id) { + id = crypto.randomUUID() + localStorage.setItem(STORAGE_KEY, id) + } + cached = id + return id + } catch { + // localStorage unavailable (private mode, disabled) — degrade gracefully. + return null + } +}