fix(ihm_client): génération et persistance locale d'une clé HMAC si VITE_JWT_SECRET_KEY absent
All checks were successful
Build and Push Docker image (ext) / docker (push) Successful in 50s

This commit is contained in:
4NK CI Bot 2025-09-18 16:53:28 +00:00
parent a6f54dc8f5
commit 4f7d51e9b2

View File

@ -21,9 +21,40 @@ export default class TokenService {
return TokenService.instance;
}
private getOrCreateSecret(): Uint8Array {
// Priorité à la variable d'environnement si définie et non vide
if (this.SECRET_KEY && String(this.SECRET_KEY).trim().length > 0) {
return new Uint8Array(this.encoder.encode(this.SECRET_KEY));
}
// Sinon, on persiste une clé aléatoire locale (stable entre sessions) côté navigateur
try {
const storageKey = 'ihm_jwt_secret_key_v1';
let secretB64 = localStorage.getItem(storageKey);
if (!secretB64) {
const random = new Uint8Array(32);
crypto.getRandomValues(random);
// Stocker en base64 pour être textuel
secretB64 = btoa(String.fromCharCode(...random));
localStorage.setItem(storageKey, secretB64);
}
// Décoder base64 → Uint8Array
const binary = atob(secretB64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return bytes;
} catch (_e) {
// Fallback minimal si localStorage indisponible (mode très restrictif)
const fallback = 'fallback-secret-key-please-persist';
return new Uint8Array(this.encoder.encode(fallback));
}
}
async generateSessionToken(origin: string): Promise<TokenPair> {
const secret = new Uint8Array(this.encoder.encode(this.SECRET_KEY));
const secret = this.getOrCreateSecret();
const accessToken = await new jose.SignJWT({ origin, type: 'access' })
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
@ -41,16 +72,16 @@ export default class TokenService {
async validateToken(token: string, origin: string): Promise<boolean> {
try {
const secret = new Uint8Array(this.encoder.encode(this.SECRET_KEY));
const secret = this.getOrCreateSecret();
const { payload } = await jose.jwtVerify(token, secret);
return payload.origin === origin;
} catch (error: any) {
if (error?.code === 'ERR_JWT_EXPIRED') {
console.log('Token expiré');
return false;
}
console.error('Erreur de validation du token:', error);
return false;
}
@ -65,7 +96,7 @@ export default class TokenService {
}
// Vérifier le type du token
const secret = new Uint8Array(this.encoder.encode(this.SECRET_KEY));
const secret = this.getOrCreateSecret();
const { payload } = await jose.jwtVerify(refreshToken, secret);
if (payload.type !== 'refresh') {
return null;