Very basic working implementation of sanctum for API validation
This commit is contained in:
parent
4b32828423
commit
d60e8a193b
23 changed files with 24212 additions and 88 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -77,3 +77,6 @@ yarn-error.log
|
||||||
!.env.example
|
!.env.example
|
||||||
.env*
|
.env*
|
||||||
*.log
|
*.log
|
||||||
|
_ide_helper_models.php
|
||||||
|
_ide_helper.php
|
||||||
|
.phpstorm.meta.php
|
||||||
|
|
2267
.phpstorm.meta.php
Normal file
2267
.phpstorm.meta.php
Normal file
File diff suppressed because it is too large
Load diff
20589
_ide_helper.php
Normal file
20589
_ide_helper.php
Normal file
File diff suppressed because it is too large
Load diff
1128
_ide_helper_models.php
Normal file
1128
_ide_helper_models.php
Normal file
File diff suppressed because it is too large
Load diff
|
@ -12,11 +12,14 @@ use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
|
||||||
use Pterodactyl\Transformers\Api\Client\ApiKeyTransformer;
|
use Pterodactyl\Transformers\Api\Client\ApiKeyTransformer;
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
use Pterodactyl\Http\Requests\Api\Client\Account\StoreApiKeyRequest;
|
use Pterodactyl\Http\Requests\Api\Client\Account\StoreApiKeyRequest;
|
||||||
|
use Pterodactyl\Transformers\Api\Client\PersonalAccessTokenTransformer;
|
||||||
|
|
||||||
class ApiKeyController extends ClientApiController
|
class ApiKeyController extends ClientApiController
|
||||||
{
|
{
|
||||||
private Encrypter $encrypter;
|
private Encrypter $encrypter;
|
||||||
|
|
||||||
private ApiKeyRepository $repository;
|
private ApiKeyRepository $repository;
|
||||||
|
|
||||||
private KeyCreationService $keyCreationService;
|
private KeyCreationService $keyCreationService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,8 +44,8 @@ class ApiKeyController extends ClientApiController
|
||||||
*/
|
*/
|
||||||
public function index(ClientApiRequest $request): array
|
public function index(ClientApiRequest $request): array
|
||||||
{
|
{
|
||||||
return $this->fractal->collection($request->user()->apiKeys)
|
return $this->fractal->collection($request->user()->tokens)
|
||||||
->transformWith($this->getTransformer(ApiKeyTransformer::class))
|
->transformWith($this->getTransformer(PersonalAccessTokenTransformer::class))
|
||||||
->toArray();
|
->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,25 +53,22 @@ class ApiKeyController extends ClientApiController
|
||||||
* Store a new API key for a user's account.
|
* Store a new API key for a user's account.
|
||||||
*
|
*
|
||||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
|
||||||
* @throws \Illuminate\Contracts\Container\BindingResolutionException
|
* @throws \Illuminate\Contracts\Container\BindingResolutionException
|
||||||
*/
|
*/
|
||||||
public function store(StoreApiKeyRequest $request): array
|
public function store(StoreApiKeyRequest $request): array
|
||||||
{
|
{
|
||||||
if ($request->user()->apiKeys->count() >= 5) {
|
if ($request->user()->tokens->count() >= 10) {
|
||||||
throw new DisplayException('You have reached the account limit for number of API keys.');
|
throw new DisplayException('You have reached the account limit for number of API keys.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$key = $this->keyCreationService->setKeyType(ApiKey::TYPE_ACCOUNT)->handle([
|
// TODO: this should accept an array of different scopes to apply as permissions
|
||||||
'user_id' => $request->user()->id,
|
// for the token. Right now it allows any account level permission.
|
||||||
'memo' => $request->input('description'),
|
$token = $request->user()->createToken($request->input('description'));
|
||||||
'allowed_ips' => $request->input('allowed_ips') ?? [],
|
|
||||||
]);
|
|
||||||
|
|
||||||
return $this->fractal->item($key)
|
return $this->fractal->item($token->accessToken)
|
||||||
->transformWith($this->getTransformer(ApiKeyTransformer::class))
|
->transformWith($this->getTransformer(PersonalAccessTokenTransformer::class))
|
||||||
->addMeta([
|
->addMeta([
|
||||||
'secret_token' => $this->encrypter->decrypt($key->token),
|
'secret_token' => $token->plainTextToken,
|
||||||
])
|
])
|
||||||
->toArray();
|
->toArray();
|
||||||
}
|
}
|
||||||
|
@ -78,15 +78,7 @@ class ApiKeyController extends ClientApiController
|
||||||
*/
|
*/
|
||||||
public function delete(ClientApiRequest $request, string $identifier): Response
|
public function delete(ClientApiRequest $request, string $identifier): Response
|
||||||
{
|
{
|
||||||
$response = $this->repository->deleteWhere([
|
$request->user()->tokens()->where('id', $identifier)->delete();
|
||||||
'key_type' => ApiKey::TYPE_ACCOUNT,
|
|
||||||
'user_id' => $request->user()->id,
|
|
||||||
'identifier' => $identifier,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!$response) {
|
|
||||||
throw new NotFoundHttpException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->returnNoContent();
|
return $this->returnNoContent();
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ abstract class ClientApiController extends ApplicationApiController
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($transformer instanceof BaseClientTransformer) {
|
if ($transformer instanceof BaseClientTransformer) {
|
||||||
$transformer->setKey($this->request->attributes->get('api_key'));
|
// $transformer->setKey($this->request->attributes->get('api_key'));
|
||||||
$transformer->setUser($this->request->user());
|
$transformer->setUser($this->request->user());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,8 +123,6 @@ class LoginController extends AbstractLoginController
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->auth->guard()->login($user, true);
|
|
||||||
|
|
||||||
return $this->sendLoginResponse($user, $request);
|
return $this->sendLoginResponse($user, $request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,9 @@ use Pterodactyl\Http\Middleware\Api\Daemon\DaemonAuthenticate;
|
||||||
use Pterodactyl\Http\Middleware\RequireTwoFactorAuthentication;
|
use Pterodactyl\Http\Middleware\RequireTwoFactorAuthentication;
|
||||||
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode;
|
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode;
|
||||||
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
|
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
|
||||||
|
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
|
||||||
use Pterodactyl\Http\Middleware\Api\Client\SubstituteClientApiBindings;
|
use Pterodactyl\Http\Middleware\Api\Client\SubstituteClientApiBindings;
|
||||||
|
use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance;
|
||||||
use Pterodactyl\Http\Middleware\Api\Application\AuthenticateApplicationUser;
|
use Pterodactyl\Http\Middleware\Api\Application\AuthenticateApplicationUser;
|
||||||
|
|
||||||
class Kernel extends HttpKernel
|
class Kernel extends HttpKernel
|
||||||
|
@ -43,12 +45,11 @@ class Kernel extends HttpKernel
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $middleware = [
|
protected $middleware = [
|
||||||
CheckForMaintenanceMode::class,
|
TrustProxies::class,
|
||||||
EncryptCookies::class,
|
PreventRequestsDuringMaintenance::class,
|
||||||
ValidatePostSize::class,
|
ValidatePostSize::class,
|
||||||
TrimStrings::class,
|
TrimStrings::class,
|
||||||
ConvertEmptyStringsToNull::class,
|
ConvertEmptyStringsToNull::class,
|
||||||
TrustProxies::class,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,6 +59,7 @@ class Kernel extends HttpKernel
|
||||||
*/
|
*/
|
||||||
protected $middlewareGroups = [
|
protected $middlewareGroups = [
|
||||||
'web' => [
|
'web' => [
|
||||||
|
EncryptCookies::class,
|
||||||
AddQueuedCookiesToResponse::class,
|
AddQueuedCookiesToResponse::class,
|
||||||
StartSession::class,
|
StartSession::class,
|
||||||
AuthenticateSession::class,
|
AuthenticateSession::class,
|
||||||
|
@ -70,19 +72,23 @@ class Kernel extends HttpKernel
|
||||||
'api' => [
|
'api' => [
|
||||||
IsValidJson::class,
|
IsValidJson::class,
|
||||||
ApiSubstituteBindings::class,
|
ApiSubstituteBindings::class,
|
||||||
SetSessionDriver::class,
|
EnsureFrontendRequestsAreStateful::class,
|
||||||
'api..key:' . ApiKey::TYPE_APPLICATION,
|
// SetSessionDriver::class,
|
||||||
|
// 'api..key:' . ApiKey::TYPE_APPLICATION,
|
||||||
AuthenticateApplicationUser::class,
|
AuthenticateApplicationUser::class,
|
||||||
AuthenticateIPAccess::class,
|
// AuthenticateIPAccess::class,
|
||||||
],
|
],
|
||||||
'client-api' => [
|
'client-api' => [
|
||||||
StartSession::class,
|
// StartSession::class,
|
||||||
SetSessionDriver::class,
|
// SetSessionDriver::class,
|
||||||
AuthenticateSession::class,
|
// AuthenticateSession::class,
|
||||||
IsValidJson::class,
|
IsValidJson::class,
|
||||||
|
EnsureFrontendRequestsAreStateful::class,
|
||||||
|
'auth:sanctum',
|
||||||
|
// 'throttle:api',
|
||||||
SubstituteClientApiBindings::class,
|
SubstituteClientApiBindings::class,
|
||||||
'api..key:' . ApiKey::TYPE_ACCOUNT,
|
// 'api..key:' . ApiKey::TYPE_ACCOUNT,
|
||||||
AuthenticateIPAccess::class,
|
// AuthenticateIPAccess::class,
|
||||||
// This is perhaps a little backwards with the Client API, but logically you'd be unable
|
// This is perhaps a little backwards with the Client API, but logically you'd be unable
|
||||||
// to create/get an API key without first enabling 2FA on the account, so I suppose in the
|
// to create/get an API key without first enabling 2FA on the account, so I suppose in the
|
||||||
// end it makes sense.
|
// end it makes sense.
|
||||||
|
|
|
@ -14,6 +14,6 @@ class VerifyCsrfToken extends BaseVerifier
|
||||||
protected $except = [
|
protected $except = [
|
||||||
'remote/*',
|
'remote/*',
|
||||||
'daemon/*',
|
'daemon/*',
|
||||||
'api/*',
|
// 'api/*',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,18 +4,6 @@ namespace Pterodactyl\Models;
|
||||||
|
|
||||||
use Pterodactyl\Services\Acl\Api\AdminAcl;
|
use Pterodactyl\Services\Acl\Api\AdminAcl;
|
||||||
|
|
||||||
/**
|
|
||||||
* @property int $id
|
|
||||||
* @property int $user_id
|
|
||||||
* @property int $key_type
|
|
||||||
* @property string $identifier
|
|
||||||
* @property string $token
|
|
||||||
* @property array $allowed_ips
|
|
||||||
* @property string $memo
|
|
||||||
* @property \Carbon\Carbon|null $last_used_at
|
|
||||||
* @property \Carbon\Carbon $created_at
|
|
||||||
* @property \Carbon\Carbon $updated_at
|
|
||||||
*/
|
|
||||||
class ApiKey extends Model
|
class ApiKey extends Model
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
10
app/Models/PersonalAccessToken.php
Normal file
10
app/Models/PersonalAccessToken.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pterodactyl\Models;
|
||||||
|
|
||||||
|
use Laravel\Sanctum\PersonalAccessToken as SanctumPersonalAccessToken;
|
||||||
|
|
||||||
|
class PersonalAccessToken extends SanctumPersonalAccessToken
|
||||||
|
{
|
||||||
|
public const RESOURCE_NAME = 'personal_access_token';
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
namespace Pterodactyl\Models;
|
namespace Pterodactyl\Models;
|
||||||
|
|
||||||
use Pterodactyl\Rules\Username;
|
use Pterodactyl\Rules\Username;
|
||||||
|
use Laravel\Sanctum\HasApiTokens;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Auth\Authenticatable;
|
use Illuminate\Auth\Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
@ -12,36 +13,12 @@ use Pterodactyl\Traits\Helpers\AvailableLanguages;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||||
use Illuminate\Foundation\Auth\Access\Authorizable;
|
use Illuminate\Foundation\Auth\Access\Authorizable;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
|
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
|
||||||
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
|
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
|
||||||
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
|
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
|
||||||
use Pterodactyl\Notifications\SendPasswordReset as ResetPasswordNotification;
|
use Pterodactyl\Notifications\SendPasswordReset as ResetPasswordNotification;
|
||||||
|
|
||||||
/**
|
|
||||||
* @property int $id
|
|
||||||
* @property string|null $external_id
|
|
||||||
* @property string $uuid
|
|
||||||
* @property string $username
|
|
||||||
* @property string $email
|
|
||||||
* @property string $password
|
|
||||||
* @property string|null $remember_token
|
|
||||||
* @property string $language
|
|
||||||
* @property int $admin_role_id
|
|
||||||
* @property bool $root_admin
|
|
||||||
* @property bool $use_totp
|
|
||||||
* @property string|null $totp_secret
|
|
||||||
* @property \Carbon\Carbon|null $totp_authenticated_at
|
|
||||||
* @property bool $gravatar
|
|
||||||
* @property \Carbon\Carbon $created_at
|
|
||||||
* @property \Carbon\Carbon $updated_at
|
|
||||||
* @property string $name
|
|
||||||
* @property \Pterodactyl\Models\AdminRole $adminRole
|
|
||||||
* @property \Pterodactyl\Models\ApiKey[]|\Illuminate\Database\Eloquent\Collection $apiKeys
|
|
||||||
* @property \Pterodactyl\Models\Server[]|\Illuminate\Database\Eloquent\Collection $servers
|
|
||||||
* @property \Pterodactyl\Models\UserSSHKey|\Illuminate\Database\Eloquent\Collection $sshKeys
|
|
||||||
* @property \Pterodactyl\Models\RecoveryToken[]|\Illuminate\Database\Eloquent\Collection $recoveryTokens
|
|
||||||
* @property \Pterodactyl\Models\WebauthnKey[]|\Illuminate\Database\Eloquent\Collection $webauthnKeys
|
|
||||||
*/
|
|
||||||
class User extends Model implements
|
class User extends Model implements
|
||||||
AuthenticatableContract,
|
AuthenticatableContract,
|
||||||
AuthorizableContract,
|
AuthorizableContract,
|
||||||
|
@ -51,6 +28,8 @@ class User extends Model implements
|
||||||
use Authorizable;
|
use Authorizable;
|
||||||
use AvailableLanguages;
|
use AvailableLanguages;
|
||||||
use CanResetPassword;
|
use CanResetPassword;
|
||||||
|
use HasApiTokens;
|
||||||
|
use HasFactory;
|
||||||
use Notifiable;
|
use Notifiable;
|
||||||
|
|
||||||
public const USER_LEVEL_USER = 0;
|
public const USER_LEVEL_USER = 0;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace Pterodactyl\Providers;
|
namespace Pterodactyl\Providers;
|
||||||
|
|
||||||
use Pterodactyl\Models\User;
|
use Pterodactyl\Models\User;
|
||||||
|
use Laravel\Sanctum\Sanctum;
|
||||||
use Pterodactyl\Models\Server;
|
use Pterodactyl\Models\Server;
|
||||||
use Pterodactyl\Models\Subuser;
|
use Pterodactyl\Models\Subuser;
|
||||||
use Illuminate\Support\Facades\Schema;
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
@ -10,6 +11,7 @@ use Illuminate\Support\ServiceProvider;
|
||||||
use Pterodactyl\Observers\UserObserver;
|
use Pterodactyl\Observers\UserObserver;
|
||||||
use Pterodactyl\Observers\ServerObserver;
|
use Pterodactyl\Observers\ServerObserver;
|
||||||
use Pterodactyl\Observers\SubuserObserver;
|
use Pterodactyl\Observers\SubuserObserver;
|
||||||
|
use Pterodactyl\Models\PersonalAccessToken;
|
||||||
|
|
||||||
class AppServiceProvider extends ServiceProvider
|
class AppServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
|
@ -23,6 +25,11 @@ class AppServiceProvider extends ServiceProvider
|
||||||
User::observe(UserObserver::class);
|
User::observe(UserObserver::class);
|
||||||
Server::observe(ServerObserver::class);
|
Server::observe(ServerObserver::class);
|
||||||
Subuser::observe(SubuserObserver::class);
|
Subuser::observe(SubuserObserver::class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://laravel.com/docs/8.x/sanctum#overriding-default-models
|
||||||
|
*/
|
||||||
|
Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -48,7 +48,7 @@ class RouteServiceProvider extends ServiceProvider
|
||||||
->group(base_path('routes/api-application.php'));
|
->group(base_path('routes/api-application.php'));
|
||||||
|
|
||||||
Route::middleware([
|
Route::middleware([
|
||||||
sprintf('throttle:%s,%s', config('http.rate_limit.client'), config('http.rate_limit.client_period')),
|
//sprintf('throttle:%s,%s', config('http.rate_limit.client'), config('http.rate_limit.client_period')),
|
||||||
'client-api',
|
'client-api',
|
||||||
])->prefix('/api/client')
|
])->prefix('/api/client')
|
||||||
->namespace($this->namespace . '\Api\Client')
|
->namespace($this->namespace . '\Api\Client')
|
||||||
|
|
|
@ -84,11 +84,12 @@ abstract class BaseTransformer extends TransformerAbstract
|
||||||
*/
|
*/
|
||||||
protected function authorize(string $resource): bool
|
protected function authorize(string $resource): bool
|
||||||
{
|
{
|
||||||
if ($this->getKey()->key_type === ApiKey::TYPE_ACCOUNT && $this->isRootAdmin()) {
|
return true;
|
||||||
return true;
|
// if ($this->getKey()->key_type === ApiKey::TYPE_ACCOUNT && $this->isRootAdmin()) {
|
||||||
}
|
// return true;
|
||||||
|
// }
|
||||||
return AdminAcl::check($this->getKey(), $resource, AdminAcl::READ);
|
//
|
||||||
|
// return AdminAcl::check($this->getKey(), $resource, AdminAcl::READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -104,7 +105,7 @@ abstract class BaseTransformer extends TransformerAbstract
|
||||||
{
|
{
|
||||||
/** @var \Pterodactyl\Transformers\Api\Application\BaseTransformer $transformer */
|
/** @var \Pterodactyl\Transformers\Api\Application\BaseTransformer $transformer */
|
||||||
$transformer = Container::getInstance()->makeWith($abstract, $parameters);
|
$transformer = Container::getInstance()->makeWith($abstract, $parameters);
|
||||||
$transformer->setKey($this->getKey());
|
// $transformer->setKey($this->getKey());
|
||||||
|
|
||||||
if (!$transformer instanceof self) {
|
if (!$transformer instanceof self) {
|
||||||
throw new InvalidTransformerLevelException('Calls to ' . __METHOD__ . ' must return a transformer that is an instance of ' . __CLASS__);
|
throw new InvalidTransformerLevelException('Calls to ' . __METHOD__ . ' must return a transformer that is an instance of ' . __CLASS__);
|
||||||
|
|
|
@ -58,7 +58,7 @@ abstract class BaseClientTransformer extends BaseApplicationTransformer
|
||||||
{
|
{
|
||||||
/** @var \Pterodactyl\Transformers\Api\Application\BaseTransformer $transformer */
|
/** @var \Pterodactyl\Transformers\Api\Application\BaseTransformer $transformer */
|
||||||
$transformer = Container::getInstance()->makeWith($abstract, $parameters);
|
$transformer = Container::getInstance()->makeWith($abstract, $parameters);
|
||||||
$transformer->setKey($this->getKey());
|
// $transformer->setKey($this->getKey());
|
||||||
|
|
||||||
if (!$transformer instanceof self) {
|
if (!$transformer instanceof self) {
|
||||||
throw new InvalidTransformerLevelException('Calls to ' . __METHOD__ . ' must return a transformer that is an instance of ' . __CLASS__);
|
throw new InvalidTransformerLevelException('Calls to ' . __METHOD__ . ' must return a transformer that is an instance of ' . __CLASS__);
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pterodactyl\Transformers\Api\Client;
|
||||||
|
|
||||||
|
use Pterodactyl\Models\PersonalAccessToken;
|
||||||
|
|
||||||
|
class PersonalAccessTokenTransformer extends BaseClientTransformer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getResourceName(): string
|
||||||
|
{
|
||||||
|
return PersonalAccessToken::RESOURCE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Pterodactyl\Models\PersonalAccessToken $model
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function transform(PersonalAccessToken $model): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $model->tokenable_id,
|
||||||
|
'name' => $model->name,
|
||||||
|
'abilities' => $model->abilities ?? [],
|
||||||
|
'last_used_at' => $model->last_used_at ? $model->last_used_at->toIso8601String() : null,
|
||||||
|
'created_at' => $model->created_at->toIso8601String(),
|
||||||
|
'updated_at' => $model->updated_at->toIso8601String(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,7 +38,8 @@ class ServerTransformer extends BaseClientTransformer
|
||||||
$service = Container::getInstance()->make(StartupCommandService::class);
|
$service = Container::getInstance()->make(StartupCommandService::class);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'server_owner' => $this->getKey()->user_id === $server->owner_id,
|
'server_owner' => true,
|
||||||
|
// 'server_owner' => $this->getKey()->user_id === $server->owner_id,
|
||||||
'identifier' => $server->uuidShort,
|
'identifier' => $server->uuidShort,
|
||||||
'internal_id' => $server->id,
|
'internal_id' => $server->id,
|
||||||
'uuid' => $server->uuid,
|
'uuid' => $server->uuid,
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
"laracasts/utilities": "^3.2",
|
"laracasts/utilities": "^3.2",
|
||||||
"laravel/framework": "^8.52",
|
"laravel/framework": "^8.52",
|
||||||
"laravel/helpers": "^1.4",
|
"laravel/helpers": "^1.4",
|
||||||
|
"laravel/sanctum": "^2.11",
|
||||||
"laravel/tinker": "^2.6",
|
"laravel/tinker": "^2.6",
|
||||||
"laravel/ui": "^3.3",
|
"laravel/ui": "^3.3",
|
||||||
"lcobucci/jwt": "^4.1",
|
"lcobucci/jwt": "^4.1",
|
||||||
|
|
33
config/cors.php
Normal file
33
config/cors.php
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Cross-Origin Resource Sharing (CORS) Configuration
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may configure your settings for cross-origin resource sharing
|
||||||
|
| or "CORS". This determines what cross-origin operations may execute
|
||||||
|
| in web browsers. You are free to adjust these settings as needed.
|
||||||
|
|
|
||||||
|
| To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'paths' => ['api/*'],
|
||||||
|
|
||||||
|
'allowed_methods' => ['*'],
|
||||||
|
|
||||||
|
'allowed_origins' => ['*'],
|
||||||
|
|
||||||
|
'allowed_origins_patterns' => [],
|
||||||
|
|
||||||
|
'allowed_headers' => ['*'],
|
||||||
|
|
||||||
|
'exposed_headers' => [],
|
||||||
|
|
||||||
|
'max_age' => 7200,
|
||||||
|
|
||||||
|
'supports_credentials' => true,
|
||||||
|
];
|
51
config/sanctum.php
Normal file
51
config/sanctum.php
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Stateful Domains
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Requests from the following domains / hosts will receive stateful API
|
||||||
|
| authentication cookies. Typically, these should include your local
|
||||||
|
| and production domains which access your API via a frontend SPA.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
|
||||||
|
'%s%s',
|
||||||
|
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1,pterodactyl.test',
|
||||||
|
env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
|
||||||
|
))),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Expiration Minutes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value controls the number of minutes until an issued token will be
|
||||||
|
| considered expired. If this value is null, personal access tokens do
|
||||||
|
| not expire. This won't tweak the lifetime of first-party sessions.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'expiration' => null,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Sanctum Middleware
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When authenticating your first-party SPA with Sanctum you may need to
|
||||||
|
| customize some of the middleware Sanctum uses while processing the
|
||||||
|
| request. You may change the middleware listed below as required.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'middleware' => [
|
||||||
|
'verify_csrf_token' => Pterodactyl\Http\Middleware\VerifyCsrfToken::class,
|
||||||
|
'encrypt_cookies' => Pterodactyl\Http\Middleware\EncryptCookies::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class CreatePersonalAccessTokensTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('personal_access_tokens', function (Blueprint $table) {
|
||||||
|
$table->bigIncrements('id');
|
||||||
|
$table->morphs('tokenable');
|
||||||
|
$table->string('name');
|
||||||
|
$table->string('token', 64)->unique();
|
||||||
|
$table->text('abilities')->nullable();
|
||||||
|
$table->timestamp('last_used_at')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('personal_access_tokens');
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use Pterodactyl\Http\Controllers\Api\Client;
|
||||||
use Pterodactyl\Http\Middleware\RequireTwoFactorAuthentication;
|
use Pterodactyl\Http\Middleware\RequireTwoFactorAuthentication;
|
||||||
use Pterodactyl\Http\Middleware\Api\Client\Server\ResourceBelongsToServer;
|
use Pterodactyl\Http\Middleware\Api\Client\Server\ResourceBelongsToServer;
|
||||||
use Pterodactyl\Http\Middleware\Api\Client\Server\AuthenticateServerAccess;
|
use Pterodactyl\Http\Middleware\Api\Client\Server\AuthenticateServerAccess;
|
||||||
|
|
||||||
use Pterodactyl\Http\Controllers\Api\Client;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Client Control API
|
| Client Control API
|
||||||
|
@ -27,9 +26,9 @@ Route::group(['prefix' => '/account'], function () {
|
||||||
Route::put('/email', 'AccountController@updateEmail')->name('api:client.account.update-email');
|
Route::put('/email', 'AccountController@updateEmail')->name('api:client.account.update-email');
|
||||||
Route::put('/password', 'AccountController@updatePassword')->name('api:client.account.update-password');
|
Route::put('/password', 'AccountController@updatePassword')->name('api:client.account.update-password');
|
||||||
|
|
||||||
Route::get('/api-keys', 'ApiKeyController@index');
|
Route::get('/api-keys', [Client\ApiKeyController::class, 'index']);
|
||||||
Route::post('/api-keys', 'ApiKeyController@store');
|
Route::post('/api-keys', [Client\ApiKeyController::class, 'store']);
|
||||||
Route::delete('/api-keys/{identifier}', 'ApiKeyController@delete');
|
Route::delete('/api-keys/{identifier}', [Client\ApiKeyController::class, 'delete']);
|
||||||
|
|
||||||
Route::get('/webauthn', 'WebauthnController@index')->withoutMiddleware(RequireTwoFactorAuthentication::class);
|
Route::get('/webauthn', 'WebauthnController@index')->withoutMiddleware(RequireTwoFactorAuthentication::class);
|
||||||
Route::get('/webauthn/register', 'WebauthnController@register')->withoutMiddleware(RequireTwoFactorAuthentication::class);
|
Route::get('/webauthn/register', 'WebauthnController@register')->withoutMiddleware(RequireTwoFactorAuthentication::class);
|
||||||
|
@ -49,7 +48,10 @@ Route::group(['prefix' => '/account'], function () {
|
||||||
| Endpoint: /api/client/servers/{server}
|
| Endpoint: /api/client/servers/{server}
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
Route::group(['prefix' => '/servers/{server}', 'middleware' => [AuthenticateServerAccess::class, ResourceBelongsToServer::class]], function () {
|
Route::group([
|
||||||
|
'prefix' => '/servers/{server}',
|
||||||
|
'middleware' => [AuthenticateServerAccess::class, ResourceBelongsToServer::class],
|
||||||
|
], function () {
|
||||||
Route::get('/', 'Servers\ServerController@index')->name('api:client:server.view');
|
Route::get('/', 'Servers\ServerController@index')->name('api:client:server.view');
|
||||||
Route::get('/websocket', 'Servers\WebsocketController')->name('api:client:server.ws');
|
Route::get('/websocket', 'Servers\WebsocketController')->name('api:client:server.ws');
|
||||||
Route::get('/resources', 'Servers\ResourceUtilizationController')->name('api:client:server.resources');
|
Route::get('/resources', 'Servers\ResourceUtilizationController')->name('api:client:server.resources');
|
||||||
|
|
Loading…
Reference in a new issue