66use CodedMonkey \Dirigent \Doctrine \Repository \UserRepository ;
77use CodedMonkey \Dirigent \Form \AccountFormType ;
88use CodedMonkey \Dirigent \Form \ChangePasswordFormType ;
9+ use CodedMonkey \Dirigent \Form \MfaClearFormType ;
10+ use CodedMonkey \Dirigent \Form \MfaSetupFormType ;
11+ use Scheb \TwoFactorBundle \Security \TwoFactor \Provider \Totp \TotpAuthenticatorInterface ;
912use Symfony \Bundle \FrameworkBundle \Controller \AbstractController ;
10- use Symfony \Component \Form \FormError ;
1113use Symfony \Component \HttpFoundation \Request ;
1214use Symfony \Component \HttpFoundation \Response ;
13- use Symfony \Component \PasswordHasher \Hasher \UserPasswordHasherInterface ;
1415use Symfony \Component \Routing \Attribute \Route ;
1516use Symfony \Component \Security \Http \Attribute \CurrentUser ;
1617use Symfony \Component \Security \Http \Attribute \IsGranted ;
@@ -19,7 +20,7 @@ class DashboardAccountController extends AbstractController
1920{
2021 public function __construct (
2122 private readonly UserRepository $ userRepository ,
22- private readonly UserPasswordHasherInterface $ passwordHasher ,
23+ private readonly TotpAuthenticatorInterface $ totpAuthenticator ,
2324 ) {
2425 }
2526
@@ -28,8 +29,6 @@ public function __construct(
2829 public function account (Request $ request , #[CurrentUser] User $ user ): Response
2930 {
3031 $ accountForm = $ this ->createForm (AccountFormType::class, $ user );
31- $ passwordForm = $ this ->createForm (ChangePasswordFormType::class);
32-
3332 $ accountForm ->handleRequest ($ request );
3433
3534 if ($ accountForm ->isSubmitted () && $ accountForm ->isValid ()) {
@@ -40,29 +39,84 @@ public function account(Request $request, #[CurrentUser] User $user): Response
4039 return $ this ->redirectToRoute ('dashboard_account ' );
4140 }
4241
42+ $ passwordForm = $ this ->createForm (ChangePasswordFormType::class);
4343 $ passwordForm ->handleRequest ($ request );
4444
45- if ($ passwordForm ->isSubmitted ()) {
46- $ currentPassword = $ passwordForm ->get ('currentPassword ' )->getData ();
45+ if ($ passwordForm ->isSubmitted () && $ passwordForm -> isValid () ) {
46+ $ user -> setPlainPassword ( $ passwordForm ->get ('newPassword ' )->getData () );
4747
48- if (!$ this ->passwordHasher ->isPasswordValid ($ user , $ currentPassword )) {
49- $ passwordForm ->get ('currentPassword ' )->addError (new FormError ('Your current password is incorrect. ' ));
50- }
51-
52- if ($ passwordForm ->isValid ()) {
53- $ user ->setPlainPassword ($ passwordForm ->get ('newPassword ' )->getData ());
54-
55- $ this ->userRepository ->save ($ user , true );
48+ $ this ->userRepository ->save ($ user , true );
5649
57- $ this ->addFlash ('success ' , 'Your password was successfully updated. ' );
50+ $ this ->addFlash ('success ' , 'Your password was successfully updated. ' );
5851
59- return $ this ->redirectToRoute ('dashboard_account ' );
60- }
52+ return $ this ->redirectToRoute ('dashboard_account ' );
6153 }
6254
63- return $ this ->render ('dashboard/account.html.twig ' , [
55+ return $ this ->render ('dashboard/account/account .html.twig ' , [
6456 'accountForm ' => $ accountForm ,
6557 'passwordForm ' => $ passwordForm ,
6658 ]);
6759 }
60+
61+ #[Route('/account/mfa ' , name: 'dashboard_account_mfa ' )]
62+ #[IsGranted('ROLE_USER ' )]
63+ public function mfa (Request $ request , #[CurrentUser] User $ user ): Response
64+ {
65+ if ($ user ->isTotpAuthenticationEnabled ()) {
66+ return $ this ->clearMfa ($ request , $ user );
67+ }
68+
69+ return $ this ->setupMfa ($ request , $ user );
70+ }
71+
72+ private function setupMfa (Request $ request , User $ user ): Response
73+ {
74+ $ session = $ request ->getSession ();
75+
76+ if (null === $ totpSecret = $ session ->get ('totp_secret ' )) {
77+ $ totpSecret = $ this ->totpAuthenticator ->generateSecret ();
78+
79+ $ session ->set ('totp_secret ' , $ totpSecret );
80+ }
81+
82+ $ user ->setTotpSecret ($ totpSecret );
83+
84+ $ form = $ this ->createForm (MfaSetupFormType::class);
85+ $ form ->handleRequest ($ request );
86+
87+ if ($ form ->isSubmitted () && $ form ->isValid ()) {
88+ $ this ->userRepository ->save ($ user , true );
89+
90+ $ this ->addFlash ('success ' , 'Multi-factor authentication was successfully enabled. ' );
91+
92+ $ session ->remove ('totp_secret ' );
93+
94+ return $ this ->redirectToRoute ('dashboard_account ' );
95+ }
96+
97+ return $ this ->render ('dashboard/account/mfa_setup.html.twig ' , [
98+ 'form ' => $ form ,
99+ 'totpContent ' => $ this ->totpAuthenticator ->getQRContent ($ user ),
100+ ]);
101+ }
102+
103+ public function clearMfa (Request $ request , User $ user ): Response
104+ {
105+ $ form = $ this ->createForm (MfaClearFormType::class);
106+ $ form ->handleRequest ($ request );
107+
108+ if ($ form ->isSubmitted () && $ form ->isValid ()) {
109+ $ user ->setTotpSecret (null );
110+
111+ $ this ->userRepository ->save ($ user , true );
112+
113+ $ this ->addFlash ('warning ' , 'Multi-factor authentication was successfully disabled. ' );
114+
115+ return $ this ->redirectToRoute ('dashboard_account ' );
116+ }
117+
118+ return $ this ->render ('dashboard/account/mfa_clear.html.twig ' , [
119+ 'form ' => $ form ,
120+ ]);
121+ }
68122}
0 commit comments