diff --git a/app/Models/AuditLog.php b/app/Models/AuditLog.php new file mode 100644 index 000000000..fdf166e68 --- /dev/null +++ b/app/Models/AuditLog.php @@ -0,0 +1,120 @@ + 'required|uuid', + 'action' => 'required|string', + 'device' => 'required|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. + * + * @param string $action + * @param array $metadata + * @param bool $isSystem + * @return $this + */ + public static function factory(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->user() ? $request->user()->id : null, + 'server_id' => null, + 'action' => $action, + 'device' => $request ? [ + 'ip_address' => $request->getClientIp(), + 'user_agent' => $request->userAgent(), + ] : [], + 'metadata' => $metadata, + ]); + } +} diff --git a/app/Models/Server.php b/app/Models/Server.php index aace86d0b..b617db0a2 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -50,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 { @@ -326,4 +327,29 @@ class Server extends Model { return $this->hasManyThrough(Mount::class, MountServer::class, 'server_id', 'id', 'id', 'mount_id'); } + + /** + * Saves an audit entry to the database for the server. + * + * @param string $action + * @param array $metadata + * @return \Pterodactyl\Models\AuditLog + */ + public function audit(string $action, array $metadata): AuditLog + { + $model = AuditLog::factory($action, $metadata)->fill([ + 'server_id' => $this->id, + ]); + $model->save(); + + return $model; + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function audits() + { + return $this->hasMany(AuditLog::class); + } } diff --git a/database/migrations/2021_01_17_102401_create_audit_logs_table.php b/database/migrations/2021_01_17_102401_create_audit_logs_table.php new file mode 100644 index 000000000..7586c1b8c --- /dev/null +++ b/database/migrations/2021_01_17_102401_create_audit_logs_table.php @@ -0,0 +1,31 @@ +id(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('audit_logs'); + } +}