Merge branch 'develop' into feature/react-admin
This commit is contained in:
commit
a87fef37ec
77 changed files with 1082 additions and 839 deletions
125
app/Models/AuditLog.php
Normal file
125
app/Models/AuditLog.php
Normal file
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Models;
|
||||
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Container\Container;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $uuid
|
||||
* @property bool $is_system
|
||||
* @property int|null $user_id
|
||||
* @property int|null $server_id
|
||||
* @property string $action
|
||||
* @property string|null $subaction
|
||||
* @property array $device
|
||||
* @property array $metadata
|
||||
* @property \Carbon\CarbonImmutable $created_at
|
||||
* @property \Pterodactyl\Models\User|null $user
|
||||
* @property \Pterodactyl\Models\Server|null $server
|
||||
*/
|
||||
class AuditLog extends Model
|
||||
{
|
||||
public const UPDATED_AT = null;
|
||||
|
||||
public const SERVER__FILESYSTEM_DOWNLOAD = 'server:filesystem.download';
|
||||
public const SERVER__FILESYSTEM_WRITE = 'server:filesystem.write';
|
||||
public const SERVER__FILESYSTEM_DELETE = 'server:filesystem.delete';
|
||||
public const SERVER__FILESYSTEM_RENAME = 'server:filesystem.rename';
|
||||
public const SERVER__FILESYSTEM_COMPRESS = 'server:filesystem.compress';
|
||||
public const SERVER__FILESYSTEM_DECOMPRESS = 'server:filesystem.decompress';
|
||||
public const SERVER__FILESYSTEM_PULL = 'server:filesystem.pull';
|
||||
public const SERVER__BACKUP_STARTED = 'server:backup.started';
|
||||
public const SERVER__BACKUP_FAILED = 'server:backup.failed';
|
||||
public const SERVER__BACKUP_COMPELTED = 'server:backup.completed';
|
||||
public const SERVER__BACKUP_DELETED = 'server:backup.deleted';
|
||||
public const SERVER__BACKUP_RESTORE_STARTED = 'server:backup.restore.started';
|
||||
public const SERVER__BACKUP_RESTORE_COMPLETED = 'server:backup.restore.completed';
|
||||
public const SERVER__BACKUP_RESTORE_FAILED = 'server:backup.restore.failed';
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public static $validationRules = [
|
||||
'uuid' => 'required|uuid',
|
||||
'action' => 'required|string|max:191',
|
||||
'subaction' => 'nullable|string|max:191',
|
||||
'device' => 'array',
|
||||
'device.ip_address' => 'ip',
|
||||
'device.user_agent' => 'string',
|
||||
'metadata' => 'array',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'audit_logs';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $immutableDates = true;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $casts = [
|
||||
'device' => 'array',
|
||||
'metadata' => 'array',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $guarded = [
|
||||
'id',
|
||||
'created_at',
|
||||
];
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function server()
|
||||
{
|
||||
return $this->belongsTo(Server::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AuditLog model and returns it, attaching device information and the
|
||||
* currently authenticated user if available. This model is not saved at this point, so
|
||||
* you can always make modifications to it as needed before saving.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public static function instance(string $action, array $metadata, bool $isSystem = false)
|
||||
{
|
||||
/** @var \Illuminate\Http\Request $request */
|
||||
$request = Container::getInstance()->make('request');
|
||||
if ($isSystem || !$request instanceof Request) {
|
||||
$request = null;
|
||||
}
|
||||
|
||||
return (new self())->fill([
|
||||
'uuid' => Uuid::uuid4()->toString(),
|
||||
'is_system' => $isSystem,
|
||||
'user_id' => ($request && $request->user()) ? $request->user()->id : null,
|
||||
'server_id' => null,
|
||||
'action' => $action,
|
||||
'device' => $request ? [
|
||||
'ip_address' => $request->getClientIp(),
|
||||
'user_agent' => $request->userAgent(),
|
||||
] : [],
|
||||
'metadata' => $metadata,
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -39,9 +39,9 @@ class Permission extends Model
|
|||
|
||||
public const ACTION_BACKUP_READ = 'backup.read';
|
||||
public const ACTION_BACKUP_CREATE = 'backup.create';
|
||||
public const ACTION_BACKUP_UPDATE = 'backup.update';
|
||||
public const ACTION_BACKUP_DELETE = 'backup.delete';
|
||||
public const ACTION_BACKUP_DOWNLOAD = 'backup.download';
|
||||
public const ACTION_BACKUP_RESTORE = 'backup.restore';
|
||||
|
||||
public const ACTION_ALLOCATION_READ = 'allocation.read';
|
||||
public const ACTION_ALLOCATION_CREATE = 'allocation.create';
|
||||
|
@ -155,9 +155,9 @@ class Permission extends Model
|
|||
'keys' => [
|
||||
'create' => 'Allows a user to create new backups for this server.',
|
||||
'read' => 'Allows a user to view all backups that exist for this server.',
|
||||
'update' => '',
|
||||
'delete' => 'Allows a user to remove backups from the system.',
|
||||
'download' => 'Allows a user to download backups.',
|
||||
'download' => 'Allows a user to download a backup for the server. Danger: this allows a user to access all files for the server in the backup.',
|
||||
'restore' => 'Allows a user to restore a backup for the server. Danger: this allows the user to delete all of the server files in the process.',
|
||||
],
|
||||
],
|
||||
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
|
||||
namespace Pterodactyl\Models;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Znck\Eloquent\Traits\BelongsToThrough;
|
||||
use Pterodactyl\Exceptions\Http\Server\ServerStateConflictException;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
|
@ -14,8 +16,8 @@ use Znck\Eloquent\Traits\BelongsToThrough;
|
|||
* @property int $node_id
|
||||
* @property string $name
|
||||
* @property string $description
|
||||
* @property string|null $status
|
||||
* @property bool $skip_scripts
|
||||
* @property bool $suspended
|
||||
* @property int $owner_id
|
||||
* @property int $memory
|
||||
* @property int $swap
|
||||
|
@ -29,7 +31,6 @@ use Znck\Eloquent\Traits\BelongsToThrough;
|
|||
* @property int $egg_id
|
||||
* @property string $startup
|
||||
* @property string $image
|
||||
* @property int $installed
|
||||
* @property int $allocation_limit
|
||||
* @property int $database_limit
|
||||
* @property int $backup_limit
|
||||
|
@ -49,6 +50,7 @@ use Znck\Eloquent\Traits\BelongsToThrough;
|
|||
* @property \Pterodactyl\Models\ServerTransfer $transfer
|
||||
* @property \Pterodactyl\Models\Backup[]|\Illuminate\Database\Eloquent\Collection $backups
|
||||
* @property \Pterodactyl\Models\Mount[]|\Illuminate\Database\Eloquent\Collection $mounts
|
||||
* @property \Pterodactyl\Models\AuditLog[] $audits
|
||||
*/
|
||||
class Server extends Model
|
||||
{
|
||||
|
@ -61,9 +63,10 @@ class Server extends Model
|
|||
*/
|
||||
public const RESOURCE_NAME = 'server';
|
||||
|
||||
public const STATUS_INSTALLING = 0;
|
||||
public const STATUS_INSTALLED = 1;
|
||||
public const STATUS_INSTALL_FAILED = 2;
|
||||
public const STATUS_INSTALLING = 'installing';
|
||||
public const STATUS_INSTALL_FAILED = 'install_failed';
|
||||
public const STATUS_SUSPENDED = 'suspended';
|
||||
public const STATUS_RESTORING_BACKUP = 'restoring_backup';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
|
@ -79,6 +82,7 @@ class Server extends Model
|
|||
* @var array
|
||||
*/
|
||||
protected $attributes = [
|
||||
'status' => self::STATUS_INSTALLING,
|
||||
'oom_disabled' => true,
|
||||
];
|
||||
|
||||
|
@ -101,7 +105,7 @@ class Server extends Model
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $guarded = ['id', 'installed', self::CREATED_AT, self::UPDATED_AT, 'deleted_at'];
|
||||
protected $guarded = ['id', self::CREATED_AT, self::UPDATED_AT, 'deleted_at'];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
|
@ -112,6 +116,7 @@ class Server extends Model
|
|||
'name' => 'required|string|min:1|max:191',
|
||||
'node_id' => 'required|exists:nodes,id',
|
||||
'description' => 'string',
|
||||
'status' => 'nullable|string',
|
||||
'memory' => 'required|numeric|min:0',
|
||||
'swap' => 'required|numeric|min:-1',
|
||||
'io' => 'required|numeric|between:10,1000',
|
||||
|
@ -125,7 +130,6 @@ class Server extends Model
|
|||
'startup' => 'required|string',
|
||||
'skip_scripts' => 'sometimes|boolean',
|
||||
'image' => 'required|string|max:191',
|
||||
'installed' => 'in:0,1,2',
|
||||
'database_limit' => 'present|nullable|integer|min:0',
|
||||
'allocation_limit' => 'sometimes|nullable|integer|min:0',
|
||||
'backup_limit' => 'present|nullable|integer|min:0',
|
||||
|
@ -139,7 +143,6 @@ class Server extends Model
|
|||
protected $casts = [
|
||||
'node_id' => 'integer',
|
||||
'skip_scripts' => 'boolean',
|
||||
'suspended' => 'boolean',
|
||||
'owner_id' => 'integer',
|
||||
'memory' => 'integer',
|
||||
'swap' => 'integer',
|
||||
|
@ -150,7 +153,6 @@ class Server extends Model
|
|||
'allocation_id' => 'integer',
|
||||
'nest_id' => 'integer',
|
||||
'egg_id' => 'integer',
|
||||
'installed' => 'integer',
|
||||
'database_limit' => 'integer',
|
||||
'allocation_limit' => 'integer',
|
||||
'backup_limit' => 'integer',
|
||||
|
@ -168,7 +170,12 @@ class Server extends Model
|
|||
|
||||
public function isInstalled(): bool
|
||||
{
|
||||
return $this->installed === 1;
|
||||
return $this->status !== self::STATUS_INSTALLING && $this->status !== self::STATUS_INSTALL_FAILED;
|
||||
}
|
||||
|
||||
public function isSuspended(): bool
|
||||
{
|
||||
return $this->status === self::STATUS_SUSPENDED;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -320,4 +327,68 @@ class Server extends Model
|
|||
{
|
||||
return $this->hasManyThrough(Mount::class, MountServer::class, 'server_id', 'id', 'id', 'mount_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a fresh AuditLog model for the server. This model is not saved to the
|
||||
* database when created, so it is up to the caller to correctly store it as needed.
|
||||
*
|
||||
* @return \Pterodactyl\Models\AuditLog
|
||||
*/
|
||||
public function newAuditEvent(string $action, array $metadata = []): AuditLog
|
||||
{
|
||||
return AuditLog::instance($action, $metadata)->fill([
|
||||
'server_id' => $this->id,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a new audit event for a server by using a transaction. If the transaction
|
||||
* fails for any reason everything executed within will be rolled back. The callback
|
||||
* passed in will receive the AuditLog model before it is saved and the second argument
|
||||
* will be the current server instance. The callback should modify the audit entry as
|
||||
* needed before finishing, any changes will be persisted.
|
||||
*
|
||||
* The response from the callback is returned to the caller.
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function audit(string $action, Closure $callback)
|
||||
{
|
||||
return $this->getConnection()->transaction(function () use ($action, $callback) {
|
||||
$model = $this->newAuditEvent($action);
|
||||
$response = $callback($model, $this);
|
||||
$model->save();
|
||||
|
||||
return $response;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function audits()
|
||||
{
|
||||
return $this->hasMany(AuditLog::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the server is currently in a user-accessible state. If not, an
|
||||
* exception is raised. This should be called whenever something needs to make
|
||||
* sure the server is not in a weird state that should block user access.
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Server\ServerStateConflictException
|
||||
*/
|
||||
public function validateCurrentState()
|
||||
{
|
||||
if (
|
||||
$this->isSuspended() ||
|
||||
!$this->isInstalled() ||
|
||||
$this->status === self::STATUS_RESTORING_BACKUP ||
|
||||
!is_null($this->transfer)
|
||||
) {
|
||||
throw new ServerStateConflictException($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue