Skip to content

Commit 2b3303c

Browse files
committed
Fix changing a user password to not incorrectly handle logging out old sessions; closes pterodactyl#3531
1 parent 25d9ba4 commit 2b3303c

File tree

5 files changed

+32
-28
lines changed

5 files changed

+32
-28
lines changed

app/Http/Controllers/Api/Client/AccountController.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,17 @@ public function updateEmail(UpdateEmailRequest $request): JsonResponse
5858
* Update the authenticated user's password. All existing sessions will be logged
5959
* out immediately.
6060
*
61-
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
62-
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
61+
* @throws \Throwable
6362
*/
6463
public function updatePassword(UpdatePasswordRequest $request): JsonResponse
6564
{
66-
$this->updateService->handle($request->user(), $request->validated());
65+
$user = $this->updateService->handle($request->user(), $request->validated());
66+
67+
// If you do not update the user in the session you'll end up working with a
68+
// cached copy of the user that does not include the updated password. Do this
69+
// to correctly store the new user details in the guard and allow the logout
70+
// other devices functionality to work.
71+
$this->sessionGuard->setUser($user);
6772

6873
$this->sessionGuard->logoutOtherDevices($request->input('password'));
6974

app/Http/Requests/Api/Client/Account/UpdateEmailRequest.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
namespace Pterodactyl\Http\Requests\Api\Client\Account;
44

55
use Pterodactyl\Models\User;
6+
use Illuminate\Container\Container;
7+
use Illuminate\Contracts\Hashing\Hasher;
68
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
79
use Pterodactyl\Exceptions\Http\Base\InvalidPasswordProvidedException;
810

@@ -17,8 +19,10 @@ public function authorize(): bool
1719
return false;
1820
}
1921

22+
$hasher = Container::getInstance()->make(Hasher::class);
23+
2024
// Verify password matches when changing password or email.
21-
if (!password_verify($this->input('password'), $this->user()->password)) {
25+
if (!$hasher->check($this->input('password'), $this->user()->password)) {
2226
throw new InvalidPasswordProvidedException(trans('validation.internal.invalid_password'));
2327
}
2428

app/Http/Requests/Api/Client/Account/UpdatePasswordRequest.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Pterodactyl\Http\Requests\Api\Client\Account;
44

5+
use Illuminate\Container\Container;
6+
use Illuminate\Contracts\Hashing\Hasher;
57
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
68
use Pterodactyl\Exceptions\Http\Base\InvalidPasswordProvidedException;
79

@@ -16,8 +18,10 @@ public function authorize(): bool
1618
return false;
1719
}
1820

21+
$hasher = Container::getInstance()->make(Hasher::class);
22+
1923
// Verify password matches when changing password or email.
20-
if (!password_verify($this->input('current_password'), $this->user()->password)) {
24+
if (!$hasher->check($this->input('current_password'), $this->user()->password)) {
2125
throw new InvalidPasswordProvidedException(trans('validation.internal.invalid_password'));
2226
}
2327

app/Services/Users/UserUpdateService.php

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
use Pterodactyl\Models\User;
66
use Illuminate\Contracts\Hashing\Hasher;
77
use Pterodactyl\Traits\Services\HasUserLevels;
8-
use Pterodactyl\Repositories\Eloquent\UserRepository;
98

109
class UserUpdateService
1110
{
@@ -16,39 +15,29 @@ class UserUpdateService
1615
*/
1716
private $hasher;
1817

19-
/**
20-
* @var \Pterodactyl\Repositories\Eloquent\UserRepository
21-
*/
22-
private $repository;
23-
2418
/**
2519
* UpdateService constructor.
2620
*/
27-
public function __construct(Hasher $hasher, UserRepository $repository)
21+
public function __construct(Hasher $hasher)
2822
{
2923
$this->hasher = $hasher;
30-
$this->repository = $repository;
3124
}
3225

3326
/**
34-
* Update the user model instance.
35-
*
36-
* @return \Pterodactyl\Models\User
27+
* Update the user model instance and return the updated model.
3728
*
38-
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
39-
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
29+
* @throws \Throwable
4030
*/
41-
public function handle(User $user, array $data)
31+
public function handle(User $user, array $data): User
4232
{
4333
if (!empty(array_get($data, 'password'))) {
4434
$data['password'] = $this->hasher->make($data['password']);
4535
} else {
4636
unset($data['password']);
4737
}
4838

49-
/** @var \Pterodactyl\Models\User $response */
50-
$response = $this->repository->update($user->id, $data);
39+
$user->forceFill($data)->saveOrFail();
5140

52-
return $response;
41+
return $user->refresh();
5342
}
5443
}

tests/Integration/Api/Client/AccountControllerTest.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
namespace Pterodactyl\Tests\Integration\Api\Client;
44

5-
use Mockery;
65
use Pterodactyl\Models\User;
76
use Illuminate\Http\Response;
8-
use Illuminate\Auth\AuthManager;
7+
use Illuminate\Support\Facades\Hash;
98

109
class AccountControllerTest extends ClientApiIntegrationTestCase
1110
{
@@ -106,17 +105,20 @@ public function testPasswordIsUpdated()
106105
/** @var \Pterodactyl\Models\User $user */
107106
$user = User::factory()->create();
108107

109-
$mock = Mockery::mock(AuthManager::class);
110-
$mock->expects('logoutOtherDevices')->with('New_Password1');
111-
112-
$this->app->instance(AuthManager::class, $mock);
108+
$initialHash = $user->password;
113109

114110
$response = $this->actingAs($user)->putJson('/api/client/account/password', [
115111
'current_password' => 'password',
116112
'password' => 'New_Password1',
117113
'password_confirmation' => 'New_Password1',
118114
]);
119115

116+
$user = $user->refresh();
117+
118+
$this->assertNotEquals($user->password, $initialHash);
119+
$this->assertTrue(Hash::check('New_Password1', $user->password));
120+
$this->assertFalse(Hash::check('password', $user->password));
121+
120122
$response->assertStatus(Response::HTTP_NO_CONTENT);
121123
}
122124

0 commit comments

Comments
 (0)