]> BookStack Code Mirror - bookstack/blob - app/Http/Controllers/Auth/MfaController.php
Complete base flow for TOTP setup
[bookstack] / app / Http / Controllers / Auth / MfaController.php
1 <?php
2
3 namespace BookStack\Http\Controllers\Auth;
4
5 use BookStack\Actions\ActivityType;
6 use BookStack\Auth\Access\Mfa\MfaValue;
7 use BookStack\Auth\Access\Mfa\TotpService;
8 use BookStack\Auth\Access\Mfa\TotpValidationRule;
9 use BookStack\Http\Controllers\Controller;
10 use Illuminate\Http\Request;
11 use Illuminate\Validation\ValidationException;
12
13 class MfaController extends Controller
14 {
15     protected const TOTP_SETUP_SECRET_SESSION_KEY = 'mfa-setup-totp-secret';
16
17     /**
18      * Show the view to setup MFA for the current user.
19      */
20     public function setup()
21     {
22         $userMethods = user()->mfaValues()
23             ->get(['id', 'method'])
24             ->groupBy('method');
25         return view('mfa.setup', [
26             'userMethods' => $userMethods,
27         ]);
28     }
29
30     /**
31      * Show a view that generates and displays a TOTP QR code.
32      */
33     public function totpGenerate(TotpService $totp)
34     {
35         if (session()->has(static::TOTP_SETUP_SECRET_SESSION_KEY)) {
36             $totpSecret = decrypt(session()->get(static::TOTP_SETUP_SECRET_SESSION_KEY));
37         } else {
38             $totpSecret = $totp->generateSecret();
39             session()->put(static::TOTP_SETUP_SECRET_SESSION_KEY, encrypt($totpSecret));
40         }
41
42         $qrCodeUrl = $totp->generateUrl($totpSecret);
43         $svg = $totp->generateQrCodeSvg($qrCodeUrl);
44
45         return view('mfa.totp-generate', [
46             'secret' => $totpSecret,
47             'svg' => $svg,
48         ]);
49     }
50
51     /**
52      * Confirm the setup of TOTP and save the auth method secret
53      * against the current user.
54      * @throws ValidationException
55      */
56     public function totpConfirm(Request $request)
57     {
58         $totpSecret = decrypt(session()->get(static::TOTP_SETUP_SECRET_SESSION_KEY));
59         $this->validate($request, [
60             'code' => [
61                 'required',
62                 'max:12', 'min:4',
63                 new TotpValidationRule($totpSecret),
64             ]
65         ]);
66
67         MfaValue::upsertWithValue(user(), MfaValue::METHOD_TOTP, $totpSecret);
68         $this->logActivity(ActivityType::MFA_SETUP_METHOD, 'totp');
69
70         return redirect('/mfa/setup');
71     }
72 }