X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/1af5bbf3f7404ef9380477657ac1b5df0df119aa..refs/pull/3693/head:/app/Http/Controllers/Auth/MfaBackupCodesController.php diff --git a/app/Http/Controllers/Auth/MfaBackupCodesController.php b/app/Http/Controllers/Auth/MfaBackupCodesController.php index b89050565..4ceb394b0 100644 --- a/app/Http/Controllers/Auth/MfaBackupCodesController.php +++ b/app/Http/Controllers/Auth/MfaBackupCodesController.php @@ -3,10 +3,15 @@ namespace BookStack\Http\Controllers\Auth; use BookStack\Actions\ActivityType; +use BookStack\Auth\Access\LoginService; use BookStack\Auth\Access\Mfa\BackupCodeService; +use BookStack\Auth\Access\Mfa\MfaSession; use BookStack\Auth\Access\Mfa\MfaValue; +use BookStack\Exceptions\NotFoundException; use BookStack\Http\Controllers\Controller; use Exception; +use Illuminate\Http\Request; +use Illuminate\Validation\ValidationException; class MfaBackupCodesController extends Controller { @@ -15,7 +20,7 @@ class MfaBackupCodesController extends Controller protected const SETUP_SECRET_SESSION_KEY = 'mfa-setup-backup-codes'; /** - * Show a view that generates and displays backup codes + * Show a view that generates and displays backup codes. */ public function generate(BackupCodeService $codeService) { @@ -24,14 +29,17 @@ class MfaBackupCodesController extends Controller $downloadUrl = 'data:application/octet-stream;base64,' . base64_encode(implode("\n\n", $codes)); + $this->setPageTitle(trans('auth.mfa_gen_backup_codes_title')); + return view('mfa.backup-codes-generate', [ - 'codes' => $codes, + 'codes' => $codes, 'downloadUrl' => $downloadUrl, ]); } /** * Confirm the setup of backup codes, storing them against the user. + * * @throws Exception */ public function confirm() @@ -44,6 +52,48 @@ class MfaBackupCodesController extends Controller MfaValue::upsertWithValue($this->currentOrLastAttemptedUser(), MfaValue::METHOD_BACKUP_CODES, json_encode($codes)); $this->logActivity(ActivityType::MFA_SETUP_METHOD, 'backup-codes'); + + if (!auth()->check()) { + $this->showSuccessNotification(trans('auth.mfa_setup_login_notification')); + + return redirect('/login'); + } + return redirect('/mfa/setup'); } + + /** + * Verify the MFA method submission on check. + * + * @throws NotFoundException + * @throws ValidationException + */ + public function verify(Request $request, BackupCodeService $codeService, MfaSession $mfaSession, LoginService $loginService) + { + $user = $this->currentOrLastAttemptedUser(); + $codes = MfaValue::getValueForUser($user, MfaValue::METHOD_BACKUP_CODES) ?? '[]'; + + $this->validate($request, [ + 'code' => [ + 'required', 'max:12', 'min:8', + function ($attribute, $value, $fail) use ($codeService, $codes) { + if (!$codeService->inputCodeExistsInSet($value, $codes)) { + $fail(trans('validation.backup_codes')); + } + }, + ], + ]); + + $updatedCodes = $codeService->removeInputCodeFromSet($request->get('code'), $codes); + MfaValue::upsertWithValue($user, MfaValue::METHOD_BACKUP_CODES, $updatedCodes); + + $mfaSession->markVerifiedForUser($user); + $loginService->reattemptLoginFor($user); + + if ($codeService->countCodesInSet($updatedCodes) < 5) { + $this->showWarningNotification(trans('auth.mfa_backup_codes_usage_limit_warning')); + } + + return redirect()->intended(); + } }