Keep an audit log of who did what, and how they came in
Written from model events, spatie's role events and panel sign-ins, only for what a person did, with secrets masked; pruned after a year. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,10 +8,13 @@ use App\Auth\PireonTokenGuard;
|
||||
use App\Models\Application;
|
||||
use App\Models\ReviewComment;
|
||||
use App\Models\Revision;
|
||||
use App\Models\User;
|
||||
use App\Services\Git\GitManager;
|
||||
use App\Services\Pireon\PireonClient;
|
||||
use App\Services\Pireon\TokenStore;
|
||||
use App\Support\Audit\Auditor;
|
||||
use App\Support\Webhooks\Webhooks;
|
||||
use Illuminate\Auth\Events\Login;
|
||||
use Illuminate\Auth\Events\Logout;
|
||||
use Illuminate\Cache\RateLimiting\Limit;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
@@ -22,6 +25,9 @@ use Illuminate\Support\Facades\RateLimiter;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\Permission\Events\RoleAttached;
|
||||
use Spatie\Permission\Events\RoleDetached;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -38,6 +44,19 @@ class AppServiceProvider extends ServiceProvider
|
||||
$this->app->singleton(GitManager::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, string>
|
||||
*/
|
||||
protected static function roleNames(mixed $rolesOrIds): array
|
||||
{
|
||||
return Role::query()
|
||||
->whereIn('id', collect(is_iterable($rolesOrIds) ? $rolesOrIds : [$rolesOrIds])
|
||||
->map(fn ($role) => $role instanceof Role ? $role->id : $role)
|
||||
->all())
|
||||
->pluck('name')
|
||||
->all();
|
||||
}
|
||||
|
||||
public function boot(): void
|
||||
{
|
||||
// Outgoing webhooks, fed by the records themselves so the panel, the
|
||||
@@ -46,6 +65,24 @@ class AppServiceProvider extends ServiceProvider
|
||||
Revision::created(fn (Revision $revision) => Webhooks::revisionRecorded($revision));
|
||||
ReviewComment::created(fn (ReviewComment $comment) => Webhooks::reviewRecorded($comment));
|
||||
|
||||
// The audit log: every change a person makes to an audited record,
|
||||
// role changes, and signing in to the panel.
|
||||
foreach (['created', 'updated', 'deleted', 'restored'] as $event) {
|
||||
Event::listen("eloquent.{$event}: *", function (string $name, array $payload) use ($event): void {
|
||||
if (($payload[0] ?? null) instanceof Model) {
|
||||
Auditor::modelEvent($event, $payload[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Event::listen(RoleAttached::class, fn (RoleAttached $e) => Auditor::record('users.roles_added', $e->model, ['roles' => self::roleNames($e->rolesOrIds)]));
|
||||
Event::listen(RoleDetached::class, fn (RoleDetached $e) => Auditor::record('users.roles_removed', $e->model, ['roles' => self::roleNames($e->rolesOrIds)]));
|
||||
Event::listen(Login::class, function (Login $e): void {
|
||||
if ($e->user instanceof User) {
|
||||
Auditor::record('auth.login', $e->user, null, $e->user);
|
||||
}
|
||||
});
|
||||
|
||||
// Backs the "api" guard declared in config/auth.php.
|
||||
Auth::viaRequest('pireon', fn (Request $request) => $this->app
|
||||
->make(PireonTokenGuard::class)($request));
|
||||
|
||||
Reference in New Issue
Block a user