diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index bbd5d2ce2..8084dc220 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -16,6 +16,7 @@ use Illuminate\Routing\Middleware\ThrottleRequests; use Pterodactyl\Http\Middleware\LanguageMiddleware; use Illuminate\Foundation\Http\Kernel as HttpKernel; use Illuminate\Routing\Middleware\SubstituteBindings; +use Pterodactyl\Http\Middleware\Activity\TrackAPIKey; use Illuminate\Session\Middleware\AuthenticateSession; use Illuminate\View\Middleware\ShareErrorsFromSession; use Pterodactyl\Http\Middleware\MaintenanceMiddleware; @@ -68,6 +69,7 @@ class Kernel extends HttpKernel EnsureStatefulRequests::class, 'auth:sanctum', IsValidJson::class, + TrackAPIKey::class, RequireTwoFactorAuthentication::class, AuthenticateIPAccess::class, ], diff --git a/app/Http/Middleware/Activity/TrackAPIKey.php b/app/Http/Middleware/Activity/TrackAPIKey.php new file mode 100644 index 000000000..90d53759e --- /dev/null +++ b/app/Http/Middleware/Activity/TrackAPIKey.php @@ -0,0 +1,30 @@ +user()) { + $token = $request->user()->currentAccessToken(); + + LogTarget::setApiKeyId($token instanceof ApiKey ? $token->id : null); + } + + return $next($request); + } +} diff --git a/app/Models/ActivityLog.php b/app/Models/ActivityLog.php index dbf936a67..bfe324ad7 100644 --- a/app/Models/ActivityLog.php +++ b/app/Models/ActivityLog.php @@ -8,6 +8,7 @@ use Illuminate\Support\Facades\Event; use Pterodactyl\Events\ActivityLogged; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\MassPrunable; +use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\MorphTo; 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 $actor_type * @property int|null $actor_id + * @property int|null $api_key_id * @property \Illuminate\Support\Collection|null $properties * @property \Carbon\Carbon $timestamp * @property IlluminateModel|\Eloquent $actor * @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\ActivityLogSubject[] $subjects * @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 forEvent(string $action) @@ -34,6 +37,7 @@ use Illuminate\Database\Eloquent\Model as IlluminateModel; * @method static Builder|ActivityLog query() * @method static Builder|ActivityLog whereActorId($value) * @method static Builder|ActivityLog whereActorType($value) + * @method static Builder|ActivityLog whereApiKeyId($value) * @method static Builder|ActivityLog whereBatch($value) * @method static Builder|ActivityLog whereDescription($value) * @method static Builder|ActivityLog whereEvent($value) @@ -86,6 +90,11 @@ class ActivityLog extends Model 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 { return $builder->where('event', $action); diff --git a/app/Services/Activity/ActivityLogService.php b/app/Services/Activity/ActivityLogService.php index cb45dc33d..cfdd5a9cd 100644 --- a/app/Services/Activity/ActivityLogService.php +++ b/app/Services/Activity/ActivityLogService.php @@ -210,6 +210,7 @@ class ActivityLogService 'ip' => Request::ip(), 'batch_uuid' => $this->batch->uuid(), 'properties' => Collection::make([]), + 'api_key_id' => $this->targetable->apiKeyId(), ]); if ($subject = $this->targetable->subject()) { diff --git a/app/Services/Activity/ActivityLogTargetableService.php b/app/Services/Activity/ActivityLogTargetableService.php index a4da5b5f3..4d37e9828 100644 --- a/app/Services/Activity/ActivityLogTargetableService.php +++ b/app/Services/Activity/ActivityLogTargetableService.php @@ -10,6 +10,8 @@ class ActivityLogTargetableService protected ?Model $subject = null; + protected ?int $apiKeyId = null; + public function setActor(Model $actor): void { $this->actor = $actor; @@ -20,6 +22,11 @@ class ActivityLogTargetableService $this->subject = $subject; } + public function setApiKeyId(?int $apiKeyId): void + { + $this->apiKeyId = $apiKeyId; + } + public function actor(): ?Model { return $this->actor; @@ -30,9 +37,15 @@ class ActivityLogTargetableService return $this->subject; } + public function apiKeyId(): ?int + { + return $this->apiKeyId; + } + public function reset(): void { $this->actor = null; $this->subject = null; + $this->apiKeyId = null; } } diff --git a/app/Transformers/Api/Client/ActivityLogTransformer.php b/app/Transformers/Api/Client/ActivityLogTransformer.php index e6ff72a6f..1a0154b6f 100644 --- a/app/Transformers/Api/Client/ActivityLogTransformer.php +++ b/app/Transformers/Api/Client/ActivityLogTransformer.php @@ -19,6 +19,7 @@ class ActivityLogTransformer extends BaseClientTransformer return [ 'batch' => $model->batch, 'event' => $model->event, + 'is_api' => !is_null($model->api_key_id), 'ip' => $model->ip, 'description' => $model->description, 'properties' => $model->properties ? $model->properties->toArray() : [], diff --git a/database/migrations/2022_06_18_112822_track_api_key_usage_for_activity_events.php b/database/migrations/2022_06_18_112822_track_api_key_usage_for_activity_events.php new file mode 100644 index 000000000..6e35df9a2 --- /dev/null +++ b/database/migrations/2022_06_18_112822_track_api_key_usage_for_activity_events.php @@ -0,0 +1,31 @@ +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'); + }); + } +};