]> BookStack Code Mirror - bookstack/blob - app/Auth/Access/Mfa/TotpService.php
e73c549fe0790230f89cb97334afcdc1ca9079a0
[bookstack] / app / Auth / Access / Mfa / TotpService.php
1 <?php
2
3 namespace BookStack\Auth\Access\Mfa;
4
5 use BaconQrCode\Renderer\Color\Rgb;
6 use BaconQrCode\Renderer\Image\SvgImageBackEnd;
7 use BaconQrCode\Renderer\ImageRenderer;
8 use BaconQrCode\Renderer\RendererStyle\Fill;
9 use BaconQrCode\Renderer\RendererStyle\RendererStyle;
10 use BaconQrCode\Writer;
11 use BookStack\Auth\User;
12 use PragmaRX\Google2FA\Google2FA;
13 use PragmaRX\Google2FA\Support\Constants;
14
15 class TotpService
16 {
17     protected $google2fa;
18
19     public function __construct(Google2FA $google2fa)
20     {
21         $this->google2fa = $google2fa;
22         // Use SHA1 as a default, Personal testing of other options in 2021 found
23         // many apps lack support for other algorithms yet still will scan
24         // the code causing a confusing UX.
25         $this->google2fa->setAlgorithm(Constants::SHA1);
26     }
27
28     /**
29      * Generate a new totp secret key.
30      */
31     public function generateSecret(): string
32     {
33         /** @noinspection PhpUnhandledExceptionInspection */
34         return $this->google2fa->generateSecretKey();
35     }
36
37     /**
38      * Generate a TOTP URL from secret key.
39      */
40     public function generateUrl(string $secret, User $user): string
41     {
42         return $this->google2fa->getQRCodeUrl(
43             setting('app-name'),
44             $user->email,
45             $secret
46         );
47     }
48
49     /**
50      * Generate a QR code to display a TOTP URL.
51      */
52     public function generateQrCodeSvg(string $url): string
53     {
54         $color = Fill::uniformColor(new Rgb(255, 255, 255), new Rgb(32, 110, 167));
55
56         return (new Writer(
57             new ImageRenderer(
58                 new RendererStyle(192, 4, null, null, $color),
59                 new SvgImageBackEnd()
60             )
61         ))->writeString($url);
62     }
63
64     /**
65      * Verify that the user provided code is valid for the secret.
66      * The secret must be known, not user-provided.
67      */
68     public function verifyCode(string $code, string $secret): bool
69     {
70         /** @noinspection PhpUnhandledExceptionInspection */
71         return $this->google2fa->verifyKey($secret, $code);
72     }
73 }