84 lines
2.3 KiB
PHP
84 lines
2.3 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\TwoFactorMethod;
|
|
use App\Models\TwoFactorRecoveryCode;
|
|
use App\Models\User;
|
|
use BaconQrCode\Renderer\Image\SvgImageBackEnd;
|
|
use BaconQrCode\Renderer\ImageRenderer;
|
|
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
|
|
use BaconQrCode\Writer;
|
|
use PragmaRX\Google2FA\Google2FA;
|
|
|
|
class TotpService
|
|
{
|
|
public function __construct(private readonly Google2FA $g2fa = new Google2FA()) {}
|
|
|
|
public function generateSecret(): string
|
|
{
|
|
return $this->g2fa->generateSecretKey(32);
|
|
}
|
|
|
|
public function verify(string $secret, string $code): bool
|
|
{
|
|
return (bool) $this->g2fa->verifyKey($secret, $code, 1);
|
|
}
|
|
|
|
public function qrCodeSvg(User $user, string $secret): string
|
|
{
|
|
$otpauth = $this->g2fa->getQRCodeUrl(
|
|
config('app.name', 'Mailwolt'),
|
|
$user->email,
|
|
$secret
|
|
);
|
|
|
|
$renderer = new ImageRenderer(
|
|
new RendererStyle(200, 2),
|
|
new SvgImageBackEnd()
|
|
);
|
|
|
|
return (new Writer($renderer))->writeString($otpauth);
|
|
}
|
|
|
|
public function enable(User $user, string $secret): array
|
|
{
|
|
TwoFactorMethod::updateOrCreate(
|
|
['user_id' => $user->id, 'method' => 'totp'],
|
|
['secret' => encrypt($secret), 'enabled' => true, 'confirmed_at' => now()]
|
|
);
|
|
|
|
$user->update(['two_factor_enabled' => true]);
|
|
|
|
return TwoFactorRecoveryCode::generateNewSet($user->id);
|
|
}
|
|
|
|
public function disable(User $user): void
|
|
{
|
|
TwoFactorMethod::where('user_id', $user->id)->where('method', 'totp')->delete();
|
|
TwoFactorRecoveryCode::where('user_id', $user->id)->delete();
|
|
|
|
if (!$user->twoFactorMethods()->where('enabled', true)->exists()) {
|
|
$user->update(['two_factor_enabled' => false]);
|
|
}
|
|
}
|
|
|
|
public function getSecret(User $user): ?string
|
|
{
|
|
$m = TwoFactorMethod::where('user_id', $user->id)
|
|
->where('method', 'totp')
|
|
->where('enabled', true)
|
|
->first();
|
|
|
|
return $m ? decrypt($m->secret) : null;
|
|
}
|
|
|
|
public function isEnabled(User $user): bool
|
|
{
|
|
return TwoFactorMethod::where('user_id', $user->id)
|
|
->where('method', 'totp')
|
|
->where('enabled', true)
|
|
->exists();
|
|
}
|
|
}
|