WebauthnController.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. <?php
  2. namespace App\Http\Controllers\Auth;
  3. use App\Actions\RegisterKeyStore;
  4. use App\Facades\Webauthn as WebauthnFacade;
  5. use App\Models\WebauthnKey;
  6. use Illuminate\Database\Eloquent\ModelNotFoundException;
  7. use Illuminate\Http\Request;
  8. use Illuminate\Support\Facades\Redirect;
  9. use Illuminate\Support\Facades\Response;
  10. use Illuminate\Support\Str;
  11. use LaravelWebauthn\Actions\RegisterKeyPrepare;
  12. use LaravelWebauthn\Http\Controllers\WebauthnKeyController as ControllersWebauthnController;
  13. use LaravelWebauthn\Services\Webauthn;
  14. use Webauthn\PublicKeyCredentialCreationOptions;
  15. class WebauthnController extends ControllersWebauthnController
  16. {
  17. public function index()
  18. {
  19. return user()->webauthnKeys()->latest()->select(['id','name','enabled','created_at'])->get()->values();
  20. }
  21. /**
  22. * PublicKey Creation session name.
  23. *
  24. * @var string
  25. */
  26. private const SESSION_PUBLICKEY_CREATION = 'webauthn.publicKeyCreation';
  27. /**
  28. * Return the register data to attempt a Webauthn registration.
  29. *
  30. * @param \Illuminate\Http\Request $request
  31. * @return RegisterViewResponse
  32. */
  33. public function create(Request $request)
  34. {
  35. $publicKey = $this->app[RegisterKeyPrepare::class]($request->user());
  36. $request->session()->put(Webauthn::SESSION_PUBLICKEY_CREATION, $publicKey);
  37. return view('vendor.webauthn.register')->with('publicKey', $publicKey);
  38. }
  39. /**
  40. * Validate and create the Webauthn request.
  41. *
  42. * @param \Illuminate\Http\Request $request
  43. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
  44. */
  45. public function store(Request $request)
  46. {
  47. $request->validate([
  48. 'register' => 'required|string',
  49. 'name' => 'required|string|max:50'
  50. ]);
  51. try {
  52. $publicKey = $request->session()->pull(self::SESSION_PUBLICKEY_CREATION);
  53. if (! $publicKey instanceof PublicKeyCredentialCreationOptions) {
  54. throw new ModelNotFoundException(trans('webauthn::errors.create_data_not_found'));
  55. }
  56. /** @var \LaravelWebauthn\Models\WebauthnKey|null */
  57. $webauthnKey = $this->app[RegisterKeyStore::class](
  58. $request->user(),
  59. $publicKey,
  60. $request->input('register'),
  61. $request->input('name')
  62. );
  63. if ($webauthnKey !== null) {
  64. $request->session()->put(Webauthn::SESSION_WEBAUTHNID_CREATED, $webauthnKey->id);
  65. }
  66. user()->update([
  67. 'two_factor_enabled' => false
  68. ]);
  69. return $this->redirectAfterSuccessRegister();
  70. } catch (\Exception $e) {
  71. return Response::json([
  72. 'error' => [
  73. 'message' => $e->getMessage(),
  74. ],
  75. ], 403);
  76. }
  77. }
  78. /**
  79. * Return the redirect destination after a successfull register.
  80. *
  81. * @param WebauthnKey $webauthnKey
  82. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
  83. */
  84. protected function redirectAfterSuccessRegister()
  85. {
  86. // If the user already has at least one key do not generate a new backup code.
  87. if (user()->webauthnKeys()->count() > 1) {
  88. return Redirect::intended('/settings');
  89. }
  90. user()->update([
  91. 'two_factor_backup_code' => bcrypt($code = Str::random(40))
  92. ]);
  93. return Redirect::intended('/settings')->with(['backupCode' => $code]);
  94. }
  95. /**
  96. * Remove an existing Webauthn key.
  97. *
  98. * @param \Illuminate\Http\Request $request
  99. * @return \Illuminate\Http\JsonResponse
  100. */
  101. public function destroy(Request $request, $webauthnKeyId)
  102. {
  103. try {
  104. user()->webauthnKeys()
  105. ->findOrFail($webauthnKeyId)
  106. ->delete();
  107. if (! WebauthnFacade::hasKey(user())) {
  108. WebauthnFacade::logout();
  109. }
  110. return Response::json([
  111. 'deleted' => true,
  112. 'id' => $webauthnKeyId,
  113. ]);
  114. } catch (ModelNotFoundException $e) {
  115. return Response::json([
  116. 'error' => [
  117. 'message' => trans('webauthn::errors.object_not_found'),
  118. ],
  119. ], 404);
  120. }
  121. }
  122. }