@@ -12,19 +12,24 @@ use \Psr\Http\Message\ResponseInterface;
1212 */
1313class MFA extends \NDB_Page
1414{
15- public $ skipTemplate = true ;
15+ public $ skipTemplate = true ;
1616
17- public function getBreadcrumbs (): \LORIS \BreadcrumbTrail
18- {
19- return new \LORIS \BreadcrumbTrail (
20- new \LORIS \Breadcrumb (
21- dgettext ("loris " , "My Preferences " )
22- ),
23- new \LORIS \Breadcrumb (
24- dgettext ("my_preferences " , "Configure 2FA " )
25- ),
26- );
27- }
17+ /**
18+ * {@inheritDoc}
19+ *
20+ * @return \LORIS\BreadcrumbTrail
21+ */
22+ public function getBreadcrumbs (): \LORIS \BreadcrumbTrail
23+ {
24+ return new \LORIS \BreadcrumbTrail (
25+ new \LORIS \Breadcrumb (
26+ dgettext ("loris " , "My Preferences " )
27+ ),
28+ new \LORIS \Breadcrumb (
29+ dgettext ("my_preferences " , "Configure 2FA " )
30+ ),
31+ );
32+ }
2833
2934 /**
3035 * {@inheritDoc}
@@ -35,15 +40,18 @@ class MFA extends \NDB_Page
3540 */
3641 public function handle (ServerRequestInterface $ request ) : ResponseInterface
3742 {
38- switch ($ request ->getMethod ()) {
39- case 'GET ' :
40- return parent ::handle ($ request );
41- case 'POST ' :
42- return $ this ->validateCodeAndSave ($ request ->getAttribute ("user " ), $ request ->getParsedBody ());
43- default :
44- return new \LORIS \Http \Response \JSON \MethodNotAllowed (['GET ' , 'POST ' ]);
43+ switch ($ request ->getMethod ()) {
44+ case 'GET ' :
45+ return parent ::handle ($ request );
46+ case 'POST ' :
47+ return $ this ->validateCodeAndSave (
48+ $ request ->getAttribute ("user " ),
49+ $ request ->getParsedBody ()
50+ );
51+ default :
52+ return new \LORIS \Http \Response \JSON \MethodNotAllowed (['GET ' , 'POST ' ]);
4553
46- }
54+ }
4755 }
4856 /**
4957 * {@inheritDoc}
@@ -63,27 +71,48 @@ class MFA extends \NDB_Page
6371 );
6472 }
6573
66- function validateCodeAndSave (\User $ user , array $ values ): ResponseInterface {
67- if (!isset ($ values ['code ' ]) || !isset ($ values ['secret ' ])) {
68- return new \LORIS \Http \Response \JSON \BadRequest ('Missing code or secret to validate ' );
69- }
70- $ base32Decoder = new Base32 ();
71- $ secret = $ base32Decoder ->decode ($ values ['secret ' ]);
72- $ validator = new \LORIS \Security \OTP \TOTP (secret: $ secret );
73- $ counter = $ validator ->getTimeCounter ();
74- $ wantCode = $ validator ->getCode ($ counter , 6 );
75- if ($ wantCode !== strval ($ values ['code ' ])) {
76- return new \LORIS \Http \Response \JSON \BadRequest ('Code does not match expected value ' );
77- }
78- $ db = $ this ->loris ->getDatabaseConnection ();
79- $ db ->_trackChanges = false ;
80- // We are dealing with binary data that never gets exposed to the user
81- $ db ->unsafeUpdate ("users " , ['TOTPSecret ' => $ secret ], ['ID ' => $ user ->getId ()]);
74+ /**
75+ * Validates the code passed by the user matches the secret key that they
76+ * provided and save the secret key to the database if it matches
77+ *
78+ * @param \User $user The user providing the 2FA code
79+ * @param array $values The parsed values submitted by the user
80+ *
81+ * @return ResponseInterface
82+ */
83+ function validateCodeAndSave (\User $ user , array $ values ): ResponseInterface
84+ {
85+ if (!isset ($ values ['code ' ]) || !isset ($ values ['secret ' ])) {
86+ return new \LORIS \Http \Response \JSON \BadRequest (
87+ 'Missing code or secret to validate '
88+ );
89+ }
90+ $ base32Decoder = new Base32 ();
91+ $ secret = $ base32Decoder ->decode ($ values ['secret ' ]);
92+ $ validator = new \LORIS \Security \OTP \TOTP (secret: $ secret );
93+ $ counter = $ validator ->getTimeCounter ();
94+ $ wantCode = $ validator ->getCode ($ counter , 6 );
95+ if ($ wantCode !== strval ($ values ['code ' ])) {
96+ return new \LORIS \Http \Response \JSON \BadRequest (
97+ 'Code does not match expected value '
98+ );
99+ }
100+ $ db = $ this ->loris ->getDatabaseConnection ();
101+ $ db ->_trackChanges = false ;
102+ // We are dealing with binary data that never gets exposed to the user
103+ $ db ->unsafeUpdate (
104+ "users " ,
105+ ['TOTPSecret ' => $ secret ],
106+ ['ID ' => $ user ->getId ()]
107+ );
82108
83- $ login = $ _SESSION ['state ' ]->getProperty ('login ' );
84- $ login ->setPassedMFA ();
85- return new \LORIS \Http \Response \JSON \OK (['ok ' => 'success ' ,
86- 'message ' => 'Successfully registered multifactor authenticator ' ]);
109+ $ login = $ _SESSION ['State ' ]->getProperty ('login ' );
110+ $ login ->setPassedMFA ();
111+ return new \LORIS \Http \Response \JSON \OK (
112+ ['ok ' => 'success ' ,
113+ 'message ' => 'Successfully registered multifactor authenticator '
114+ ]
115+ );
87116 }
88117}
89118
0 commit comments