| 
									
										
										
										
											2021-07-01 05:10:02 +08:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace BookStack\Auth\Access\Mfa; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | use BaconQrCode\Renderer\Color\Rgb; | 
					
						
							|  |  |  | use BaconQrCode\Renderer\Image\SvgImageBackEnd; | 
					
						
							|  |  |  | use BaconQrCode\Renderer\ImageRenderer; | 
					
						
							|  |  |  | use BaconQrCode\Renderer\RendererStyle\Fill; | 
					
						
							|  |  |  | use BaconQrCode\Renderer\RendererStyle\RendererStyle; | 
					
						
							|  |  |  | use BaconQrCode\Writer; | 
					
						
							| 
									
										
										
										
											2021-10-15 01:02:16 +08:00
										 |  |  | use BookStack\Auth\User; | 
					
						
							| 
									
										
										
										
											2021-07-01 05:10:02 +08:00
										 |  |  | use PragmaRX\Google2FA\Google2FA; | 
					
						
							| 
									
										
										
										
											2021-08-08 21:52:29 +08:00
										 |  |  | use PragmaRX\Google2FA\Support\Constants; | 
					
						
							| 
									
										
										
										
											2021-07-01 05:10:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | class TotpService | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     protected $google2fa; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function __construct(Google2FA $google2fa) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->google2fa = $google2fa; | 
					
						
							| 
									
										
										
										
											2021-08-08 21:52:29 +08:00
										 |  |  |         // Use SHA1 as a default, Personal testing of other options in 2021 found
 | 
					
						
							|  |  |  |         // many apps lack support for other algorithms yet still will scan
 | 
					
						
							|  |  |  |         // the code causing a confusing UX.
 | 
					
						
							|  |  |  |         $this->google2fa->setAlgorithm(Constants::SHA1); | 
					
						
							| 
									
										
										
										
											2021-07-01 05:10:02 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Generate a new totp secret key. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function generateSecret(): string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /** @noinspection PhpUnhandledExceptionInspection */ | 
					
						
							|  |  |  |         return $this->google2fa->generateSecretKey(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Generate a TOTP URL from secret key. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-10-15 01:02:16 +08:00
										 |  |  |     public function generateUrl(string $secret, User $user): string | 
					
						
							| 
									
										
										
										
											2021-07-01 05:10:02 +08:00
										 |  |  |     { | 
					
						
							|  |  |  |         return $this->google2fa->getQRCodeUrl( | 
					
						
							|  |  |  |             setting('app-name'), | 
					
						
							| 
									
										
										
										
											2021-10-15 01:02:16 +08:00
										 |  |  |             $user->email, | 
					
						
							| 
									
										
										
										
											2021-07-01 05:10:02 +08:00
										 |  |  |             $secret | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Generate a QR code to display a TOTP URL. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function generateQrCodeSvg(string $url): string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $color = Fill::uniformColor(new Rgb(255, 255, 255), new Rgb(32, 110, 167)); | 
					
						
							| 
									
										
										
										
											2021-08-21 22:49:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 05:10:02 +08:00
										 |  |  |         return (new Writer( | 
					
						
							|  |  |  |             new ImageRenderer( | 
					
						
							| 
									
										
										
										
											2021-09-13 21:23:54 +08:00
										 |  |  |                 new RendererStyle(192, 4, null, null, $color), | 
					
						
							| 
									
										
										
										
											2021-08-21 22:49:40 +08:00
										 |  |  |                 new SvgImageBackEnd() | 
					
						
							| 
									
										
										
										
											2021-07-01 05:10:02 +08:00
										 |  |  |             ) | 
					
						
							|  |  |  |         ))->writeString($url); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Verify that the user provided code is valid for the secret. | 
					
						
							|  |  |  |      * The secret must be known, not user-provided. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function verifyCode(string $code, string $secret): bool | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /** @noinspection PhpUnhandledExceptionInspection */ | 
					
						
							|  |  |  |         return $this->google2fa->verifyKey($secret, $code); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-08-21 22:49:40 +08:00
										 |  |  | } |