Skip to content

Commit b15679d

Browse files
committed
Add base logic for audit logging
1 parent 9684456 commit b15679d

File tree

3 files changed

+177
-0
lines changed

3 files changed

+177
-0
lines changed

app/Models/AuditLog.php

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
<?php
2+
3+
namespace Pterodactyl\Models;
4+
5+
use Ramsey\Uuid\Uuid;
6+
use Illuminate\Http\Request;
7+
use Illuminate\Container\Container;
8+
9+
/**
10+
* @property int $id
11+
* @property string $uuid
12+
* @property bool $is_system
13+
* @property int|null $user_id
14+
* @property int|null $server_id
15+
* @property string $action
16+
* @property array $device
17+
* @property array $metadata
18+
* @property \Carbon\CarbonImmutable $created_at
19+
*
20+
* @property \Pterodactyl\Models\User|null $user
21+
* @property \Pterodactyl\Models\Server|null $server
22+
*/
23+
class AuditLog extends Model
24+
{
25+
const UPDATED_AT = null;
26+
27+
const ACTION_USER_AUTH_LOGIN = 'user:auth.login';
28+
const ACTION_USER_AUTH_FAILED = 'user:auth.failed';
29+
const ACTION_USER_AUTH_PASSWORD_CHANGED = 'user:auth.password-changed';
30+
31+
const ACTION_SERVER_BACKUP_RESTORE_STARTED = 'server:backup.restore.started';
32+
const ACTION_SERVER_BACKUP_RESTORE_COMPLETED = 'server:backup.restore.completed';
33+
const ACTION_SERVER_BACKUP_RESTORE_FAILED = 'server:backup.restore.failed';
34+
35+
/**
36+
* @var string[]
37+
*/
38+
public static $validationRules = [
39+
'uuid' => 'required|uuid',
40+
'action' => 'required|string',
41+
'device' => 'required|array',
42+
'device.ip_address' => 'ip',
43+
'device.user_agent' => 'string',
44+
'metadata' => 'array',
45+
];
46+
47+
/**
48+
* @var string
49+
*/
50+
protected $table = 'audit_logs';
51+
52+
/**
53+
* @var bool
54+
*/
55+
protected $immutableDates = true;
56+
57+
/**
58+
* @var string[]
59+
*/
60+
protected $casts = [
61+
'device' => 'array',
62+
'metadata' => 'array',
63+
];
64+
65+
/**
66+
* @var string[]
67+
*/
68+
protected $guarded = [
69+
'id',
70+
'created_at',
71+
];
72+
73+
/**
74+
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
75+
*/
76+
public function user()
77+
{
78+
return $this->belongsTo(User::class);
79+
}
80+
81+
/**
82+
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
83+
*/
84+
public function server()
85+
{
86+
return $this->belongsTo(Server::class);
87+
}
88+
89+
/**
90+
* Creates a new AuditLog model and returns it, attaching device information and the
91+
* currently authenticated user if available. This model is not saved at this point, so
92+
* you can always make modifications to it as needed before saving.
93+
*
94+
* @param string $action
95+
* @param array $metadata
96+
* @param bool $isSystem
97+
* @return $this
98+
*/
99+
public static function factory(string $action, array $metadata, bool $isSystem = false)
100+
{
101+
/** @var \Illuminate\Http\Request $request */
102+
$request = Container::getInstance()->make('request');
103+
if (! $isSystem || ! $request instanceof Request) {
104+
$request = null;
105+
}
106+
107+
return (new self())->fill([
108+
'uuid' => Uuid::uuid4()->toString(),
109+
'is_system' => $isSystem,
110+
'user_id' => $request->user() ? $request->user()->id : null,
111+
'server_id' => null,
112+
'action' => $action,
113+
'device' => $request ? [
114+
'ip_address' => $request->getClientIp(),
115+
'user_agent' => $request->userAgent(),
116+
] : [],
117+
'metadata' => $metadata,
118+
]);
119+
}
120+
}

app/Models/Server.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
* @property \Pterodactyl\Models\ServerTransfer $transfer
5151
* @property \Pterodactyl\Models\Backup[]|\Illuminate\Database\Eloquent\Collection $backups
5252
* @property \Pterodactyl\Models\Mount[]|\Illuminate\Database\Eloquent\Collection $mounts
53+
* @property \Pterodactyl\Models\AuditLog[] $audits
5354
*/
5455
class Server extends Model
5556
{
@@ -326,4 +327,29 @@ public function mounts()
326327
{
327328
return $this->hasManyThrough(Mount::class, MountServer::class, 'server_id', 'id', 'id', 'mount_id');
328329
}
330+
331+
/**
332+
* Saves an audit entry to the database for the server.
333+
*
334+
* @param string $action
335+
* @param array $metadata
336+
* @return \Pterodactyl\Models\AuditLog
337+
*/
338+
public function audit(string $action, array $metadata): AuditLog
339+
{
340+
$model = AuditLog::factory($action, $metadata)->fill([
341+
'server_id' => $this->id,
342+
]);
343+
$model->save();
344+
345+
return $model;
346+
}
347+
348+
/**
349+
* @return \Illuminate\Database\Eloquent\Relations\HasMany
350+
*/
351+
public function audits()
352+
{
353+
return $this->hasMany(AuditLog::class);
354+
}
329355
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
class CreateAuditLogsTable extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*
12+
* @return void
13+
*/
14+
public function up()
15+
{
16+
Schema::create('audit_logs', function (Blueprint $table) {
17+
$table->id();
18+
$table->timestamps();
19+
});
20+
}
21+
22+
/**
23+
* Reverse the migrations.
24+
*
25+
* @return void
26+
*/
27+
public function down()
28+
{
29+
Schema::dropIfExists('audit_logs');
30+
}
31+
}

0 commit comments

Comments
 (0)