]> BookStack Code Mirror - bookstack/blob - app/Access/Controllers/ResetPasswordController.php
Routes: Added throttling to a range of auth-related endpoints
[bookstack] / app / Access / Controllers / ResetPasswordController.php
1 <?php
2
3 namespace BookStack\Access\Controllers;
4
5 use BookStack\Access\LoginService;
6 use BookStack\Activity\ActivityType;
7 use BookStack\Http\Controller;
8 use BookStack\Users\Models\User;
9 use Illuminate\Http\RedirectResponse;
10 use Illuminate\Http\Request;
11 use Illuminate\Support\Facades\Hash;
12 use Illuminate\Support\Facades\Password;
13 use Illuminate\Support\Str;
14 use Illuminate\Validation\Rules\Password as PasswordRule;
15
16 class ResetPasswordController extends Controller
17 {
18     public function __construct(
19         protected LoginService $loginService
20     ) {
21         $this->middleware('guest');
22         $this->middleware('guard:standard');
23     }
24
25     /**
26      * Display the password reset view for the given token.
27      * If no token is present, display the link request form.
28      */
29     public function showResetForm(Request $request)
30     {
31         $token = $request->route()->parameter('token');
32
33         return view('auth.passwords.reset')->with(
34             ['token' => $token, 'email' => $request->email]
35         );
36     }
37
38     /**
39      * Reset the given user's password.
40      */
41     public function reset(Request $request)
42     {
43         $request->validate([
44             'token' => 'required',
45             'email' => 'required|email',
46             'password' => ['required', 'confirmed', PasswordRule::defaults()],
47         ]);
48
49         // Here we will attempt to reset the user's password. If it is successful we
50         // will update the password on an actual user model and persist it to the
51         // database. Otherwise we will parse the error and return the response.
52         $credentials = $request->only('email', 'password', 'password_confirmation', 'token');
53         $response = Password::broker()->reset($credentials, function (User $user, string $password) {
54             $user->password = Hash::make($password);
55             $user->setRememberToken(Str::random(60));
56             $user->save();
57
58             $this->loginService->login($user, auth()->getDefaultDriver());
59         });
60
61         // If the password was successfully reset, we will redirect the user back to
62         // the application's home authenticated view. If there is an error we can
63         // redirect them back to where they came from with their error message.
64         return $response === Password::PASSWORD_RESET
65             ? $this->sendResetResponse()
66             : $this->sendResetFailedResponse($request, $response, $request->get('token'));
67     }
68
69     /**
70      * Get the response for a successful password reset.
71      */
72     protected function sendResetResponse(): RedirectResponse
73     {
74         $this->showSuccessNotification(trans('auth.reset_password_success'));
75         $this->logActivity(ActivityType::AUTH_PASSWORD_RESET_UPDATE, user());
76
77         return redirect('/');
78     }
79
80     /**
81      * Get the response for a failed password reset.
82      */
83     protected function sendResetFailedResponse(Request $request, string $response, string $token): RedirectResponse
84     {
85         // We show invalid users as invalid tokens as to not leak what
86         // users may exist in the system.
87         if ($response === Password::INVALID_USER) {
88             $response = Password::INVALID_TOKEN;
89         }
90
91         return redirect("/password/reset/{$token}")
92             ->withInput($request->only('email'))
93             ->withErrors(['email' => trans($response)]);
94     }
95 }