forked from Alex/Pterodactyl-Panel
Begin implementation of new daemon authentication scheme
This commit is contained in:
parent
8722571037
commit
906a699ee2
46
app/Contracts/Repository/DaemonKeyRepositoryInterface.php
Normal file
46
app/Contracts/Repository/DaemonKeyRepositoryInterface.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Pterodactyl - Panel
|
||||||
|
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Pterodactyl\Contracts\Repository;
|
||||||
|
|
||||||
|
interface DaemonKeyRepositoryInterface extends RepositoryInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Gets the daemon keys associated with a specific server.
|
||||||
|
*
|
||||||
|
* @param int $server
|
||||||
|
* @return \Illuminate\Support\Collection
|
||||||
|
*/
|
||||||
|
public function getServerKeys($server);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a daemon key with the associated server relation attached.
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @return \Pterodactyl\Models\DaemonKey
|
||||||
|
*
|
||||||
|
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||||
|
*/
|
||||||
|
public function getKeyWithServer($key);
|
||||||
|
}
|
@ -46,6 +46,17 @@ interface SubuserRepositoryInterface extends RepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function getWithPermissions($id);
|
public function getWithPermissions($id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a subuser and associated permissions given a user_id and server_id.
|
||||||
|
*
|
||||||
|
* @param int $user
|
||||||
|
* @param int $server
|
||||||
|
* @return \Pterodactyl\Models\Subuser
|
||||||
|
*
|
||||||
|
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||||
|
*/
|
||||||
|
public function getWithPermissionsUsingUserAndServer($user, $server);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a subuser and return with server and permissions relationships.
|
* Find a subuser and return with server and permissions relationships.
|
||||||
*
|
*
|
||||||
@ -55,4 +66,15 @@ interface SubuserRepositoryInterface extends RepositoryInterface
|
|||||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||||
*/
|
*/
|
||||||
public function getWithServerAndPermissions($id);
|
public function getWithServerAndPermissions($id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a subuser and their associated connection key for a server.
|
||||||
|
*
|
||||||
|
* @param int $user
|
||||||
|
* @param int $server
|
||||||
|
* @return \Pterodactyl\Models\Subuser
|
||||||
|
*
|
||||||
|
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||||
|
*/
|
||||||
|
public function getWithKey($user, $server);
|
||||||
}
|
}
|
||||||
|
@ -66,11 +66,16 @@ class Handler extends ExceptionHandler
|
|||||||
$displayError = 'An unhandled exception was encountered with this request.';
|
$displayError = 'An unhandled exception was encountered with this request.';
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = response()->json([
|
$response = response()->json(
|
||||||
|
[
|
||||||
'error' => $displayError,
|
'error' => $displayError,
|
||||||
'http_code' => (! $this->isHttpException($exception)) ?: $exception->getStatusCode(),
|
'http_code' => (! $this->isHttpException($exception)) ?: $exception->getStatusCode(),
|
||||||
'trace' => (! config('app.debug')) ? null : class_basename($exception) . ' in ' . $exception->getFile() . ' on line ' . $exception->getLine(),
|
'trace' => (! config('app.debug')) ? null : $exception->getTrace(),
|
||||||
], ($this->isHttpException($exception)) ? $exception->getStatusCode() : 500, [], JSON_UNESCAPED_SLASHES);
|
],
|
||||||
|
$this->isHttpException($exception) ? $exception->getStatusCode() : 500,
|
||||||
|
$this->isHttpException($exception) ? $exception->getHeaders() : [],
|
||||||
|
JSON_UNESCAPED_SLASHES
|
||||||
|
);
|
||||||
|
|
||||||
parent::report($exception);
|
parent::report($exception);
|
||||||
} elseif ($exception instanceof DisplayException) {
|
} elseif ($exception instanceof DisplayException) {
|
||||||
|
90
app/Http/Controllers/API/Remote/ValidateKeyController.php
Normal file
90
app/Http/Controllers/API/Remote/ValidateKeyController.php
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Pterodactyl - Panel
|
||||||
|
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Pterodactyl\Http\Controllers\API\Remote;
|
||||||
|
|
||||||
|
use Spatie\Fractal\Fractal;
|
||||||
|
use Pterodactyl\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
|
use Illuminate\Foundation\Testing\HttpException;
|
||||||
|
use League\Fractal\Serializer\JsonApiSerializer;
|
||||||
|
use Pterodactyl\Transformers\Daemon\ApiKeyTransformer;
|
||||||
|
use Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface;
|
||||||
|
|
||||||
|
class ValidateKeyController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \Illuminate\Contracts\Foundation\Application
|
||||||
|
*/
|
||||||
|
protected $app;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface
|
||||||
|
*/
|
||||||
|
protected $daemonKeyRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Spatie\Fractal\Fractal
|
||||||
|
*/
|
||||||
|
protected $fractal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ValidateKeyController constructor.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Contracts\Foundation\Application $app
|
||||||
|
* @param \Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface $daemonKeyRepository
|
||||||
|
* @param \Spatie\Fractal\Fractal $fractal
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
Application $app,
|
||||||
|
DaemonKeyRepositoryInterface $daemonKeyRepository,
|
||||||
|
Fractal $fractal
|
||||||
|
) {
|
||||||
|
$this->app = $app;
|
||||||
|
$this->daemonKeyRepository = $daemonKeyRepository;
|
||||||
|
$this->fractal = $fractal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the server(s) and permissions associated with an API key.
|
||||||
|
*
|
||||||
|
* @param string $token
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
* @throws \Illuminate\Foundation\Testing\HttpException
|
||||||
|
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||||
|
*/
|
||||||
|
public function index($token)
|
||||||
|
{
|
||||||
|
if (! starts_with($token, 'i_')) {
|
||||||
|
throw new HttpException(501);
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = $this->daemonKeyRepository->getKeyWithServer($token);
|
||||||
|
|
||||||
|
return $this->fractal->item($key, $this->app->make(ApiKeyTransformer::class), 'server')
|
||||||
|
->serializeWith(JsonApiSerializer::class)
|
||||||
|
->toArray();
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
namespace Pterodactyl\Http;
|
namespace Pterodactyl\Http;
|
||||||
|
|
||||||
|
use Pterodactyl\Http\Middleware\DaemonAuthenticate;
|
||||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||||
|
use Illuminate\Routing\Middleware\SubstituteBindings;
|
||||||
|
|
||||||
class Kernel extends HttpKernel
|
class Kernel extends HttpKernel
|
||||||
{
|
{
|
||||||
@ -43,6 +45,10 @@ class Kernel extends HttpKernel
|
|||||||
'throttle:60,1',
|
'throttle:60,1',
|
||||||
'bindings',
|
'bindings',
|
||||||
],
|
],
|
||||||
|
'daemon' => [
|
||||||
|
\Pterodactyl\Http\Middleware\Daemon\DaemonAuthenticate::class,
|
||||||
|
SubstituteBindings::class,
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,7 +63,7 @@ class Kernel extends HttpKernel
|
|||||||
'server' => \Pterodactyl\Http\Middleware\ServerAuthenticate::class,
|
'server' => \Pterodactyl\Http\Middleware\ServerAuthenticate::class,
|
||||||
'subuser' => \Pterodactyl\Http\Middleware\SubuserAccessAuthenticate::class,
|
'subuser' => \Pterodactyl\Http\Middleware\SubuserAccessAuthenticate::class,
|
||||||
'admin' => \Pterodactyl\Http\Middleware\AdminAuthenticate::class,
|
'admin' => \Pterodactyl\Http\Middleware\AdminAuthenticate::class,
|
||||||
'daemon' => \Pterodactyl\Http\Middleware\DaemonAuthenticate::class,
|
'daemon-old' => DaemonAuthenticate::class,
|
||||||
'csrf' => \Pterodactyl\Http\Middleware\VerifyCsrfToken::class,
|
'csrf' => \Pterodactyl\Http\Middleware\VerifyCsrfToken::class,
|
||||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||||
|
82
app/Http/Middleware/Daemon/DaemonAuthenticate.php
Normal file
82
app/Http/Middleware/Daemon/DaemonAuthenticate.php
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Pterodactyl - Panel
|
||||||
|
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Pterodactyl\Http\Middleware\Daemon;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||||
|
use Pterodactyl\Contracts\Repository\NodeRepositoryInterface;
|
||||||
|
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
|
||||||
|
|
||||||
|
class DaemonAuthenticate
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $except = ['daemon.configuration'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Contracts\Repository\NodeRepositoryInterface
|
||||||
|
*/
|
||||||
|
protected $repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DaemonAuthenticate constructor.
|
||||||
|
*
|
||||||
|
* @param \Pterodactyl\Contracts\Repository\NodeRepositoryInterface $repository
|
||||||
|
*/
|
||||||
|
public function __construct(NodeRepositoryInterface $repository)
|
||||||
|
{
|
||||||
|
$this->repository = $repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a request from the daemon can be properly attributed back to a single node instance.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Closure $next
|
||||||
|
* @return mixed
|
||||||
|
*
|
||||||
|
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next)
|
||||||
|
{
|
||||||
|
$token = $request->bearerToken();
|
||||||
|
|
||||||
|
if (is_null($token)) {
|
||||||
|
throw new HttpException(401, null, null, ['WWW-Authenticate' => 'Bearer']);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$node = $this->repository->findFirstWhere([['daemonSecret', '=', $token]]);
|
||||||
|
} catch (RecordNotFoundException $exception) {
|
||||||
|
throw new HttpException(403);
|
||||||
|
}
|
||||||
|
|
||||||
|
$request->attributes->set('node.model', $node);
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
@ -70,8 +70,8 @@ class ScheduleAccess
|
|||||||
* @param \Closure $next
|
* @param \Closure $next
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*
|
*
|
||||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
|
||||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
|
||||||
*/
|
*/
|
||||||
public function handle($request, Closure $next)
|
public function handle($request, Closure $next)
|
||||||
{
|
{
|
||||||
|
@ -63,6 +63,7 @@ class SubuserAccess
|
|||||||
*
|
*
|
||||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||||
|
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
|
||||||
*/
|
*/
|
||||||
public function handle($request, Closure $next)
|
public function handle($request, Closure $next)
|
||||||
{
|
{
|
||||||
|
@ -82,6 +82,8 @@ class ServerAuthenticate
|
|||||||
*
|
*
|
||||||
* @throws \Illuminate\Auth\AuthenticationException
|
* @throws \Illuminate\Auth\AuthenticationException
|
||||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||||
|
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||||
|
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
|
||||||
*/
|
*/
|
||||||
public function handle(Request $request, Closure $next)
|
public function handle(Request $request, Closure $next)
|
||||||
{
|
{
|
||||||
|
103
app/Models/DaemonKey.php
Normal file
103
app/Models/DaemonKey.php
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Pterodactyl - Panel
|
||||||
|
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Pterodactyl\Models;
|
||||||
|
|
||||||
|
use Sofa\Eloquence\Eloquence;
|
||||||
|
use Sofa\Eloquence\Validable;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Sofa\Eloquence\Contracts\CleansAttributes;
|
||||||
|
use Sofa\Eloquence\Contracts\Validable as ValidableContract;
|
||||||
|
|
||||||
|
class DaemonKey extends Model implements CleansAttributes, ValidableContract
|
||||||
|
{
|
||||||
|
use Eloquence, Validable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $table = 'daemon_keys';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'user_id' => 'integer',
|
||||||
|
'server_id' => 'integer',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $dates = [
|
||||||
|
self::CREATED_AT,
|
||||||
|
self::UPDATED_AT,
|
||||||
|
'expires_at',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = ['user_id', 'server_id', 'secret', 'expires_at'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected static $applicationRules = [
|
||||||
|
'user_id' => 'required',
|
||||||
|
'server_id' => 'required',
|
||||||
|
'secret' => 'required',
|
||||||
|
'expires_at' => 'required',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected static $dataIntegrityRules = [
|
||||||
|
'user_id' => 'numeric|exists:users,id',
|
||||||
|
'server_id' => 'numeric|exists:servers,id',
|
||||||
|
'secret' => 'string|min:20',
|
||||||
|
'expires_at' => 'date',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the server relation.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function server()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Server::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the user relation.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
}
|
@ -24,21 +24,18 @@
|
|||||||
|
|
||||||
namespace Pterodactyl\Models;
|
namespace Pterodactyl\Models;
|
||||||
|
|
||||||
use Auth;
|
|
||||||
use Cache;
|
|
||||||
use Carbon;
|
|
||||||
use Schema;
|
use Schema;
|
||||||
use Javascript;
|
|
||||||
use Sofa\Eloquence\Eloquence;
|
use Sofa\Eloquence\Eloquence;
|
||||||
use Sofa\Eloquence\Validable;
|
use Sofa\Eloquence\Validable;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
use Znck\Eloquent\Traits\BelongsToThrough;
|
||||||
use Sofa\Eloquence\Contracts\CleansAttributes;
|
use Sofa\Eloquence\Contracts\CleansAttributes;
|
||||||
use Sofa\Eloquence\Contracts\Validable as ValidableContract;
|
use Sofa\Eloquence\Contracts\Validable as ValidableContract;
|
||||||
|
|
||||||
class Server extends Model implements CleansAttributes, ValidableContract
|
class Server extends Model implements CleansAttributes, ValidableContract
|
||||||
{
|
{
|
||||||
use Eloquence, Notifiable, Validable;
|
use BelongsToThrough, Eloquence, Notifiable, Validable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The table associated with the model.
|
* The table associated with the model.
|
||||||
@ -52,7 +49,7 @@ class Server extends Model implements CleansAttributes, ValidableContract
|
|||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $hidden = ['daemonSecret', 'sftp_password'];
|
protected $hidden = ['sftp_password'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The attributes that should be mutated to dates.
|
* The attributes that should be mutated to dates.
|
||||||
@ -152,109 +149,6 @@ class Server extends Model implements CleansAttributes, ValidableContract
|
|||||||
'node.name' => 2,
|
'node.name' => 2,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a single server specified by UUID.
|
|
||||||
* DO NOT USE THIS TO MODIFY SERVER DETAILS OR SAVE THOSE DETAILS.
|
|
||||||
* YOU WILL OVERWRITE THE SECRET KEY AND BREAK THINGS.
|
|
||||||
*
|
|
||||||
* @param string $uuid
|
|
||||||
* @param array $with
|
|
||||||
* @param array $withCount
|
|
||||||
* @return \Pterodactyl\Models\Server
|
|
||||||
* @throws \Exception
|
|
||||||
* @todo Remove $with and $withCount due to cache issues, they aren't used anyways.
|
|
||||||
*/
|
|
||||||
public static function byUuid($uuid, array $with = [], array $withCount = [])
|
|
||||||
{
|
|
||||||
if (! Auth::check()) {
|
|
||||||
throw new \Exception('You must call Server:byUuid as an authenticated user.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Results are cached because we call this functions a few times on page load.
|
|
||||||
$result = Cache::tags(['Model:Server', 'Model:Server:byUuid:' . $uuid])->remember('Model:Server:byUuid:' . $uuid . Auth::user()->uuid, Carbon::now()->addMinutes(15), function () use ($uuid) {
|
|
||||||
$query = self::with('service', 'node')->where(function ($q) use ($uuid) {
|
|
||||||
$q->where('uuidShort', $uuid)->orWhere('uuid', $uuid);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (! Auth::user()->isRootAdmin()) {
|
|
||||||
$query->whereIn('id', Auth::user()->serverAccessArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
return $query->first();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (! is_null($result)) {
|
|
||||||
$result->daemonSecret = Auth::user()->daemonToken($result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns non-administrative headers for accessing a server on the daemon.
|
|
||||||
*
|
|
||||||
* @param Pterodactyl\Models\User|null $user
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function guzzleHeaders(User $user = null)
|
|
||||||
{
|
|
||||||
// If no specific user is passed, see if we can find an active
|
|
||||||
// auth session to pull data from.
|
|
||||||
if (is_null($user) && Auth::check()) {
|
|
||||||
$user = Auth::user();
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
'X-Access-Server' => $this->uuid,
|
|
||||||
'X-Access-Token' => ($user) ? $user->daemonToken($this) : $this->daemonSecret,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an instance of the Guzzle client for this specific server using defined access token.
|
|
||||||
*
|
|
||||||
* @param Pterodactyl\Models\User|null $user
|
|
||||||
* @return \GuzzleHttp\Client
|
|
||||||
*/
|
|
||||||
public function guzzleClient(User $user = null)
|
|
||||||
{
|
|
||||||
return $this->node->guzzleClient($this->guzzleHeaders($user));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns javascript object to be embedded on server view pages with relevant information.
|
|
||||||
*
|
|
||||||
* @param array|null $additional
|
|
||||||
* @param array|null $overwrite
|
|
||||||
* @return \Laracasts\Utilities\JavaScript\JavaScriptFacade
|
|
||||||
*/
|
|
||||||
public function js($additional = null, $overwrite = null)
|
|
||||||
{
|
|
||||||
$response = [
|
|
||||||
'server' => collect($this->makeVisible('daemonSecret'))->only([
|
|
||||||
'uuid',
|
|
||||||
'uuidShort',
|
|
||||||
'daemonSecret',
|
|
||||||
'username',
|
|
||||||
]),
|
|
||||||
'node' => collect($this->node)->only([
|
|
||||||
'fqdn',
|
|
||||||
'scheme',
|
|
||||||
'daemonListen',
|
|
||||||
]),
|
|
||||||
];
|
|
||||||
|
|
||||||
if (is_array($additional)) {
|
|
||||||
$response = array_merge($response, $additional);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_array($overwrite)) {
|
|
||||||
$response = $overwrite;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Javascript::put($response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the columns available for this table.
|
* Return the columns available for this table.
|
||||||
*
|
*
|
||||||
@ -358,12 +252,11 @@ class Server extends Model implements CleansAttributes, ValidableContract
|
|||||||
/**
|
/**
|
||||||
* Gets information for the tasks associated with this server.
|
* Gets information for the tasks associated with this server.
|
||||||
*
|
*
|
||||||
* @TODO adjust server column in tasks to be server_id
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
*/
|
*/
|
||||||
public function tasks()
|
public function schedule()
|
||||||
{
|
{
|
||||||
return $this->hasMany(Task::class);
|
return $this->hasMany(Schedule::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -377,12 +270,34 @@ class Server extends Model implements CleansAttributes, ValidableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the location of the server.
|
* Returns the location that a server belongs to.
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
* @return \Znck\Eloquent\Relations\BelongsToThrough
|
||||||
|
*
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function location()
|
public function location()
|
||||||
{
|
{
|
||||||
return $this->node->location();
|
return $this->belongsToThrough(Location::class, Node::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the key belonging to the server owner.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||||
|
*/
|
||||||
|
public function ownerKey()
|
||||||
|
{
|
||||||
|
return $this->hasOne(DaemonKey::class, 'user_id', 'owner_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all of the daemon keys belonging to this server.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
|
*/
|
||||||
|
public function keys()
|
||||||
|
{
|
||||||
|
return $this->hasMany(DaemonKey::class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,13 +42,6 @@ class Subuser extends Model implements CleansAttributes, ValidableContract
|
|||||||
*/
|
*/
|
||||||
protected $table = 'subusers';
|
protected $table = 'subusers';
|
||||||
|
|
||||||
/**
|
|
||||||
* The attributes excluded from the model's JSON form.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $hidden = ['daemonSecret'];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fields that are not mass assignable.
|
* Fields that are not mass assignable.
|
||||||
*
|
*
|
||||||
@ -72,7 +65,6 @@ class Subuser extends Model implements CleansAttributes, ValidableContract
|
|||||||
protected static $applicationRules = [
|
protected static $applicationRules = [
|
||||||
'user_id' => 'required',
|
'user_id' => 'required',
|
||||||
'server_id' => 'required',
|
'server_id' => 'required',
|
||||||
'daemonSecret' => 'required',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -81,7 +73,6 @@ class Subuser extends Model implements CleansAttributes, ValidableContract
|
|||||||
protected static $dataIntegrityRules = [
|
protected static $dataIntegrityRules = [
|
||||||
'user_id' => 'numeric|exists:users,id',
|
'user_id' => 'numeric|exists:users,id',
|
||||||
'server_id' => 'numeric|exists:servers,id',
|
'server_id' => 'numeric|exists:servers,id',
|
||||||
'daemonSecret' => 'string',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,6 +28,7 @@ use View;
|
|||||||
use Cache;
|
use Cache;
|
||||||
use Pterodactyl\Models;
|
use Pterodactyl\Models;
|
||||||
use Pterodactyl\Observers;
|
use Pterodactyl\Observers;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
class AppServiceProvider extends ServiceProvider
|
class AppServiceProvider extends ServiceProvider
|
||||||
@ -37,6 +38,8 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
*/
|
*/
|
||||||
public function boot()
|
public function boot()
|
||||||
{
|
{
|
||||||
|
Schema::defaultStringLength(191);
|
||||||
|
|
||||||
Models\User::observe(Observers\UserObserver::class);
|
Models\User::observe(Observers\UserObserver::class);
|
||||||
Models\Server::observe(Observers\ServerObserver::class);
|
Models\Server::observe(Observers\ServerObserver::class);
|
||||||
Models\Subuser::observe(Observers\SubuserObserver::class);
|
Models\Subuser::observe(Observers\SubuserObserver::class);
|
||||||
|
@ -40,6 +40,7 @@ use Pterodactyl\Repositories\Eloquent\SubuserRepository;
|
|||||||
use Pterodactyl\Repositories\Eloquent\DatabaseRepository;
|
use Pterodactyl\Repositories\Eloquent\DatabaseRepository;
|
||||||
use Pterodactyl\Repositories\Eloquent\LocationRepository;
|
use Pterodactyl\Repositories\Eloquent\LocationRepository;
|
||||||
use Pterodactyl\Repositories\Eloquent\ScheduleRepository;
|
use Pterodactyl\Repositories\Eloquent\ScheduleRepository;
|
||||||
|
use Pterodactyl\Repositories\Eloquent\DaemonKeyRepository;
|
||||||
use Pterodactyl\Repositories\Eloquent\AllocationRepository;
|
use Pterodactyl\Repositories\Eloquent\AllocationRepository;
|
||||||
use Pterodactyl\Repositories\Eloquent\PermissionRepository;
|
use Pterodactyl\Repositories\Eloquent\PermissionRepository;
|
||||||
use Pterodactyl\Repositories\Daemon\ConfigurationRepository;
|
use Pterodactyl\Repositories\Daemon\ConfigurationRepository;
|
||||||
@ -61,6 +62,7 @@ use Pterodactyl\Repositories\Eloquent\ServiceVariableRepository;
|
|||||||
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
|
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
|
||||||
use Pterodactyl\Contracts\Repository\LocationRepositoryInterface;
|
use Pterodactyl\Contracts\Repository\LocationRepositoryInterface;
|
||||||
use Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface;
|
use Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface;
|
||||||
|
use Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface;
|
||||||
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
|
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
|
||||||
use Pterodactyl\Contracts\Repository\PermissionRepositoryInterface;
|
use Pterodactyl\Contracts\Repository\PermissionRepositoryInterface;
|
||||||
use Pterodactyl\Contracts\Repository\Daemon\FileRepositoryInterface;
|
use Pterodactyl\Contracts\Repository\Daemon\FileRepositoryInterface;
|
||||||
@ -87,6 +89,7 @@ class RepositoryServiceProvider extends ServiceProvider
|
|||||||
$this->app->bind(AllocationRepositoryInterface::class, AllocationRepository::class);
|
$this->app->bind(AllocationRepositoryInterface::class, AllocationRepository::class);
|
||||||
$this->app->bind(ApiKeyRepositoryInterface::class, ApiKeyRepository::class);
|
$this->app->bind(ApiKeyRepositoryInterface::class, ApiKeyRepository::class);
|
||||||
$this->app->bind(ApiPermissionRepositoryInterface::class, ApiPermissionRepository::class);
|
$this->app->bind(ApiPermissionRepositoryInterface::class, ApiPermissionRepository::class);
|
||||||
|
$this->app->bind(DaemonKeyRepositoryInterface::class, DaemonKeyRepository::class);
|
||||||
$this->app->bind(DatabaseRepositoryInterface::class, DatabaseRepository::class);
|
$this->app->bind(DatabaseRepositoryInterface::class, DatabaseRepository::class);
|
||||||
$this->app->bind(DatabaseHostRepositoryInterface::class, DatabaseHostRepository::class);
|
$this->app->bind(DatabaseHostRepositoryInterface::class, DatabaseHostRepository::class);
|
||||||
$this->app->bind(LocationRepositoryInterface::class, LocationRepository::class);
|
$this->app->bind(LocationRepositoryInterface::class, LocationRepository::class);
|
||||||
|
@ -54,7 +54,11 @@ class RouteServiceProvider extends ServiceProvider
|
|||||||
->namespace($this->namespace . '\Server')
|
->namespace($this->namespace . '\Server')
|
||||||
->group(base_path('routes/server.php'));
|
->group(base_path('routes/server.php'));
|
||||||
|
|
||||||
Route::middleware(['web', 'daemon'])->prefix('/daemon')
|
Route::middleware(['daemon'])->prefix('/api/remote')
|
||||||
|
->namespace($this->namespace . '\API\Remote')
|
||||||
|
->group(base_path('routes/api-remote.php'));
|
||||||
|
|
||||||
|
Route::middleware(['web', 'daemon-old'])->prefix('/daemon')
|
||||||
->namespace($this->namespace . '\Daemon')
|
->namespace($this->namespace . '\Daemon')
|
||||||
->group(base_path('routes/daemon.php'));
|
->group(base_path('routes/daemon.php'));
|
||||||
}
|
}
|
||||||
|
66
app/Repositories/Eloquent/DaemonKeyRepository.php
Normal file
66
app/Repositories/Eloquent/DaemonKeyRepository.php
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Pterodactyl - Panel
|
||||||
|
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Pterodactyl\Repositories\Eloquent;
|
||||||
|
|
||||||
|
use Webmozart\Assert\Assert;
|
||||||
|
use Pterodactyl\Models\DaemonKey;
|
||||||
|
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
|
||||||
|
use Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface;
|
||||||
|
|
||||||
|
class DaemonKeyRepository extends EloquentRepository implements DaemonKeyRepositoryInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function model()
|
||||||
|
{
|
||||||
|
return DaemonKey::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getServerKeys($server)
|
||||||
|
{
|
||||||
|
Assert::integerish($server, 'First argument passed to getServerKeys must be integer, received %s.');
|
||||||
|
|
||||||
|
return $this->getBuilder()->where('server_id', $server)->get($this->getColumns());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getKeyWithServer($key)
|
||||||
|
{
|
||||||
|
Assert::stringNotEmpty($key, 'First argument passed to getServerByKey must be string, received %s.');
|
||||||
|
|
||||||
|
$instance = $this->getBuilder()->with('server')->where('secret', '=', $key)->first();
|
||||||
|
if (is_null($instance)) {
|
||||||
|
throw new RecordNotFoundException;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $instance;
|
||||||
|
}
|
||||||
|
}
|
@ -69,6 +69,26 @@ class SubuserRepository extends EloquentRepository implements SubuserRepositoryI
|
|||||||
return $instance;
|
return $instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getWithPermissionsUsingUserAndServer($user, $server)
|
||||||
|
{
|
||||||
|
Assert::integerish($user, 'First argument passed to getWithPermissionsUsingUserAndServer must be integer, received %s.');
|
||||||
|
Assert::integerish($server, 'Second argument passed to getWithPermissionsUsingUserAndServer must be integer, received %s.');
|
||||||
|
|
||||||
|
$instance = $this->getBuilder()->with('permissions')->where([
|
||||||
|
['user_id', '=', $user],
|
||||||
|
['server_id', '=', $server],
|
||||||
|
])->first();
|
||||||
|
|
||||||
|
if (is_null($instance)) {
|
||||||
|
throw new RecordNotFoundException;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $instance;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
@ -83,4 +103,24 @@ class SubuserRepository extends EloquentRepository implements SubuserRepositoryI
|
|||||||
|
|
||||||
return $instance;
|
return $instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getWithKey($user, $server)
|
||||||
|
{
|
||||||
|
Assert::integerish($user, 'First argument passed to getWithKey must be integer, received %s.');
|
||||||
|
Assert::integerish($server, 'Second argument passed to getWithKey must be integer, received %s.');
|
||||||
|
|
||||||
|
$instance = $this->getBuilder()->with('key')->where([
|
||||||
|
['user_id', '=', $user],
|
||||||
|
['server_id', '=', $server],
|
||||||
|
])->first();
|
||||||
|
|
||||||
|
if (is_null($instance)) {
|
||||||
|
throw new RecordNotFoundException;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $instance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,24 +29,54 @@ use Pterodactyl\Models\Server;
|
|||||||
use Illuminate\Cache\Repository as CacheRepository;
|
use Illuminate\Cache\Repository as CacheRepository;
|
||||||
use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
|
use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
|
||||||
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
||||||
use Pterodactyl\Contracts\Repository\SubuserRepositoryInterface;
|
use Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface;
|
||||||
use Pterodactyl\Exceptions\Service\Server\UserNotLinkedToServerException;
|
use Pterodactyl\Exceptions\Service\Server\UserNotLinkedToServerException;
|
||||||
|
|
||||||
class ServerAccessHelperService
|
class ServerAccessHelperService
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var \Illuminate\Cache\Repository
|
||||||
|
*/
|
||||||
|
protected $cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface
|
||||||
|
*/
|
||||||
|
protected $daemonKeyRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
|
||||||
|
*/
|
||||||
|
protected $repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Contracts\Repository\UserRepositoryInterface
|
||||||
|
*/
|
||||||
|
protected $userRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ServerAccessHelperService constructor.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Cache\Repository $cache
|
||||||
|
* @param \Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface $daemonKeyRepository
|
||||||
|
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
|
||||||
|
* @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $userRepository
|
||||||
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
CacheRepository $cache,
|
CacheRepository $cache,
|
||||||
|
DaemonKeyRepositoryInterface $daemonKeyRepository,
|
||||||
ServerRepositoryInterface $repository,
|
ServerRepositoryInterface $repository,
|
||||||
SubuserRepositoryInterface $subuserRepository,
|
|
||||||
UserRepositoryInterface $userRepository
|
UserRepositoryInterface $userRepository
|
||||||
) {
|
) {
|
||||||
$this->cache = $cache;
|
$this->cache = $cache;
|
||||||
|
$this->daemonKeyRepository = $daemonKeyRepository;
|
||||||
$this->repository = $repository;
|
$this->repository = $repository;
|
||||||
$this->subuserRepository = $subuserRepository;
|
|
||||||
$this->userRepository = $userRepository;
|
$this->userRepository = $userRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Return the daemon secret to use when making a connection.
|
||||||
|
*
|
||||||
* @param int|\Pterodactyl\Models\Server $server
|
* @param int|\Pterodactyl\Models\Server $server
|
||||||
* @param int|\Pterodactyl\Models\User $user
|
* @param int|\Pterodactyl\Models\User $user
|
||||||
* @return string
|
* @return string
|
||||||
@ -64,19 +94,17 @@ class ServerAccessHelperService
|
|||||||
$user = $this->userRepository->find($user);
|
$user = $this->userRepository->find($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($user->root_admin || $server->owner_id === $user->id) {
|
$keys = $server->relationLoaded('keys') ? $server->keys : $this->daemonKeyRepository->getServerKeys($server->id);
|
||||||
return $server->daemonSecret;
|
|
||||||
|
$key = array_get($keys->where('user_id', $user->id)->first(null, []), 'secret');
|
||||||
|
if ($user->root_admin) {
|
||||||
|
$key = array_get($keys->where('user_id', $server->owner_id)->first(null, []), 'secret');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! in_array($server->id, $this->repository->getUserAccessServers($user->id))) {
|
if (is_null($key)) {
|
||||||
throw new UserNotLinkedToServerException;
|
throw new UserNotLinkedToServerException;
|
||||||
}
|
}
|
||||||
|
|
||||||
$subuser = $this->subuserRepository->withColumns('daemonSecret')->findWhere([
|
return $key;
|
||||||
['user_id', '=', $user->id],
|
|
||||||
['server_id', '=', $server->id],
|
|
||||||
]);
|
|
||||||
|
|
||||||
return $subuser->daemonSecret;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
82
app/Transformers/Daemon/ApiKeyTransformer.php
Normal file
82
app/Transformers/Daemon/ApiKeyTransformer.php
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Pterodactyl - Panel
|
||||||
|
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Pterodactyl\Transformers\Daemon;
|
||||||
|
|
||||||
|
use Pterodactyl\Models\DaemonKey;
|
||||||
|
use Pterodactyl\Models\Permission;
|
||||||
|
use League\Fractal\TransformerAbstract;
|
||||||
|
use Pterodactyl\Contracts\Repository\SubuserRepositoryInterface;
|
||||||
|
|
||||||
|
class ApiKeyTransformer extends TransformerAbstract
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Contracts\Repository\SubuserRepositoryInterface
|
||||||
|
*/
|
||||||
|
protected $repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ApiKeyTransformer constructor.
|
||||||
|
*
|
||||||
|
* @param \Pterodactyl\Contracts\Repository\SubuserRepositoryInterface $repository
|
||||||
|
*/
|
||||||
|
public function __construct(SubuserRepositoryInterface $repository)
|
||||||
|
{
|
||||||
|
$this->repository = $repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a listing of servers that a daemon key can access.
|
||||||
|
*
|
||||||
|
* @param \Pterodactyl\Models\DaemonKey $key
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||||
|
*/
|
||||||
|
public function transform(DaemonKey $key)
|
||||||
|
{
|
||||||
|
if ($key->user_id === $key->server->owner_id) {
|
||||||
|
return [
|
||||||
|
'id' => $key->server->uuid,
|
||||||
|
'permissions' => ['s:*'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$subuser = $this->repository->getWithPermissionsUsingUserAndServer($key->user_id, $key->server_id);
|
||||||
|
|
||||||
|
$permissions = $subuser->permissions->pluck('permission')->toArray();
|
||||||
|
$mappings = Permission::getPermissions(true);
|
||||||
|
$daemonPermissions = [];
|
||||||
|
|
||||||
|
foreach ($permissions as $permission) {
|
||||||
|
if (! is_null($mappings[$permission])) {
|
||||||
|
$daemonPermissions[] = $mappings[$permission];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
$key->server->uuid => $daemonPermissions,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class CreateDaemonKeysTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('daemon_keys', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->unsignedInteger('server_id');
|
||||||
|
$table->unsignedInteger('user_id');
|
||||||
|
$table->string('secret')->unique();
|
||||||
|
$table->timestamp('expires_at');
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
$table->index(['server_id', 'user_id']);
|
||||||
|
$table->foreign('server_id')->references('id')->on('servers')->onDelete('cascade');
|
||||||
|
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('daemon_keys');
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class RemoveDaemonSecretFromServersTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$inserts = [];
|
||||||
|
|
||||||
|
$servers = DB::table('servers')->select('id', 'owner_id')->get();
|
||||||
|
$servers->each(function ($server) use (&$inserts) {
|
||||||
|
$inserts[] = [
|
||||||
|
'user_id' => $server->owner_id,
|
||||||
|
'server_id' => $server->id,
|
||||||
|
'secret' => 'i_' . str_random(40),
|
||||||
|
'expires_at' => Carbon::now()->addHours(24),
|
||||||
|
'created_at' => Carbon::now(),
|
||||||
|
'updated_at' => Carbon::now(),
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
DB::transaction(function () use ($inserts) {
|
||||||
|
DB::table('daemon_keys')->insert($inserts);
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('servers', function (Blueprint $table) {
|
||||||
|
$table->dropUnique(['daemonSecret']);
|
||||||
|
$table->dropColumn('daemonSecret');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('servers', function (Blueprint $table) {
|
||||||
|
$table->char('daemonSecret', 36)->after('startup')->unique();
|
||||||
|
});
|
||||||
|
|
||||||
|
DB::table('daemon_keys')->truncate();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class RemoveDaemonSecretFromSubusersTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$inserts = [];
|
||||||
|
$subusers = DB::table('subusers')->get();
|
||||||
|
$subusers->each(function ($subuser) use (&$inserts) {
|
||||||
|
$inserts[] = [
|
||||||
|
'user_id' => $subuser->user_id,
|
||||||
|
'server_id' => $subuser->server_id,
|
||||||
|
'secret' => 'i_' . str_random(40),
|
||||||
|
'expires_at' => Carbon::now()->addHours(24),
|
||||||
|
'created_at' => Carbon::now(),
|
||||||
|
'updated_at' => Carbon::now(),
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
DB::transaction(function () use ($inserts) {
|
||||||
|
DB::table('daemon_keys')->insert($inserts);
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('subusers', function (Blueprint $table) {
|
||||||
|
$table->dropUnique(['daemonSecret']);
|
||||||
|
$table->dropColumn('daemonSecret');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('subusers', function (Blueprint $table) {
|
||||||
|
$table->char('daemonSecret', 36)->after('server_id')->unique();
|
||||||
|
});
|
||||||
|
|
||||||
|
$subusers = DB::table('subusers')->get();
|
||||||
|
$subusers->each(function ($subuser) {
|
||||||
|
DB::table('daemon_keys')->delete($subuser->id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
24
routes/api-remote.php
Normal file
24
routes/api-remote.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Pterodactyl - Panel
|
||||||
|
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
Route::get('/authenticate/{token}', 'ValidateKeyController@index')->name('post.api.remote.authenticate');
|
Loading…
Reference in New Issue
Block a user