Add activity logging to most of the endpoints
This commit is contained in:
parent
287fd60891
commit
9b7af02690
11 changed files with 170 additions and 30 deletions
|
@ -16,6 +16,7 @@ use Pterodactyl\Services\Activity\ActivityLogService;
|
|||
* @method static ActivityLogService property(string|array $key, mixed $value = null)
|
||||
* @method static \Pterodactyl\Models\ActivityLog log(string $description = null)
|
||||
* @method static ActivityLogService clone()
|
||||
* @method static void reset()
|
||||
* @method static mixed transaction(\Closure $callback)
|
||||
*/
|
||||
class Activity extends Facade
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
|
|||
use Illuminate\Http\Response;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Models\Database;
|
||||
use Pterodactyl\Facades\Activity;
|
||||
use Pterodactyl\Repositories\Eloquent\DatabaseRepository;
|
||||
use Pterodactyl\Services\Databases\DatabasePasswordService;
|
||||
use Pterodactyl\Transformers\Api\Client\DatabaseTransformer;
|
||||
|
@ -76,6 +77,11 @@ class DatabaseController extends ClientApiController
|
|||
{
|
||||
$database = $this->deployDatabaseService->handle($server, $request->validated());
|
||||
|
||||
Activity::event('server:database.create')
|
||||
->subject($database)
|
||||
->property('name', $database->database)
|
||||
->log();
|
||||
|
||||
return $this->fractal->item($database)
|
||||
->parseIncludes(['password'])
|
||||
->transformWith($this->getTransformer(DatabaseTransformer::class))
|
||||
|
@ -95,6 +101,8 @@ class DatabaseController extends ClientApiController
|
|||
$this->passwordService->handle($database);
|
||||
$database->refresh();
|
||||
|
||||
Activity::event('server:database.rotate-password')->subject($database)->log();
|
||||
|
||||
return $this->fractal->item($database)
|
||||
->parseIncludes(['password'])
|
||||
->transformWith($this->getTransformer(DatabaseTransformer::class))
|
||||
|
@ -110,6 +118,11 @@ class DatabaseController extends ClientApiController
|
|||
{
|
||||
$this->managementService->delete($database);
|
||||
|
||||
Activity::event('server:database.delete')
|
||||
->subject($database)
|
||||
->property('name', $database->database)
|
||||
->log();
|
||||
|
||||
return Response::create('', Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
|
|||
|
||||
use Pterodactyl\Models\Server;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Pterodactyl\Facades\Activity;
|
||||
use Pterodactyl\Models\Allocation;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||
|
@ -68,9 +69,16 @@ class NetworkAllocationController extends ClientApiController
|
|||
*/
|
||||
public function update(UpdateAllocationRequest $request, Server $server, Allocation $allocation): array
|
||||
{
|
||||
$allocation = $this->repository->update($allocation->id, [
|
||||
'notes' => $request->input('notes'),
|
||||
]);
|
||||
$original = $allocation->notes;
|
||||
|
||||
$allocation->forceFill(['notes' => $request->input('notes')])->save();
|
||||
|
||||
if ($original !== $allocation->notes) {
|
||||
Activity::event('server:allocation.notes')
|
||||
->subject($allocation)
|
||||
->property(['allocation' => $allocation->toString(), 'old' => $original, 'new' => $allocation->notes])
|
||||
->log();
|
||||
}
|
||||
|
||||
return $this->fractal->item($allocation)
|
||||
->transformWith($this->getTransformer(AllocationTransformer::class))
|
||||
|
@ -87,6 +95,11 @@ class NetworkAllocationController extends ClientApiController
|
|||
{
|
||||
$this->serverRepository->update($server->id, ['allocation_id' => $allocation->id]);
|
||||
|
||||
Activity::event('server:allocation.primary')
|
||||
->subject($allocation)
|
||||
->property('allocation', $allocation->toString())
|
||||
->log();
|
||||
|
||||
return $this->fractal->item($allocation)
|
||||
->transformWith($this->getTransformer(AllocationTransformer::class))
|
||||
->toArray();
|
||||
|
@ -106,6 +119,11 @@ class NetworkAllocationController extends ClientApiController
|
|||
|
||||
$allocation = $this->assignableAllocationService->handle($server);
|
||||
|
||||
Activity::event('server:allocation.create')
|
||||
->subject($allocation)
|
||||
->property('allocation', $allocation->toString())
|
||||
->log();
|
||||
|
||||
return $this->fractal->item($allocation)
|
||||
->transformWith($this->getTransformer(AllocationTransformer::class))
|
||||
->toArray();
|
||||
|
@ -135,6 +153,11 @@ class NetworkAllocationController extends ClientApiController
|
|||
'server_id' => null,
|
||||
]);
|
||||
|
||||
Activity::event('server:allocation.delete')
|
||||
->subject($allocation)
|
||||
->property('allocation', $allocation->toString())
|
||||
->log();
|
||||
|
||||
return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use Illuminate\Http\Response;
|
|||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Models\Schedule;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Pterodactyl\Facades\Activity;
|
||||
use Pterodactyl\Helpers\Utilities;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Repositories\Eloquent\ScheduleRepository;
|
||||
|
@ -83,6 +84,11 @@ class ScheduleController extends ClientApiController
|
|||
'next_run_at' => $this->getNextRunAt($request),
|
||||
]);
|
||||
|
||||
Activity::event('server:schedule.create')
|
||||
->subject($model)
|
||||
->property('name', $model->name)
|
||||
->log();
|
||||
|
||||
return $this->fractal->item($model)
|
||||
->transformWith($this->getTransformer(ScheduleTransformer::class))
|
||||
->toArray();
|
||||
|
@ -141,6 +147,11 @@ class ScheduleController extends ClientApiController
|
|||
|
||||
$this->repository->update($schedule->id, $data);
|
||||
|
||||
Activity::event('server:schedule.update')
|
||||
->subject($schedule)
|
||||
->property(['name' => $schedule->name, 'active' => $active])
|
||||
->log();
|
||||
|
||||
return $this->fractal->item($schedule->refresh())
|
||||
->transformWith($this->getTransformer(ScheduleTransformer::class))
|
||||
->toArray();
|
||||
|
@ -158,6 +169,8 @@ class ScheduleController extends ClientApiController
|
|||
{
|
||||
$this->service->handle($schedule, true);
|
||||
|
||||
Activity::event('server:schedule.execute')->subject($schedule)->property('name', $schedule->name)->log();
|
||||
|
||||
return new JsonResponse([], JsonResponse::HTTP_ACCEPTED);
|
||||
}
|
||||
|
||||
|
@ -170,6 +183,8 @@ class ScheduleController extends ClientApiController
|
|||
{
|
||||
$this->repository->delete($schedule->id);
|
||||
|
||||
Activity::event('server:schedule.delete')->subject($schedule)->property('name', $schedule->name)->log();
|
||||
|
||||
return new JsonResponse([], Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ use Illuminate\Http\Response;
|
|||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Models\Schedule;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Pterodactyl\Facades\Activity;
|
||||
use Pterodactyl\Models\Permission;
|
||||
use Pterodactyl\Repositories\Eloquent\TaskRepository;
|
||||
use Pterodactyl\Exceptions\Http\HttpForbiddenException;
|
||||
|
@ -67,6 +68,11 @@ class ScheduleTaskController extends ClientApiController
|
|||
'continue_on_failure' => (bool) $request->input('continue_on_failure'),
|
||||
]);
|
||||
|
||||
Activity::event('server:task.create')
|
||||
->subject($schedule, $task)
|
||||
->property(['name' => $schedule->name, 'action' => $task->action, 'payload' => $task->payload])
|
||||
->log();
|
||||
|
||||
return $this->fractal->item($task)
|
||||
->transformWith($this->getTransformer(TaskTransformer::class))
|
||||
->toArray();
|
||||
|
@ -98,6 +104,11 @@ class ScheduleTaskController extends ClientApiController
|
|||
'continue_on_failure' => (bool) $request->input('continue_on_failure'),
|
||||
]);
|
||||
|
||||
Activity::event('server:task.update')
|
||||
->subject($schedule, $task)
|
||||
->property(['name' => $schedule->name, 'action' => $task->action, 'payload' => $task->payload])
|
||||
->log();
|
||||
|
||||
return $this->fractal->item($task->refresh())
|
||||
->transformWith($this->getTransformer(TaskTransformer::class))
|
||||
->toArray();
|
||||
|
@ -127,6 +138,8 @@ class ScheduleTaskController extends ClientApiController
|
|||
|
||||
$task->delete();
|
||||
|
||||
Activity::event('server:task.delete')->subject($schedule, $task)->property('name', $schedule->name)->log();
|
||||
|
||||
return new JsonResponse(null, Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
|
|||
use Illuminate\Http\Response;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Pterodactyl\Facades\Activity;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||
use Pterodactyl\Services\Servers\ReinstallServerService;
|
||||
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
|
||||
|
@ -52,6 +53,12 @@ class SettingsController extends ClientApiController
|
|||
'name' => $request->input('name'),
|
||||
]);
|
||||
|
||||
if ($server->name !== $request->input('name')) {
|
||||
Activity::event('server:settings.rename')
|
||||
->property(['old' => $server->name, 'new' => $request->input('name')])
|
||||
->log();
|
||||
}
|
||||
|
||||
return new JsonResponse([], Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
|
||||
|
@ -66,6 +73,8 @@ class SettingsController extends ClientApiController
|
|||
{
|
||||
$this->reinstallServerService->handle($server);
|
||||
|
||||
Activity::event('server:reinstall')->log();
|
||||
|
||||
return new JsonResponse([], Response::HTTP_ACCEPTED);
|
||||
}
|
||||
|
||||
|
@ -82,8 +91,15 @@ class SettingsController extends ClientApiController
|
|||
throw new BadRequestHttpException('This server\'s Docker image has been manually set by an administrator and cannot be updated.');
|
||||
}
|
||||
|
||||
$original = $server->image;
|
||||
$server->forceFill(['image' => $request->input('docker_image')])->saveOrFail();
|
||||
|
||||
if ($original !== $server->image) {
|
||||
Activity::event('server:startup.image')
|
||||
->property(['old' => $original, 'new' => $request->input('docker_image')])
|
||||
->log();
|
||||
}
|
||||
|
||||
return new JsonResponse([], Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
|
||||
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Facades\Activity;
|
||||
use Pterodactyl\Services\Servers\StartupCommandService;
|
||||
use Pterodactyl\Services\Servers\VariableValidatorService;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerVariableRepository;
|
||||
|
@ -75,6 +76,7 @@ class StartupController extends ClientApiController
|
|||
{
|
||||
/** @var \Pterodactyl\Models\EggVariable $variable */
|
||||
$variable = $server->variables()->where('env_variable', $request->input('key'))->first();
|
||||
$original = $variable->server_value;
|
||||
|
||||
if (is_null($variable) || !$variable->user_viewable) {
|
||||
throw new BadRequestHttpException('The environment variable you are trying to edit does not exist.');
|
||||
|
@ -97,6 +99,17 @@ class StartupController extends ClientApiController
|
|||
|
||||
$startup = $this->startupCommandService->handle($server, false);
|
||||
|
||||
if ($variable->env_variable !== $request->input('value')) {
|
||||
Activity::event('server:startup.edit')
|
||||
->subject($variable)
|
||||
->property([
|
||||
'variable' => $variable->env_variable,
|
||||
'old' => $original,
|
||||
'new' => $request->input('value'),
|
||||
])
|
||||
->log();
|
||||
}
|
||||
|
||||
return $this->fractal->item($variable)
|
||||
->transformWith($this->getTransformer(EggVariableTransformer::class))
|
||||
->addMeta([
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
|
|||
use Illuminate\Http\Request;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Pterodactyl\Facades\Activity;
|
||||
use Pterodactyl\Models\Permission;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Pterodactyl\Repositories\Eloquent\SubuserRepository;
|
||||
|
@ -94,6 +95,11 @@ class SubuserController extends ClientApiController
|
|||
$this->getDefaultPermissions($request)
|
||||
);
|
||||
|
||||
Activity::event('server:subuser.create')
|
||||
->subject($response->user)
|
||||
->property(['email' => $request->input('email'), 'permissions' => $this->getDefaultPermissions($request)])
|
||||
->log();
|
||||
|
||||
return $this->fractal->item($response)
|
||||
->transformWith($this->getTransformer(SubuserTransformer::class))
|
||||
->toArray();
|
||||
|
@ -116,9 +122,19 @@ class SubuserController extends ClientApiController
|
|||
sort($permissions);
|
||||
sort($current);
|
||||
|
||||
$log = Activity::event('server:subuser.update')
|
||||
->subject($subuser->user)
|
||||
->property([
|
||||
'email' => $subuser->user->email,
|
||||
'old' => $current,
|
||||
'new' => $permissions,
|
||||
'revoked' => true,
|
||||
]);
|
||||
|
||||
// Only update the database and hit up the Wings instance to invalidate JTI's if the permissions
|
||||
// have actually changed for the user.
|
||||
if ($permissions !== $current) {
|
||||
$log->transaction(function ($instance) use ($request, $subuser, $server) {
|
||||
$this->repository->update($subuser->id, [
|
||||
'permissions' => $this->getDefaultPermissions($request),
|
||||
]);
|
||||
|
@ -129,9 +145,14 @@ class SubuserController extends ClientApiController
|
|||
// Don't block this request if we can't connect to the Wings instance. Chances are it is
|
||||
// offline in this event and the token will be invalid anyways once Wings boots back.
|
||||
Log::warning($exception, ['user_id' => $subuser->user_id, 'server_id' => $server->id]);
|
||||
|
||||
$instance->property('revoked', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$log->reset();
|
||||
|
||||
return $this->fractal->item($subuser->refresh())
|
||||
->transformWith($this->getTransformer(SubuserTransformer::class))
|
||||
->toArray();
|
||||
|
@ -147,14 +168,23 @@ class SubuserController extends ClientApiController
|
|||
/** @var \Pterodactyl\Models\Subuser $subuser */
|
||||
$subuser = $request->attributes->get('subuser');
|
||||
|
||||
$this->repository->delete($subuser->id);
|
||||
$log = Activity::event('server:subuser.delete')
|
||||
->subject($subuser->user)
|
||||
->property('email', $subuser->user->email)
|
||||
->property('revoked', true);
|
||||
|
||||
$log->transaction(function ($instance) use ($server, $subuser) {
|
||||
$subuser->delete();
|
||||
|
||||
try {
|
||||
$this->serverRepository->setServer($server)->revokeUserJTI($subuser->user_id);
|
||||
} catch (DaemonConnectionException $exception) {
|
||||
// Don't block this request if we can't connect to the Wings instance.
|
||||
Log::warning($exception, ['user_id' => $subuser->user_id, 'server_id' => $server->id]);
|
||||
|
||||
$instance->property('revoked', false);
|
||||
}
|
||||
});
|
||||
|
||||
return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT);
|
||||
}
|
||||
|
|
|
@ -122,6 +122,11 @@ class Allocation extends Model
|
|||
return !is_null($this->ip_alias);
|
||||
}
|
||||
|
||||
public function toString(): string
|
||||
{
|
||||
return sprintf('%s:%s', $this->ip, $this->port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets information for the server associated with this allocation.
|
||||
*
|
||||
|
|
|
@ -4,12 +4,8 @@ namespace Pterodactyl\Providers;
|
|||
|
||||
use View;
|
||||
use Cache;
|
||||
use Pterodactyl\Models;
|
||||
use Illuminate\Support\Str;
|
||||
use Pterodactyl\Models\User;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Models\Backup;
|
||||
use Pterodactyl\Models\ApiKey;
|
||||
use Pterodactyl\Models\UserSSHKey;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Illuminate\Pagination\Paginator;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
@ -41,11 +37,17 @@ class AppServiceProvider extends ServiceProvider
|
|||
}
|
||||
|
||||
Relation::enforceMorphMap([
|
||||
'api_key' => ApiKey::class,
|
||||
'backup' => Backup::class,
|
||||
'server' => Server::class,
|
||||
'ssh_key' => UserSSHKey::class,
|
||||
'user' => User::class,
|
||||
'allocation' => Models\Allocation::class,
|
||||
'api_key' => Models\ApiKey::class,
|
||||
'backup' => Models\Backup::class,
|
||||
'database' => Models\Database::class,
|
||||
'egg' => Models\Egg::class,
|
||||
'egg_variable' => Models\EggVariable::class,
|
||||
'schedule' => Models\Schedule::class,
|
||||
'server' => Models\Server::class,
|
||||
'ssh_key' => Models\UserSSHKey::class,
|
||||
'task' => Models\Task::class,
|
||||
'user' => Models\User::class,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -188,6 +188,15 @@ class ActivityLogService
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the instance and clears out the log.
|
||||
*/
|
||||
public function reset(): void
|
||||
{
|
||||
$this->activity = null;
|
||||
$this->subjects = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current activity log instance.
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue