Licence EUPL-1.2 + hardening anti-abus
P1 — Licence : - Ajout du fichier LICENSE (EUPL-1.2 complet) - README mis à jour : section licence, table docs, vars d'environnement - En-têtes EUPL ajoutés dans les fichiers sources principaux (Flask, React) P2 — Hardening anti-abus : - Rate limiting Redis-ready (REDIS_URL) avec clé fingerprint + IP - Honeypot anti-bot : champ caché côté client + vérification serveur - Fingerprinting non-PII via FingerprintJS (hash SHA-256, colonne ideas.fingerprint_hash) - Cooldown session : cookie httpOnly signé HMAC-SHA256 (SECRET_KEY requis) - Détection de flood : alerte WARNING si > FLOOD_THRESHOLD soumissions / 5 min - hCaptcha stub : intégré, activable via HCAPTCHA_SECRET_KEY + VITE_HCAPTCHA_SITE_KEY - Nouvelles dépendances : redis (backend), @fingerprintjs/fingerprintjs + @hcaptcha/react-hcaptcha (frontend) - docs/SECURITE_ANTI_ABUS.md : documentation complète des seuils et de la configuration Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,35 @@ const DEFAULT_JSON_ACCEPT = "application/json, application/problem+json";
|
||||
let _baseUrl: string | null = null;
|
||||
let _authTokenGetter: AuthTokenGetter | null = null;
|
||||
|
||||
// Identifiant de visite non-PII issu de FingerprintJS (hash côté serveur)
|
||||
let _visitorId: string | null = null;
|
||||
|
||||
// En-têtes supplémentaires par requête (ex. token hCaptcha)
|
||||
const _extraHeaders: Record<string, string> = {};
|
||||
|
||||
/**
|
||||
* Enregistre l'identifiant de visite FingerprintJS.
|
||||
* Envoyé automatiquement comme en-tête X-Visitor-Id sur chaque requête.
|
||||
*/
|
||||
export function setVisitorId(id: string): void {
|
||||
_visitorId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajoute ou met à jour un en-tête supplémentaire pour les prochaines requêtes.
|
||||
* Utiliser pour passer des tokens à usage unique (ex. hCaptcha).
|
||||
*/
|
||||
export function addExtraHeader(key: string, value: string): void {
|
||||
_extraHeaders[key] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime un en-tête supplémentaire.
|
||||
*/
|
||||
export function removeExtraHeader(key: string): void {
|
||||
delete _extraHeaders[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a base URL that is prepended to every relative request URL
|
||||
* (i.e. paths that start with `/`).
|
||||
@@ -358,6 +387,18 @@ export async function customFetch<T = unknown>(
|
||||
}
|
||||
}
|
||||
|
||||
// En-tête fingerprint non-PII (FingerprintJS)
|
||||
if (_visitorId && !headers.has("x-visitor-id")) {
|
||||
headers.set("x-visitor-id", _visitorId);
|
||||
}
|
||||
|
||||
// En-têtes supplémentaires (ex. token hCaptcha)
|
||||
for (const [key, value] of Object.entries(_extraHeaders)) {
|
||||
if (value && !headers.has(key)) {
|
||||
headers.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
const requestInfo = { method, url: resolveUrl(input) };
|
||||
|
||||
const response = await fetch(input, { ...init, method, headers });
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
export * from "./generated/api";
|
||||
export * from "./generated/api.schemas";
|
||||
export { setBaseUrl, setAuthTokenGetter } from "./custom-fetch";
|
||||
export {
|
||||
setBaseUrl,
|
||||
setAuthTokenGetter,
|
||||
setVisitorId,
|
||||
addExtraHeader,
|
||||
removeExtraHeader,
|
||||
} from "./custom-fetch";
|
||||
export type { AuthTokenGetter } from "./custom-fetch";
|
||||
|
||||
Reference in New Issue
Block a user