diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index a94ad8aad..55c1d8831 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -47,6 +47,18 @@ class Handler extends ExceptionHandler ValidationException::class, ]; + /** + * Maps exceptions to a specific response code. This handles special exception + * types that don't have a defined response code. + * + * @var array + */ + protected static array $exceptionResponseCodes = [ + AuthenticationException::class => 401, + AuthorizationException::class => 403, + ValidationException::class => 422, + ]; + /** * A list of the inputs that are never flashed for validation exceptions. * @@ -187,12 +199,14 @@ class Handler extends ExceptionHandler */ public static function convertToArray(Throwable $exception, array $override = []): array { + $match = self::$exceptionResponseCodes[get_class($exception)] ?? null; + $error = [ 'code' => class_basename($exception), 'status' => method_exists($exception, 'getStatusCode') ? strval($exception->getStatusCode()) - : ($exception instanceof ValidationException ? '422' : '500'), - 'detail' => $exception instanceof HttpExceptionInterface + : strval($match ?? '500'), + 'detail' => $exception instanceof HttpExceptionInterface || !is_null($match) ? $exception->getMessage() : 'An unexpected error was encountered while processing this request, please try again.', ]; diff --git a/app/Http/Controllers/Api/Client/AccountController.php b/app/Http/Controllers/Api/Client/AccountController.php index ead296d3c..963c01374 100644 --- a/app/Http/Controllers/Api/Client/AccountController.php +++ b/app/Http/Controllers/Api/Client/AccountController.php @@ -19,19 +19,19 @@ class AccountController extends ClientApiController private $updateService; /** - * @var \Illuminate\Auth\SessionGuard + * @var \Illuminate\Auth\AuthManager */ - private $sessionGuard; + private $manager; /** * AccountController constructor. */ - public function __construct(AuthManager $sessionGuard, UserUpdateService $updateService) + public function __construct(AuthManager $manager, UserUpdateService $updateService) { parent::__construct(); $this->updateService = $updateService; - $this->sessionGuard = $sessionGuard; + $this->manager = $manager; } public function index(Request $request): array @@ -64,13 +64,17 @@ class AccountController extends ClientApiController { $user = $this->updateService->handle($request->user(), $request->validated()); + $guard = $this->manager->guard(); // If you do not update the user in the session you'll end up working with a // cached copy of the user that does not include the updated password. Do this // to correctly store the new user details in the guard and allow the logout // other devices functionality to work. - $this->sessionGuard->setUser($user); + $guard->setUser($user); - $this->sessionGuard->logoutOtherDevices($request->input('password')); + // This method doesn't exist in the stateless Sanctum world. + if (method_exists($guard, 'logoutOtherDevices')) { + $guard->logoutOtherDevices($request->input('password')); + } return new JsonResponse([], Response::HTTP_NO_CONTENT); } diff --git a/app/Models/ApiKey.php b/app/Models/ApiKey.php index 32c6fa03e..cd5a0ddca 100644 --- a/app/Models/ApiKey.php +++ b/app/Models/ApiKey.php @@ -195,9 +195,13 @@ class ApiKey extends Model public static function findToken($token) { $id = Str::substr($token, 0, self::IDENTIFIER_LENGTH); - $token = Str::substr($token, strlen($id)); - return static::where('identifier', $id)->where('token', encrypt($token))->first(); + $model = static::where('identifier', $id)->first(); + if (!is_null($model) && decrypt($model->token) === Str::substr($token, strlen($id))) { + return $model; + } + + return null; } /** diff --git a/database/Factories/ApiKeyFactory.php b/database/Factories/ApiKeyFactory.php index 1faa4be55..77795e607 100644 --- a/database/Factories/ApiKeyFactory.php +++ b/database/Factories/ApiKeyFactory.php @@ -25,7 +25,7 @@ class ApiKeyFactory extends Factory return [ 'key_type' => ApiKey::TYPE_APPLICATION, - 'identifier' => Str::random(ApiKey::IDENTIFIER_LENGTH), + 'identifier' => ApiKey::generateTokenIdentifier(), 'token' => $token ?: $token = encrypt(Str::random(ApiKey::KEY_LENGTH)), 'allowed_ips' => null, 'memo' => 'Test Function Key', diff --git a/tests/Integration/Api/Application/ApplicationApiIntegrationTestCase.php b/tests/Integration/Api/Application/ApplicationApiIntegrationTestCase.php index 8220f0252..bc919cdc3 100644 --- a/tests/Integration/Api/Application/ApplicationApiIntegrationTestCase.php +++ b/tests/Integration/Api/Application/ApplicationApiIntegrationTestCase.php @@ -2,8 +2,8 @@ namespace Pterodactyl\Tests\Integration\Api\Application; -use Pterodactyl\Models\User; use Illuminate\Http\Request; +use Pterodactyl\Models\User; use PHPUnit\Framework\Assert; use Pterodactyl\Models\ApiKey; use Pterodactyl\Services\Acl\Api\AdminAcl; @@ -41,10 +41,9 @@ abstract class ApplicationApiIntegrationTestCase extends IntegrationTestCase $this->user = $this->createApiUser(); $this->key = $this->createApiKey($this->user); - $this->withHeader('Accept', 'application/vnd.pterodactyl.v1+json'); - $this->withHeader('Authorization', 'Bearer ' . $this->getApiKey()->identifier . decrypt($this->getApiKey()->token)); - - $this->withMiddleware('api..key:' . ApiKey::TYPE_APPLICATION); + $this + ->withHeader('Accept', 'application/vnd.pterodactyl.v1+json') + ->withHeader('Authorization', 'Bearer ' . $this->key->identifier . decrypt($this->key->token)); } public function getApiUser(): User @@ -63,19 +62,12 @@ abstract class ApplicationApiIntegrationTestCase extends IntegrationTestCase protected function createNewDefaultApiKey(User $user, array $permissions = []): ApiKey { $this->key = $this->createApiKey($user, $permissions); - $this->refreshHeaders($this->key); + + $this->withHeader('Authorization', 'Bearer ' . $this->key->identifier . decrypt($this->key->token)); return $this->key; } - /** - * Refresh the authorization header for a request to use a different API key. - */ - protected function refreshHeaders(ApiKey $key) - { - $this->withHeader('Authorization', 'Bearer ' . $key->identifier . decrypt($key->token)); - } - /** * Create an administrative user. */