feat: Implémentation authentification NIST SP 800-63B v3.0.8

- Ajout du service PasswordSecurityService conforme NIST SP 800-63B
- Vérification des mots de passe contre la base Have I Been Pwned
- Validation : minimum 8 caractères, maximum 64 caractères
- Pas d'exigences de composition obligatoires (conforme NIST)
- Intégration dans LoginController et UserController
- Génération de mots de passe sécurisés non compromis

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-08-15 15:31:23 +02:00
parent 206c76c7db
commit 5e255ebf5e
49 changed files with 152716 additions and 149802 deletions

View File

@@ -436,7 +436,7 @@ class _LoginPageState extends State<LoginPage> {
final success =
await userRepository.loginWithSpinner(
context,
_usernameController.text.trim(),
_usernameController.text, // NIST: ne pas faire de trim
_passwordController.text,
type: _loginType,
);
@@ -580,7 +580,7 @@ class _LoginPageState extends State<LoginPage> {
final success = await userRepository
.loginWithSpinner(
context,
_usernameController.text.trim(),
_usernameController.text, // NIST: ne pas faire de trim
_passwordController.text,
type: _loginType,
);
@@ -648,28 +648,64 @@ class _LoginPageState extends State<LoginPage> {
),
const SizedBox(height: 24),
// Inscription administrateur uniquement
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Pas encore de compte ?',
style: theme.textTheme.bodyMedium,
),
TextButton(
onPressed: () {
context.go('/register');
},
child: const Text(
'Inscription Administrateur',
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold,
),
),
),
],
),
// Inscription administrateur uniquement en mode admin
if (_loginType == 'admin') ...[
// Détecter si on est sur mobile
LayoutBuilder(
builder: (context, constraints) {
final isMobile = constraints.maxWidth < 400;
if (isMobile) {
// Sur mobile : afficher sur deux lignes
return Column(
children: [
Text(
'Pas encore de compte ?',
style: theme.textTheme.bodyMedium,
textAlign: TextAlign.center,
),
const SizedBox(height: 4),
TextButton(
onPressed: () {
context.go('/register');
},
child: const Text(
'Inscription Administrateur',
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold,
),
),
),
],
);
} else {
// Sur desktop : afficher sur une ligne
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Pas encore de compte ?',
style: theme.textTheme.bodyMedium,
),
TextButton(
onPressed: () {
context.go('/register');
},
child: const Text(
'Inscription Administrateur',
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold,
),
),
),
],
);
}
},
),
],
// Lien vers la page d'accueil
TextButton(
@@ -683,6 +719,35 @@ class _LoginPageState extends State<LoginPage> {
),
),
),
// Badge de version dans la card
if (_appVersion.isNotEmpty) ...[
const SizedBox(height: 16),
Center(
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
decoration: BoxDecoration(
color: theme.colorScheme.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: theme.colorScheme.primary.withOpacity(0.3),
width: 1,
),
),
child: Text(
'v$_appVersion',
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.primary.withOpacity(0.8),
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
),
),
],
],
),
),
@@ -694,34 +759,6 @@ class _LoginPageState extends State<LoginPage> {
),
),
),
// Badge de version en bas à droite
if (_appVersion.isNotEmpty)
Positioned(
bottom: 16,
right: 16,
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration(
color: theme.colorScheme.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: theme.colorScheme.primary.withOpacity(0.3),
width: 1,
),
),
child: Text(
'v$_appVersion',
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.primary.withOpacity(0.8),
fontSize: 10,
fontWeight: FontWeight.w500,
),
),
),
),
],
),
);