diff --git a/app/Contracts/Repository/ServerRepositoryInterface.php b/app/Contracts/Repository/ServerRepositoryInterface.php index 9e597bb73..c1862b953 100644 --- a/app/Contracts/Repository/ServerRepositoryInterface.php +++ b/app/Contracts/Repository/ServerRepositoryInterface.php @@ -118,7 +118,7 @@ interface ServerRepositoryInterface extends RepositoryInterface, SearchableInter * Return a server by UUID. * * @param string $uuid - * @return \Illuminate\Database\Eloquent\Collection + * @return \Pterodactyl\Models\Server * * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ diff --git a/app/Contracts/Repository/SubuserRepositoryInterface.php b/app/Contracts/Repository/SubuserRepositoryInterface.php index a740bad9c..8d913a259 100644 --- a/app/Contracts/Repository/SubuserRepositoryInterface.php +++ b/app/Contracts/Repository/SubuserRepositoryInterface.php @@ -13,7 +13,7 @@ interface SubuserRepositoryInterface extends RepositoryInterface * @param bool $refresh * @return \Pterodactyl\Models\Subuser */ - public function getWithServer(Subuser $subuser, bool $refresh = false): Subuser; + public function loadServerAndUserRelations(Subuser $subuser, bool $refresh = false): Subuser; /** * Return a subuser with the associated permissions relationship. diff --git a/app/Http/Controllers/Base/IndexController.php b/app/Http/Controllers/Base/IndexController.php index 03e7fbb5b..8e16f8605 100644 --- a/app/Http/Controllers/Base/IndexController.php +++ b/app/Http/Controllers/Base/IndexController.php @@ -93,7 +93,7 @@ class IndexController extends Controller public function status(Request $request, $uuid) { $server = $this->repository->findFirstWhere([['uuidShort', '=', $uuid]]); - $token = $this->keyProviderService->handle($server->id, $request->user()->id); + $token = $this->keyProviderService->handle($server, $request->user()); if (! $server->installed) { return response()->json(['status' => 20]); diff --git a/app/Http/Middleware/AdminAuthenticate.php b/app/Http/Middleware/AdminAuthenticate.php index 7c47ed0c1..c9b51bdc2 100644 --- a/app/Http/Middleware/AdminAuthenticate.php +++ b/app/Http/Middleware/AdminAuthenticate.php @@ -11,7 +11,7 @@ namespace Pterodactyl\Http\Middleware; use Closure; use Illuminate\Http\Request; -use Symfony\Component\HttpKernel\Exception\HttpException; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; class AdminAuthenticate { @@ -25,7 +25,7 @@ class AdminAuthenticate public function handle(Request $request, Closure $next) { if (! $request->user() || ! $request->user()->root_admin) { - throw new HttpException(403, 'Access Denied'); + throw new AccessDeniedHttpException; } return $next($request); diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php index 473ad5064..d85cf95bf 100644 --- a/app/Http/Middleware/Authenticate.php +++ b/app/Http/Middleware/Authenticate.php @@ -20,11 +20,7 @@ class Authenticate public function handle(Request $request, Closure $next) { if (! $request->user()) { - if ($request->ajax() || $request->expectsJson()) { - throw new AuthenticationException(); - } else { - return redirect()->route('auth.login'); - } + throw new AuthenticationException; } return $next($request); diff --git a/app/Http/Middleware/Daemon/DaemonAuthenticate.php b/app/Http/Middleware/Daemon/DaemonAuthenticate.php index d06711af9..f9d8a8bc9 100644 --- a/app/Http/Middleware/Daemon/DaemonAuthenticate.php +++ b/app/Http/Middleware/Daemon/DaemonAuthenticate.php @@ -29,6 +29,7 @@ use Illuminate\Http\Request; use Symfony\Component\HttpKernel\Exception\HttpException; use Pterodactyl\Contracts\Repository\NodeRepositoryInterface; use Pterodactyl\Exceptions\Repository\RecordNotFoundException; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; class DaemonAuthenticate { @@ -80,7 +81,7 @@ class DaemonAuthenticate try { $node = $this->repository->findFirstWhere([['daemonSecret', '=', $token]]); } catch (RecordNotFoundException $exception) { - throw new HttpException(403); + throw new AccessDeniedHttpException; } $request->attributes->set('node', $node); diff --git a/app/Http/Middleware/Server/AuthenticateAsSubuser.php b/app/Http/Middleware/Server/AuthenticateAsSubuser.php index 47f2bc885..8ec07d94d 100644 --- a/app/Http/Middleware/Server/AuthenticateAsSubuser.php +++ b/app/Http/Middleware/Server/AuthenticateAsSubuser.php @@ -12,9 +12,9 @@ namespace Pterodactyl\Http\Middleware\Server; use Closure; use Illuminate\Http\Request; use Illuminate\Contracts\Session\Session; -use Illuminate\Auth\AuthenticationException; use Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService; use Pterodactyl\Exceptions\Repository\RecordNotFoundException; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; class AuthenticateAsSubuser { @@ -56,9 +56,9 @@ class AuthenticateAsSubuser $server = $request->attributes->get('server'); try { - $token = $this->keyProviderService->handle($server->id, $request->user()->id); + $token = $this->keyProviderService->handle($server, $request->user()); } catch (RecordNotFoundException $exception) { - throw new AuthenticationException('This account does not have permission to access this server.'); + throw new AccessDeniedHttpException('This account does not have permission to access this server.'); } $this->session->now('server_data.token', $token); diff --git a/app/Jobs/Schedule/RunTaskJob.php b/app/Jobs/Schedule/RunTaskJob.php index 3f1b5195f..88590883a 100644 --- a/app/Jobs/Schedule/RunTaskJob.php +++ b/app/Jobs/Schedule/RunTaskJob.php @@ -92,20 +92,21 @@ class RunTaskJob extends Job implements ShouldQueue $this->taskRepository = $taskRepository; $task = $this->taskRepository->getTaskWithServer($this->task); - $server = $task->server; + $server = $task->getRelation('server'); + $user = $server->getRelation('user'); // Perform the provided task aganist the daemon. switch ($task->action) { case 'power': $this->powerRepository->setNode($server->node_id) ->setAccessServer($server->uuid) - ->setAccessToken($keyProviderService->handle($server->id, $server->owner_id)) + ->setAccessToken($keyProviderService->handle($server, $user)) ->sendSignal($task->payload); break; case 'command': $this->commandRepository->setNode($server->node_id) ->setAccessServer($server->uuid) - ->setAccessToken($keyProviderService->handle($server->id, $server->owner_id)) + ->setAccessToken($keyProviderService->handle($server, $user)) ->send($task->payload); break; default: diff --git a/app/Repositories/Eloquent/SubuserRepository.php b/app/Repositories/Eloquent/SubuserRepository.php index 863479934..1b89db8e8 100644 --- a/app/Repositories/Eloquent/SubuserRepository.php +++ b/app/Repositories/Eloquent/SubuserRepository.php @@ -31,12 +31,16 @@ class SubuserRepository extends EloquentRepository implements SubuserRepositoryI * @param bool $refresh * @return \Pterodactyl\Models\Subuser */ - public function getWithServer(Subuser $subuser, bool $refresh = false): Subuser + public function loadServerAndUserRelations(Subuser $subuser, bool $refresh = false): Subuser { if (! $subuser->relationLoaded('server') || $refresh) { $subuser->load('server'); } + if (! $subuser->relationLoaded('user') || $refresh) { + $subuser->load('user'); + } + return $subuser; } diff --git a/app/Repositories/Eloquent/TaskRepository.php b/app/Repositories/Eloquent/TaskRepository.php index 49e23dcc5..c44aa2fc6 100644 --- a/app/Repositories/Eloquent/TaskRepository.php +++ b/app/Repositories/Eloquent/TaskRepository.php @@ -31,7 +31,7 @@ class TaskRepository extends EloquentRepository implements TaskRepositoryInterfa { Assert::integerish($id, 'First argument passed to getTaskWithServer must be numeric, received %s.'); - $instance = $this->getBuilder()->with('server')->find($id, $this->getColumns()); + $instance = $this->getBuilder()->with('server.user')->find($id, $this->getColumns()); if (! $instance) { throw new RecordNotFoundException; } diff --git a/app/Services/DaemonKeys/DaemonKeyProviderService.php b/app/Services/DaemonKeys/DaemonKeyProviderService.php index a0da5c42e..2d4ae2b2f 100644 --- a/app/Services/DaemonKeys/DaemonKeyProviderService.php +++ b/app/Services/DaemonKeys/DaemonKeyProviderService.php @@ -25,39 +25,30 @@ namespace Pterodactyl\Services\DaemonKeys; use Carbon\Carbon; -use Webmozart\Assert\Assert; +use Pterodactyl\Models\User; +use Pterodactyl\Models\Server; use Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface; class DaemonKeyProviderService { - /** - * @var \Carbon\Carbon - */ - protected $carbon; - /** * @var \Pterodactyl\Services\DaemonKeys\DaemonKeyUpdateService */ - protected $keyUpdateService; + private $keyUpdateService; /** * @var \Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface */ - protected $repository; + private $repository; /** * GetDaemonKeyService constructor. * - * @param \Carbon\Carbon $carbon * @param \Pterodactyl\Services\DaemonKeys\DaemonKeyUpdateService $keyUpdateService * @param \Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface $repository */ - public function __construct( - Carbon $carbon, - DaemonKeyUpdateService $keyUpdateService, - DaemonKeyRepositoryInterface $repository - ) { - $this->carbon = $carbon; + public function __construct(DaemonKeyUpdateService $keyUpdateService, DaemonKeyRepositoryInterface $repository) + { $this->keyUpdateService = $keyUpdateService; $this->repository = $repository; } @@ -65,25 +56,24 @@ class DaemonKeyProviderService /** * Get the access key for a user on a specific server. * - * @param int $server - * @param int $user - * @param bool $updateIfExpired + * @param \Pterodactyl\Models\Server $server + * @param \Pterodactyl\Models\User $user + * @param bool $updateIfExpired * @return string * * @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ - public function handle($server, $user, $updateIfExpired = true) + public function handle(Server $server, User $user, $updateIfExpired = true): string { - Assert::integerish($server, 'First argument passed to handle must be an integer, received %s.'); - Assert::integerish($user, 'Second argument passed to handle must be an integer, received %s.'); + $userId = $user->root_admin ? $server->owner_id : $user->id; $key = $this->repository->findFirstWhere([ - ['user_id', '=', $user], - ['server_id', '=', $server], + ['user_id', '=', $userId], + ['server_id', '=', $server->id], ]); - if (! $updateIfExpired || $this->carbon->now()->diffInSeconds($key->expires_at, false) > 0) { + if (! $updateIfExpired || Carbon::now()->diffInSeconds($key->expires_at, false) > 0) { return $key->secret; } diff --git a/app/Services/Sftp/AuthenticateUsingPasswordService.php b/app/Services/Sftp/AuthenticateUsingPasswordService.php index 487d251d4..16ac56b67 100644 --- a/app/Services/Sftp/AuthenticateUsingPasswordService.php +++ b/app/Services/Sftp/AuthenticateUsingPasswordService.php @@ -84,7 +84,7 @@ class AuthenticateUsingPasswordService return [ 'server' => $server->uuid, - 'token' => $this->keyProviderService->handle($server->id, $user->id), + 'token' => $this->keyProviderService->handle($server, $user), ]; } } diff --git a/app/Services/Subusers/SubuserUpdateService.php b/app/Services/Subusers/SubuserUpdateService.php index f4cd2c1a7..9cf02e4b4 100644 --- a/app/Services/Subusers/SubuserUpdateService.php +++ b/app/Services/Subusers/SubuserUpdateService.php @@ -88,14 +88,14 @@ class SubuserUpdateService */ public function handle(Subuser $subuser, array $permissions) { - $subuser = $this->repository->getWithServer($subuser); + $subuser = $this->repository->loadServerAndUserRelations($subuser); $this->connection->beginTransaction(); $this->permissionRepository->deleteWhere([['subuser_id', '=', $subuser->id]]); $this->permissionService->handle($subuser->id, $permissions); try { - $token = $this->keyProviderService->handle($subuser->server_id, $subuser->user_id, false); + $token = $this->keyProviderService->handle($subuser->getRelation('server'), $subuser->getRelation('user'), false); $this->daemonRepository->setNode($subuser->getRelation('server')->node_id)->revokeAccessKey($token); } catch (RequestException $exception) { $this->connection->rollBack(); diff --git a/tests/Unit/Http/Controllers/Base/IndexControllerTest.php b/tests/Unit/Http/Controllers/Base/IndexControllerTest.php index f3f5b0d90..7245e9662 100644 --- a/tests/Unit/Http/Controllers/Base/IndexControllerTest.php +++ b/tests/Unit/Http/Controllers/Base/IndexControllerTest.php @@ -10,17 +10,16 @@ namespace Tests\Unit\Http\Controllers\Base; use Mockery as m; -use Tests\TestCase; -use Illuminate\Http\Request; use Pterodactyl\Models\User; use Pterodactyl\Models\Server; use Tests\Assertions\ControllerAssertionsTrait; +use Tests\Unit\Http\Controllers\ControllerTestCase; use Pterodactyl\Http\Controllers\Base\IndexController; use Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService; use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; use Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface as DaemonServerRepositoryInterface; -class IndexControllerTest extends TestCase +class IndexControllerTest extends ControllerTestCase { use ControllerAssertionsTrait; @@ -44,11 +43,6 @@ class IndexControllerTest extends TestCase */ protected $repository; - /** - * @var \Illuminate\Http\Request|\Mockery\Mock - */ - protected $request; - /** * Setup tests. */ @@ -59,7 +53,6 @@ class IndexControllerTest extends TestCase $this->daemonRepository = m::mock(DaemonServerRepositoryInterface::class); $this->keyProviderService = m::mock(DaemonKeyProviderService::class); $this->repository = m::mock(ServerRepositoryInterface::class); - $this->request = m::mock(Request::class); $this->controller = new IndexController($this->keyProviderService, $this->daemonRepository, $this->repository); } @@ -69,9 +62,8 @@ class IndexControllerTest extends TestCase */ public function testIndexController() { - $model = factory(User::class)->make(); + $model = $this->setRequestUser(); - $this->request->shouldReceive('user')->withNoArgs()->andReturn($model); $this->request->shouldReceive('input')->with('query')->once()->andReturn('searchTerm'); $this->repository->shouldReceive('search')->with('searchTerm')->once()->andReturnSelf() ->shouldReceive('filterUserAccessServers')->with( @@ -90,12 +82,11 @@ class IndexControllerTest extends TestCase */ public function testStatusController() { - $user = factory(User::class)->make(); + $user = $this->setRequestUser(); $server = factory(Server::class)->make(['suspended' => 0, 'installed' => 1]); - $this->request->shouldReceive('user')->withNoArgs()->once()->andReturn($user); $this->repository->shouldReceive('findFirstWhere')->with([['uuidShort', '=', $server->uuidShort]])->once()->andReturn($server); - $this->keyProviderService->shouldReceive('handle')->with($server->id, $user->id)->once()->andReturn('test123'); + $this->keyProviderService->shouldReceive('handle')->with($server, $user)->once()->andReturn('test123'); $this->daemonRepository->shouldReceive('setNode')->with($server->node_id)->once()->andReturnSelf() ->shouldReceive('setAccessServer')->with($server->uuid)->once()->andReturnSelf() @@ -114,12 +105,11 @@ class IndexControllerTest extends TestCase */ public function testStatusControllerWhenServerNotInstalled() { - $user = factory(User::class)->make(); + $user = $this->setRequestUser(); $server = factory(Server::class)->make(['suspended' => 0, 'installed' => 0]); - $this->request->shouldReceive('user')->withNoArgs()->once()->andReturn($user); $this->repository->shouldReceive('findFirstWhere')->with([['uuidShort', '=', $server->uuidShort]])->once()->andReturn($server); - $this->keyProviderService->shouldReceive('handle')->with($server->id, $user->id)->once()->andReturn('test123'); + $this->keyProviderService->shouldReceive('handle')->with($server, $user)->once()->andReturn('test123'); $response = $this->controller->status($this->request, $server->uuidShort); $this->assertIsJsonResponse($response); @@ -137,7 +127,7 @@ class IndexControllerTest extends TestCase $this->request->shouldReceive('user')->withNoArgs()->once()->andReturn($user); $this->repository->shouldReceive('findFirstWhere')->with([['uuidShort', '=', $server->uuidShort]])->once()->andReturn($server); - $this->keyProviderService->shouldReceive('handle')->with($server->id, $user->id)->once()->andReturn('test123'); + $this->keyProviderService->shouldReceive('handle')->with($server, $user)->once()->andReturn('test123'); $response = $this->controller->status($this->request, $server->uuidShort); $this->assertIsJsonResponse($response); diff --git a/tests/Unit/Http/Middleware/AdminAuthenticateTest.php b/tests/Unit/Http/Middleware/AdminAuthenticateTest.php index 2e1850505..eee9a6969 100644 --- a/tests/Unit/Http/Middleware/AdminAuthenticateTest.php +++ b/tests/Unit/Http/Middleware/AdminAuthenticateTest.php @@ -4,7 +4,6 @@ namespace Tests\Unit\Http\Middleware; use Pterodactyl\Models\User; use Pterodactyl\Http\Middleware\AdminAuthenticate; -use Symfony\Component\HttpKernel\Exception\HttpException; class AdminAuthenticateTest extends MiddlewareTestCase { @@ -22,20 +21,20 @@ class AdminAuthenticateTest extends MiddlewareTestCase /** * Test that a missing user in the request triggers an error. + * + * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException */ public function testExceptionIsThrownIfUserDoesNotExist() { $this->request->shouldReceive('user')->withNoArgs()->once()->andReturnNull(); - try { - $this->getMiddleware()->handle($this->request, $this->getClosureAssertions()); - } catch (HttpException $exception) { - $this->assertEquals(403, $exception->getStatusCode()); - } + $this->getMiddleware()->handle($this->request, $this->getClosureAssertions()); } /** * Test that an exception is thrown if the user is not an admin. + * + * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException */ public function testExceptionIsThrownIfUserIsNotAnAdmin() { @@ -43,11 +42,7 @@ class AdminAuthenticateTest extends MiddlewareTestCase $this->request->shouldReceive('user')->withNoArgs()->twice()->andReturn($user); - try { - $this->getMiddleware()->handle($this->request, $this->getClosureAssertions()); - } catch (HttpException $exception) { - $this->assertEquals(403, $exception->getStatusCode()); - } + $this->getMiddleware()->handle($this->request, $this->getClosureAssertions()); } /** diff --git a/tests/Unit/Http/Middleware/AuthenticateTest.php b/tests/Unit/Http/Middleware/AuthenticateTest.php index 88c5990d5..76c7ebc95 100644 --- a/tests/Unit/Http/Middleware/AuthenticateTest.php +++ b/tests/Unit/Http/Middleware/AuthenticateTest.php @@ -2,7 +2,6 @@ namespace Tests\Unit\Http\Middleware; -use Illuminate\Http\RedirectResponse; use Pterodactyl\Http\Middleware\Authenticate; class AuthenticateTest extends MiddlewareTestCase @@ -18,29 +17,13 @@ class AuthenticateTest extends MiddlewareTestCase } /** - * Test that a logged out user results in a redirect. + * Test that a logged out user results in an exception. + * + * @expectedException \Illuminate\Auth\AuthenticationException */ public function testLoggedOutUser() { $this->request->shouldReceive('user')->withNoArgs()->once()->andReturnNull(); - $this->request->shouldReceive('ajax')->withNoArgs()->once()->andReturn(false); - $this->request->shouldReceive('expectsJson')->withNoArgs()->once()->andReturn(false); - - $response = $this->getMiddleware()->handle($this->request, $this->getClosureAssertions()); - $this->assertInstanceOf(RedirectResponse::class, $response); - $this->assertEquals(302, $response->getStatusCode()); - $this->assertEquals(route('auth.login'), $response->getTargetUrl()); - } - - /** - * Test that a logged out user via an API/Ajax request returns a HTTP error. - * - * @expectedException \Illuminate\Auth\AuthenticationException - */ - public function testLoggedOUtUserApiRequest() - { - $this->request->shouldReceive('user')->withNoArgs()->once()->andReturnNull(); - $this->request->shouldReceive('ajax')->withNoArgs()->once()->andReturn(true); $this->getMiddleware()->handle($this->request, $this->getClosureAssertions()); } diff --git a/tests/Unit/Http/Middleware/Daemon/DaemonAuthenticateTest.php b/tests/Unit/Http/Middleware/Daemon/DaemonAuthenticateTest.php index 140c07286..c0d0826d6 100644 --- a/tests/Unit/Http/Middleware/Daemon/DaemonAuthenticateTest.php +++ b/tests/Unit/Http/Middleware/Daemon/DaemonAuthenticateTest.php @@ -60,6 +60,8 @@ class DaemonAuthenticateTest extends MiddlewareTestCase /** * Test that passing in an invalid node daemon secret will result in a HTTP/403 * error response. + * + * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException */ public function testResponseShouldFailIfNoNodeIsFound() { @@ -68,11 +70,7 @@ class DaemonAuthenticateTest extends MiddlewareTestCase $this->repository->shouldReceive('findFirstWhere')->with([['daemonSecret', '=', 'test1234']])->once()->andThrow(new RecordNotFoundException); - try { - $this->getMiddleware()->handle($this->request, $this->getClosureAssertions()); - } catch (HttpException $exception) { - $this->assertEquals(403, $exception->getStatusCode(), 'Assert that a status code of 403 is returned.'); - } + $this->getMiddleware()->handle($this->request, $this->getClosureAssertions()); } /** diff --git a/tests/Unit/Http/Middleware/Server/AuthenticateAsSubuserTest.php b/tests/Unit/Http/Middleware/Server/AuthenticateAsSubuserTest.php index 9645ddb6b..8ee1a0e4c 100644 --- a/tests/Unit/Http/Middleware/Server/AuthenticateAsSubuserTest.php +++ b/tests/Unit/Http/Middleware/Server/AuthenticateAsSubuserTest.php @@ -42,7 +42,7 @@ class AuthenticateAsSubuserTest extends MiddlewareTestCase $user = $this->setRequestUser(); $this->setRequestAttribute('server', $model); - $this->keyProviderService->shouldReceive('handle')->with($model->id, $user->id)->once()->andReturn('abc123'); + $this->keyProviderService->shouldReceive('handle')->with($model, $user)->once()->andReturn('abc123'); $this->session->shouldReceive('now')->with('server_data.token', 'abc123')->once()->andReturnNull(); $this->getMiddleware()->handle($this->request, $this->getClosureAssertions()); @@ -53,7 +53,7 @@ class AuthenticateAsSubuserTest extends MiddlewareTestCase /** * Test middleware handles missing token exception. * - * @expectedException \Illuminate\Auth\AuthenticationException + * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException * @expectedExceptionMessage This account does not have permission to access this server. */ public function testExceptionIsThrownIfNoTokenIsFound() @@ -62,7 +62,7 @@ class AuthenticateAsSubuserTest extends MiddlewareTestCase $user = $this->setRequestUser(); $this->setRequestAttribute('server', $model); - $this->keyProviderService->shouldReceive('handle')->with($model->id, $user->id)->once()->andThrow(new RecordNotFoundException); + $this->keyProviderService->shouldReceive('handle')->with($model, $user)->once()->andThrow(new RecordNotFoundException); $this->getMiddleware()->handle($this->request, $this->getClosureAssertions()); } diff --git a/tests/Unit/Jobs/Schedule/RunTaskJobTest.php b/tests/Unit/Jobs/Schedule/RunTaskJobTest.php index 9a27c59c1..176eb4d85 100644 --- a/tests/Unit/Jobs/Schedule/RunTaskJobTest.php +++ b/tests/Unit/Jobs/Schedule/RunTaskJobTest.php @@ -13,6 +13,7 @@ use Mockery as m; use Carbon\Carbon; use Tests\TestCase; use Pterodactyl\Models\Task; +use Pterodactyl\Models\User; use Pterodactyl\Models\Server; use Pterodactyl\Models\Schedule; use Illuminate\Support\Facades\Bus; @@ -63,6 +64,7 @@ class RunTaskJobTest extends TestCase { parent::setUp(); Bus::fake(); + Carbon::setTestNow(); $this->commandRepository = m::mock(CommandRepositoryInterface::class); $this->config = m::mock(Repository::class); @@ -81,17 +83,15 @@ class RunTaskJobTest extends TestCase */ public function testPowerAction() { - Carbon::setTestNow(); - $schedule = factory(Schedule::class)->make(); $task = factory(Task::class)->make(['action' => 'power', 'sequence_id' => 1]); - $server = factory(Server::class)->make(); - $task->server = $server; + $task->setRelation('server', $server = factory(Server::class)->make()); + $server->setRelation('user', factory(User::class)->make()); $this->taskRepository->shouldReceive('getTaskWithServer')->with($task->id)->once()->andReturn($task); - $this->keyProviderService->shouldReceive('handle')->with($server->id, $server->owner_id)->once()->andReturn('123456'); - $this->powerRepository->shouldReceive('setNode')->with($server->node_id)->once()->andReturnSelf() - ->shouldReceive('setAccessServer')->with($server->uuid)->once()->andReturnSelf() + $this->keyProviderService->shouldReceive('handle')->with($server, $server->user)->once()->andReturn('123456'); + $this->powerRepository->shouldReceive('setNode')->with($task->server->node_id)->once()->andReturnSelf() + ->shouldReceive('setAccessServer')->with($task->server->uuid)->once()->andReturnSelf() ->shouldReceive('setAccessToken')->with('123456')->once()->andReturnSelf() ->shouldReceive('sendSignal')->with($task->payload)->once()->andReturnNull(); @@ -113,17 +113,15 @@ class RunTaskJobTest extends TestCase */ public function testCommandAction() { - Carbon::setTestNow(); - $schedule = factory(Schedule::class)->make(); $task = factory(Task::class)->make(['action' => 'command', 'sequence_id' => 1]); - $server = factory(Server::class)->make(); - $task->server = $server; + $task->setRelation('server', $server = factory(Server::class)->make()); + $server->setRelation('user', factory(User::class)->make()); $this->taskRepository->shouldReceive('getTaskWithServer')->with($task->id)->once()->andReturn($task); - $this->keyProviderService->shouldReceive('handle')->with($server->id, $server->owner_id)->once()->andReturn('123456'); - $this->commandRepository->shouldReceive('setNode')->with($server->node_id)->once()->andReturnSelf() - ->shouldReceive('setAccessServer')->with($server->uuid)->once()->andReturnSelf() + $this->keyProviderService->shouldReceive('handle')->with($server, $server->user)->once()->andReturn('123456'); + $this->commandRepository->shouldReceive('setNode')->with($task->server->node_id)->once()->andReturnSelf() + ->shouldReceive('setAccessServer')->with($task->server->uuid)->once()->andReturnSelf() ->shouldReceive('setAccessToken')->with('123456')->once()->andReturnSelf() ->shouldReceive('send')->with($task->payload)->once()->andReturnNull(); @@ -145,17 +143,15 @@ class RunTaskJobTest extends TestCase */ public function testNextTaskQueuedIfExists() { - Carbon::setTestNow(); - $schedule = factory(Schedule::class)->make(); $task = factory(Task::class)->make(['action' => 'command', 'sequence_id' => 1]); - $server = factory(Server::class)->make(); - $task->server = $server; + $task->setRelation('server', $server = factory(Server::class)->make()); + $server->setRelation('user', factory(User::class)->make()); $this->taskRepository->shouldReceive('getTaskWithServer')->with($task->id)->once()->andReturn($task); - $this->keyProviderService->shouldReceive('handle')->with($server->id, $server->owner_id)->once()->andReturn('123456'); - $this->commandRepository->shouldReceive('setNode')->with($server->node_id)->once()->andReturnSelf() - ->shouldReceive('setAccessServer')->with($server->uuid)->once()->andReturnSelf() + $this->keyProviderService->shouldReceive('handle')->with($server, $server->user)->once()->andReturn('123456'); + $this->commandRepository->shouldReceive('setNode')->with($task->server->node_id)->once()->andReturnSelf() + ->shouldReceive('setAccessServer')->with($task->server->uuid)->once()->andReturnSelf() ->shouldReceive('setAccessToken')->with('123456')->once()->andReturnSelf() ->shouldReceive('send')->with($task->payload)->once()->andReturnNull(); @@ -187,7 +183,8 @@ class RunTaskJobTest extends TestCase public function testInvalidActionPassedToJob() { $task = factory(Task::class)->make(['action' => 'invalid', 'sequence_id' => 1]); - $task->server = []; + $task->setRelation('server', $server = factory(Server::class)->make()); + $server->setRelation('user', factory(User::class)->make()); $this->taskRepository->shouldReceive('getTaskWithServer')->with($task->id)->once()->andReturn($task); diff --git a/tests/Unit/Services/DaemonKeys/DaemonKeyProviderServiceTest.php b/tests/Unit/Services/DaemonKeys/DaemonKeyProviderServiceTest.php index b369fff63..ec2273148 100644 --- a/tests/Unit/Services/DaemonKeys/DaemonKeyProviderServiceTest.php +++ b/tests/Unit/Services/DaemonKeys/DaemonKeyProviderServiceTest.php @@ -12,6 +12,8 @@ namespace Tests\Unit\Services\DaemonKeys; use Mockery as m; use Carbon\Carbon; use Tests\TestCase; +use Pterodactyl\Models\User; +use Pterodactyl\Models\Server; use Pterodactyl\Models\DaemonKey; use Pterodactyl\Services\DaemonKeys\DaemonKeyUpdateService; use Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService; @@ -19,25 +21,15 @@ use Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface; class DaemonKeyProviderServiceTest extends TestCase { - /** - * @var \Carbon\Carbon|\Mockery\Mock - */ - protected $carbon; - /** * @var \Pterodactyl\Services\DaemonKeys\DaemonKeyUpdateService|\Mockery\Mock */ - protected $keyUpdateService; + private $keyUpdateService; /** * @var \Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface|\Mockery\Mock */ - protected $repository; - - /** - * @var \Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService - */ - protected $service; + private $repository; /** * Setup tests. @@ -45,29 +37,46 @@ class DaemonKeyProviderServiceTest extends TestCase public function setUp() { parent::setUp(); - - $this->carbon = new Carbon(); - $this->carbon->setTestNow(); + Carbon::setTestNow(); $this->keyUpdateService = m::mock(DaemonKeyUpdateService::class); $this->repository = m::mock(DaemonKeyRepositoryInterface::class); - - $this->service = new DaemonKeyProviderService($this->carbon, $this->keyUpdateService, $this->repository); } /** - * Test that a key is returned. + * Test that a key is returned correctly as a non-admin. */ public function testKeyIsReturned() { + $server = factory(Server::class)->make(); + $user = factory(User::class)->make(['root_admin' => 0]); $key = factory(DaemonKey::class)->make(); $this->repository->shouldReceive('findFirstWhere')->with([ - ['user_id', '=', $key->user_id], - ['server_id', '=', $key->server_id], + ['user_id', '=', $user->id], + ['server_id', '=', $server->id], ])->once()->andReturn($key); - $response = $this->service->handle($key->server_id, $key->user_id); + $response = $this->getService()->handle($server, $user); + $this->assertNotEmpty($response); + $this->assertEquals($key->secret, $response); + } + + /** + * Test that an admin user gets the server owner's key as the response. + */ + public function testServerOwnerKeyIsReturnedIfUserIsAdministrator() + { + $server = factory(Server::class)->make(); + $user = factory(User::class)->make(['root_admin' => 1]); + $key = factory(DaemonKey::class)->make(); + + $this->repository->shouldReceive('findFirstWhere')->with([ + ['user_id', '=', $server->owner_id], + ['server_id', '=', $server->id], + ])->once()->andReturn($key); + + $response = $this->getService()->handle($server, $user); $this->assertNotEmpty($response); $this->assertEquals($key->secret, $response); } @@ -77,20 +86,20 @@ class DaemonKeyProviderServiceTest extends TestCase */ public function testExpiredKeyIsUpdated() { - $key = factory(DaemonKey::class)->make([ - 'expires_at' => $this->carbon->subHour(), - ]); + $server = factory(Server::class)->make(); + $user = factory(User::class)->make(['root_admin' => 0]); + $key = factory(DaemonKey::class)->make(['expires_at' => Carbon::now()->subHour()]); $this->repository->shouldReceive('findFirstWhere')->with([ - ['user_id', '=', $key->user_id], - ['server_id', '=', $key->server_id], + ['user_id', '=', $user->id], + ['server_id', '=', $server->id], ])->once()->andReturn($key); - $this->keyUpdateService->shouldReceive('handle')->with($key->id)->once()->andReturn(true); + $this->keyUpdateService->shouldReceive('handle')->with($key->id)->once()->andReturn('abc123'); - $response = $this->service->handle($key->server_id, $key->user_id); + $response = $this->getService()->handle($server, $user); $this->assertNotEmpty($response); - $this->assertTrue($response); + $this->assertEquals('abc123', $response); } /** @@ -98,17 +107,27 @@ class DaemonKeyProviderServiceTest extends TestCase */ public function testExpiredKeyIsNotUpdated() { - $key = factory(DaemonKey::class)->make([ - 'expires_at' => $this->carbon->subHour(), - ]); + $server = factory(Server::class)->make(); + $user = factory(User::class)->make(['root_admin' => 0]); + $key = factory(DaemonKey::class)->make(['expires_at' => Carbon::now()->subHour()]); $this->repository->shouldReceive('findFirstWhere')->with([ - ['user_id', '=', $key->user_id], - ['server_id', '=', $key->server_id], + ['user_id', '=', $user->id], + ['server_id', '=', $server->id], ])->once()->andReturn($key); - $response = $this->service->handle($key->server_id, $key->user_id, false); + $response = $this->getService()->handle($server, $user, false); $this->assertNotEmpty($response); $this->assertEquals($key->secret, $response); } + + /** + * Return an instance of the service with mocked dependencies. + * + * @return \Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService + */ + private function getService(): DaemonKeyProviderService + { + return new DaemonKeyProviderService($this->keyUpdateService, $this->repository); + } } diff --git a/tests/Unit/Services/Sftp/AuthenticateUsingPasswordServiceTest.php b/tests/Unit/Services/Sftp/AuthenticateUsingPasswordServiceTest.php index 87ceccd07..904f10a0a 100644 --- a/tests/Unit/Services/Sftp/AuthenticateUsingPasswordServiceTest.php +++ b/tests/Unit/Services/Sftp/AuthenticateUsingPasswordServiceTest.php @@ -55,7 +55,7 @@ class AuthenticateUsingPasswordServiceTest extends TestCase $this->repository->shouldReceive('withColumns')->with(['id', 'node_id', 'owner_id', 'uuid'])->once()->andReturnSelf(); $this->repository->shouldReceive('getByUuid')->with($server->uuidShort)->once()->andReturn($server); - $this->keyProviderService->shouldReceive('handle')->with($server->id, $user->id)->once()->andReturn('server_token'); + $this->keyProviderService->shouldReceive('handle')->with($server, $user)->once()->andReturn('server_token'); $response = $this->getService()->handle($user->username, 'password', 1, $server->uuidShort); $this->assertNotEmpty($response); @@ -80,7 +80,7 @@ class AuthenticateUsingPasswordServiceTest extends TestCase $this->repository->shouldReceive('withColumns')->with(['id', 'node_id', 'owner_id', 'uuid'])->once()->andReturnSelf(); $this->repository->shouldReceive('getByUuid')->with($server->uuidShort)->once()->andReturn($server); - $this->keyProviderService->shouldReceive('handle')->with($server->id, $user->id)->once()->andReturn('server_token'); + $this->keyProviderService->shouldReceive('handle')->with($server, $user)->once()->andReturn('server_token'); $response = $this->getService()->handle($user->username, 'password', 1, $server->uuidShort); $this->assertNotEmpty($response); diff --git a/tests/Unit/Services/Subusers/SubuserUpdateServiceTest.php b/tests/Unit/Services/Subusers/SubuserUpdateServiceTest.php index 7a6aaf454..6b9f8ab32 100644 --- a/tests/Unit/Services/Subusers/SubuserUpdateServiceTest.php +++ b/tests/Unit/Services/Subusers/SubuserUpdateServiceTest.php @@ -11,6 +11,7 @@ namespace Tests\Unit\Services\Subusers; use Mockery as m; use Tests\TestCase; +use Pterodactyl\Models\User; use Pterodactyl\Models\Server; use Pterodactyl\Models\Subuser; use Tests\Traits\MocksRequestException; @@ -81,13 +82,14 @@ class SubuserUpdateServiceTest extends TestCase { $subuser = factory(Subuser::class)->make(); $subuser->setRelation('server', factory(Server::class)->make()); + $subuser->setRelation('user', factory(User::class)->make()); - $this->repository->shouldReceive('getWithServer')->with($subuser)->once()->andReturn($subuser); + $this->repository->shouldReceive('loadServerAndUserRelations')->with($subuser)->once()->andReturn($subuser); $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); $this->permissionRepository->shouldReceive('deleteWhere')->with([['subuser_id', '=', $subuser->id]])->once()->andReturnNull(); $this->permissionService->shouldReceive('handle')->with($subuser->id, ['some-permission'])->once()->andReturnNull(); - $this->keyProviderService->shouldReceive('handle')->with($subuser->server_id, $subuser->user_id, false)->once()->andReturn('test123'); + $this->keyProviderService->shouldReceive('handle')->with($subuser->server, $subuser->user, false)->once()->andReturn('test123'); $this->daemonRepository->shouldReceive('setNode')->with($subuser->server->node_id)->once()->andReturnSelf(); $this->daemonRepository->shouldReceive('revokeAccessKey')->with('test123')->once()->andReturnNull(); @@ -106,13 +108,14 @@ class SubuserUpdateServiceTest extends TestCase $subuser = factory(Subuser::class)->make(); $subuser->setRelation('server', factory(Server::class)->make()); + $subuser->setRelation('user', factory(User::class)->make()); - $this->repository->shouldReceive('getWithServer')->with($subuser)->once()->andReturn($subuser); + $this->repository->shouldReceive('loadServerAndUserRelations')->with($subuser)->once()->andReturn($subuser); $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); $this->permissionRepository->shouldReceive('deleteWhere')->with([['subuser_id', '=', $subuser->id]])->once()->andReturnNull(); $this->permissionService->shouldReceive('handle')->with($subuser->id, [])->once()->andReturnNull(); - $this->keyProviderService->shouldReceive('handle')->with($subuser->server_id, $subuser->user_id, false)->once()->andReturn('test123'); + $this->keyProviderService->shouldReceive('handle')->with($subuser->server, $subuser->user, false)->once()->andReturn('test123'); $this->daemonRepository->shouldReceive('setNode')->with($subuser->server->node_id)->once()->andThrow($this->getExceptionMock()); $this->connection->shouldReceive('rollBack')->withNoArgs()->once()->andReturnNull();