Checkpoint: Application complète de dématérialisation de facturation avec extraction IA (Mistral), authentification locale + Azure AD, stockage local, et export SFTP.
Fonctionnalités implémentées : ✅ Authentification locale (email/password) + Azure AD + Manus OAuth ✅ Upload drag-and-drop de fichiers PDF avec suivi en temps réel ✅ Extraction automatique avec Mistral AI (OCR + LLM) ✅ Détection de doublons (fournisseur, numéro, date) ✅ Score de qualité d'extraction (0-100) ✅ Tableau de bord avec statistiques ✅ Liste des factures avec recherche et filtres ✅ Paramètres utilisateur (LLM, keywords, SFTP) ✅ Historique des imports avec logs détaillés ✅ Gestion des utilisateurs (admin) ✅ Export SFTP manuel/automatique ✅ Stockage local avec organisation YYYY-MM ✅ Tests unitaires d'authentification Architecture : - Frontend : React 19 + Vite + TailwindCSS + Radix UI - Backend : Express + tRPC + Drizzle ORM - Base de données : MySQL (6 tables) - IA : Mistral AI pour extraction - Stockage : Local filesystem - Export : SFTP Pages : - Login (choix local/Azure/Manus) - Dashboard (statistiques) - Upload (drag-and-drop) - Invoices (liste avec recherche) - Settings (LLM, keywords, SFTP) - History (logs d'import) - Users (gestion admin)
This commit is contained in:
68
server/auth.test.ts
Normal file
68
server/auth.test.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { hashPassword, verifyPassword, generateToken, verifyToken } from "./auth";
|
||||
|
||||
describe("Authentication", () => {
|
||||
describe("Password hashing", () => {
|
||||
it("should hash a password", async () => {
|
||||
const password = "testpassword123";
|
||||
const hash = await hashPassword(password);
|
||||
|
||||
expect(hash).toBeDefined();
|
||||
expect(hash).not.toBe(password);
|
||||
expect(hash.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("should verify a correct password", async () => {
|
||||
const password = "testpassword123";
|
||||
const hash = await hashPassword(password);
|
||||
|
||||
const isValid = await verifyPassword(password, hash);
|
||||
expect(isValid).toBe(true);
|
||||
});
|
||||
|
||||
it("should reject an incorrect password", async () => {
|
||||
const password = "testpassword123";
|
||||
const hash = await hashPassword(password);
|
||||
|
||||
const isValid = await verifyPassword("wrongpassword", hash);
|
||||
expect(isValid).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("JWT tokens", () => {
|
||||
it("should generate a valid JWT token", () => {
|
||||
const user = {
|
||||
id: 1,
|
||||
email: "test@example.com",
|
||||
role: "user",
|
||||
};
|
||||
|
||||
const token = generateToken(user);
|
||||
|
||||
expect(token).toBeDefined();
|
||||
expect(typeof token).toBe("string");
|
||||
expect(token.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("should verify and decode a valid token", () => {
|
||||
const user = {
|
||||
id: 1,
|
||||
email: "test@example.com",
|
||||
role: "user",
|
||||
};
|
||||
|
||||
const token = generateToken(user);
|
||||
const decoded = verifyToken(token);
|
||||
|
||||
expect(decoded).toBeDefined();
|
||||
expect(decoded?.userId).toBe(user.id);
|
||||
expect(decoded?.email).toBe(user.email);
|
||||
expect(decoded?.role).toBe(user.role);
|
||||
});
|
||||
|
||||
it("should reject an invalid token", () => {
|
||||
const decoded = verifyToken("invalid-token");
|
||||
expect(decoded).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user