diff --git a/app/Console/Commands/Environment/AppSettingsCommand.php b/app/Console/Commands/Environment/AppSettingsCommand.php index dc9cc70d8..b143719fe 100644 --- a/app/Console/Commands/Environment/AppSettingsCommand.php +++ b/app/Console/Commands/Environment/AppSettingsCommand.php @@ -43,7 +43,8 @@ class AppSettingsCommand extends Command {--redis-host= : Redis host to use for connections.} {--redis-pass= : Password used to connect to redis.} {--redis-port= : Port to connect to redis over.} - {--settings-ui= : Enable or disable the settings UI.}'; + {--settings-ui= : Enable or disable the settings UI.} + {--telemetry= : Enable or disable anonymous telemetry.}'; protected array $variables = []; @@ -118,6 +119,12 @@ class AppSettingsCommand extends Command $this->variables['APP_ENVIRONMENT_ONLY'] = $this->confirm('Enable UI based settings editor?', true) ? 'false' : 'true'; } + $this->output->comment('Please reference https://pterodactyl.io/panel/1.0/additional_configuration.html#telemetry for more detailed information regarding telemetry data and collection.'); + $this->variables['PTERODACTYL_TELEMETRY_ENABLED'] = $this->option('telemetry') ?? $this->confirm( + 'Enable sending anonymous telemetry data?', + config('pterodactyl.telemetry.enabled', true) + ) ? 'true' : 'false'; + // Make sure session cookies are set as "secure" when using HTTPS if (str_starts_with($this->variables['APP_URL'], 'https://')) { $this->variables['SESSION_SECURE_COOKIE'] = 'true'; diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index a00b17b6d..f79e6c905 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -56,10 +56,10 @@ class Kernel extends ConsoleKernel { $settingsRepository = app()->make(SettingsRepository::class); - $uuid = $settingsRepository->get('app:uuid'); + $uuid = $settingsRepository->get('app:telemetry:uuid'); if (is_null($uuid)) { $uuid = Uuid::uuid4()->toString(); - $settingsRepository->set('app:uuid', $uuid); + $settingsRepository->set('app:telemetry:uuid', $uuid); } // Calculate a fixed time to run the data push at, this will be the same time every day. diff --git a/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php b/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php index 72153bf25..c14ddea97 100644 --- a/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php +++ b/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php @@ -11,6 +11,7 @@ use Illuminate\Database\ConnectionInterface; use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Repositories\Eloquent\ServerRepository; use Pterodactyl\Repositories\Wings\DaemonServerRepository; +use Symfony\Component\HttpKernel\Exception\ConflictHttpException; use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException; class ServerTransferController extends Controller @@ -33,8 +34,12 @@ class ServerTransferController extends Controller public function failure(string $uuid): JsonResponse { $server = $this->repository->getByUuid($uuid); + $transfer = $server->transfer; + if (is_null($transfer)) { + throw new ConflictHttpException('Server is not being transferred.'); + } - return $this->processFailedTransfer($server->transfer); + return $this->processFailedTransfer($transfer); } /** @@ -46,6 +51,9 @@ class ServerTransferController extends Controller { $server = $this->repository->getByUuid($uuid); $transfer = $server->transfer; + if (is_null($transfer)) { + throw new ConflictHttpException('Server is not being transferred.'); + } /** @var \Pterodactyl\Models\Server $server */ $server = $this->connection->transaction(function () use ($server, $transfer) { diff --git a/app/Services/Telemetry/TelemetryCollectionService.php b/app/Services/Telemetry/TelemetryCollectionService.php index 479d9dec8..f90bec033 100644 --- a/app/Services/Telemetry/TelemetryCollectionService.php +++ b/app/Services/Telemetry/TelemetryCollectionService.php @@ -51,10 +51,10 @@ class TelemetryCollectionService */ public function collect(): array { - $uuid = $this->settingsRepository->get('app:uuid'); + $uuid = $this->settingsRepository->get('app:telemetry:uuid'); if (is_null($uuid)) { $uuid = Uuid::uuid4()->toString(); - $this->settingsRepository->set('app:uuid', $uuid); + $this->settingsRepository->set('app:telemetry:uuid', $uuid); } $nodes = Node::all()->map(function ($node) { @@ -115,9 +115,11 @@ class TelemetryCollectionService 'backup' => [ 'type' => config('backups.default'), ], + 'cache' => [ 'type' => config('cache.default'), ], + 'database' => [ 'type' => config('database.default'), 'version' => DB::getPdo()->getAttribute(\PDO::ATTR_SERVER_VERSION), @@ -138,7 +140,10 @@ class TelemetryCollectionService 'eggs' => [ 'count' => Egg::count(), - 'ids' => Egg::pluck('uuid')->toArray(), + 'server_usage' => Egg::all() + ->flatMap(fn (Egg $egg) => [$egg->uuid => $egg->servers->count()]) + ->filter(fn (int $count) => $count > 0) + ->toArray(), ], 'locations' => [ @@ -151,6 +156,10 @@ class TelemetryCollectionService 'nests' => [ 'count' => Nest::count(), + 'server_usage' => Nest::all() + ->flatMap(fn (Nest $nest) => [$nest->uuid => $nest->eggs->sum(fn (Egg $egg) => $egg->servers->count())]) + ->filter(fn (int $count) => $count > 0) + ->toArray(), ], 'nodes' => [ diff --git a/config/activity.php b/config/activity.php index 3491d2e2b..6c492d334 100644 --- a/config/activity.php +++ b/config/activity.php @@ -1,7 +1,7 @@ env('APP_ACTIVITY_PRUNE_DAYS', 90), // If set to true activity log entries generated by an admin user that is not also diff --git a/config/pterodactyl.php b/config/pterodactyl.php index e5ceb3525..43c7c57be 100644 --- a/config/pterodactyl.php +++ b/config/pterodactyl.php @@ -187,6 +187,6 @@ return [ */ 'telemetry' => [ - 'enabled' => env('PTERODACTYL_TELEMETRY_ENABLED', false), + 'enabled' => env('PTERODACTYL_TELEMETRY_ENABLED', true), ], ]; diff --git a/database/Seeders/eggs/voice-servers/egg-teamspeak3-server.json b/database/Seeders/eggs/voice-servers/egg-teamspeak3-server.json index 2212a3c08..ef15f1ca0 100644 --- a/database/Seeders/eggs/voice-servers/egg-teamspeak3-server.json +++ b/database/Seeders/eggs/voice-servers/egg-teamspeak3-server.json @@ -13,7 +13,7 @@ "ghcr.io\/pterodactyl\/yolks:debian" ], "file_denylist": [], - "startup": ".\/ts3server default_voice_port={{SERVER_PORT}} query_port={{QUERY_PORT}} filetransfer_ip=0.0.0.0 filetransfer_port={{FILE_TRANSFER}} license_accepted=1", + "startup": ".\/ts3server default_voice_port={{SERVER_PORT}} query_port={{QUERY_PORT}} filetransfer_ip=0.0.0.0 filetransfer_port={{FILE_TRANSFER}} query_http_port={{QUERY_HTTP}} query_ssh_port={{QUERY_SSH}} query_protocols={{QUERY_PROTOCOLS_VAR}} license_accepted=1", "config": { "files": "{}", "startup": "{\r\n \"done\": \"listening on 0.0.0.0:\"\r\n}", @@ -22,7 +22,7 @@ }, "scripts": { "installation": { - "script": "#!\/bin\/ash\r\n# TS3 Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\n\r\nif [ -z ${TS_VERSION} ] || [ ${TS_VERSION} == latest ]; then\r\n TS_VERSION=$(curl -sSL https:\/\/teamspeak.com\/versions\/server.json | jq -r '.linux.x86_64.version')\r\nfi\r\n\r\ncd \/mnt\/server\r\n\r\necho -e \"getting files from http:\/\/files.teamspeak-services.com\/releases\/server\/${TS_VERSION}\/teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2\" \r\ncurl -L http:\/\/files.teamspeak-services.com\/releases\/server\/${TS_VERSION}\/teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2 | tar -xvj --strip-components=1", + "script": "#!\/bin\/ash\r\n# TS3 Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\n\r\nif [ -z ${TS_VERSION} ] || [ ${TS_VERSION} == latest ]; then\r\n TS_VERSION=$(curl -sSL https:\/\/teamspeak.com\/versions\/server.json | jq -r '.linux.x86_64.version')\r\nfi\r\n\r\ncd \/mnt\/server\r\n\r\necho -e \"getting files from http:\/\/files.teamspeak-services.com\/releases\/server\/${TS_VERSION}\/teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2\" \r\ncurl -L http:\/\/files.teamspeak-services.com\/releases\/server\/${TS_VERSION}\/teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2 | tar -xvj --strip-components=1\r\ncp .\/redist\/libmariadb.so.2 .\/", "container": "ghcr.io\/pterodactyl\/installers:alpine", "entrypoint": "ash" } @@ -35,7 +35,8 @@ "default_value": "latest", "user_viewable": true, "user_editable": true, - "rules": "required|string|max:6" + "rules": "required|string|max:6", + "field_type": "text" }, { "name": "File Transfer Port", @@ -44,7 +45,8 @@ "default_value": "30033", "user_viewable": true, "user_editable": false, - "rules": "required|integer|between:1,65535" + "rules": "required|integer|between:1025,65535", + "field_type": "text" }, { "name": "Query Port", @@ -53,7 +55,38 @@ "default_value": "10011", "user_viewable": true, "user_editable": false, - "rules": "required|integer|between:1,65535" + "rules": "required|integer|between:1025,65535", + "field_type": "text" + }, + { + "name": "Query Protocols", + "description": "Comma separated list of protocols that can be used to connect to the ServerQuery | \r\nPossible values are raw, ssh and http | \r\nE.g.: raw,ssh,http", + "env_variable": "QUERY_PROTOCOLS_VAR", + "default_value": "raw,http,ssh", + "user_viewable": true, + "user_editable": true, + "rules": "required|string|max:12", + "field_type": "text" + }, + { + "name": "Query SSH Port", + "description": "TCP Port opened for ServerQuery connections using SSH", + "env_variable": "QUERY_SSH", + "default_value": "10022", + "user_viewable": true, + "user_editable": false, + "rules": "required|integer|between:1025,65535", + "field_type": "text" + }, + { + "name": "Query HTTP Port", + "description": "TCP Port opened for ServerQuery connections using http", + "env_variable": "QUERY_HTTP", + "default_value": "10080", + "user_viewable": true, + "user_editable": false, + "rules": "required|integer|between:1025,65535", + "field_type": "text" } ] -} \ No newline at end of file +} diff --git a/routes/api-remote.php b/routes/api-remote.php index e43c62eaf..88b2a6ea1 100644 --- a/routes/api-remote.php +++ b/routes/api-remote.php @@ -15,9 +15,10 @@ Route::group(['prefix' => '/servers/{uuid}'], function () { Route::get('/install', [Remote\Servers\ServerInstallController::class, 'index']); Route::post('/install', [Remote\Servers\ServerInstallController::class, 'store']); - Route::post('/archive', [Remote\Servers\ServerTransferController::class, 'archive']); Route::get('/transfer/failure', [Remote\Servers\ServerTransferController::class, 'failure']); Route::get('/transfer/success', [Remote\Servers\ServerTransferController::class, 'success']); + Route::post('/transfer/failure', [Remote\Servers\ServerTransferController::class, 'failure']); + Route::post('/transfer/success', [Remote\Servers\ServerTransferController::class, 'success']); }); Route::group(['prefix' => '/backups'], function () { diff --git a/routes/auth.php b/routes/auth.php index 7d0930f11..36039f3a2 100644 --- a/routes/auth.php +++ b/routes/auth.php @@ -1,5 +1,6 @@ name('auth.login'); Route::get('/password', [Auth\LoginController::class, 'index'])->name('auth.forgot-password'); @@ -38,12 +39,12 @@ Route::middleware(['throttle:authentication'])->group(function () { // is created). Route::post('/password/reset', Auth\ResetPasswordController::class)->name('auth.reset-password'); -// Remove the guest middleware and apply the authenticated middleware to this endpoint +// Remove the guest middleware and apply the authenticated middleware to this endpoint, // so it cannot be used unless you're already logged in. Route::post('/logout', [Auth\LoginController::class, 'logout']) ->withoutMiddleware('guest') ->middleware('auth') ->name('auth.logout'); -// Catch any other combinations of routes and pass them off to the Vuejs component. +// Catch any other combinations of routes and pass them off to the React component. Route::fallback([Auth\LoginController::class, 'index']); diff --git a/routes/base.php b/routes/base.php index 1d3ad66a6..93f45b577 100644 --- a/routes/base.php +++ b/routes/base.php @@ -1,5 +1,6 @@