WebauthnController.php 4.3 KB

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