forked from Alex/Pterodactyl-Panel
Very basic working implementation of sanctum for API validation
This commit is contained in:
parent
4b32828423
commit
d60e8a193b
3
.gitignore
vendored
3
.gitignore
vendored
@ -77,3 +77,6 @@ yarn-error.log
|
||||
!.env.example
|
||||
.env*
|
||||
*.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 Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Account\StoreApiKeyRequest;
|
||||
use Pterodactyl\Transformers\Api\Client\PersonalAccessTokenTransformer;
|
||||
|
||||
class ApiKeyController extends ClientApiController
|
||||
{
|
||||
private Encrypter $encrypter;
|
||||
|
||||
private ApiKeyRepository $repository;
|
||||
|
||||
private KeyCreationService $keyCreationService;
|
||||
|
||||
/**
|
||||
@ -41,8 +44,8 @@ class ApiKeyController extends ClientApiController
|
||||
*/
|
||||
public function index(ClientApiRequest $request): array
|
||||
{
|
||||
return $this->fractal->collection($request->user()->apiKeys)
|
||||
->transformWith($this->getTransformer(ApiKeyTransformer::class))
|
||||
return $this->fractal->collection($request->user()->tokens)
|
||||
->transformWith($this->getTransformer(PersonalAccessTokenTransformer::class))
|
||||
->toArray();
|
||||
}
|
||||
|
||||
@ -50,25 +53,22 @@ class ApiKeyController extends ClientApiController
|
||||
* Store a new API key for a user's account.
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Illuminate\Contracts\Container\BindingResolutionException
|
||||
*/
|
||||
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.');
|
||||
}
|
||||
|
||||
$key = $this->keyCreationService->setKeyType(ApiKey::TYPE_ACCOUNT)->handle([
|
||||
'user_id' => $request->user()->id,
|
||||
'memo' => $request->input('description'),
|
||||
'allowed_ips' => $request->input('allowed_ips') ?? [],
|
||||
]);
|
||||
// TODO: this should accept an array of different scopes to apply as permissions
|
||||
// for the token. Right now it allows any account level permission.
|
||||
$token = $request->user()->createToken($request->input('description'));
|
||||
|
||||
return $this->fractal->item($key)
|
||||
->transformWith($this->getTransformer(ApiKeyTransformer::class))
|
||||
return $this->fractal->item($token->accessToken)
|
||||
->transformWith($this->getTransformer(PersonalAccessTokenTransformer::class))
|
||||
->addMeta([
|
||||
'secret_token' => $this->encrypter->decrypt($key->token),
|
||||
'secret_token' => $token->plainTextToken,
|
||||
])
|
||||
->toArray();
|
||||
}
|
||||
@ -78,15 +78,7 @@ class ApiKeyController extends ClientApiController
|
||||
*/
|
||||
public function delete(ClientApiRequest $request, string $identifier): Response
|
||||
{
|
||||
$response = $this->repository->deleteWhere([
|
||||
'key_type' => ApiKey::TYPE_ACCOUNT,
|
||||
'user_id' => $request->user()->id,
|
||||
'identifier' => $identifier,
|
||||
]);
|
||||
|
||||
if (!$response) {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
$request->user()->tokens()->where('id', $identifier)->delete();
|
||||
|
||||
return $this->returnNoContent();
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ abstract class ClientApiController extends ApplicationApiController
|
||||
]);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -123,8 +123,6 @@ class LoginController extends AbstractLoginController
|
||||
]);
|
||||
}
|
||||
|
||||
$this->auth->guard()->login($user, true);
|
||||
|
||||
return $this->sendLoginResponse($user, $request);
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,9 @@ use Pterodactyl\Http\Middleware\Api\Daemon\DaemonAuthenticate;
|
||||
use Pterodactyl\Http\Middleware\RequireTwoFactorAuthentication;
|
||||
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode;
|
||||
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
|
||||
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
|
||||
use Pterodactyl\Http\Middleware\Api\Client\SubstituteClientApiBindings;
|
||||
use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance;
|
||||
use Pterodactyl\Http\Middleware\Api\Application\AuthenticateApplicationUser;
|
||||
|
||||
class Kernel extends HttpKernel
|
||||
@ -43,12 +45,11 @@ class Kernel extends HttpKernel
|
||||
* @var array
|
||||
*/
|
||||
protected $middleware = [
|
||||
CheckForMaintenanceMode::class,
|
||||
EncryptCookies::class,
|
||||
TrustProxies::class,
|
||||
PreventRequestsDuringMaintenance::class,
|
||||
ValidatePostSize::class,
|
||||
TrimStrings::class,
|
||||
ConvertEmptyStringsToNull::class,
|
||||
TrustProxies::class,
|
||||
];
|
||||
|
||||
/**
|
||||
@ -58,6 +59,7 @@ class Kernel extends HttpKernel
|
||||
*/
|
||||
protected $middlewareGroups = [
|
||||
'web' => [
|
||||
EncryptCookies::class,
|
||||
AddQueuedCookiesToResponse::class,
|
||||
StartSession::class,
|
||||
AuthenticateSession::class,
|
||||
@ -70,19 +72,23 @@ class Kernel extends HttpKernel
|
||||
'api' => [
|
||||
IsValidJson::class,
|
||||
ApiSubstituteBindings::class,
|
||||
SetSessionDriver::class,
|
||||
'api..key:' . ApiKey::TYPE_APPLICATION,
|
||||
EnsureFrontendRequestsAreStateful::class,
|
||||
// SetSessionDriver::class,
|
||||
// 'api..key:' . ApiKey::TYPE_APPLICATION,
|
||||
AuthenticateApplicationUser::class,
|
||||
AuthenticateIPAccess::class,
|
||||
// AuthenticateIPAccess::class,
|
||||
],
|
||||
'client-api' => [
|
||||
StartSession::class,
|
||||
SetSessionDriver::class,
|
||||
AuthenticateSession::class,
|
||||
// StartSession::class,
|
||||
// SetSessionDriver::class,
|
||||
// AuthenticateSession::class,
|
||||
IsValidJson::class,
|
||||
EnsureFrontendRequestsAreStateful::class,
|
||||
'auth:sanctum',
|
||||
// 'throttle:api',
|
||||
SubstituteClientApiBindings::class,
|
||||
'api..key:' . ApiKey::TYPE_ACCOUNT,
|
||||
AuthenticateIPAccess::class,
|
||||
// 'api..key:' . ApiKey::TYPE_ACCOUNT,
|
||||
// AuthenticateIPAccess::class,
|
||||
// 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
|
||||
// end it makes sense.
|
||||
|
@ -14,6 +14,6 @@ class VerifyCsrfToken extends BaseVerifier
|
||||
protected $except = [
|
||||
'remote/*',
|
||||
'daemon/*',
|
||||
'api/*',
|
||||
// 'api/*',
|
||||
];
|
||||
}
|
||||
|
@ -4,18 +4,6 @@ namespace Pterodactyl\Models;
|
||||
|
||||
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
|
||||
{
|
||||
/**
|
||||
|
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;
|
||||
|
||||
use Pterodactyl\Rules\Username;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Auth\Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
@ -12,36 +13,12 @@ use Pterodactyl\Traits\Helpers\AvailableLanguages;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Foundation\Auth\Access\Authorizable;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
|
||||
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
|
||||
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
|
||||
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
|
||||
AuthenticatableContract,
|
||||
AuthorizableContract,
|
||||
@ -51,6 +28,8 @@ class User extends Model implements
|
||||
use Authorizable;
|
||||
use AvailableLanguages;
|
||||
use CanResetPassword;
|
||||
use HasApiTokens;
|
||||
use HasFactory;
|
||||
use Notifiable;
|
||||
|
||||
public const USER_LEVEL_USER = 0;
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace Pterodactyl\Providers;
|
||||
|
||||
use Pterodactyl\Models\User;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Models\Subuser;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
@ -10,6 +11,7 @@ use Illuminate\Support\ServiceProvider;
|
||||
use Pterodactyl\Observers\UserObserver;
|
||||
use Pterodactyl\Observers\ServerObserver;
|
||||
use Pterodactyl\Observers\SubuserObserver;
|
||||
use Pterodactyl\Models\PersonalAccessToken;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
@ -23,6 +25,11 @@ class AppServiceProvider extends ServiceProvider
|
||||
User::observe(UserObserver::class);
|
||||
Server::observe(ServerObserver::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'));
|
||||
|
||||
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',
|
||||
])->prefix('/api/client')
|
||||
->namespace($this->namespace . '\Api\Client')
|
||||
|
@ -84,11 +84,12 @@ abstract class BaseTransformer extends TransformerAbstract
|
||||
*/
|
||||
protected function authorize(string $resource): bool
|
||||
{
|
||||
if ($this->getKey()->key_type === ApiKey::TYPE_ACCOUNT && $this->isRootAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return AdminAcl::check($this->getKey(), $resource, AdminAcl::READ);
|
||||
return true;
|
||||
// if ($this->getKey()->key_type === ApiKey::TYPE_ACCOUNT && $this->isRootAdmin()) {
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// return AdminAcl::check($this->getKey(), $resource, AdminAcl::READ);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,7 +105,7 @@ abstract class BaseTransformer extends TransformerAbstract
|
||||
{
|
||||
/** @var \Pterodactyl\Transformers\Api\Application\BaseTransformer $transformer */
|
||||
$transformer = Container::getInstance()->makeWith($abstract, $parameters);
|
||||
$transformer->setKey($this->getKey());
|
||||
// $transformer->setKey($this->getKey());
|
||||
|
||||
if (!$transformer instanceof self) {
|
||||
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 */
|
||||
$transformer = Container::getInstance()->makeWith($abstract, $parameters);
|
||||
$transformer->setKey($this->getKey());
|
||||
// $transformer->setKey($this->getKey());
|
||||
|
||||
if (!$transformer instanceof self) {
|
||||
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);
|
||||
|
||||
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,
|
||||
'internal_id' => $server->id,
|
||||
'uuid' => $server->uuid,
|
||||
|
@ -26,6 +26,7 @@
|
||||
"laracasts/utilities": "^3.2",
|
||||
"laravel/framework": "^8.52",
|
||||
"laravel/helpers": "^1.4",
|
||||
"laravel/sanctum": "^2.11",
|
||||
"laravel/tinker": "^2.6",
|
||||
"laravel/ui": "^3.3",
|
||||
"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
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Pterodactyl\Http\Controllers\Api\Client;
|
||||
use Pterodactyl\Http\Middleware\RequireTwoFactorAuthentication;
|
||||
use Pterodactyl\Http\Middleware\Api\Client\Server\ResourceBelongsToServer;
|
||||
use Pterodactyl\Http\Middleware\Api\Client\Server\AuthenticateServerAccess;
|
||||
|
||||
use Pterodactyl\Http\Controllers\Api\Client;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 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('/password', 'AccountController@updatePassword')->name('api:client.account.update-password');
|
||||
|
||||
Route::get('/api-keys', 'ApiKeyController@index');
|
||||
Route::post('/api-keys', 'ApiKeyController@store');
|
||||
Route::delete('/api-keys/{identifier}', 'ApiKeyController@delete');
|
||||
Route::get('/api-keys', [Client\ApiKeyController::class, 'index']);
|
||||
Route::post('/api-keys', [Client\ApiKeyController::class, 'store']);
|
||||
Route::delete('/api-keys/{identifier}', [Client\ApiKeyController::class, 'delete']);
|
||||
|
||||
Route::get('/webauthn', 'WebauthnController@index')->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}
|
||||
|
|
||||
*/
|
||||
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('/websocket', 'Servers\WebsocketController')->name('api:client:server.ws');
|
||||
Route::get('/resources', 'Servers\ResourceUtilizationController')->name('api:client:server.resources');
|
||||
|
Loading…
Reference in New Issue
Block a user