Files
BookStack/app/Access/Mfa/TotpService.php
Dan Brown 2de3247ae4 Deps: Updated PHP package versions
Includes major version change of antonioribeiro/google2fa which changes
secret length. From manual testing of old MFA secrets and new, this
should not be breaking at all.
2025-12-19 14:22:27 +00:00

73 lines
2.0 KiB
PHP

<?php
namespace BookStack\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;
use BookStack\Users\Models\User;
use PragmaRX\Google2FA\Google2FA;
use PragmaRX\Google2FA\Support\Constants;
class TotpService
{
public function __construct(
protected Google2FA $google2fa
) {
$this->google2fa = $google2fa;
// 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);
}
/**
* Generate a new totp secret key.
*/
public function generateSecret(): string
{
/** @noinspection PhpUnhandledExceptionInspection */
return $this->google2fa->generateSecretKey();
}
/**
* Generate a TOTP URL from a secret key.
*/
public function generateUrl(string $secret, User $user): string
{
return $this->google2fa->getQRCodeUrl(
setting('app-name'),
$user->email,
$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));
return (new Writer(
new ImageRenderer(
new RendererStyle(192, 4, null, null, $color),
new SvgImageBackEnd()
)
))->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);
}
}