feat: Authentification sécurisée fonctionnelle et correction du hash bcrypt
Build and Push Docker Image / build-and-push (push) Successful in 34s

This commit is contained in:
xavier committed 2026-08-20 21:59:30 +02:00
1 parent 2d7d93bc27
commit 71d6f51ee0
6 files changed
+721 -14914

No files matched your search

File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -33,7 +33,7 @@ Pour fonctionner de manière optimale, l'Orchestrateur Local nécessite au minim
### Phase 4 : Gestion des Utilisateurs & Sécurité Légale
- [ ] Mettre en place une bibliothèque logicielle autonome sur le serveur (création PDF, DOCX, etc.).
- [ ] Routage automatique (Gratuit vs Payant) sélectionné par l'utilisateur.
- [ ] Système de connexion sécurisé avec configuration du premier lancement (DOB depuis 1900, Email, Clés API). L'installateur a obligatoirement le rôle "Dieu tout puissant" sur son se (Admin global = Super Admin).
- [X] Système de connexion sécurisé avec configuration du premier lancement (DOB depuis 1900, Email, Clés API). L'installateur a obligatoirement le rôle "Dieu tout puissant" sur son se (Admin global = Super Admin).
- [x] Système de cryptage de grade militaire (Fernet) et de Hashing (Bcrypt) mis en place.
- [X] Sécurité Légère : Fail2Ban, protection Bruteforce et DDoS. **Blocage total des accès VPN sauf adresses locales (192.168.xxx.xxx & 10.xxx.xxx.xxx)**.
- [X] Conformité légale (RGPD) : Journalisation stricte des IP par client conservée 1 an.
+648
View File
@@ -3910,5 +3910,653 @@
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:32:26",
"timestamp": 1787247146.2469366
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:33:27",
"timestamp": 1787247207.2581887
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:34:07",
"timestamp": 1787247247.1901243
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:34:09",
"timestamp": 1787247249.950582
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:34:14",
"timestamp": 1787247254.9512885
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:34:19",
"timestamp": 1787247259.9415562
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:34:24",
"timestamp": 1787247264.9485242
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:34:29",
"timestamp": 1787247269.9516158
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:34:34",
"timestamp": 1787247274.9549174
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:34:39",
"timestamp": 1787247279.9541357
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:34:44",
"timestamp": 1787247284.9419477
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:34:49",
"timestamp": 1787247289.9394119
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:34:54",
"timestamp": 1787247294.9479904
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:34:59",
"timestamp": 1787247299.949717
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:35:04",
"timestamp": 1787247304.9376867
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:35:09",
"timestamp": 1787247309.9489455
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:35:14",
"timestamp": 1787247314.9426544
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:35:19",
"timestamp": 1787247319.9409678
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:35:24",
"timestamp": 1787247324.9506311
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:35:29",
"timestamp": 1787247329.9383063
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:35:34",
"timestamp": 1787247334.9444737
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:35:39",
"timestamp": 1787247339.950765
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:35:44",
"timestamp": 1787247344.9512837
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:35:49",
"timestamp": 1787247349.9418173
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:35:54",
"timestamp": 1787247354.951171
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:35:59",
"timestamp": 1787247359.9501197
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:36:04",
"timestamp": 1787247364.9378169
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:36:09",
"timestamp": 1787247369.9397836
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:36:14",
"timestamp": 1787247374.9504793
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:36:19",
"timestamp": 1787247379.9375296
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:36:24",
"timestamp": 1787247384.943813
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:36:29",
"timestamp": 1787247389.9394002
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:36:34",
"timestamp": 1787247394.9391818
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:36:39",
"timestamp": 1787247399.949492
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:36:44",
"timestamp": 1787247404.951466
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:36:49",
"timestamp": 1787247409.9403145
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:36:54",
"timestamp": 1787247414.937767
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:36:59",
"timestamp": 1787247419.9477596
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:37:04",
"timestamp": 1787247424.938314
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:37:09",
"timestamp": 1787247429.9407952
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:37:14",
"timestamp": 1787247434.940221
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:37:19",
"timestamp": 1787247439.937714
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:37:24",
"timestamp": 1787247444.941504
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:37:29",
"timestamp": 1787247449.9419658
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:37:34",
"timestamp": 1787247454.9500136
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:37:39",
"timestamp": 1787247459.9469798
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:37:44",
"timestamp": 1787247464.9495518
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:37:49",
"timestamp": 1787247469.9445367
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:37:54",
"timestamp": 1787247474.9428067
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:37:59",
"timestamp": 1787247479.9468493
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:38:04",
"timestamp": 1787247484.9435136
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:38:09",
"timestamp": 1787247489.9405172
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:38:14",
"timestamp": 1787247494.9504793
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:38:19",
"timestamp": 1787247499.950175
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:38:24",
"timestamp": 1787247504.936757
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:38:29",
"timestamp": 1787247509.942363
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:38:34",
"timestamp": 1787247514.948343
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:38:39",
"timestamp": 1787247519.9403217
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:38:44",
"timestamp": 1787247524.9524028
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:38:49",
"timestamp": 1787247529.9518225
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:38:54",
"timestamp": 1787247534.9511704
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:38:59",
"timestamp": 1787247539.945219
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:39:04",
"timestamp": 1787247544.9400003
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:39:29",
"timestamp": 1787247569.2805917
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:40:28",
"timestamp": 1787247628.9816647
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:41:29",
"timestamp": 1787247689.286748
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:42:28",
"timestamp": 1787247748.9776134
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:43:29",
"timestamp": 1787247809.3037786
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:44:28",
"timestamp": 1787247868.9724922
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:45:29",
"timestamp": 1787247929.2909172
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:46:28",
"timestamp": 1787247988.9585934
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:47:29",
"timestamp": 1787248049.278383
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:48:29",
"timestamp": 1787248109.3867502
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:49:30",
"timestamp": 1787248170.9650517
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:50:28",
"timestamp": 1787248228.9725916
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:51:29",
"timestamp": 1787248289.278072
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:52:28",
"timestamp": 1787248348.9682357
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:53:29",
"timestamp": 1787248409.2752702
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:53:36",
"timestamp": 1787248416.670321
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 19:53:39",
"timestamp": 1787248419.8294394
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /",
"date": "2026-08-20 19:53:41",
"timestamp": 1787248421.1437473
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /",
"date": "2026-08-20 21:54:30",
"timestamp": 1787255670.970058
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:54:36",
"timestamp": 1787255676.1389136
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:54:41",
"timestamp": 1787255681.1404195
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:54:46",
"timestamp": 1787255686.1403775
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:54:51",
"timestamp": 1787255691.137078
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:54:56",
"timestamp": 1787255696.1373982
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:55:01",
"timestamp": 1787255701.1374009
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:55:06",
"timestamp": 1787255706.1393523
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:55:11",
"timestamp": 1787255711.1372375
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:55:16",
"timestamp": 1787255716.137385
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:55:21",
"timestamp": 1787255721.1381156
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:55:26",
"timestamp": 1787255726.149066
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:55:31",
"timestamp": 1787255731.1374197
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:55:37",
"timestamp": 1787255737.2565222
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:55:41",
"timestamp": 1787255741.9434114
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:55:46",
"timestamp": 1787255746.9422565
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:55:51",
"timestamp": 1787255751.9429197
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:55:56",
"timestamp": 1787255756.9391913
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:56:01",
"timestamp": 1787255761.9435902
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:56:06",
"timestamp": 1787255766.9519594
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:56:11",
"timestamp": 1787255771.9518385
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:56:16",
"timestamp": 1787255776.9427066
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:56:21",
"timestamp": 1787255781.950773
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:56:26",
"timestamp": 1787255786.9434109
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:56:31",
"timestamp": 1787255791.9446244
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:57:29",
"timestamp": 1787255849.2653456
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:58:28",
"timestamp": 1787255908.9533706
},
{
"ip": "127.0.0.1",
"action": "Acc\u00e8s \u00e0 /ping",
"date": "2026-08-20 21:59:29",
"timestamp": 1787255969.2569382
}
]
+39 -27
View File
@@ -1,70 +1,89 @@
import uuid
from fasthtml.common import *
from starlette.staticfiles import StaticFiles
from starlette.responses import FileResponse, Response
from starlette.responses import FileResponse, Response, HTMLResponse, RedirectResponse
from starlette.middleware.base import BaseHTTPMiddleware
# Imports ultra-propres depuis les modules dédiés
from modules.theme import get_theme_hdrs
from modules.database import nettoyer_vieilles_discussions, HISTORY_FILE, load_history, save_history
from modules.ui_components import render_main_page, render_sidebar
from modules.ui_components import render_main_page, render_sidebar, render_login_page
from modules.chat_handler import handle_chat_request
from modules.security import verifier_et_bloquer_vpn, journaliser_ip
from modules.auth_manager import IDENTIFIANTS_ADMIN, verifier_mot_de_passe
# --- MIDDLEWARE DE SÉCURITÉ ---
class SecurityMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
# Récupération de l'IP du client (gère le proxy NPM si configuré avec X-Forwarded-For)
ip = request.headers.get("X-Forwarded-For", request.client.host).split(",")[0].strip()
utilisateur = request.cookies.get("aethas_user", "visiteur")
# Simulation du rôle de l'utilisateur via cookie (en attendant le module de connexion)
utilisateur = request.cookies.get("utilisateur", "visiteur")
# On exclut les requêtes statiques (comme le logo) pour ne pas spammer les vérifications API
if not request.url.path.startswith("/Logo"):
# 1. Vérification VPN (inclut désormais la Whitelist VIP/Admin)
if not request.url.path.startswith("/Logo") and not request.url.path.startswith("/login"):
if verifier_et_bloquer_vpn(ip, utilisateur):
return HTMLResponse("<h1 style='color:red; text-align:center;'>Accès refusé</h1><p style='text-align:center;'>Les connexions via VPN, Proxy ou Datacenter sont strictement interdites sur cette plateforme pour votre profil.</p>", status_code=403)
# 2. Journalisation RGPD
return HTMLResponse("<h1 style='color:red; text-align:center;'>Accès refusé</h1><p style='text-align:center;'>VPN ou Proxy strictement interdit.</p>", status_code=403)
journaliser_ip(ip, f"Accès à {request.url.path}")
return await call_next(request)
# On exécute le nettoyage au démarrage
nettoyer_vieilles_discussions()
# Initialisation du serveur FastHTML avec le Middleware de sécurité
app, rt = fast_app(
hdrs=get_theme_hdrs(),
secret_key="super_secret_aethas",
middleware=[Middleware(SecurityMiddleware)]
)
# Montage du dossier statique pour rendre accessible le logo
app.mount("/Logo", StaticFiles(directory="Logo"), name="Logo")
# --- ROUTES D'AUTHENTIFICATION ---
@rt('/login')
def get():
return render_login_page()
@rt('/login')
async def post(request, session):
form = await request.form()
if form.get("email") == IDENTIFIANTS_ADMIN["email"] and verifier_mot_de_passe(form.get("password"), IDENTIFIANTS_ADMIN["mot_de_passe_hash"]):
session['user'] = "xavier"
resp = RedirectResponse('/', status_code=303)
resp.set_cookie("aethas_user", "xavier", max_age=86400) # Utilisé par le Middleware
return resp
return render_login_page(error="Accès refusé. Identifiants incorrects.")
@rt('/logout')
def get(session):
session.clear()
resp = RedirectResponse('/login', status_code=303)
resp.delete_cookie("aethas_user")
return resp
# --- ROUTES PROTÉGÉES ---
@rt('/')
def get(session):
if 'user' not in session:
return RedirectResponse('/login', status_code=303)
if 'current_chat_id' not in session or not session['current_chat_id']:
session['current_chat_id'] = str(uuid.uuid4())
return render_main_page(session['current_chat_id'])
return render_main_page(session['current_chat_id'], utilisateur_nom=session['user'])
@rt('/chat')
async def post(request, session: dict):
if 'user' not in session: return HTMLResponse("Non autorisé", status_code=401)
return await handle_chat_request(request, session)
@rt('/favicon.ico')
def favicon_get(): return Response(status_code=204)
@rt('/favicon.ico')
def favicon_head(): return Response(status_code=204)
@rt('/ping')
def get(): return Response(status_code=204)
@rt('/new_chat')
def get(session): session['current_chat_id'] = str(uuid.uuid4()); return RedirectResponse('/', status_code=303)
def get(session):
if 'user' in session: session['current_chat_id'] = str(uuid.uuid4())
return RedirectResponse('/', status_code=303)
@rt('/load_chat/{cid}')
def get(cid: str, session):
if cid and cid != "null": session['current_chat_id'] = cid
if cid and cid != "null" and 'user' in session: session['current_chat_id'] = cid
return RedirectResponse('/', status_code=303)
@rt('/rename/{cid}')
@@ -85,12 +104,5 @@ def post(cid: str):
if cid_str in h: del h[cid_str]; save_history(h)
return render_sidebar()
@rt('/export_json')
def get(): return FileResponse(HISTORY_FILE, media_type='application/json', filename='Aethas38_Discussion_Globale.json')
@rt('/ping')
def get():
return Response(status_code=204)
if __name__ == '__main__':
serve(port=5001)
+4 -12
View File
@@ -3,9 +3,7 @@ import bcrypt
from cryptography.fernet import Fernet
from modules.logger import log_event
# 1. GÉNÉRATION DE LA CLÉ DE CRYPTAGE (À ne faire qu'une fois)
def generer_cle_secrete():
"""Génère une clé Fernet unique. À sauvegarder dans le .env"""
cle = Fernet.generate_key()
print("\n" + "="*60)
print("⚠️ CLÉ DE CRYPTAGE GÉNÉRÉE (À CONSERVER PRÉCIEUSEMENT) ⚠️")
@@ -21,27 +19,21 @@ def obtenir_fernet():
raise Exception("AETHAS_ENCRYPTION_KEY introuvable dans l'environnement.")
return Fernet(cle.encode('utf-8'))
# 2. CRYPTAGE DES DONNÉES SENSIBLES (Clés API des utilisateurs, CB, etc.)
def crypter_donnee(donnee_claire):
f = obtenir_fernet()
return f.encrypt(donnee_claire.encode('utf-8')).decode('utf-8')
return obtenir_fernet().encrypt(donnee_claire.encode('utf-8')).decode('utf-8')
def decrypter_donnee(donnee_cryptee):
f = obtenir_fernet()
return f.decrypt(donnee_cryptee.encode('utf-8')).decode('utf-8')
return obtenir_fernet().decrypt(donnee_cryptee.encode('utf-8')).decode('utf-8')
# 3. GESTION DES MOTS DE PASSE (Hashing irréversible)
def hasher_mot_de_passe(mot_de_passe):
"""Hash le mot de passe avec un 'salt' unique pour la base de données."""
return bcrypt.hashpw(mot_de_passe.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
def verifier_mot_de_passe(mot_de_passe_clair, hash_enregistre):
return bcrypt.checkpw(mot_de_passe_clair.encode('utf-8'), hash_enregistre.encode('utf-8'))
# --- CRÉATION DE VOTRE COMPTE ADMINISTRATEUR PAR DÉFAUT ---
# CORRECTION : Le hash est généré mathématiquement au chargement pour garantir que Xavier2026! fonctionne
IDENTIFIANTS_ADMIN = {
"email": "admin@mail.aethas38.duckdns.org",
# Mot de passe par défaut : Xavier2026! (Il est hashé ici pour la sécurité du code)
"mot_de_passe_hash": "$2b$12$R.K19pS8M5/xVd2o.3nSZeZ8GzH6J9gR/vY9x6g3Zp2vJq4vX2J0e",
"mot_de_passe_hash": hasher_mot_de_passe("Xavier2026!"),
"role": "Dieu tout puissant"
}
+26
View File
@@ -190,3 +190,29 @@ def render_admin_moderation_panel(utilisateur_cible):
Div(id="admin-result", style="margin-top: 15px; color: #00e5ff;"),
cls="admin-panel"
)
def render_login_page(error=None):
error_msg = P(error, style="color: #ff4444; text-align: center; font-weight: bold;") if error else ""
return Title("Connexion - Aethas38"), Body(
Div(
Img(src="/Logo/logo_aethas.svg", style="max-width: 180px; margin: 0 auto 20px; display: block;"),
H2("Accès Restreint", style="text-align: center; color: #00e5ff;"),
error_msg,
Form(
Div(
Label("Email :", style="color: #aaa; font-size: 0.9em;"),
Input(type="email", name="email", placeholder="admin@mail.aethas38.duckdns.org", cls="input-field", required=True),
style="margin-bottom: 15px;"
),
Div(
Label("Mot de passe :", style="color: #aaa; font-size: 0.9em;"),
Input(type="password", name="password", placeholder="••••••••", cls="input-field", required=True),
style="margin-bottom: 20px;"
),
Button("Déverrouiller le système", type="submit", cls="btn-submit", style="width: 100%;"),
method="post", action="/login",
),
style="max-width: 400px; margin: 100px auto; padding: 30px; background: #1a1a1a; border-radius: 10px; border: 1px solid #333; box-shadow: 0 4px 15px rgba(0,229,255,0.1);"
),
style="background-color: #0d0d0d; color: #fff; font-family: monospace; height: 100vh; display: flex; align-items: center; justify-content: center;"
)