Skip to content

Commit a31e587

Browse files
committed
First round of changes to API to support simpler permissions.
1 parent 0e24c66 commit a31e587

File tree

21 files changed

+403
-169
lines changed

21 files changed

+403
-169
lines changed

app/Contracts/Repository/ApiKeyRepositoryInterface.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ interface ApiKeyRepositoryInterface extends RepositoryInterface
1818
*
1919
* @param \Pterodactyl\Models\APIKey $model
2020
* @param bool $refresh
21+
* @deprecated
2122
* @return \Pterodactyl\Models\APIKey
2223
*/
2324
public function loadPermissions(APIKey $model, bool $refresh = false): APIKey;

app/Http/Controllers/API/Admin/Users/UserController.php

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
use Pterodactyl\Transformers\Api\Admin\UserTransformer;
1616
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
1717
use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
18+
use Pterodactyl\Http\Requests\API\Admin\Users\GetUserRequest;
19+
use Pterodactyl\Http\Requests\API\Admin\Users\GetUsersRequest;
1820

1921
class UserController extends Controller
2022
{
@@ -67,19 +69,19 @@ public function __construct(
6769
}
6870

6971
/**
70-
* Handle request to list all users on the panel. Returns a JSONAPI representation
72+
* Handle request to list all users on the panel. Returns a JSON-API representation
7173
* of a collection of users including any defined relations passed in
7274
* the request.
7375
*
74-
* @param \Illuminate\Http\Request $request
76+
* @param \Pterodactyl\Http\Requests\API\Admin\Users\GetUsersRequest $request
7577
* @return array
7678
*/
77-
public function index(Request $request): array
79+
public function index(GetUsersRequest $request): array
7880
{
7981
$users = $this->repository->paginated(100);
8082

8183
return $this->fractal->collection($users)
82-
->transformWith(new UserTransformer($request))
84+
->transformWith((new UserTransformer)->setKey($request->key()))
8385
->withResourceName('user')
8486
->paginateWith(new IlluminatePaginatorAdapter($users))
8587
->toArray();
@@ -89,14 +91,14 @@ public function index(Request $request): array
8991
* Handle a request to view a single user. Includes any relations that
9092
* were defined in the request.
9193
*
92-
* @param \Illuminate\Http\Request $request
93-
* @param \Pterodactyl\Models\User $user
94+
* @param \Pterodactyl\Http\Requests\API\Admin\Users\GetUserRequest $request
95+
* @param \Pterodactyl\Models\User $user
9496
* @return array
9597
*/
96-
public function view(Request $request, User $user): array
98+
public function view(GetUserRequest $request, User $user): array
9799
{
98100
return $this->fractal->item($user)
99-
->transformWith(new UserTransformer($request))
101+
->transformWith((new UserTransformer)->setKey($request->key()))
100102
->withResourceName('user')
101103
->toArray();
102104
}

app/Http/Kernel.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
use Pterodactyl\Http\Middleware\Daemon\DaemonAuthenticate;
2626
use Illuminate\Foundation\Http\Middleware\ValidatePostSize;
2727
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
28-
use Pterodactyl\Http\Middleware\API\HasPermissionToResource;
2928
use Pterodactyl\Http\Middleware\Server\AuthenticateAsSubuser;
3029
use Pterodactyl\Http\Middleware\Server\SubuserBelongsToServer;
3130
use Pterodactyl\Http\Middleware\RequireTwoFactorAuthentication;
@@ -98,9 +97,6 @@ class Kernel extends HttpKernel
9897
'bindings' => SubstituteBindings::class,
9998
'recaptcha' => VerifyReCaptcha::class,
10099

101-
// API specific middleware.
102-
'api..user_level' => HasPermissionToResource::class,
103-
104100
// Server specific middleware (used for authenticating access to resources)
105101
//
106102
// These are only used for individual server authentication, and not gloabl

app/Http/Middleware/API/HasPermissionToResource.php

Lines changed: 0 additions & 58 deletions
This file was deleted.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Requests\API\Admin;
4+
5+
use Pterodactyl\Models\APIKey;
6+
use Illuminate\Foundation\Http\FormRequest;
7+
use Pterodactyl\Exceptions\PterodactylException;
8+
use Pterodactyl\Services\Acl\Api\AdminAcl as Acl;
9+
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
10+
11+
abstract class ApiAdminRequest extends FormRequest
12+
{
13+
/**
14+
* The resource that should be checked when performing the authorization
15+
* function for this request.
16+
*
17+
* @var string|null
18+
*/
19+
protected $resource;
20+
21+
/**
22+
* The permission level that a given API key should have for accessing
23+
* the defined $resource during the request cycle.
24+
*
25+
* @var int
26+
*/
27+
protected $permission = Acl::NONE;
28+
29+
/**
30+
* Determine if the current user is authorized to perform
31+
* the requested action aganist the API.
32+
*
33+
* @return bool
34+
*
35+
* @throws \Pterodactyl\Exceptions\PterodactylException
36+
*/
37+
public function authorize(): bool
38+
{
39+
if (is_null($this->resource)) {
40+
throw new PterodactylException('An ACL resource must be defined on API requests.');
41+
}
42+
43+
return Acl::check($this->key(), $this->resource, $this->permission);
44+
}
45+
46+
/**
47+
* Determine if the requested resource exists on the server.
48+
*
49+
* @return bool
50+
*/
51+
public function resourceExists(): bool
52+
{
53+
return true;
54+
}
55+
56+
/**
57+
* Default set of rules to apply to API requests.
58+
*
59+
* @return array
60+
*/
61+
public function rules(): array
62+
{
63+
return [];
64+
}
65+
66+
/**
67+
* Return the API key being used for the request.
68+
*
69+
* @return \Pterodactyl\Models\APIKey
70+
*/
71+
public function key(): APIKey
72+
{
73+
return $this->attributes->get('api_key');
74+
}
75+
76+
/**
77+
* Determine if the request passes the authorization check as well
78+
* as the exists check.
79+
*
80+
* @return bool
81+
*
82+
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
83+
*/
84+
protected function passesAuthorization()
85+
{
86+
$passes = parent::passesAuthorization();
87+
88+
// Only let the user know that a resource does not exist if they are
89+
// authenticated to access the endpoint. This avoids exposing that
90+
// an item exists (or does not exist) to the user until they can prove
91+
// that they have permission to know about it.
92+
if ($passes && ! $this->resourceExists()) {
93+
throw new NotFoundHttpException('The requested resource does not exist on this server.');
94+
}
95+
96+
return $passes;
97+
}
98+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Requests\API\Admin\Users;
4+
5+
use Pterodactyl\Models\User;
6+
use Pterodactyl\Services\Acl\Api\AdminAcl;
7+
use Pterodactyl\Http\Requests\API\Admin\ApiAdminRequest;
8+
9+
class GetUserRequest extends ApiAdminRequest
10+
{
11+
/**
12+
* @var string
13+
*/
14+
protected $resource = AdminAcl::RESOURCE_USERS;
15+
16+
/**
17+
* @var int
18+
*/
19+
protected $permission = AdminAcl::READ;
20+
21+
/**
22+
* Determine if the requested user exists on the Panel.
23+
*
24+
* @return bool
25+
*/
26+
public function resourceExists(): bool
27+
{
28+
$user = $this->route()->parameter('user');
29+
30+
return $user instanceof User && $user->exists;
31+
}
32+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Requests\API\Admin\Users;
4+
5+
use Pterodactyl\Services\Acl\Api\AdminAcl as Acl;
6+
use Pterodactyl\Http\Requests\API\Admin\ApiAdminRequest;
7+
8+
class GetUsersRequest extends ApiAdminRequest
9+
{
10+
/**
11+
* @var string
12+
*/
13+
protected $resource = Acl::RESOURCE_USERS;
14+
15+
/**
16+
* @var int
17+
*/
18+
protected $permission = Acl::READ;
19+
}

app/Http/Requests/API/Remote/SftpAuthenticationFormRequest.php

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

33
namespace Pterodactyl\Http\Requests\API\Remote;
44

5-
use Pterodactyl\Http\Requests\Request;
5+
use Illuminate\Foundation\Http\FormRequest;
66

7-
class SftpAuthenticationFormRequest extends Request
7+
class SftpAuthenticationFormRequest extends FormRequest
88
{
99
/**
1010
* Authenticate the request.

app/Http/Requests/Request.php

Lines changed: 0 additions & 9 deletions
This file was deleted.

app/Models/APIKey.php

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
<?php
2-
/**
3-
* Pterodactyl - Panel
4-
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
5-
*
6-
* This software is licensed under the terms of the MIT license.
7-
* https://opensource.org/licenses/MIT
8-
*/
92

103
namespace Pterodactyl\Models;
114

125
use Sofa\Eloquence\Eloquence;
136
use Sofa\Eloquence\Validable;
147
use Illuminate\Database\Eloquent\Model;
8+
use Pterodactyl\Services\Acl\Api\AdminAcl;
159
use Sofa\Eloquence\Contracts\CleansAttributes;
1610
use Sofa\Eloquence\Contracts\Validable as ValidableContract;
1711

@@ -35,14 +29,29 @@ class APIKey extends Model implements CleansAttributes, ValidableContract
3529
*/
3630
protected $casts = [
3731
'allowed_ips' => 'json',
32+
'user_id' => 'int',
33+
'r_' . AdminAcl::RESOURCE_USERS => 'int',
34+
'r_' . AdminAcl::RESOURCE_ALLOCATIONS => 'int',
35+
'r_' . AdminAcl::RESOURCE_DATABASES => 'int',
36+
'r_' . AdminAcl::RESOURCE_EGGS => 'int',
37+
'r_' . AdminAcl::RESOURCE_LOCATIONS => 'int',
38+
'r_' . AdminAcl::RESOURCE_NESTS => 'int',
39+
'r_' . AdminAcl::RESOURCE_NODES => 'int',
40+
'r_' . AdminAcl::RESOURCE_PACKS => 'int',
41+
'r_' . AdminAcl::RESOURCE_SERVERS => 'int',
3842
];
3943

4044
/**
41-
* Fields that are not mass assignable.
45+
* Fields that are mass assignable.
4246
*
4347
* @var array
4448
*/
45-
protected $guarded = ['id', 'created_at', 'updated_at'];
49+
protected $fillable = [
50+
'token',
51+
'allowed_ips',
52+
'memo',
53+
'expires_at',
54+
];
4655

4756
/**
4857
* Rules defining what fields must be passed when making a model.
@@ -66,6 +75,24 @@ class APIKey extends Model implements CleansAttributes, ValidableContract
6675
'memo' => 'nullable|string|max:500',
6776
'allowed_ips' => 'nullable|json',
6877
'expires_at' => 'nullable|datetime',
78+
'r_' . AdminAcl::RESOURCE_USERS => 'integer|min:0|max:3',
79+
'r_' . AdminAcl::RESOURCE_ALLOCATIONS => 'integer|min:0|max:3',
80+
'r_' . AdminAcl::RESOURCE_DATABASES => 'integer|min:0|max:3',
81+
'r_' . AdminAcl::RESOURCE_EGGS => 'integer|min:0|max:3',
82+
'r_' . AdminAcl::RESOURCE_LOCATIONS => 'integer|min:0|max:3',
83+
'r_' . AdminAcl::RESOURCE_NESTS => 'integer|min:0|max:3',
84+
'r_' . AdminAcl::RESOURCE_NODES => 'integer|min:0|max:3',
85+
'r_' . AdminAcl::RESOURCE_PACKS => 'integer|min:0|max:3',
86+
'r_' . AdminAcl::RESOURCE_SERVERS => 'integer|min:0|max:3',
87+
];
88+
89+
/**
90+
* @var array
91+
*/
92+
protected $dates = [
93+
self::CREATED_AT,
94+
self::UPDATED_AT,
95+
'expires_at',
6996
];
7097

7198
/**

0 commit comments

Comments
 (0)