diff --git a/app/Http/Controllers/API/User/CoreController.php b/app/Http/Controllers/API/User/CoreController.php
index 926cb3a62..5c1d07406 100644
--- a/app/Http/Controllers/API/User/CoreController.php
+++ b/app/Http/Controllers/API/User/CoreController.php
@@ -39,7 +39,7 @@ class CoreController extends Controller
*/
public function index(Request $request)
{
- $this->authorize('user-server-list', $request->apiKey());
+ $this->authorize('user.server-list', $request->apiKey());
$servers = $request->user()->access('service', 'node', 'allocation', 'option')->get();
diff --git a/app/Http/Controllers/API/User/ServerController.php b/app/Http/Controllers/API/User/ServerController.php
index 32f18eb2f..4064ad8c1 100644
--- a/app/Http/Controllers/API/User/ServerController.php
+++ b/app/Http/Controllers/API/User/ServerController.php
@@ -43,7 +43,7 @@ class ServerController extends Controller
*/
public function index(Request $request, $uuid)
{
- $this->authorize('user-server-view', $request->apiKey());
+ $this->authorize('user.server-view', $request->apiKey());
$server = Server::byUuid($uuid);
$fractal = Fractal::create()->item($server);
@@ -66,7 +66,7 @@ class ServerController extends Controller
*/
public function power(Request $request, $uuid)
{
- $this->authorize('user-server-power', $request->apiKey());
+ $this->authorize('user.server-power', $request->apiKey());
$server = Server::byUuid($uuid);
$request->user()->can('power-' . $request->input('action'), $server);
@@ -86,7 +86,7 @@ class ServerController extends Controller
*/
public function command(Request $request, $uuid)
{
- $this->authorize('user-server-command', $request->apiKey());
+ $this->authorize('user.server-command', $request->apiKey());
$server = Server::byUuid($uuid);
$request->user()->can('send-command', $server);
diff --git a/app/Http/Controllers/Base/APIController.php b/app/Http/Controllers/Base/APIController.php
index bc0ce7be4..9c3816db3 100644
--- a/app/Http/Controllers/Base/APIController.php
+++ b/app/Http/Controllers/Base/APIController.php
@@ -27,8 +27,9 @@ namespace Pterodactyl\Http\Controllers\Base;
use Log;
use Alert;
-use Pterodactyl\Models;
use Illuminate\Http\Request;
+use Pterodactyl\Models\APIKey;
+use Pterodactyl\Models\APIPermission;
use Pterodactyl\Repositories\APIRepository;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Http\Controllers\Controller;
@@ -45,7 +46,7 @@ class APIController extends Controller
public function index(Request $request)
{
return view('base.api.index', [
- 'keys' => Models\APIKey::where('user_id', $request->user()->id)->get(),
+ 'keys' => APIKey::where('user_id', $request->user()->id)->get(),
]);
}
@@ -57,7 +58,12 @@ class APIController extends Controller
*/
public function create(Request $request)
{
- return view('base.api.new');
+ return view('base.api.new', [
+ 'permissions' => [
+ 'user' => collect(APIPermission::permissions())->pull('_user'),
+ 'admin' => collect(APIPermission::permissions())->except('_user')->toArray(),
+ ],
+ ]);
}
/**
@@ -66,13 +72,13 @@ class APIController extends Controller
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*/
- public function save(Request $request)
+ public function store(Request $request)
{
try {
$repo = new APIRepository($request->user());
$secret = $repo->create($request->intersect([
'memo', 'allowed_ips',
- 'adminPermissions', 'permissions',
+ 'admin_permissions', 'permissions',
]));
Alert::success('An API Key-Pair has successfully been generated. The API secret for this public key is shown below and will not be shown again.' . $secret . '
')->flash();
diff --git a/app/Models/APIPermission.php b/app/Models/APIPermission.php
index 7450392d8..67eec35be 100644
--- a/app/Models/APIPermission.php
+++ b/app/Models/APIPermission.php
@@ -77,16 +77,45 @@ class APIPermission extends Model
// All other pemissions below are administrative actions.
'server' => [
'list',
- 'view',
- 'delete',
'create',
+ 'view',
'edit-details',
'edit-container',
+ 'edit-build',
+ 'edit-startup',
'suspend',
'install',
'rebuild',
- 'edit-build',
- 'edit-startup',
+ 'delete',
+ ],
+ 'location' => [
+ 'list',
+ ],
+ 'node' => [
+ 'list',
+ 'view',
+ 'view-config',
+ 'create',
+ 'delete',
+ ],
+ 'user' => [
+ 'list',
+ 'view',
+ 'create',
+ 'edit',
+ 'delete',
+ ],
+ 'service' => [
+ 'list',
+ 'view',
+ ],
+ 'option' => [
+ 'list',
+ 'view',
+ ],
+ 'pack' => [
+ 'list',
+ 'view',
],
];
diff --git a/app/Policies/APIKeyPolicy.php b/app/Policies/APIKeyPolicy.php
index e946433e5..58b187b48 100644
--- a/app/Policies/APIKeyPolicy.php
+++ b/app/Policies/APIKeyPolicy.php
@@ -42,6 +42,11 @@ class APIKeyPolicy
*/
protected function checkPermission(User $user, Key $key, $permission)
{
+ // Non-administrative users cannot use administrative routes.
+ if (! starts_with('user.') && ! $user->isRootAdmin()) {
+ return false;
+ }
+
// We don't tag this cache key with the user uuid because the key is already unique,
// and multiple users are not defiend for a single key.
$permissions = Cache::remember('APIKeyPolicy.' . $key->public, Carbon::now()->addSeconds(5), function () use ($key) {
diff --git a/app/Repositories/APIRepository.php b/app/Repositories/APIRepository.php
index ff2c15c87..561266c3f 100644
--- a/app/Repositories/APIRepository.php
+++ b/app/Repositories/APIRepository.php
@@ -29,65 +29,14 @@ use Auth;
use Crypt;
use Validator;
use IPTools\Network;
-use Pterodactyl\Models;
+use Pterodactyl\Models\User;
+use Pterodactyl\Models\APIKey as Key;
+use Pterodactyl\Models\APIPermission as Permission;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Exceptions\DisplayValidationException;
class APIRepository
{
- /**
- * Valid API permissions.
- *
- * @var array
- */
- protected $permissions = [
- 'admin' => [
- '*',
-
- // User Management Routes
- 'users.list',
- 'users.create',
- 'users.view',
- 'users.update',
- 'users.delete',
-
- // Server Manaement Routes
- 'servers.list',
- 'servers.create',
- 'servers.view',
- 'servers.config',
- 'servers.build',
- 'servers.suspend',
- 'servers.unsuspend',
- 'servers.delete',
-
- // Node Management Routes
- 'nodes.list',
- 'nodes.view',
- 'nodes.create',
- 'nodes.allocations',
- 'nodes.delete',
-
- // Service Routes
- 'services.list',
- 'services.view',
-
- // Location Routes
- 'locations.list',
-
- ],
- 'user' => [
- '*',
-
- // Informational
- 'me',
-
- // Server Control
- 'server',
- 'server.power',
- ],
- ];
-
/**
* Holder for listing of allowed IPs when creating a new key.
*
@@ -108,11 +57,11 @@ class APIRepository
* @param null|\Pterodactyl\Models\User $user
* @return void
*/
- public function __construct(Models\User $user = null)
+ public function __construct(User $user = null)
{
$this->user = is_null($user) ? Auth::user() : $user;
if (is_null($this->user)) {
- throw new \Exception('Cannot access API Repository without passing a user to constructor.');
+ throw new \Exception('Unable to initialize user for API repository instance.');
}
}
@@ -129,8 +78,9 @@ class APIRepository
{
$validator = Validator::make($data, [
'memo' => 'string|max:500',
+ 'allowed_ips' => 'sometimes|string',
'permissions' => 'sometimes|required|array',
- 'adminPermissions' => 'sometimes|required|array',
+ 'admin_permissions' => 'sometimes|required|array',
]);
$validator->after(function ($validator) use ($data) {
@@ -156,8 +106,7 @@ class APIRepository
DB::beginTransaction();
try {
$secretKey = str_random(16) . '.' . str_random(7) . '.' . str_random(7);
- $key = new Models\APIKey;
- $key->fill([
+ $key = Key::create([
'user_id' => $this->user->id,
'public' => str_random(16),
'secret' => Crypt::encrypt($secretKey),
@@ -165,44 +114,61 @@ class APIRepository
'memo' => $data['memo'],
'expires_at' => null,
]);
- $key->save();
$totalPermissions = 0;
+ $pNodes = Permission::permissions();
+
if (isset($data['permissions'])) {
- foreach ($data['permissions'] as $permNode) {
- if (! strpos($permNode, ':')) {
+ foreach ($data['permissions'] as $permission) {
+ $parts = explode('-', $permission);
+
+ if (count($parts) !== 2) {
continue;
}
- list($toss, $permission) = explode(':', $permNode);
- if (in_array($permission, $this->permissions['user'])) {
- $totalPermissions++;
- $model = new Models\APIPermission;
- $model->fill([
- 'key_id' => $key->id,
- 'permission' => 'api.user.' . $permission,
- ]);
- $model->save();
+ list($block, $search) = $parts;
+
+ if (! array_key_exists($block, $pNodes['_user'])) {
+ continue;
}
+
+ if (! in_array($search, $pNodes['_user'][$block])) {
+ continue;
+ }
+
+ $totalPermissions++;
+ Permission::create([
+ 'key_id' => $key->id,
+ 'permission' => 'user.' . $permission,
+ ]);
}
}
- if ($this->user->isRootAdmin() && isset($data['adminPermissions'])) {
- foreach ($data['adminPermissions'] as $permNode) {
- if (! strpos($permNode, ':')) {
+ if ($this->user->isRootAdmin() && isset($data['admin_permissions'])) {
+ unset($pNodes['_user']);
+
+ foreach ($data['admin_permissions'] as $permNode) {
+ $parts = explode('-', $permission);
+
+ if (count($parts) !== 2) {
continue;
}
- list($toss, $permission) = explode(':', $permNode);
- if (in_array($permission, $this->permissions['admin'])) {
- $totalPermissions++;
- $model = new Models\APIPermission;
- $model->fill([
- 'key_id' => $key->id,
- 'permission' => 'api.admin.' . $permission,
- ]);
- $model->save();
+ list($block, $search) = $parts;
+
+ if (! array_key_exists($block, $pNodes)) {
+ continue;
}
+
+ if (! in_array($search, $pNodes[$block])) {
+ continue;
+ }
+
+ $totalPermissions++;
+ Permission::create([
+ 'key_id' => $key->id,
+ 'permission' => $permission,
+ ]);
}
}
@@ -229,20 +195,13 @@ class APIRepository
*/
public function revoke($key)
{
- DB::beginTransaction();
-
- try {
- $model = Models\APIKey::with('permissions')->where('public', $key)->where('user_id', $this->user->id)->firstOrFail();
+ DB::transaction(function () use ($key) {
+ $model = Key::with('permissions')->where('public', $key)->where('user_id', $this->user->id)->firstOrFail();
foreach ($model->permissions as &$permission) {
$permission->delete();
}
$model->delete();
-
- DB::commit();
- } catch (\Exception $ex) {
- DB::rollBack();
- throw $ex;
- }
+ });
}
}
diff --git a/resources/lang/en/base.php b/resources/lang/en/base.php
index 5d1a18cb2..ca5aa923c 100644
--- a/resources/lang/en/base.php
+++ b/resources/lang/en/base.php
@@ -46,122 +46,162 @@ return [
'title' => 'Allowed IPs',
'description' => 'Enter a line delimitated list of IPs that are allowed to access the API using this key. CIDR notation is allowed. Leave blank to allow any IP.',
],
- 'base' => [
- 'title' => 'Base Information',
- 'information' => [
- 'title' => 'Base Information',
- 'description' => 'Returns a listing of all servers that this account has access to.',
- ],
- ],
- 'user_management' => [
- 'title' => 'User Management',
- 'list' => [
- 'title' => 'List Users',
- 'description' => 'Allows listing of all users currently on the system.',
- ],
- 'create' => [
- 'title' => 'Create User',
- 'description' => 'Allows creating a new user on the system.',
- ],
- 'view' => [
- 'title' => 'List Single User',
- 'description' => 'Allows viewing details about a specific user including active services.',
- ],
- 'update' => [
- 'title' => 'Update User',
- 'description' => 'Allows modifying user details (email, password, TOTP information).',
- ],
- 'delete' => [
- 'title' => 'Delete User',
- 'description' => 'Allows deleting a user.',
- ],
- ],
- 'node_management' => [
- 'title' => 'Node Management',
- 'list' => [
- 'title' => 'List Nodes',
- 'description' => 'Allows listing of all nodes currently on the system.',
- ],
- 'create' => [
- 'title' => 'Create Node',
- 'description' => 'Allows creating a new node on the system.',
- ],
- 'view' => [
- 'title' => 'List Single Node',
- 'description' => 'Allows viewing details about a specific node including active services.',
- ],
- 'allocations' => [
- 'title' => 'List Allocations',
- 'description' => 'Allows viewing all allocations on the panel for all nodes.',
- ],
- 'delete' => [
- 'title' => 'Delete Node',
- 'description' => 'Allows deleting a node.',
- ],
- ],
- 'server_management' => [
- 'title' => 'Server Management',
+ ],
+ 'permissions' => [
+ 'user' => [
+ 'server_header' => 'User Server Permissions',
'server' => [
- 'title' => 'Server Info',
- 'description' => 'Allows access to viewing information about a single server including current stats and allocations.',
- ],
- 'power' => [
- 'title' => 'Server Power',
- 'description' => 'Allows access to control server power status.',
- ],
- 'command' => [
- 'title' => 'Send Command',
- 'description' => 'Allows a user to send a command to a specified server.',
- ],
- 'view' => [
- 'title' => 'Show Single Server',
- 'description' => 'Allows viewing details about a specific server including the daemon_token as well as current process information.',
- ],
- 'list' => [
- 'title' => 'List Servers',
- 'description' => 'Allows listing of all servers currently on the system.',
- ],
- 'create' => [
- 'title' => 'Create Server',
- 'description' => 'Allows creating a new server on the system.',
- ],
- 'config' => [
- 'title' => 'Update Configuration',
- 'description' => 'Allows modifying server config (name, owner, and access token).',
- ],
- 'build' => [
- 'title' => 'Update Build',
- 'description' => 'Allows modifying a server\'s build parameters such as memory, CPU, and disk space along with assigned and default IPs.',
- ],
- 'suspend' => [
- 'title' => 'Suspend Server',
- 'description' => 'Allows suspending a server instance.',
- ],
- 'unsuspend' => [
- 'title' => 'Unsuspend Server',
- 'description' => 'Allows unsuspending a server instance.',
- ],
- 'delete' => [
- 'title' => 'Delete Server',
- 'description' => 'Allows deleting a server.',
+ 'list' => [
+ 'title' => 'List Servers',
+ 'desc' => 'Allows listing of all servers a user owns or has access to as a subuser.',
+ ],
+ 'view' => [
+ 'title' => 'View Server',
+ 'desc'=> 'Allows viewing of specific server user can access.',
+ ],
+ 'power' => [
+ 'title' => 'Toggle Power',
+ 'desc'=> 'Allow toggling of power status for a server.',
+ ],
+ 'command' => [
+ 'title' => 'Send Command',
+ 'desc'=> 'Allow sending of a command to a running server.',
+ ],
],
],
- 'service_management' => [
- 'title' => 'Service Management',
- 'list' => [
- 'title' => 'List Services',
- 'description' => 'Allows listing of all services configured on the system.',
+ 'admin' => [
+ 'server_header' => 'Server Control',
+ 'server' => [
+ 'list' => [
+ 'title' => 'List Servers',
+ 'desc' => 'Allows listing of all servers currently on the system.',
+ ],
+ 'view' => [
+ 'title' => 'View Server',
+ 'desc' => 'Allows view of single server including service and details.',
+ ],
+ 'delete' => [
+ 'title' => 'Delete Server',
+ 'desc' => 'Allows deletion of a server from the system.',
+ ],
+ 'create' => [
+ 'title' => 'Create Server',
+ 'desc' => 'Allows creation of a new server on the system.',
+ ],
+ 'edit-details' => [
+ 'title' => 'Edit Server Details',
+ 'desc' => 'Allows editing of server details such as name, owner, description, and secret key.',
+ ],
+ 'edit-container' => [
+ 'title' => 'Edit Server Container',
+ 'desc' => 'Allows for modification of the docker container the server runs in.',
+ ],
+ 'suspend' => [
+ 'title' => 'Suspend Server',
+ 'desc' => 'Allows for the suspension and unsuspension of a given server.',
+ ],
+ 'install' => [
+ 'title' => 'Toggle Install Status',
+ 'desc' => '',
+ ],
+ 'rebuild' => [
+ 'title' => 'Rebuild Server',
+ 'desc' => '',
+ ],
+ 'edit-build' => [
+ 'title' => 'Edit Server Build',
+ 'desc' => 'Allows editing of server build setting such as CPU and memory allocations.',
+ ],
+ 'edit-startup' => [
+ 'title' => 'Edit Server Startup',
+ 'desc' => 'Allows modification of server startup commands and parameters.',
+ ],
],
- 'view' => [
- 'title' => 'List Single Service',
- 'description' => 'Allows listing details about each service on the system including service options and variables.',
+ 'location_header' => 'Location Control',
+ 'location' => [
+ 'list' => [
+ 'title' => 'List Locations',
+ 'desc' => 'Allows listing all locations and thier associated nodes.',
+ ],
],
- ],
- 'location_management' => [
- 'title' => 'Location Management',
- 'list' => [
- 'title' => 'List Locations',
- 'description' => 'Allows listing all locations and thier associated nodes.',
+ 'node_header' => 'Node Control',
+ 'node' => [
+ 'list' => [
+ 'title' => 'List Nodes',
+ 'desc' => 'Allows listing of all nodes currently on the system.',
+ ],
+ 'view' => [
+ 'title' => 'View Node',
+ 'desc' => 'llows viewing details about a specific node including active services.',
+ ],
+ 'view-config' => [
+ 'title' => 'View Node Configuration',
+ 'desc' => 'Danger. This allows the viewing of the node configuration file used by the daemon, and exposes secret daemon tokens.',
+ ],
+ 'create' => [
+ 'title' => 'Create Node',
+ 'desc' => 'Allows creating a new node on the system.',
+ ],
+ 'delete' => [
+ 'title' => 'Delete Node',
+ 'desc' => 'Allows deletion of a node from the system.',
+ ],
+ ],
+ 'user_header' => 'User Control',
+ 'user' => [
+ 'list' => [
+ 'title' => 'List Users',
+ 'desc' => 'Allows listing of all users currently on the system.',
+ ],
+ 'view' => [
+ 'title' => 'View User',
+ 'desc' => 'Allows viewing details about a specific user including active services.',
+ ],
+ 'create' => [
+ 'title' => 'Create User',
+ 'desc' => 'Allows creating a new user on the system.',
+ ],
+ 'edit' => [
+ 'title' => 'Update User',
+ 'desc' => 'Allows modification of user details.',
+ ],
+ 'delete' => [
+ 'title' => 'Delete User',
+ 'desc' => 'Allows deleting a user.',
+ ],
+ ],
+ 'service_header' => 'Service Control',
+ 'service' => [
+ 'list' => [
+ 'title' => 'List Services',
+ 'desc' => 'Allows listing of all services configured on the system.',
+ ],
+ 'view' => [
+ 'title' => 'View Service',
+ 'desc' => 'Allows listing details about each service on the system including service options and variables.',
+ ],
+ ],
+ 'option_header' => 'Option Control',
+ 'option' => [
+ 'list' => [
+ 'title' => 'List Options',
+ 'desc' => '',
+ ],
+ 'view' => [
+ 'title' => 'View Option',
+ 'desc' => '',
+ ],
+ ],
+ 'pack_header' => 'Pack Control',
+ 'pack' => [
+ 'list' => [
+ 'title' => 'List Packs',
+ 'desc' => '',
+ ],
+ 'view' => [
+ 'title' => 'View Pack',
+ 'desc' => '',
+ ],
],
],
],
diff --git a/resources/themes/pterodactyl/base/api/new.blade.php b/resources/themes/pterodactyl/base/api/new.blade.php
index be972d67a..8f8c90a22 100644
--- a/resources/themes/pterodactyl/base/api/new.blade.php
+++ b/resources/themes/pterodactyl/base/api/new.blade.php
@@ -47,8 +47,8 @@
@endsection
@section('content')
-
@lang('base.api.new.base.information.description')
+@lang('base.api.permissions.user.' . $block . '.' . $permission . '.desc')
+@lang('base.api.new.user_management.list.description')
-@lang('base.api.new.user_management.create.description')
-@lang('base.api.new.user_management.view.description')
-@lang('base.api.new.user_management.update.description')
-@lang('base.api.new.user_management.delete.description')
-@lang('base.api.new.node_management.list.description')
-@lang('base.api.new.node_management.create.description')
-@lang('base.api.new.node_management.view.description')
-@lang('base.api.new.node_management.allocations.description')
-@lang('base.api.new.node_management.delete.description')
-@lang('base.api.new.location_management.list.description')
-@lang('base.api.new.server_management.server.description')
-@lang('base.api.new.server_management.power.description')
-@lang('base.api.new.server_management.command.description')
-@lang('base.api.new.server_management.view.description')
-@lang('base.api.new.server_management.list.description')
-@lang('base.api.new.server_management.create.description')
-@lang('base.api.new.server_management.config.description')
-@lang('base.api.new.server_management.build.description')
-@lang('base.api.new.server_management.suspend.description')
-@lang('base.api.new.server_management.unsuspend.description')
-@lang('base.api.new.server_management.delete.description')
-@lang('base.api.permissions.admin.' . $block . '.' . $permission . '.desc')
@lang('base.api.new.service_management.list.description')
-@lang('base.api.new.service_management.view.description')
-