Skip to content

Commit b1f6058

Browse files
committed
Fix daemon key provider service
Handles missing keys if user is an admin or the server owner. Step in the right direction for pterodactyl#733 where all users have their own keys now. Still need to address admin status revocation in order to fully address that issue.
1 parent 88562b5 commit b1f6058

File tree

8 files changed

+155
-49
lines changed

8 files changed

+155
-49
lines changed

app/Contracts/Repository/DaemonKeyRepositoryInterface.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,24 @@
2424

2525
namespace Pterodactyl\Contracts\Repository;
2626

27+
use Pterodactyl\Models\DaemonKey;
28+
2729
interface DaemonKeyRepositoryInterface extends RepositoryInterface
2830
{
2931
/**
3032
* String prepended to keys to identify that they are managed internally and not part of the user API.
3133
*/
3234
const INTERNAL_KEY_IDENTIFIER = 'i_';
3335

36+
/**
37+
* Load the server and user relations onto a key model.
38+
*
39+
* @param \Pterodactyl\Models\DaemonKey $key
40+
* @param bool $refresh
41+
* @return \Pterodactyl\Models\DaemonKey
42+
*/
43+
public function loadServerAndUserRelations(DaemonKey $key, bool $refresh = false): DaemonKey;
44+
3445
/**
3546
* Gets the daemon keys associated with a specific server.
3647
*

app/Contracts/Repository/SubuserRepositoryInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function getWithPermissions(Subuser $subuser, bool $refresh = false): Sub
3333
*
3434
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
3535
*/
36-
public function getWithPermissionsUsingUserAndServer($user, $server);
36+
public function getWithPermissionsUsingUserAndServer(int $user, int $server): Subuser;
3737

3838
/**
3939
* Find a subuser and return with server and permissions relationships.

app/Repositories/Eloquent/DaemonKeyRepository.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,26 @@ public function model()
3939
return DaemonKey::class;
4040
}
4141

42+
/**
43+
* Load the server and user relations onto a key model.
44+
*
45+
* @param \Pterodactyl\Models\DaemonKey $key
46+
* @param bool $refresh
47+
* @return \Pterodactyl\Models\DaemonKey
48+
*/
49+
public function loadServerAndUserRelations(DaemonKey $key, bool $refresh = false): DaemonKey
50+
{
51+
if (! $key->relationLoaded('server') || $refresh) {
52+
$key->load('server');
53+
}
54+
55+
if (! $key->relationLoaded('user') || $refresh) {
56+
$key->load('user');
57+
}
58+
59+
return $key;
60+
}
61+
4262
/**
4363
* {@inheritdoc}
4464
*/

app/Repositories/Eloquent/SubuserRepository.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,16 @@ public function getWithPermissions(Subuser $subuser, bool $refresh = false): Sub
6565
}
6666

6767
/**
68-
* {@inheritdoc}
68+
* Return a subuser and associated permissions given a user_id and server_id.
69+
*
70+
* @param int $user
71+
* @param int $server
72+
* @return \Pterodactyl\Models\Subuser
73+
*
74+
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
6975
*/
70-
public function getWithPermissionsUsingUserAndServer($user, $server)
76+
public function getWithPermissionsUsingUserAndServer(int $user, int $server): Subuser
7177
{
72-
Assert::integerish($user, 'First argument passed to getWithPermissionsUsingUserAndServer must be integer, received %s.');
73-
Assert::integerish($server, 'Second argument passed to getWithPermissionsUsingUserAndServer must be integer, received %s.');
74-
7578
$instance = $this->getBuilder()->with('permissions')->where([
7679
['user_id', '=', $user],
7780
['server_id', '=', $server],

app/Services/DaemonKeys/DaemonKeyCreationService.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
namespace Pterodactyl\Services\DaemonKeys;
2626

2727
use Carbon\Carbon;
28-
use Webmozart\Assert\Assert;
2928
use Illuminate\Contracts\Config\Repository as ConfigRepository;
3029
use Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface;
3130

@@ -72,11 +71,8 @@ public function __construct(
7271
*
7372
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
7473
*/
75-
public function handle($server, $user)
74+
public function handle(int $server, int $user)
7675
{
77-
Assert::integerish($server, 'First argument passed to handle must be an integer, received %s.');
78-
Assert::integerish($user, 'Second argument passed to handle must be an integer, received %s.');
79-
8076
$secret = DaemonKeyRepositoryInterface::INTERNAL_KEY_IDENTIFIER . str_random(40);
8177

8278
$this->repository->withoutFresh()->create([

app/Services/DaemonKeys/DaemonKeyProviderService.php

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,16 @@
2727
use Carbon\Carbon;
2828
use Pterodactyl\Models\User;
2929
use Pterodactyl\Models\Server;
30+
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
3031
use Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface;
3132

3233
class DaemonKeyProviderService
3334
{
35+
/**
36+
* @var \Pterodactyl\Services\DaemonKeys\DaemonKeyCreationService
37+
*/
38+
private $keyCreationService;
39+
3440
/**
3541
* @var \Pterodactyl\Services\DaemonKeys\DaemonKeyUpdateService
3642
*/
@@ -44,11 +50,16 @@ class DaemonKeyProviderService
4450
/**
4551
* GetDaemonKeyService constructor.
4652
*
47-
* @param \Pterodactyl\Services\DaemonKeys\DaemonKeyUpdateService $keyUpdateService
53+
* @param \Pterodactyl\Services\DaemonKeys\DaemonKeyCreationService $keyCreationService
4854
* @param \Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface $repository
55+
* @param \Pterodactyl\Services\DaemonKeys\DaemonKeyUpdateService $keyUpdateService
4956
*/
50-
public function __construct(DaemonKeyUpdateService $keyUpdateService, DaemonKeyRepositoryInterface $repository)
51-
{
57+
public function __construct(
58+
DaemonKeyCreationService $keyCreationService,
59+
DaemonKeyRepositoryInterface $repository,
60+
DaemonKeyUpdateService $keyUpdateService
61+
) {
62+
$this->keyCreationService = $keyCreationService;
5263
$this->keyUpdateService = $keyUpdateService;
5364
$this->repository = $repository;
5465
}
@@ -66,12 +77,23 @@ public function __construct(DaemonKeyUpdateService $keyUpdateService, DaemonKeyR
6677
*/
6778
public function handle(Server $server, User $user, $updateIfExpired = true): string
6879
{
69-
$userId = $user->root_admin ? $server->owner_id : $user->id;
80+
try {
81+
$key = $this->repository->findFirstWhere([
82+
['user_id', '=', $user->id],
83+
['server_id', '=', $server->id],
84+
]);
85+
} catch (RecordNotFoundException $exception) {
86+
// If key doesn't exist but we are an admin or the server owner,
87+
// create it.
88+
if ($user->root_admin || $user->id === $server->owner_id) {
89+
return $this->keyCreationService->handle($server->id, $user->id);
90+
}
7091

71-
$key = $this->repository->findFirstWhere([
72-
['user_id', '=', $userId],
73-
['server_id', '=', $server->id],
74-
]);
92+
// If they aren't the admin or owner of the server, they shouldn't get access.
93+
// Subusers should always have an entry created when they are, so if there is
94+
// no record, it should fail.
95+
throw $exception;
96+
}
7597

7698
if (! $updateIfExpired || Carbon::now()->diffInSeconds($key->expires_at, false) > 0) {
7799
return $key->secret;

app/Transformers/Daemon/ApiKeyTransformer.php

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,29 +29,30 @@
2929
use Pterodactyl\Models\Permission;
3030
use League\Fractal\TransformerAbstract;
3131
use Pterodactyl\Contracts\Repository\SubuserRepositoryInterface;
32+
use Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface;
3233

3334
class ApiKeyTransformer extends TransformerAbstract
3435
{
3536
/**
36-
* @var \Carbon\Carbon
37+
* @var \Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface
3738
*/
38-
protected $carbon;
39+
private $keyRepository;
3940

4041
/**
4142
* @var \Pterodactyl\Contracts\Repository\SubuserRepositoryInterface
4243
*/
43-
protected $repository;
44+
private $repository;
4445

4546
/**
4647
* ApiKeyTransformer constructor.
4748
*
48-
* @param \Carbon\Carbon $carbon
49-
* @param \Pterodactyl\Contracts\Repository\SubuserRepositoryInterface $repository
49+
* @param \Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface $keyRepository
50+
* @param \Pterodactyl\Contracts\Repository\SubuserRepositoryInterface $repository
5051
*/
51-
public function __construct(Carbon $carbon, SubuserRepositoryInterface $repository)
52+
public function __construct(DaemonKeyRepositoryInterface $keyRepository, SubuserRepositoryInterface $repository)
5253
{
53-
$this->carbon = $carbon;
5454
$this->repository = $repository;
55+
$this->keyRepository = $keyRepository;
5556
}
5657

5758
/**
@@ -64,18 +65,20 @@ public function __construct(Carbon $carbon, SubuserRepositoryInterface $reposito
6465
*/
6566
public function transform(DaemonKey $key)
6667
{
67-
if ($key->user_id === $key->server->owner_id) {
68+
$this->keyRepository->loadServerAndUserRelations($key);
69+
70+
if ($key->user_id === $key->getRelation('server')->owner_id || $key->getRelation('user')->root_admin) {
6871
return [
69-
'id' => $key->server->uuid,
72+
'id' => $key->getRelation('server')->uuid,
7073
'is_temporary' => true,
71-
'expires_in' => max($this->carbon->now()->diffInSeconds($key->expires_at, false), 0),
74+
'expires_in' => max(Carbon::now()->diffInSeconds($key->expires_at, false), 0),
7275
'permissions' => ['s:*'],
7376
];
7477
}
7578

7679
$subuser = $this->repository->getWithPermissionsUsingUserAndServer($key->user_id, $key->server_id);
7780

78-
$permissions = $subuser->permissions->pluck('permission')->toArray();
81+
$permissions = $subuser->getRelation('permissions')->pluck('permission')->toArray();
7982
$mappings = Permission::getPermissions(true);
8083
$daemonPermissions = [];
8184

@@ -86,9 +89,9 @@ public function transform(DaemonKey $key)
8689
}
8790

8891
return [
89-
'id' => $key->server->uuid,
92+
'id' => $key->getRelation('server')->uuid,
9093
'is_temporary' => true,
91-
'expires_in' => max($this->carbon->now()->diffInSeconds($key->expires_at, false), 0),
94+
'expires_in' => max(Carbon::now()->diffInSeconds($key->expires_at, false), 0),
9295
'permissions' => $daemonPermissions,
9396
];
9497
}

0 commit comments

Comments
 (0)