Merge branch 'develop' into feature/option-scripts

# Conflicts:
#	app/Http/Routes/AdminRoutes.php
#	app/Http/Routes/DaemonRoutes.php
#	app/Models/ServiceOption.php
This commit is contained in:
Dane Everitt 2017-04-20 17:08:08 -04:00
commit 8d24e5f168
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
683 changed files with 8854 additions and 12362 deletions

View file

@ -29,99 +29,58 @@ use Auth;
use Crypt;
use Validator;
use IPTools\Network;
use Pterodactyl\Models;
use Pterodactyl\Models\User;
use Pterodactyl\Models\APIKey as Key;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Models\APIPermission as Permission;
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.
*
* @var array
*/
protected $allowed = [];
/**
* The eloquent model for a user.
*
* @var \Pterodactyl\Models\User
*/
protected $user;
/**
* Constructor.
* Constructor for API Repository.
*
* @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.');
}
}
/**
* Create a New API Keypair on the system.
*
* @param array $data An array with a permissions and allowed_ips key.
* @param array $data
* @return string
*
* @throws Pterodactyl\Exceptions\DisplayException if there was an error that can be safely displayed to end-users.
* @throws Pterodactyl\Exceptions\DisplayValidationException if there was a validation error.
*
* @return string Returns the generated secret token.
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function create(array $data)
{
$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) {
@ -147,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),
@ -156,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 $permission) {
$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,
]);
}
}
@ -213,28 +188,20 @@ class APIRepository
/**
* Revokes an API key and associated permissions.
*
* @param string $key The public key.
*
* @throws Illuminate\Database\Eloquent\ModelNotFoundException
*
* @param string $key
* @return void
*
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
*/
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;
}
});
}
}

View file

@ -24,44 +24,67 @@
namespace Pterodactyl\Repositories\Daemon;
use Pterodactyl\Models;
use GuzzleHttp\Exception\RequestException;
use Pterodactyl\Models\User;
use Pterodactyl\Models\Server;
use GuzzleHttp\Exception\ConnectException;
use Pterodactyl\Exceptions\DisplayException;
class CommandRepository
{
/**
* The Eloquent Model associated with the requested server.
*
* @var \Pterodactyl\Models\Server
*/
protected $server;
public function __construct($server)
/**
* The Eloquent Model associated with the user to run the request as.
*
* @var \Pterodactyl\Models\User|null
*/
protected $user;
/**
* Constuctor for repository.
*
* @param \Pterodactyl\Models\Server $server
* @param \Pterodactyl\Models\User|null $user
* @return void
*/
public function __construct(Server $server, User $user = null)
{
$this->server = ($server instanceof Models\Server) ? $server : Models\Server::findOrFail($server);
$this->server = $server;
$this->user = $user;
}
/**
* [send description].
* @param string $command
* @return bool
* @throws DisplayException
* @throws RequestException
* Sends a command to the daemon.
*
* @param string $command
* @return string
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \GuzzleHttp\Exception\RequestException
*/
public function send($command)
{
// We don't use the user's specific daemon secret here since we
// are assuming that a call to this function has been validated.
// Additionally not all calls to this will be from a logged in user.
// (e.g. task queue or API)
try {
$response = $this->server->node->guzzleClient([
'X-Access-Token' => $this->server->daemonSecret,
'X-Access-Server' => $this->server->uuid,
])->request('POST', '/server/command', ['json' => ['command' => $command]]);
$response = $this->server->guzzleClient($this->user)->request('POST', '/server/command', [
'http_errors' => false,
'json' => [
'command' => $command,
],
]);
if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) {
throw new DisplayException('Command sending responded with a non-200 error code.');
throw new DisplayException('Command sending responded with a non-200 error code (HTTP/' . $response->getStatusCode() . ').');
}
return $response->getBody();
} catch (\Exception $ex) {
} catch (ConnectException $ex) {
throw $ex;
}
}

View file

@ -35,14 +35,15 @@ class FileRepository
/**
* The Eloquent Model associated with the requested server.
*
* @var \Illuminate\Database\Eloquent\Model
* @var \Pterodactyl\Models\Server
*/
protected $server;
/**
* Constructor.
*
* @param string $server The server Short UUID
* @param string $uuid
* @return void
*/
public function __construct($uuid)
{
@ -52,8 +53,11 @@ class FileRepository
/**
* Get the contents of a requested file for the server.
*
* @param string $file
* @param string $file
* @return array
*
* @throws \GuzzleHttp\Exception\RequestException
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function returnFileContents($file)
{
@ -95,9 +99,12 @@ class FileRepository
/**
* Save the contents of a requested file on the daemon.
*
* @param string $file
* @param string $content
* @param string $file
* @param string $content
* @return bool
*
* @throws \GuzzleHttp\Exception\RequestException
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function saveFileContents($file, $content)
{
@ -125,8 +132,11 @@ class FileRepository
/**
* Returns a listing of all files and folders within a specified directory on the daemon.
*
* @param string $directory
* @param string $directory
* @return object
*
* @throws \GuzzleHttp\Exception\RequestException
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function returnDirectoryListing($directory)
{

View file

@ -24,55 +24,104 @@
namespace Pterodactyl\Repositories\Daemon;
use Pterodactyl\Models;
use Pterodactyl\Models\User;
use Pterodactyl\Models\Server;
use GuzzleHttp\Exception\ConnectException;
use Pterodactyl\Exceptions\DisplayException;
class PowerRepository
{
/**
* The Eloquent Model associated with the requested server.
*
* @var \Pterodactyl\Models\Server
*/
protected $server;
public function __construct($server)
/**
* The Eloquent Model associated with the user to run the request as.
*
* @var \Pterodactyl\Models\User|null
*/
protected $user;
/**
* Constuctor for repository.
*
* @param \Pterodactyl\Models\Server $server
* @param \Pterodactyl\Models\User|null $user
* @return void
*/
public function __construct(Server $server, User $user = null)
{
$this->server = ($server instanceof Models\Server) ? $server : Models\Server::findOrFail($server);
$this->server = $server;
$this->user = $user;
}
/**
* Sends a power option to the daemon.
*
* @param string $action
* @return string
*
* @throws \GuzzleHttp\Exception\RequestException
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function do($action)
{
// We don't use the user's specific daemon secret here since we
// are assuming that a call to this function has been validated.
// Additionally not all calls to this will be from a logged in user.
// (e.g. task queue or API)
try {
$response = $this->server->node->guzzleClient([
'X-Access-Token' => $this->server->daemonSecret,
'X-Access-Server' => $this->server->uuid,
])->request('PUT', '/server/power', ['json' => ['action' => $action]]);
$response = $this->server->guzzleClient($this->user)->request('PUT', '/server/power', [
'http_errors' => false,
'json' => [
'action' => $action,
],
]);
if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) {
throw new DisplayException('Power status responded with a non-200 error code.');
throw new DisplayException('Power toggle endpoint responded with a non-200 error code (HTTP/' . $response->getStatusCode() . ').');
}
return $response->getBody();
} catch (\Exception $ex) {
} catch (ConnectException $ex) {
throw $ex;
}
}
/**
* Starts a server.
*
* @return void
*/
public function start()
{
$this->do('start');
}
/**
* Stops a server.
*
* @return void
*/
public function stop()
{
$this->do('stop');
}
/**
* Restarts a server.
*
* @return void
*/
public function restart()
{
$this->do('restart');
}
/**
* Kills a server.
*
* @return void
*/
public function kill()
{
$this->do('kill');

View file

@ -39,8 +39,8 @@ class DatabaseRepository
/**
* Adds a new database to a specified database host server.
*
* @param int $id
* @param array $data
* @param int $id
* @param array $data
* @return \Pterodactyl\Models\Database
*
* @throws \Pterodactyl\Exceptions\DisplayException
@ -84,18 +84,9 @@ class DatabaseRepository
throw $ex;
}
Config::set('database.connections.dynamic', [
'driver' => 'mysql',
'host' => $host->host,
'port' => $host->port,
'database' => 'mysql',
'username' => $host->username,
'password' => Crypt::decrypt($host->password),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
]);
try {
$host->setDynamicConnection();
DB::connection('dynamic')->statement(sprintf('CREATE DATABASE IF NOT EXISTS `%s`', $database->database));
DB::connection('dynamic')->statement(sprintf(
'CREATE USER `%s`@`%s` IDENTIFIED BY \'%s\'',
@ -128,8 +119,8 @@ class DatabaseRepository
/**
* Updates the password for a given database.
*
* @param int $id
* @param string $password
* @param int $id
* @param string $password
* @return void
*
* @todo Fix logic behind resetting passwords.
@ -137,21 +128,11 @@ class DatabaseRepository
public function password($id, $password)
{
$database = Database::with('host')->findOrFail($id);
$database->host->setDynamicConnection();
DB::transaction(function () use ($database, $password) {
$database->password = Crypt::encrypt($password);
Config::set('database.connections.dynamic', [
'driver' => 'mysql',
'host' => $database->host->host,
'port' => $database->host->port,
'database' => 'mysql',
'username' => $database->host->username,
'password' => Crypt::decrypt($database->host->password),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
]);
// We have to do the whole delete user, create user thing rather than
// SET PASSWORD ... because MariaDB and PHP statements ends up inserting
// a corrupted password. A way around this is strtoupper(sha1(sha1($password, true)))
@ -174,25 +155,15 @@ class DatabaseRepository
/**
* Drops a database from the associated database host.
*
* @param int $id
* @param int $id
* @return void
*/
public function drop($id)
{
$database = Database::with('host')->findOrFail($id);
$database->host->setDynamicConnection();
DB::transaction(function () use ($database) {
Config::set('database.connections.dynamic', [
'driver' => 'mysql',
'host' => $database->host->host,
'port' => $database->host->port,
'database' => 'mysql',
'username' => $database->host->username,
'password' => Crypt::decrypt($database->host->password),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
]);
DB::connection('dynamic')->statement(sprintf('DROP DATABASE IF EXISTS `%s`', $database->database));
DB::connection('dynamic')->statement(sprintf('DROP USER IF EXISTS `%s`@`%s`', $database->username, $database->remote));
DB::connection('dynamic')->statement('FLUSH PRIVILEGES');
@ -204,7 +175,7 @@ class DatabaseRepository
/**
* Deletes a database host from the system if it has no associated databases.
*
* @param int $server
* @param int $id
* @return void
*
* @throws \Pterodactyl\Exceptions\DisplayException
@ -223,7 +194,7 @@ class DatabaseRepository
/**
* Adds a new Database Host to the system.
*
* @param array $data
* @param array $data
* @return \Pterodactyl\Models\DatabaseHost
*
* @throws \Pterodactyl\Exceptions\DisplayValidationException
@ -248,20 +219,6 @@ class DatabaseRepository
}
return DB::transaction(function () use ($data) {
Config::set('database.connections.dynamic', [
'driver' => 'mysql',
'host' => $data['host'],
'port' => $data['port'],
'database' => 'mysql',
'username' => $data['username'],
'password' => $data['password'],
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
]);
// Allows us to check that we can connect to things.
DB::connection('dynamic')->select('SELECT 1 FROM dual');
$host = new DatabaseHost;
$host->password = Crypt::encrypt($data['password']);
@ -274,6 +231,10 @@ class DatabaseRepository
'node_id' => (isset($data['node_id'])) ? $data['node_id'] : null,
])->save();
// Allows us to check that we can connect to things.
$host->setDynamicConnection();
DB::connection('dynamic')->select('SELECT 1 FROM dual');
return $host;
});
}
@ -281,8 +242,8 @@ class DatabaseRepository
/**
* Updates a Database Host on the system.
*
* @param int $id
* @param array $data
* @param int $id
* @param array $data
* @return \Pterodactyl\Models\DatabaseHost
*
* @throws \Pterodactyl\Exceptions\DisplayValidationException
@ -315,18 +276,7 @@ class DatabaseRepository
$host->fill($data)->save();
// Check that we can still connect with these details.
Config::set('database.connections.dynamic', [
'driver' => 'mysql',
'host' => $host->host,
'port' => $host->port,
'database' => 'mysql',
'username' => $host->username,
'password' => Crypt::decrypt($host->password),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
]);
// Allows us to check that we can connect to things.
$host->setDynamicConnection();
DB::connection('dynamic')->select('SELECT 1 FROM dual');
return $host;

View file

@ -28,6 +28,7 @@ class HelperRepository
{
/**
* Listing of editable files in the control panel.
*
* @var array
*/
protected static $editable = [
@ -44,17 +45,13 @@ class HelperRepository
'inode/x-empty',
];
public function __construct()
{
//
}
/**
* Converts from bytes to the largest possible size that is still readable.
*
* @param int $bytes
* @param int $decimals
* @param int $bytes
* @param int $decimals
* @return string
* @deprecated
*/
public static function bytesToHuman($bytes, $decimals = 2)
{
@ -64,6 +61,11 @@ class HelperRepository
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . ' ' . $sz[$factor];
}
/**
* Returns array of editable files.
*
* @return array
*/
public static function editableFiles()
{
return self::$editable;

View file

@ -35,8 +35,9 @@ class LocationRepository
* Creates a new location on the system.
*
* @param array $data
* @throws \Pterodactyl\Exceptions\DisplayValidationException
* @return \Pterodactyl\Models\Location
*
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function create(array $data)
{
@ -58,11 +59,11 @@ class LocationRepository
/**
* Modifies a location.
*
* @param int $id
* @param array $data
* @param int $id
* @param array $data
* @return \Pterodactyl\Models\Location
*
* @throws Pterodactyl\Exceptions\DisplayValidationException
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function update($id, array $data)
{
@ -85,10 +86,10 @@ class LocationRepository
/**
* Deletes a location from the system.
*
* @param int $id
* @param int $id
* @return void
*
* @throws Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function delete($id)
{

View file

@ -34,11 +34,15 @@ use Pterodactyl\Exceptions\DisplayValidationException;
class NodeRepository
{
public function __construct()
{
//
}
/**
* Creates a new node on the system.
*
* @param array $data
* @return \Pterodactyl\Models\Node
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function create(array $data)
{
// Validate Fields
@ -84,6 +88,16 @@ class NodeRepository
return Models\Node::create($data);
}
/**
* Updates a node on the system.
*
* @param int $id
* @param array $data
* @return \Pterodactyl\Models\Node
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function update($id, array $data)
{
$node = Models\Node::findOrFail($id);
@ -179,8 +193,13 @@ class NodeRepository
/**
* Adds allocations to a provided node.
* @param int $id
* @param array $data
*
* @param int $id
* @param array $data
* @return void
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function addAllocations($id, array $data)
{
@ -203,7 +222,7 @@ class NodeRepository
}
}
DB::transaction(function () use ($parsed, $node, $data) {
DB::transaction(function () use ($data, $node) {
foreach (Network::parse(gethostbyname($data['allocation_ip'])) as $ip) {
foreach ($data['allocation_ports'] as $port) {
// Determine if this is a valid single port, or a valid port range.
@ -243,6 +262,14 @@ class NodeRepository
});
}
/**
* Deletes a node on the system.
*
* @param int $id
* @return void
*
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function delete($id)
{
$node = Models\Node::withCount('servers')->findOrFail($id);
@ -250,13 +277,9 @@ class NodeRepository
throw new DisplayException('You cannot delete a node with servers currently attached to it.');
}
DB::beginTransaction();
try {
DB::transaction(function () use ($node) {
// Unlink Database Servers
Models\DatabaseServer::where('linked_node', $node->id)->update([
'linked_node' => null,
]);
Models\DatabaseHost::where('node_id', $node->id)->update(['node_id' => null]);
// Delete Allocations
Models\Allocation::where('node_id', $node->id)->delete();
@ -266,11 +289,6 @@ class NodeRepository
// Delete Node
$node->delete();
DB::commit();
} catch (\Exception $ex) {
DB::rollback();
throw $ex;
}
});
}
}

View file

@ -73,7 +73,7 @@ class OptionRepository
/**
* Deletes a service option from the system.
*
* @param int $id
* @param int $id
* @return void
*
* @throws \Pterodactyl\Exceptions\DisplayException

View file

@ -38,7 +38,7 @@ class PackRepository
/**
* Creates a new pack on the system.
*
* @param array $data
* @param array $data
* @return \Pterodactyl\Models\Pack
*
* @throws \Pterodactyl\Exceptions\DisplayException
@ -101,7 +101,7 @@ class PackRepository
/**
* Creates a new pack on the system given a template file.
*
* @param array $data
* @param array $data
* @return \Pterodactyl\Models\Pack
*
* @throws \Pterodactyl\Exceptions\DisplayException
@ -173,8 +173,8 @@ class PackRepository
/**
* Updates a pack on the system.
*
* @param int $id
* @param array $data
* @param int $id
* @param array $data
* @return \Pterodactyl\Models\Pack
*
* @throws \Pterodactyl\Exceptions\DisplayException
@ -225,7 +225,7 @@ class PackRepository
*/
public function delete($id)
{
$pack = Models\Pack::withCount('servers')->findOrFail($id);
$pack = Pack::withCount('servers')->findOrFail($id);
if ($pack->servers_count > 0) {
throw new DisplayException('Cannot delete a pack from the system if servers are assocaited with it.');

View file

@ -25,11 +25,11 @@
namespace Pterodactyl\Repositories;
use DB;
use Log;
use Crypt;
use Validator;
use Pterodactyl\Models;
use Pterodactyl\Services\UuidService;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\TransferException;
use Pterodactyl\Services\DeploymentService;
use Pterodactyl\Exceptions\DisplayException;
@ -37,21 +37,21 @@ use Pterodactyl\Exceptions\DisplayValidationException;
class ServerRepository
{
/**
* An array of daemon permission to assign to this server.
*
* @var array
*/
protected $daemonPermissions = [
's:*',
];
public function __construct()
{
//
}
/**
* Generates a SFTP username for a server given a server name.
* format: mumble_67c7a4b0.
*
* @param string $name
* @param string $identifier
* @param string $name
* @param null|string $identifier
* @return string
*/
protected function generateSFTPUsername($name, $identifier = null)
@ -75,8 +75,12 @@ class ServerRepository
/**
* Adds a new server to the system.
* @param array $data An array of data descriptors for creating the server. These should align to the columns in the database.
* @return int
*
* @param array $data
* @return \Pterodactyl\Models\Server
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function create(array $data)
{
@ -85,6 +89,7 @@ class ServerRepository
$validator = Validator::make($data, [
'user_id' => 'required|exists:users,id',
'name' => 'required|regex:/^([\w .-]{1,200})$/',
'description' => 'sometimes|nullable|string',
'memory' => 'required|numeric|min:0',
'swap' => 'required|numeric|min:-1',
'io' => 'required|numeric|min:10|max:1000',
@ -96,7 +101,7 @@ class ServerRepository
'pack_id' => 'sometimes|nullable|numeric|min:0',
'custom_container' => 'string',
'startup' => 'string',
'auto_deploy' => 'sometimes|boolean',
'auto_deploy' => 'sometimes|required|accepted',
'custom_id' => 'sometimes|required|numeric|unique:servers,id',
]);
@ -243,6 +248,7 @@ class ServerRepository
'uuidShort' => $genShortUuid,
'node_id' => $node->id,
'name' => $data['name'],
'description' => $data['description'],
'suspended' => 0,
'owner_id' => $user->id,
'memory' => $data['memory'],
@ -325,15 +331,13 @@ class ServerRepository
(string) $server->daemonSecret => $this->daemonPermissions,
],
'rebuild' => false,
'start_on_completion' => isset($data['start_on_completion']),
],
]);
DB::commit();
return $server;
} catch (TransferException $ex) {
DB::rollBack();
throw new DisplayException('There was an error while attempting to connect to the daemon to add this server.', $ex);
} catch (\Exception $ex) {
DB::rollBack();
throw $ex;
@ -341,10 +345,14 @@ class ServerRepository
}
/**
* [updateDetails description].
* @param int $id
* @param array $data
* @return bool
* Update the details for a server.
*
* @param int $id
* @param array $data
* @return \Pterodactyl\Models\Server
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function updateDetails($id, array $data)
{
@ -355,6 +363,7 @@ class ServerRepository
$validator = Validator::make($data, [
'owner_id' => 'sometimes|required|integer|exists:users,id',
'name' => 'sometimes|required|regex:([\w .-]{1,200})',
'description' => 'sometimes|required|string',
'reset_token' => 'sometimes|required|accepted',
]);
@ -376,24 +385,12 @@ class ServerRepository
$resetDaemonKey = true;
}
// Update Server Owner if it was passed.
if (isset($data['owner_id']) && (int) $data['owner_id'] !== $server->user->id) {
$server->owner_id = $data['owner_id'];
}
// Update Server Name if it was passed.
if (isset($data['name'])) {
$server->name = $data['name'];
}
// Save our changes
$server->save();
$server->fill($data)->save();
// Do we need to update? If not, return successful.
if (! $resetDaemonKey) {
DB::commit();
return true;
return DB::commit();
}
$res = $server->node->guzzleClient([
@ -412,22 +409,24 @@ class ServerRepository
if ($res->getStatusCode() === 204) {
DB::commit();
return true;
return $server;
} else {
throw new DisplayException('Daemon returned a a non HTTP/204 error code. HTTP/' + $res->getStatusCode());
}
} catch (\Exception $ex) {
DB::rollBack();
Log::error($ex);
throw new DisplayException('An error occured while attempting to update this server\'s information.');
throw $ex;
}
}
/**
* [updateContainer description].
* @param int $id
* @param array $data
* @return bool
* Update the container for a server.
*
* @param int $id
* @param array $data
* @return \Pterodactyl\Models\Server
*
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function updateContainer($id, array $data)
{
@ -461,10 +460,7 @@ class ServerRepository
DB::commit();
return true;
} catch (TransferException $ex) {
DB::rollBack();
throw new DisplayException('A TransferException occured while attempting to update the container image. Is the daemon online? This error has been logged.', $ex);
return $server;
} catch (\Exception $ex) {
DB::rollBack();
throw $ex;
@ -472,10 +468,14 @@ class ServerRepository
}
/**
* [changeBuild description].
* @param int $id
* @param array $data
* @return bool
* Update the build details for a server.
*
* @param int $id
* @param array $data
* @return \Pterodactyl\Models\Server
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function changeBuild($id, array $data)
{
@ -518,23 +518,7 @@ class ServerRepository
}
$newPorts = false;
// Remove Assignments
if (isset($data['remove_allocations'])) {
foreach ($data['remove_allocations'] as $allocation) {
// Can't remove the assigned IP/Port combo
if ((int) $allocation === $server->allocation_id) {
continue;
}
$newPorts = true;
Models\Allocation::where('id', $allocation)->where('server_id', $server->id)->update([
'server_id' => null,
]);
}
$server->load('allocations');
}
$firstNewAllocation = null;
// Add Assignments
if (isset($data['add_allocations'])) {
foreach ($data['add_allocations'] as $allocation) {
@ -544,6 +528,7 @@ class ServerRepository
}
$newPorts = true;
$firstNewAllocation = (is_null($firstNewAllocation)) ? $model->id : $firstNewAllocation;
$model->update([
'server_id' => $server->id,
]);
@ -552,6 +537,29 @@ class ServerRepository
$server->load('allocations');
}
// Remove Assignments
if (isset($data['remove_allocations'])) {
foreach ($data['remove_allocations'] as $allocation) {
// Can't remove the assigned IP/Port combo
if ((int) $allocation === $server->allocation_id) {
// No New Allocation
if (is_null($firstNewAllocation)) {
continue;
}
// New Allocation, set as the default.
$server->allocation_id = $firstNewAllocation;
}
$newPorts = true;
Models\Allocation::where('id', $allocation)->where('server_id', $server->id)->update([
'server_id' => null,
]);
}
$server->load('allocations');
}
if ($newPorts) {
$newBuild['ports|overwrite'] = $server->allocations->groupBy('ip')->map(function ($item) {
return $item->pluck('port');
@ -605,15 +613,24 @@ class ServerRepository
DB::commit();
return $server;
} catch (TransferException $ex) {
DB::rollBack();
throw new DisplayException('A TransferException occured while attempting to update the server configuration, check that the daemon is online. This error has been logged.', $ex);
} catch (\Exception $ex) {
DB::rollBack();
throw $ex;
}
}
/**
* Update the startup details for a server.
*
* @param int $id
* @param array $data
* @param bool $admin
* @return void
*
* @throws \GuzzleHttp\Exception\RequestException
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function updateStartup($id, array $data, $admin = false)
{
$server = Models\Server::with('variables', 'option.variables')->findOrFail($id);
@ -691,34 +708,18 @@ class ServerRepository
});
}
public function queueDeletion($id, $force = false)
{
$server = Models\Server::findOrFail($id);
DB::beginTransaction();
try {
if ($force) {
$server->installed = 3;
$server->save();
}
$server->delete();
return DB::commit();
} catch (\Exception $ex) {
DB::rollBack();
throw $ex;
}
}
/**
* Delete a server from the system permanetly.
*
* @param int $id
* @param bool $force
* @return void
*
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function delete($id, $force = false)
{
$server = Models\Server::withTrashed()->with('node', 'allocations', 'variables')->findOrFail($id);
// Handle server being restored previously or
// an accidental queue.
if (! $server->trashed()) {
return;
}
$server = Models\Server::with('node', 'allocations', 'variables')->findOrFail($id);
// Due to MySQL lockouts if the daemon response fails, we need to
// delete the server from the daemon first. If it succeedes and then
@ -730,8 +731,18 @@ class ServerRepository
'X-Access-Token' => $server->node->daemonSecret,
'X-Access-Server' => $server->uuid,
])->request('DELETE', '/servers');
} catch (ClientException $ex) {
// Exception is thrown on 4XX HTTP errors, so catch and determine
// if we should continue, or if there is a permissions error.
//
// Daemon throws a 404 if the server doesn't exist, if that is returned
// continue with deletion, even if not a force deletion.
$response = $ex->getResponse();
if ($ex->getResponse()->getStatusCode() !== 404 && ! $force) {
throw new DisplayException($ex->getMessage());
}
} catch (TransferException $ex) {
if ($server->installed !== 3 && ! $force) {
if (! $force) {
throw new DisplayException($ex->getMessage());
}
} catch (\Exception $ex) {
@ -744,45 +755,40 @@ class ServerRepository
$item->save();
});
$server->variables->each(function ($item) {
$item->delete();
$server->variables->each->delete();
$server->load('subusers.permissions');
$server->subusers->each(function ($subuser) {
$subuser->permissions->each(function ($permission) {
$perm->delete();
});
$subuser->delete();
});
foreach (Models\Subuser::with('permissions')->where('server_id', $server->id)->get() as &$subuser) {
foreach ($subuser->permissions as &$permission) {
$permission->delete();
}
$subuser->delete();
}
// Remove Downloads
Models\Download::where('server', $server->uuid)->delete();
// Clear Tasks
Models\Task::where('server', $server->id)->delete();
$server->downloads->each->delete();
$server->tasks->each->delete();
// Delete Databases
// This is the one un-recoverable point where
// transactions will not save us.
$repository = new DatabaseRepository;
foreach (Models\Database::select('id')->where('server_id', $server->id)->get() as $database) {
$repository->drop($database->id);
}
$server->databases->each(function ($item) {
$repository->drop($item->id);
});
// Fully delete the server.
$server->forceDelete();
$server->delete();
});
}
public function cancelDeletion($id)
{
$server = Models\Server::withTrashed()->findOrFail($id);
$server->restore();
$server->installed = 1;
$server->save();
}
/**
* Toggle the install status of a serve.
*
* @param int $id
* @return bool
*
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function toggleInstall($id)
{
$server = Models\Server::findOrFail($id);
@ -795,77 +801,43 @@ class ServerRepository
}
/**
* Suspends a server instance making it unable to be booted or used by a user.
* @param int $id
* @return bool
* Suspends or unsuspends a server.
*
* @param int $id
* @param bool $unsuspend
* @return void
*/
public function suspend($id, $deleted = false)
{
$server = Models\Server::withTrashed()->with('node')->findOrFail($id);
DB::beginTransaction();
try {
// Already suspended, no need to make more requests.
if ($server->suspended) {
return true;
}
$server->suspended = 1;
$server->save();
$server->node->guzzleClient([
'X-Access-Token' => $server->node->daemonSecret,
'X-Access-Server' => $server->uuid,
])->request('POST', '/server/suspend');
return DB::commit();
} catch (TransferException $ex) {
DB::rollBack();
throw new DisplayException('An error occured while attempting to contact the remote daemon to suspend this server.', $ex);
} catch (\Exception $ex) {
DB::rollBack();
throw $ex;
}
}
/**
* Unsuspends a server instance.
* @param int $id
* @return bool
*/
public function unsuspend($id)
public function toggleAccess($id, $unsuspend = true)
{
$server = Models\Server::with('node')->findOrFail($id);
DB::beginTransaction();
try {
// Already unsuspended, no need to make more requests.
if ($server->suspended === 0) {
DB::transaction(function () use ($server, $unsuspend) {
if (
(! $unsuspend && $server->suspended) ||
($unsuspend && ! $server->suspended)
) {
return true;
}
$server->suspended = 0;
$server->suspended = ! $unsuspend;
$server->save();
$server->node->guzzleClient([
'X-Access-Token' => $server->node->daemonSecret,
'X-Access-Server' => $server->uuid,
])->request('POST', '/server/unsuspend');
return DB::commit();
} catch (TransferException $ex) {
DB::rollBack();
throw new DisplayException('An error occured while attempting to contact the remote daemon to un-suspend this server.', $ex);
} catch (\Exception $ex) {
DB::rollBack();
throw $ex;
}
])->request('POST', ($unsuspend) ? '/server/unsuspend' : '/server/suspend');
});
}
/**
* Updates the SFTP password for a server.
*
* @param int $id
* @param string $password
* @return void
*
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function updateSFTPPassword($id, $password)
{
$server = Models\Server::with('node')->findOrFail($id);
@ -878,10 +850,8 @@ class ServerRepository
throw new DisplayValidationException(json_encode($validator->errors()));
}
DB::beginTransaction();
$server->sftp_password = Crypt::encrypt($password);
try {
DB::transaction(function () use ($password, $server) {
$server->sftp_password = Crypt::encrypt($password);
$server->save();
$server->node->guzzleClient([
@ -890,16 +860,6 @@ class ServerRepository
])->request('POST', '/server/password', [
'json' => ['password' => $password],
]);
DB::commit();
return true;
} catch (TransferException $ex) {
DB::rollBack();
throw new DisplayException('There was an error while attmping to contact the remote service to change the password.', $ex);
} catch (\Exception $ex) {
DB::rollBack();
throw $ex;
}
});
}
}

View file

@ -37,6 +37,8 @@ class ServiceRepository
*
* @param array $data
* @return \Pterodactyl\Models\Service
*
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function create(array $data)
{
@ -80,6 +82,8 @@ class ServiceRepository
* @param int $id
* @param array $data
* @return \Pterodactyl\Models\Service
*
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function update($id, array $data)
{
@ -109,6 +113,8 @@ class ServiceRepository
*
* @param int $id
* @return void
*
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function delete($id)
{

View file

@ -26,8 +26,12 @@ namespace Pterodactyl\Repositories;
use DB;
use Validator;
use Pterodactyl\Models;
use Pterodactyl\Models\User;
use Pterodactyl\Models\Server;
use Pterodactyl\Models\Subuser;
use Pterodactyl\Models\Permission;
use Pterodactyl\Services\UuidService;
use GuzzleHttp\Exception\TransferException;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Exceptions\DisplayValidationException;
@ -37,6 +41,7 @@ class SubuserRepository
* Core permissions required for every subuser on the daemon.
* Without this we cannot connect the websocket or get basic
* information about the server.
*
* @var array
*/
protected $coreDaemonPermissions = [
@ -44,77 +49,19 @@ class SubuserRepository
's:console',
];
/**
* Allowed permissions and their related daemon permission.
* @var array
*/
protected $permissions = [
// Power Permissions
'power-start' => 's:power:start',
'power-stop' => 's:power:stop',
'power-restart' => 's:power:restart',
'power-kill' => 's:power:kill',
// Commands
'send-command' => 's:command',
// File Manager
'list-files' => 's:files:get',
'edit-files' => 's:files:read',
'save-files' => 's:files:post',
'create-files' => 's:files:create',
'download-files' => null,
'upload-files' => 's:files:upload',
'delete-files' => 's:files:delete',
'move-files' => 's:files:move',
'copy-files' => 's:files:copy',
'compress-files' => 's:files:compress',
'decompress-files' => 's:files:decompress',
// Subusers
'list-subusers' => null,
'view-subuser' => null,
'edit-subuser' => null,
'create-subuser' => null,
'delete-subuser' => null,
// Tasks
'list-tasks' => null,
'view-task' => null,
'toggle-task' => null,
'delete-task' => null,
'create-task' => null,
'queue-task' => null,
// Management
'set-connection' => null,
'view-startup' => null,
'edit-startup' => null,
'view-sftp' => null,
'reset-sftp' => 's:set-password',
'view-sftp-password' => null,
// Databases
'view-databases' => null,
'reset-db-password' => null,
];
public function __construct()
{
//
}
/**
* Creates a new subuser on the server.
* @param int $id The ID of the server to add this subuser to.
*
* @param int $sid
* @param array $data
* @throws DisplayValidationException
* @throws DisplayException
* @return \Pterodactyl\Models\Subuser
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function create($sid, array $data)
{
$server = Models\Server::with('node')->findOrFail($sid);
$server = Server::with('node')->findOrFail($sid);
$validator = Validator::make($data, [
'permissions' => 'required|array',
@ -129,7 +76,7 @@ class SubuserRepository
try {
// Determine if this user exists or if we need to make them an account.
$user = Models\User::where('email', $data['email'])->first();
$user = User::where('email', $data['email'])->first();
if (! $user) {
try {
$repo = new UserRepository;
@ -145,26 +92,28 @@ class SubuserRepository
}
} elseif ($server->owner_id === $user->id) {
throw new DisplayException('You cannot add the owner of a server as a subuser.');
} elseif (Models\Subuser::select('id')->where('user_id', $user->id)->where('server_id', $server->id)->first()) {
} elseif (Subuser::select('id')->where('user_id', $user->id)->where('server_id', $server->id)->first()) {
throw new DisplayException('A subuser with that email already exists for this server.');
}
$uuid = new UuidService;
$subuser = Models\Subuser::create([
$subuser = Subuser::create([
'user_id' => $user->id,
'server_id' => $server->id,
'daemonSecret' => (string) $uuid->generate('servers', 'uuid'),
]);
$perms = Permission::list(true);
$daemonPermissions = $this->coreDaemonPermissions;
foreach ($data['permissions'] as $permission) {
if (array_key_exists($permission, $this->permissions)) {
if (array_key_exists($permission, $perms)) {
// Build the daemon permissions array for sending.
if (! is_null($this->permissions[$permission])) {
array_push($daemonPermissions, $this->permissions[$permission]);
if (! is_null($perms[$permission])) {
array_push($daemonPermissions, $perms[$permission]);
}
Models\Permission::create([
Permission::create([
'subuser_id' => $subuser->id,
'permission' => $permission,
]);
@ -189,7 +138,7 @@ class SubuserRepository
DB::commit();
return $subuser;
} catch (\GuzzleHttp\Exception\TransferException $ex) {
} catch (TransferException $ex) {
DB::rollBack();
throw new DisplayException('There was an error attempting to connect to the daemon to add this user.', $ex);
} catch (\Exception $ex) {
@ -202,15 +151,15 @@ class SubuserRepository
/**
* Revokes a users permissions on a server.
* @param int $id The ID of the subuser row in MySQL.
* @param array $data
* @throws DisplayValidationException
* @throws DisplayException
*
* @param int $id
* @return void
*
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function delete($id)
{
$subuser = Models\Subuser::with('server.node')->findOrFail($id);
$subuser = Subuser::with('server.node')->findOrFail($id);
$server = $subuser->server;
DB::beginTransaction();
@ -232,26 +181,24 @@ class SubuserRepository
}
$subuser->delete();
DB::commit();
return true;
} catch (\GuzzleHttp\Exception\TransferException $ex) {
} catch (TransferException $ex) {
DB::rollBack();
throw new DisplayException('There was an error attempting to connect to the daemon to delete this subuser.', $ex);
} catch (\Exception $ex) {
DB::rollBack();
throw $ex;
}
return false;
}
/**
* Updates permissions for a given subuser.
* @param int $id The ID of the subuser row in MySQL. (Not the user ID)
*
* @param int $id
* @param array $data
* @throws DisplayValidationException
* @throws DisplayException
* @return void
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function update($id, array $data)
{
@ -265,7 +212,7 @@ class SubuserRepository
throw new DisplayValidationException(json_encode($validator->all()));
}
$subuser = Models\Subuser::with('server.node')->findOrFail($id);
$subuser = Subuser::with('server.node')->findOrFail($id);
$server = $subuser->server;
DB::beginTransaction();
@ -275,14 +222,16 @@ class SubuserRepository
$permission->delete();
}
$perms = Permission::list(true);
$daemonPermissions = $this->coreDaemonPermissions;
foreach ($data['permissions'] as $permission) {
if (array_key_exists($permission, $this->permissions)) {
if (array_key_exists($permission, $perms)) {
// Build the daemon permissions array for sending.
if (! is_null($this->permissions[$permission])) {
array_push($daemonPermissions, $this->permissions[$permission]);
if (! is_null($perms[$permission])) {
array_push($daemonPermissions, $perms[$permission]);
}
Models\Permission::create([
Permission::create([
'subuser_id' => $subuser->id,
'permission' => $permission,
]);
@ -304,16 +253,12 @@ class SubuserRepository
]);
DB::commit();
return true;
} catch (\GuzzleHttp\Exception\TransferException $ex) {
} catch (TransferException $ex) {
DB::rollBack();
throw new DisplayException('There was an error attempting to connect to the daemon to update permissions.', $ex);
} catch (\Exception $ex) {
DB::rollBack();
throw $ex;
}
return false;
}
}

View file

@ -24,14 +24,22 @@
namespace Pterodactyl\Repositories;
use DB;
use Cron;
use Validator;
use Pterodactyl\Models;
use Pterodactyl\Models\Task;
use Pterodactyl\Models\User;
use Pterodactyl\Models\Server;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Exceptions\DisplayValidationException;
class TaskRepository
{
/**
* The default values to use for new tasks.
*
* @var array
*/
protected $defaults = [
'year' => '*',
'day_of_week' => '*',
@ -41,66 +49,60 @@ class TaskRepository
'minute' => '*/30',
];
/**
* Task action types.
*
* @var array
*/
protected $actions = [
'command',
'power',
];
public function __construct()
{
//
}
/**
* Deletes a given task.
* @param int $id
*
* @param int $id
* @return bool
*/
public function delete($id)
{
$task = Models\Task::findOrFail($id);
try {
$task->delete();
return true;
} catch (\Exception $ex) {
throw $ex;
}
$task = Task::findOrFail($id);
$task->delete();
}
/**
* Toggles a task active or inactive.
* @param int $id
*
* @return int
* @param int $id
* @return bool
*/
public function toggle($id)
{
$task = Models\Task::findOrFail($id);
try {
$task->active = ($task->active === 1) ? 0 : 1;
$task->queued = 0;
$task->save();
$task = Task::findOrFail($id);
return $task->active;
} catch (\Exception $ex) {
throw $ex;
}
$task->active = ! $task->active;
$task->queued = false;
$task->save();
return $task->active;
}
/**
* Create a new scheduled task for a given server.
* @param int $id
* @param array $data
*
* @throws DisplayException
* @throws DisplayValidationException
* @return void
* @param int $server
* @param int $user
* @param array $data
* @return \Pterodactyl\Models\Task
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function create($id, $data)
public function create($server, $user, $data)
{
$server = Models\Server::findOrFail($id);
$server = Server::findOrFail($server);
$user = User::findOrFail($user);
$validator = Validator::make($data, [
'action' => 'string|required',
@ -142,9 +144,9 @@ class TaskRepository
throw $ex;
}
$task = new Models\Task;
$task->fill([
'server' => $server->id,
return Task::create([
'user_id' => $user->id,
'server_id' => $server->id,
'active' => 1,
'action' => $data['action'],
'data' => $data['data'],
@ -158,7 +160,5 @@ class TaskRepository
'last_run' => null,
'next_run' => $buildCron->getNextRunDate(),
]);
return $task->save();
}
}

View file

@ -38,19 +38,13 @@ use Pterodactyl\Exceptions\DisplayValidationException;
class UserRepository
{
public function __construct()
{
//
}
/**
* Creates a user on the panel. Returns the created user's ID.
*
* @param string $email
* @param string|null $password An unhashed version of the user's password.
* @param bool $admin Boolean value if user should be an admin or not.
* @param int $token A custom user ID.
* @return bool|int
* @param array $data
* @return \Pterodactyl\Models\User
*
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function create(array $data)
{
@ -118,9 +112,11 @@ class UserRepository
/**
* Updates a user on the panel.
*
* @param int $id
* @param array $data An array of columns and their associated values to update for the user.
* @return bool
* @param int $id
* @param array $data
* @return \Pterodactyl\Models\User
*
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function update($id, array $data)
{
@ -151,16 +147,19 @@ class UserRepository
unset($data['password']);
}
$user->fill($data);
$user->fill($data)->save();
return $user->save();
return $user;
}
/**
* Deletes a user on the panel, returns the number of records deleted.
* Deletes a user on the panel.
*
* @param int $id
* @return int
* @return void
* @todo Move user self-deletion checking to the controller, rather than the repository.
*
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function delete($id)
{
@ -168,8 +167,7 @@ class UserRepository
throw new DisplayException('Cannot delete a user with active servers attached to thier account.');
}
// @TODO: this should probably be checked outside of this method because we won't always have Auth::user()
if (! is_null(Auth::user()) && Auth::user()->id === $id) {
if (! is_null(Auth::user()) && (int) Auth::user()->id === (int) $id) {
throw new DisplayException('Cannot delete your own account.');
}
@ -186,8 +184,6 @@ class UserRepository
Models\User::destroy($id);
DB::commit();
return true;
} catch (\Exception $ex) {
DB::rollBack();
throw $ex;

View file

@ -91,7 +91,7 @@ class VariableRepository
* Deletes a specified option variable as well as all server
* variables currently assigned.
*
* @param int $id
* @param int $id
* @return void
*/
public function delete($id)