Add support for tracking when an activity event is triggered from an API key
This commit is contained in:
parent
92c1c162af
commit
0520014c0f
7 changed files with 87 additions and 0 deletions
|
@ -16,6 +16,7 @@ use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||||
use Pterodactyl\Http\Middleware\LanguageMiddleware;
|
use Pterodactyl\Http\Middleware\LanguageMiddleware;
|
||||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||||
use Illuminate\Routing\Middleware\SubstituteBindings;
|
use Illuminate\Routing\Middleware\SubstituteBindings;
|
||||||
|
use Pterodactyl\Http\Middleware\Activity\TrackAPIKey;
|
||||||
use Illuminate\Session\Middleware\AuthenticateSession;
|
use Illuminate\Session\Middleware\AuthenticateSession;
|
||||||
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
||||||
use Pterodactyl\Http\Middleware\MaintenanceMiddleware;
|
use Pterodactyl\Http\Middleware\MaintenanceMiddleware;
|
||||||
|
@ -68,6 +69,7 @@ class Kernel extends HttpKernel
|
||||||
EnsureStatefulRequests::class,
|
EnsureStatefulRequests::class,
|
||||||
'auth:sanctum',
|
'auth:sanctum',
|
||||||
IsValidJson::class,
|
IsValidJson::class,
|
||||||
|
TrackAPIKey::class,
|
||||||
RequireTwoFactorAuthentication::class,
|
RequireTwoFactorAuthentication::class,
|
||||||
AuthenticateIPAccess::class,
|
AuthenticateIPAccess::class,
|
||||||
],
|
],
|
||||||
|
|
30
app/Http/Middleware/Activity/TrackAPIKey.php
Normal file
30
app/Http/Middleware/Activity/TrackAPIKey.php
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pterodactyl\Http\Middleware\Activity;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Pterodactyl\Models\ApiKey;
|
||||||
|
use Pterodactyl\Facades\LogTarget;
|
||||||
|
|
||||||
|
class TrackAPIKey
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determines if the authenticated user making this request is using an actual
|
||||||
|
* API key, or it is just a cookie authenticated session. This data is set in a
|
||||||
|
* request singleton so that all tracked activity log events are properly associated
|
||||||
|
* with the given API key.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next)
|
||||||
|
{
|
||||||
|
if ($request->user()) {
|
||||||
|
$token = $request->user()->currentAccessToken();
|
||||||
|
|
||||||
|
LogTarget::setApiKeyId($token instanceof ApiKey ? $token->id : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ use Illuminate\Support\Facades\Event;
|
||||||
use Pterodactyl\Events\ActivityLogged;
|
use Pterodactyl\Events\ActivityLogged;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\MassPrunable;
|
use Illuminate\Database\Eloquent\MassPrunable;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||||
use Illuminate\Database\Eloquent\Model as IlluminateModel;
|
use Illuminate\Database\Eloquent\Model as IlluminateModel;
|
||||||
|
|
||||||
|
@ -21,11 +22,13 @@ use Illuminate\Database\Eloquent\Model as IlluminateModel;
|
||||||
* @property string|null $description
|
* @property string|null $description
|
||||||
* @property string|null $actor_type
|
* @property string|null $actor_type
|
||||||
* @property int|null $actor_id
|
* @property int|null $actor_id
|
||||||
|
* @property int|null $api_key_id
|
||||||
* @property \Illuminate\Support\Collection|null $properties
|
* @property \Illuminate\Support\Collection|null $properties
|
||||||
* @property \Carbon\Carbon $timestamp
|
* @property \Carbon\Carbon $timestamp
|
||||||
* @property IlluminateModel|\Eloquent $actor
|
* @property IlluminateModel|\Eloquent $actor
|
||||||
* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\ActivityLogSubject[] $subjects
|
* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\ActivityLogSubject[] $subjects
|
||||||
* @property int|null $subjects_count
|
* @property int|null $subjects_count
|
||||||
|
* @property \Pterodactyl\Models\ApiKey|null $apiKey
|
||||||
*
|
*
|
||||||
* @method static Builder|ActivityLog forActor(\Illuminate\Database\Eloquent\Model $actor)
|
* @method static Builder|ActivityLog forActor(\Illuminate\Database\Eloquent\Model $actor)
|
||||||
* @method static Builder|ActivityLog forEvent(string $action)
|
* @method static Builder|ActivityLog forEvent(string $action)
|
||||||
|
@ -34,6 +37,7 @@ use Illuminate\Database\Eloquent\Model as IlluminateModel;
|
||||||
* @method static Builder|ActivityLog query()
|
* @method static Builder|ActivityLog query()
|
||||||
* @method static Builder|ActivityLog whereActorId($value)
|
* @method static Builder|ActivityLog whereActorId($value)
|
||||||
* @method static Builder|ActivityLog whereActorType($value)
|
* @method static Builder|ActivityLog whereActorType($value)
|
||||||
|
* @method static Builder|ActivityLog whereApiKeyId($value)
|
||||||
* @method static Builder|ActivityLog whereBatch($value)
|
* @method static Builder|ActivityLog whereBatch($value)
|
||||||
* @method static Builder|ActivityLog whereDescription($value)
|
* @method static Builder|ActivityLog whereDescription($value)
|
||||||
* @method static Builder|ActivityLog whereEvent($value)
|
* @method static Builder|ActivityLog whereEvent($value)
|
||||||
|
@ -86,6 +90,11 @@ class ActivityLog extends Model
|
||||||
return $this->hasMany(ActivityLogSubject::class);
|
return $this->hasMany(ActivityLogSubject::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function apiKey(): HasOne
|
||||||
|
{
|
||||||
|
return $this->hasOne(ApiKey::class, 'id', 'api_key_id');
|
||||||
|
}
|
||||||
|
|
||||||
public function scopeForEvent(Builder $builder, string $action): Builder
|
public function scopeForEvent(Builder $builder, string $action): Builder
|
||||||
{
|
{
|
||||||
return $builder->where('event', $action);
|
return $builder->where('event', $action);
|
||||||
|
|
|
@ -210,6 +210,7 @@ class ActivityLogService
|
||||||
'ip' => Request::ip(),
|
'ip' => Request::ip(),
|
||||||
'batch_uuid' => $this->batch->uuid(),
|
'batch_uuid' => $this->batch->uuid(),
|
||||||
'properties' => Collection::make([]),
|
'properties' => Collection::make([]),
|
||||||
|
'api_key_id' => $this->targetable->apiKeyId(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($subject = $this->targetable->subject()) {
|
if ($subject = $this->targetable->subject()) {
|
||||||
|
|
|
@ -10,6 +10,8 @@ class ActivityLogTargetableService
|
||||||
|
|
||||||
protected ?Model $subject = null;
|
protected ?Model $subject = null;
|
||||||
|
|
||||||
|
protected ?int $apiKeyId = null;
|
||||||
|
|
||||||
public function setActor(Model $actor): void
|
public function setActor(Model $actor): void
|
||||||
{
|
{
|
||||||
$this->actor = $actor;
|
$this->actor = $actor;
|
||||||
|
@ -20,6 +22,11 @@ class ActivityLogTargetableService
|
||||||
$this->subject = $subject;
|
$this->subject = $subject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setApiKeyId(?int $apiKeyId): void
|
||||||
|
{
|
||||||
|
$this->apiKeyId = $apiKeyId;
|
||||||
|
}
|
||||||
|
|
||||||
public function actor(): ?Model
|
public function actor(): ?Model
|
||||||
{
|
{
|
||||||
return $this->actor;
|
return $this->actor;
|
||||||
|
@ -30,9 +37,15 @@ class ActivityLogTargetableService
|
||||||
return $this->subject;
|
return $this->subject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function apiKeyId(): ?int
|
||||||
|
{
|
||||||
|
return $this->apiKeyId;
|
||||||
|
}
|
||||||
|
|
||||||
public function reset(): void
|
public function reset(): void
|
||||||
{
|
{
|
||||||
$this->actor = null;
|
$this->actor = null;
|
||||||
$this->subject = null;
|
$this->subject = null;
|
||||||
|
$this->apiKeyId = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ class ActivityLogTransformer extends BaseClientTransformer
|
||||||
return [
|
return [
|
||||||
'batch' => $model->batch,
|
'batch' => $model->batch,
|
||||||
'event' => $model->event,
|
'event' => $model->event,
|
||||||
|
'is_api' => !is_null($model->api_key_id),
|
||||||
'ip' => $model->ip,
|
'ip' => $model->ip,
|
||||||
'description' => $model->description,
|
'description' => $model->description,
|
||||||
'properties' => $model->properties ? $model->properties->toArray() : [],
|
'properties' => $model->properties ? $model->properties->toArray() : [],
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
return new class () extends Migration {
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('activity_logs', function (Blueprint $table) {
|
||||||
|
$table->unsignedInteger('api_key_id')->nullable()->after('actor_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('activity_logs', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('api_key_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in a new issue