diff --git a/CHANGELOG.md b/CHANGELOG.md index 0876656bb..1d3e3f19d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * Logo now links to the correct location on all pages. * Permissions checking to determine if a user can see the task management page now works correctly. * Fixed `pterodactyl.environment_variables` to be used correctly for global environment variables. The wrong config variable name was being using previously. +* Fixes tokens being sent to users when their account is created to actually work. Implements Laravel's internal token creation mechanisms rather than trying to do it custom. ### Changed * Attempting to upload a folder via the web file manager will now display a warning telling the user to use SFTP. diff --git a/app/Notifications/AccountCreated.php b/app/Notifications/AccountCreated.php index 29b084d5e..7dd258dd4 100644 --- a/app/Notifications/AccountCreated.php +++ b/app/Notifications/AccountCreated.php @@ -23,7 +23,7 @@ class AccountCreated extends Notification implements ShouldQueue /** * The user model for the created user. * - * @var object + * @var \Pterodactyl\Models\User */ public $user; @@ -65,7 +65,7 @@ class AccountCreated extends Notification implements ShouldQueue ->line('Email: ' . $this->user->email); if (! is_null($this->token)) { - return $message->action('Setup Your Account', url('/auth/password/reset/' . $this->token . '?email=' . $this->user->email)); + return $message->action('Setup Your Account', url('/auth/password/reset/' . $this->token . '?email=' . urlencode($this->user->email))); } return $message; diff --git a/app/Services/Helpers/TemporaryPasswordService.php b/app/Services/Helpers/TemporaryPasswordService.php deleted file mode 100644 index c9ccfa5df..000000000 --- a/app/Services/Helpers/TemporaryPasswordService.php +++ /dev/null @@ -1,59 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Pterodactyl\Services\Helpers; - -use Ramsey\Uuid\Uuid; -use Illuminate\Contracts\Hashing\Hasher; -use Illuminate\Database\ConnectionInterface; - -class TemporaryPasswordService -{ - const HMAC_ALGO = 'sha256'; - - /** - * @var \Illuminate\Database\ConnectionInterface - */ - protected $connection; - - /** - * @var \Illuminate\Contracts\Hashing\Hasher - */ - protected $hasher; - - /** - * TemporaryPasswordService constructor. - * - * @param \Illuminate\Database\ConnectionInterface $connection - * @param \Illuminate\Contracts\Hashing\Hasher $hasher - */ - public function __construct(ConnectionInterface $connection, Hasher $hasher) - { - $this->connection = $connection; - $this->hasher = $hasher; - } - - /** - * Store a password reset token for a specific email address. - * - * @param string $email - * @return string - */ - public function handle($email) - { - $token = hash_hmac(self::HMAC_ALGO, Uuid::uuid4()->toString(), config('app.key')); - - $this->connection->table('password_resets')->insert([ - 'email' => $email, - 'token' => $this->hasher->make($token), - ]); - - return $token; - } -} diff --git a/app/Services/Users/UserCreationService.php b/app/Services/Users/UserCreationService.php index f4824e48b..b54c4f2de 100644 --- a/app/Services/Users/UserCreationService.php +++ b/app/Services/Users/UserCreationService.php @@ -5,8 +5,8 @@ namespace Pterodactyl\Services\Users; use Ramsey\Uuid\Uuid; use Illuminate\Contracts\Hashing\Hasher; use Illuminate\Database\ConnectionInterface; +use Illuminate\Contracts\Auth\PasswordBroker; use Pterodactyl\Notifications\AccountCreated; -use Pterodactyl\Services\Helpers\TemporaryPasswordService; use Pterodactyl\Contracts\Repository\UserRepositoryInterface; class UserCreationService @@ -22,9 +22,9 @@ class UserCreationService private $hasher; /** - * @var \Pterodactyl\Services\Helpers\TemporaryPasswordService + * @var \Illuminate\Contracts\Auth\PasswordBroker */ - private $passwordService; + private $passwordBroker; /** * @var \Pterodactyl\Contracts\Repository\UserRepositoryInterface @@ -36,18 +36,18 @@ class UserCreationService * * @param \Illuminate\Database\ConnectionInterface $connection * @param \Illuminate\Contracts\Hashing\Hasher $hasher - * @param \Pterodactyl\Services\Helpers\TemporaryPasswordService $passwordService + * @param \Illuminate\Contracts\Auth\PasswordBroker $passwordBroker * @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $repository */ public function __construct( ConnectionInterface $connection, Hasher $hasher, - TemporaryPasswordService $passwordService, + PasswordBroker $passwordBroker, UserRepositoryInterface $repository ) { $this->connection = $connection; $this->hasher = $hasher; - $this->passwordService = $passwordService; + $this->passwordBroker = $passwordBroker; $this->repository = $repository; } @@ -68,8 +68,8 @@ class UserCreationService $this->connection->beginTransaction(); if (! isset($data['password']) || empty($data['password'])) { + $generateResetToken = true; $data['password'] = $this->hasher->make(str_random(30)); - $token = $this->passwordService->handle($data['email']); } /** @var \Pterodactyl\Models\User $user */ @@ -77,6 +77,10 @@ class UserCreationService 'uuid' => Uuid::uuid4()->toString(), ]), true, true); + if (isset($generateResetToken)) { + $token = $this->passwordBroker->createToken($user); + } + $this->connection->commit(); $user->notify(new AccountCreated($user, $token ?? null)); diff --git a/tests/Unit/Services/Helpers/TemporaryPasswordServiceTest.php b/tests/Unit/Services/Helpers/TemporaryPasswordServiceTest.php deleted file mode 100644 index 2d8b6dbe5..000000000 --- a/tests/Unit/Services/Helpers/TemporaryPasswordServiceTest.php +++ /dev/null @@ -1,62 +0,0 @@ -connection = m::mock(ConnectionInterface::class); - $this->hasher = m::mock(Hasher::class); - - $this->service = new TemporaryPasswordService($this->connection, $this->hasher); - } - - /** - * Test that a temporary password is stored and the token is returned. - */ - public function testTemporaryPasswordIsStored() - { - $token = hash_hmac(TemporaryPasswordService::HMAC_ALGO, $this->getKnownUuid(), config('app.key')); - - $this->hasher->shouldReceive('make')->with($token)->once()->andReturn('hashed_token'); - $this->connection->shouldReceive('table')->with('password_resets')->once()->andReturnSelf(); - $this->connection->shouldReceive('insert')->with([ - 'email' => 'test@example.com', - 'token' => 'hashed_token', - ])->once()->andReturnNull(); - - $response = $this->service->handle('test@example.com'); - $this->assertNotEmpty($response); - $this->assertEquals($token, $response); - } -} diff --git a/tests/Unit/Services/Users/UserCreationServiceTest.php b/tests/Unit/Services/Users/UserCreationServiceTest.php index 4012dc655..25219b70a 100644 --- a/tests/Unit/Services/Users/UserCreationServiceTest.php +++ b/tests/Unit/Services/Users/UserCreationServiceTest.php @@ -9,9 +9,9 @@ use Tests\Traits\MocksUuids; use Illuminate\Contracts\Hashing\Hasher; use Illuminate\Database\ConnectionInterface; use Illuminate\Support\Facades\Notification; +use Illuminate\Contracts\Auth\PasswordBroker; use Pterodactyl\Notifications\AccountCreated; use Pterodactyl\Services\Users\UserCreationService; -use Pterodactyl\Services\Helpers\TemporaryPasswordService; use Pterodactyl\Contracts\Repository\UserRepositoryInterface; class UserCreationServiceTest extends TestCase @@ -29,9 +29,9 @@ class UserCreationServiceTest extends TestCase private $hasher; /** - * @var \Pterodactyl\Services\Helpers\TemporaryPasswordService|\Mockery\Mock + * @var \Illuminate\Contracts\Auth\PasswordBroker|\Mockery\Mock */ - private $passwordService; + private $passwordBroker; /** * @var \Pterodactyl\Contracts\Repository\UserRepositoryInterface|\Mockery\Mock @@ -48,7 +48,7 @@ class UserCreationServiceTest extends TestCase Notification::fake(); $this->connection = m::mock(ConnectionInterface::class); $this->hasher = m::mock(Hasher::class); - $this->passwordService = m::mock(TemporaryPasswordService::class); + $this->passwordBroker = m::mock(PasswordBroker::class); $this->repository = m::mock(UserRepositoryInterface::class); } @@ -121,7 +121,7 @@ class UserCreationServiceTest extends TestCase $this->hasher->shouldNotReceive('make'); $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); $this->hasher->shouldReceive('make')->once()->andReturn('created-enc-password'); - $this->passwordService->shouldReceive('handle')->with($user->email)->once()->andReturn('random-token'); + $this->passwordBroker->shouldReceive('createToken')->with($user)->once()->andReturn('random-token'); $this->repository->shouldReceive('create')->with([ 'password' => 'created-enc-password', @@ -152,6 +152,6 @@ class UserCreationServiceTest extends TestCase */ private function getService(): UserCreationService { - return new UserCreationService($this->connection, $this->hasher, $this->passwordService, $this->repository); + return new UserCreationService($this->connection, $this->hasher, $this->passwordBroker, $this->repository); } }