Skip to content

Commit e9c633f

Browse files
committed
Update transformers and controllers to no longer pull an API key attribute
1 parent bd37978 commit e9c633f

File tree

9 files changed

+90
-172
lines changed

9 files changed

+90
-172
lines changed

app/Http/Controllers/Api/Application/ApplicationApiController.php

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,20 @@ public function loadDependencies(Fractal $fractal, Request $request)
5555
/**
5656
* Return an instance of an application transformer.
5757
*
58-
* @return \Pterodactyl\Transformers\Api\Application\BaseTransformer
58+
* @template T of \Pterodactyl\Transformers\Api\Application\BaseTransformer
59+
*
60+
* @param class-string<T> $abstract
61+
*
62+
* @return T
63+
*
64+
* @noinspection PhpDocSignatureInspection
65+
* @noinspection PhpUndefinedClassInspection
5966
*/
6067
public function getTransformer(string $abstract)
6168
{
62-
/** @var \Pterodactyl\Transformers\Api\Application\BaseTransformer $transformer */
63-
$transformer = Container::getInstance()->make($abstract);
64-
$transformer->setKey($this->request->attributes->get('api_key'));
65-
66-
Assert::isInstanceOf($transformer, BaseTransformer::class);
69+
Assert::subclassOf($abstract, BaseTransformer::class);
6770

68-
return $transformer;
71+
return $abstract::fromRequest($this->request);
6972
}
7073

7174
/**

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

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
namespace Pterodactyl\Http\Controllers\Api\Client;
44

55
use Webmozart\Assert\Assert;
6-
use Illuminate\Container\Container;
76
use Pterodactyl\Transformers\Daemon\BaseDaemonTransformer;
87
use Pterodactyl\Transformers\Api\Client\BaseClientTransformer;
98
use Pterodactyl\Http\Controllers\Api\Application\ApplicationApiController;
@@ -45,21 +44,23 @@ protected function parseIncludes()
4544
/**
4645
* Return an instance of an application transformer.
4746
*
48-
* @return \Pterodactyl\Transformers\Api\Client\BaseClientTransformer
47+
* @template T of \Pterodactyl\Transformers\Api\Client\BaseClientTransformer
48+
*
49+
* @param class-string<T> $abstract
50+
*
51+
* @return T
52+
*
53+
* @noinspection PhpUndefinedClassInspection
54+
* @noinspection PhpDocSignatureInspection
4955
*/
5056
public function getTransformer(string $abstract)
5157
{
52-
/** @var \Pterodactyl\Transformers\Api\Client\BaseClientTransformer $transformer */
53-
$transformer = Container::getInstance()->make($abstract);
54-
Assert::isInstanceOfAny($transformer, [
55-
BaseClientTransformer::class,
56-
BaseDaemonTransformer::class,
57-
]);
58+
Assert::methodExists($abstract, 'fromRequest');
5859

59-
if ($transformer instanceof BaseClientTransformer) {
60-
$transformer->setKey($this->request->attributes->get('api_key'));
61-
$transformer->setUser($this->request->user());
62-
}
60+
/** @var T $transformer */
61+
$transformer = $abstract::fromRequest($this->request);
62+
63+
Assert::isInstanceOfAny($transformer, [BaseClientTransformer::class, BaseDaemonTransformer::class]);
6364

6465
return $transformer;
6566
}

app/Http/Requests/Api/Application/ApplicationApiRequest.php

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Pterodactyl\Http\Requests\Api\Application;
44

55
use Webmozart\Assert\Assert;
6+
use Laravel\Sanctum\TransientToken;
67
use Illuminate\Validation\Validator;
78
use Illuminate\Database\Eloquent\Model;
89
use Pterodactyl\Services\Acl\Api\AdminAcl;
@@ -11,14 +12,6 @@
1112

1213
abstract class ApplicationApiRequest extends FormRequest
1314
{
14-
/**
15-
* Tracks if the request has been validated internally or not to avoid
16-
* making duplicate validation calls.
17-
*
18-
* @var bool
19-
*/
20-
private $hasValidated = false;
21-
2215
/**
2316
* The resource that should be checked when performing the authorization
2417
* function for this request.
@@ -47,7 +40,12 @@ public function authorize(): bool
4740
throw new PterodactylException('An ACL resource must be defined on API requests.');
4841
}
4942

50-
return AdminAcl::check($this->attributes->get('api_key'), $this->resource, $this->permission);
43+
$token = $this->user()->currentAccessToken();
44+
if ($token instanceof TransientToken) {
45+
return true;
46+
}
47+
48+
return AdminAcl::check($token, $this->resource, $this->permission);
5149
}
5250

5351
/**

app/Transformers/Api/Application/BaseTransformer.php

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
namespace Pterodactyl\Transformers\Api\Application;
44

55
use Carbon\CarbonImmutable;
6+
use Illuminate\Http\Request;
7+
use Webmozart\Assert\Assert;
68
use Pterodactyl\Models\ApiKey;
79
use Illuminate\Container\Container;
810
use Illuminate\Database\Eloquent\Model;
911
use League\Fractal\TransformerAbstract;
1012
use Pterodactyl\Services\Acl\Api\AdminAcl;
11-
use Pterodactyl\Exceptions\Transformer\InvalidTransformerLevelException;
1213

1314
/**
1415
* @method array transform(Model $model)
@@ -17,15 +18,7 @@ abstract class BaseTransformer extends TransformerAbstract
1718
{
1819
public const RESPONSE_TIMEZONE = 'UTC';
1920

20-
/**
21-
* @var \Pterodactyl\Models\ApiKey
22-
*/
23-
private $key;
24-
25-
/**
26-
* Return the resource name for the JSONAPI output.
27-
*/
28-
abstract public function getResourceName(): string;
21+
protected Request $request;
2922

3023
/**
3124
* BaseTransformer constructor.
@@ -39,54 +32,69 @@ public function __construct()
3932
}
4033

4134
/**
42-
* Set the HTTP request class being used for this request.
35+
* Return the resource name for the JSONAPI output.
36+
*/
37+
abstract public function getResourceName(): string;
38+
39+
/**
40+
* Sets the request on the instance.
4341
*
44-
* @return $this
42+
* @return static
4543
*/
46-
public function setKey(ApiKey $key)
44+
public function setRequest(Request $request): self
4745
{
48-
$this->key = $key;
46+
$this->request = $request;
4947

5048
return $this;
5149
}
5250

5351
/**
54-
* Return the request instance being used for this transformer.
52+
* Returns a new transformer instance with the request set on the instance.
53+
*
54+
* @return \Pterodactyl\Transformers\Api\Application\BaseTransformer
5555
*/
56-
public function getKey(): ApiKey
56+
public static function fromRequest(Request $request)
5757
{
58-
return $this->key;
58+
return app(static::class)->setRequest($request);
5959
}
6060

6161
/**
6262
* Determine if the API key loaded onto the transformer has permission
6363
* to access a different resource. This is used when including other
6464
* models on a transformation request.
65+
*
66+
* @deprecated — prefer $user->can/cannot methods
6567
*/
6668
protected function authorize(string $resource): bool
6769
{
68-
return AdminAcl::check($this->getKey(), $resource, AdminAcl::READ);
70+
$token = $this->request->user()->currentAccessToken();
71+
if (!$token instanceof ApiKey || $token->key_type !== ApiKey::TYPE_APPLICATION) {
72+
return false;
73+
}
74+
75+
return AdminAcl::check($token, $resource, AdminAcl::READ);
6976
}
7077

7178
/**
7279
* Create a new instance of the transformer and pass along the currently
7380
* set API key.
7481
*
75-
* @return \Pterodactyl\Transformers\Api\Application\BaseTransformer
82+
* @template T of \Pterodactyl\Transformers\Api\Application\BaseTransformer
83+
*
84+
* @param class-string<T> $abstract
85+
*
86+
* @return T
7687
*
7788
* @throws \Pterodactyl\Exceptions\Transformer\InvalidTransformerLevelException
89+
*
90+
* @noinspection PhpUndefinedClassInspection
91+
* @noinspection PhpDocSignatureInspection
7892
*/
79-
protected function makeTransformer(string $abstract, array $parameters = [])
93+
protected function makeTransformer(string $abstract)
8094
{
81-
/** @var \Pterodactyl\Transformers\Api\Application\BaseTransformer $transformer */
82-
$transformer = Container::getInstance()->makeWith($abstract, $parameters);
83-
$transformer->setKey($this->getKey());
84-
85-
if (!$transformer instanceof self) {
86-
throw new InvalidTransformerLevelException('Calls to ' . __METHOD__ . ' must return a transformer that is an instance of ' . __CLASS__);
87-
}
95+
Assert::subclassOf($abstract, self::class);
8896

89-
return $transformer;
97+
return $abstract::fromRequest($this->request);
9098
}
9199

92100
/**

app/Transformers/Api/Client/BaseClientTransformer.php

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,65 +5,39 @@
55
use Pterodactyl\Models\User;
66
use Webmozart\Assert\Assert;
77
use Pterodactyl\Models\Server;
8-
use Illuminate\Container\Container;
9-
use Pterodactyl\Exceptions\Transformer\InvalidTransformerLevelException;
108
use Pterodactyl\Transformers\Api\Application\BaseTransformer as BaseApplicationTransformer;
119

1210
abstract class BaseClientTransformer extends BaseApplicationTransformer
1311
{
14-
/**
15-
* @var \Pterodactyl\Models\User
16-
*/
17-
private $user;
18-
1912
/**
2013
* Return the user model of the user requesting this transformation.
2114
*/
2215
public function getUser(): User
2316
{
24-
return $this->user;
25-
}
26-
27-
/**
28-
* Set the user model of the user requesting this transformation.
29-
*/
30-
public function setUser(User $user)
31-
{
32-
$this->user = $user;
17+
return $this->request->user();
3318
}
3419

3520
/**
3621
* Determine if the API key loaded onto the transformer has permission
3722
* to access a different resource. This is used when including other
3823
* models on a transformation request.
3924
*
40-
* @param \Pterodactyl\Models\Server $server
25+
* @noinspection PhpParameterNameChangedDuringInheritanceInspection
4126
*/
4227
protected function authorize(string $ability, Server $server = null): bool
4328
{
4429
Assert::isInstanceOf($server, Server::class);
4530

46-
return $this->getUser()->can($ability, [$server]);
31+
return $this->request->user()->can($ability, [$server]);
4732
}
4833

4934
/**
50-
* Create a new instance of the transformer and pass along the currently
51-
* set API key.
52-
*
53-
* @return self
54-
*
55-
* @throws \Pterodactyl\Exceptions\Transformer\InvalidTransformerLevelException
35+
* {@inheritDoc}
5636
*/
57-
protected function makeTransformer(string $abstract, array $parameters = [])
37+
protected function makeTransformer(string $abstract)
5838
{
59-
/** @var \Pterodactyl\Transformers\Api\Application\BaseTransformer $transformer */
60-
$transformer = Container::getInstance()->makeWith($abstract, $parameters);
61-
$transformer->setKey($this->getKey());
62-
63-
if (!$transformer instanceof self) {
64-
throw new InvalidTransformerLevelException('Calls to ' . __METHOD__ . ' must return a transformer that is an instance of ' . __CLASS__);
65-
}
39+
Assert::subclassOf($abstract, self::class);
6640

67-
return $transformer;
41+
return parent::makeTransformer($abstract);
6842
}
6943
}

app/Transformers/Api/Client/DatabaseTransformer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public function transform(Database $model): array
5959
*/
6060
public function includePassword(Database $database)
6161
{
62-
if (!$this->getUser()->can(Permission::ACTION_DATABASE_VIEW_PASSWORD, $database->server)) {
62+
if (!$this->request->user()->can(Permission::ACTION_DATABASE_VIEW_PASSWORD, $database->server)) {
6363
return $this->null();
6464
}
6565

app/Transformers/Api/Client/ServerTransformer.php

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ public function transform(Server $server): array
3434
/** @var \Pterodactyl\Services\Servers\StartupCommandService $service */
3535
$service = Container::getInstance()->make(StartupCommandService::class);
3636

37+
$user = $this->request->user();
38+
3739
return [
38-
'server_owner' => $this->getKey()->user_id === $server->owner_id,
40+
'server_owner' => $user->id === $server->owner_id,
3941
'identifier' => $server->uuidShort,
4042
'internal_id' => $server->id,
4143
'uuid' => $server->uuid,
@@ -55,7 +57,7 @@ public function transform(Server $server): array
5557
'threads' => $server->threads,
5658
'oom_disabled' => $server->oom_disabled,
5759
],
58-
'invocation' => $service->handle($server, !$this->getUser()->can(Permission::ACTION_STARTUP_READ, $server)),
60+
'invocation' => $service->handle($server, !$user->can(Permission::ACTION_STARTUP_READ, $server)),
5961
'docker_image' => $server->image,
6062
'egg_features' => $server->egg->inherit_features,
6163
'feature_limits' => [
@@ -75,22 +77,23 @@ public function transform(Server $server): array
7577
/**
7678
* Returns the allocations associated with this server.
7779
*
78-
* @return \League\Fractal\Resource\Collection|\League\Fractal\Resource\NullResource
80+
* @return \League\Fractal\Resource\Collection
7981
*
8082
* @throws \Pterodactyl\Exceptions\Transformer\InvalidTransformerLevelException
8183
*/
8284
public function includeAllocations(Server $server)
8385
{
8486
$transformer = $this->makeTransformer(AllocationTransformer::class);
8587

88+
$user = $this->request->user();
8689
// While we include this permission, we do need to actually handle it slightly different here
8790
// for the purpose of keeping things functionally working. If the user doesn't have read permissions
8891
// for the allocations we'll only return the primary server allocation, and any notes associated
8992
// with it will be hidden.
9093
//
9194
// This allows us to avoid too much permission regression, without also hiding information that
9295
// is generally needed for the frontend to make sense when browsing or searching results.
93-
if (!$this->getUser()->can(Permission::ACTION_ALLOCATION_READ, $server)) {
96+
if (!$user->can(Permission::ACTION_ALLOCATION_READ, $server)) {
9497
$primary = clone $server->allocation;
9598
$primary->notes = null;
9699

@@ -107,7 +110,7 @@ public function includeAllocations(Server $server)
107110
*/
108111
public function includeVariables(Server $server)
109112
{
110-
if (!$this->getUser()->can(Permission::ACTION_STARTUP_READ, $server)) {
113+
if (!$this->request->user()->can(Permission::ACTION_STARTUP_READ, $server)) {
111114
return $this->null();
112115
}
113116

@@ -139,7 +142,7 @@ public function includeEgg(Server $server)
139142
*/
140143
public function includeSubusers(Server $server)
141144
{
142-
if (!$this->getUser()->can(Permission::ACTION_USER_READ, $server)) {
145+
if (!$this->request->user()->can(Permission::ACTION_USER_READ, $server)) {
143146
return $this->null();
144147
}
145148

tests/Integration/Api/Application/ApplicationApiIntegrationTestCase.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Pterodactyl\Tests\Integration\Api\Application;
44

55
use Pterodactyl\Models\User;
6+
use Illuminate\Http\Request;
67
use PHPUnit\Framework\Assert;
78
use Pterodactyl\Models\ApiKey;
89
use Pterodactyl\Services\Acl\Api\AdminAcl;
@@ -110,9 +111,12 @@ protected function createApiKey(User $user, array $permissions = []): ApiKey
110111
*/
111112
protected function getTransformer(string $abstract): BaseTransformer
112113
{
113-
/** @var \Pterodactyl\Transformers\Api\Application\BaseTransformer $transformer */
114-
$transformer = $this->app->make($abstract);
115-
$transformer->setKey($this->getApiKey());
114+
$request = Request::createFromGlobals();
115+
$request->setUserResolver(function () {
116+
return $this->getApiKey()->user;
117+
});
118+
119+
$transformer = $abstract::fromRequest($request);
116120

117121
Assert::assertInstanceOf(BaseTransformer::class, $transformer);
118122
Assert::assertNotInstanceOf(BaseClientTransformer::class, $transformer);

0 commit comments

Comments
 (0)