diff --git a/.env.example b/.env.example index e90d4b5f6..5a2dd4dbf 100644 --- a/.env.example +++ b/.env.example @@ -2,10 +2,10 @@ APP_ENV=production APP_DEBUG=false APP_KEY=SomeRandomString3232RandomString APP_THEME=pterodactyl -APP_TIMEZONE=UTC +APP_TIMEZONE=America/New_York APP_CLEAR_TASKLOG=720 APP_DELETE_MINUTES=10 -APP_URL=http://yoursite.com/ +APP_URL= DB_HOST=127.0.0.1 DB_PORT=3306 @@ -13,8 +13,8 @@ DB_DATABASE=panel DB_USERNAME=pterodactyl DB_PASSWORD= -CACHE_DRIVER=redis -SESSION_DRIVER=database +CACHE_DRIVER= +SESSION_DRIVER= HASHIDS_SALT= HASHIDS_LENGTH=8 @@ -25,9 +25,9 @@ MAIL_PORT=2525 MAIL_USERNAME= MAIL_PASSWORD= MAIL_ENCRYPTION=tls -MAIL_FROM=you@example.com +MAIL_FROM=no-reply@example.com -QUEUE_DRIVER=database +QUEUE_DRIVER= QUEUE_HIGH=high QUEUE_STANDARD=standard QUEUE_LOW=low diff --git a/.travis.yml b/.travis.yml index b0590806e..277c25df2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,9 +13,10 @@ services: before_install: - mysql -e 'CREATE DATABASE IF NOT EXISTS travis;' before_script: + - echo 'opcache.enable_cli=1' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini - cp .env.travis .env - - composer install --no-interaction --prefer-dist --no-suggest --verbose - - php artisan migrate --seed -v + - composer install --no-interaction --prefer-dist --no-suggest + - php artisan migrate --seed script: - vendor/bin/phpunit --coverage-clover coverage.xml notifications: diff --git a/CHANGELOG.md b/CHANGELOG.md index 822175062..825277fb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ This file is a running track of new features and fixes to each version of the pa This project follows [Semantic Versioning](http://semver.org) guidelines. ## v0.7.0-beta.3 (Derelict Dermodactylus) +### Fixed +* `[beta.2]` — Fixes a bug that would cause an endless exception message stream in the console when attemping to setup environment settings in certain instances. +* `[beta.2]` — Fixes a bug causing the dropdown menu for a server's egg to display the wrong selected value. +* `[beta.2]` — Fixes a bug that would throw a red page of death when submitting an invalid egg variable value for a server in the Admin CP. +* `[beta.2]` — Someone found a `@todo` that I never `@todid` and thus database hosts could not be created without being linked to a node. This is fixed... +* `[beta.2]` — Fixes bug that caused incorrect rendering of CPU usage on server graphs due to missing variable. + ### Changed * API keys have been changed to only use a single public key passed in a bearer token. All existing keys can continue being used, however only the first 32 characters should be sent. diff --git a/app/Console/Commands/Environment/AppSettingsCommand.php b/app/Console/Commands/Environment/AppSettingsCommand.php index fbfa117f7..8f27d1adb 100644 --- a/app/Console/Commands/Environment/AppSettingsCommand.php +++ b/app/Console/Commands/Environment/AppSettingsCommand.php @@ -9,6 +9,7 @@ namespace Pterodactyl\Console\Commands\Environment; +use DateTimeZone; use Illuminate\Console\Command; use Illuminate\Contracts\Console\Kernel; use Pterodactyl\Traits\Commands\EnvironmentWriterTrait; @@ -18,6 +19,25 @@ class AppSettingsCommand extends Command { use EnvironmentWriterTrait; + const ALLOWED_CACHE_DRIVERS = [ + 'redis' => 'Redis (recommended)', + 'memcached' => 'Memcached', + ]; + + const ALLOWED_SESSION_DRIVERS = [ + 'redis' => 'Redis (recommended)', + 'memcached' => 'Memcached', + 'database' => 'MySQL Database', + 'file' => 'Filesystem', + 'cookie' => 'Cookie', + ]; + + const ALLOWED_QUEUE_DRIVERS = [ + 'redis' => 'Redis (recommended)', + 'database' => 'MySQL Database', + 'sync' => 'Sync', + ]; + /** * @var \Illuminate\Contracts\Console\Kernel */ @@ -37,11 +57,13 @@ class AppSettingsCommand extends Command * @var string */ protected $signature = 'p:environment:setup + {--new-salt : Wether or not to generate a new salt for Hashids.} {--author= : The email that services created on this instance should be linked to.} {--url= : The URL that this Panel is running on.} {--timezone= : The timezone to use for Panel times.} {--cache= : The cache driver backend to use.} {--session= : The session driver backend to use.} + {--queue= : The queue driver backend to use.} {--redis-host= : Redis host to use for connections.} {--redis-pass= : Password used to connect to redis.} {--redis-port= : Port to connect to redis over.}'; @@ -72,7 +94,7 @@ class AppSettingsCommand extends Command */ public function handle() { - if (empty($this->config->get('hashids.salt')) || $this->option('--new-salt')) { + if (empty($this->config->get('hashids.salt')) || $this->option('new-salt')) { $this->variables['HASHIDS_SALT'] = str_random(20); } @@ -87,33 +109,31 @@ class AppSettingsCommand extends Command ); $this->output->comment(trans('command/messages.environment.app.timezone_help')); - $this->variables['APP_TIMEZONE'] = $this->option('timezone') ?? $this->ask( - trans('command/messages.environment.app.timezone'), $this->config->get('app.timezone') + $this->variables['APP_TIMEZONE'] = $this->option('timezone') ?? $this->anticipate( + trans('command/messages.environment.app.timezone'), + DateTimeZone::listIdentifiers(DateTimeZone::ALL), + $this->config->get('app.timezone') ); + $selected = $this->config->get('cache.default', 'redis'); $this->variables['CACHE_DRIVER'] = $this->option('cache') ?? $this->choice( - trans('command/messages.environment.app.cache_driver'), [ - 'redis' => 'Redis (recommended)', - 'memcached' => 'Memcached', - ], $this->config->get('cache.default', 'redis') + trans('command/messages.environment.app.cache_driver'), + self::ALLOWED_CACHE_DRIVERS, + array_key_exists($selected, self::ALLOWED_CACHE_DRIVERS) ? $selected : null ); + $selected = $this->config->get('session.driver', 'redis'); $this->variables['SESSION_DRIVER'] = $this->option('session') ?? $this->choice( - trans('command/messages.environment.app.session_driver'), [ - 'redis' => 'Redis (recommended)', - 'memcached' => 'Memcached', - 'database' => 'MySQL Database', - 'file' => 'Filesystem', - 'cookie' => 'Cookie', - ], $this->config->get('session.driver', 'redis') + trans('command/messages.environment.app.session_driver'), + self::ALLOWED_SESSION_DRIVERS, + array_key_exists($selected, self::ALLOWED_SESSION_DRIVERS) ? $selected : null ); - $this->variables['QUEUE_DRIVER'] = $this->option('session') ?? $this->choice( - trans('command/messages.environment.app.session_driver'), [ - 'redis' => 'Redis (recommended)', - 'database' => 'MySQL Database', - 'sync' => 'Sync', - ], $this->config->get('queue.driver', 'redis') + $selected = $this->config->get('queue.default', 'redis'); + $this->variables['QUEUE_DRIVER'] = $this->option('queue') ?? $this->choice( + trans('command/messages.environment.app.queue_driver'), + self::ALLOWED_QUEUE_DRIVERS, + array_key_exists($selected, self::ALLOWED_QUEUE_DRIVERS) ? $selected : null ); $this->checkForRedis(); diff --git a/app/Exceptions/DisplayValidationException.php b/app/Exceptions/DisplayValidationException.php index 3ffae9648..38ae082f6 100644 --- a/app/Exceptions/DisplayValidationException.php +++ b/app/Exceptions/DisplayValidationException.php @@ -9,6 +9,6 @@ namespace Pterodactyl\Exceptions; -class DisplayValidationException extends PterodactylException +class DisplayValidationException extends DisplayException { } diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 0bf3610f7..1cd63a20d 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -319,14 +319,14 @@ class ServersController extends Controller /** * Display startup configuration page for a server. * - * @param int $server + * @param \Pterodactyl\Models\Server $server * @return \Illuminate\View\View * * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ - public function viewStartup($server) + public function viewStartup(Server $server) { - $parameters = $this->repository->getVariablesWithValues($server, true); + $parameters = $this->repository->getVariablesWithValues($server->id, true); if (! $parameters->server->installed) { abort(404); } @@ -334,6 +334,7 @@ class ServersController extends Controller $nests = $this->nestRepository->getWithEggs(); Javascript::put([ + 'server' => $server, 'nests' => $nests->map(function ($item) { return array_merge($item->toArray(), [ 'eggs' => $item->eggs->keyBy('id')->toArray(), diff --git a/app/Http/Controllers/Server/ConsoleController.php b/app/Http/Controllers/Server/ConsoleController.php index 1e873474c..0c1959251 100644 --- a/app/Http/Controllers/Server/ConsoleController.php +++ b/app/Http/Controllers/Server/ConsoleController.php @@ -38,6 +38,9 @@ class ConsoleController extends Controller $server = $request->attributes->get('server'); $this->setRequest($request)->injectJavascript([ + 'server' => [ + 'cpu' => $server->cpu, + ], 'meta' => [ 'saveFile' => route('server.files.save', $server->uuidShort), 'csrfToken' => csrf_token(), diff --git a/app/Http/Requests/Admin/DatabaseHostFormRequest.php b/app/Http/Requests/Admin/DatabaseHostFormRequest.php index f16d1439c..1feb42ed1 100644 --- a/app/Http/Requests/Admin/DatabaseHostFormRequest.php +++ b/app/Http/Requests/Admin/DatabaseHostFormRequest.php @@ -18,6 +18,10 @@ class DatabaseHostFormRequest extends AdminFormRequest */ public function rules() { + if (! $this->has('node_id')) { + $this->merge(['node_id' => null]); + } + if ($this->method() !== 'POST') { return DatabaseHost::getUpdateRulesForId($this->route()->parameter('host')->id); } diff --git a/app/Models/DatabaseHost.php b/app/Models/DatabaseHost.php index 203df690f..2fb339add 100644 --- a/app/Models/DatabaseHost.php +++ b/app/Models/DatabaseHost.php @@ -63,14 +63,13 @@ class DatabaseHost extends Model implements CleansAttributes, ValidableContract 'host' => 'required', 'port' => 'required', 'username' => 'required', - 'node_id' => 'sometimes|required', + 'node_id' => 'sometimes', ]; /** * Validation rules to assign to this model. * * @var array - * @todo the node_id field doesn't validate correctly if no node is provided in request */ protected static $dataIntegrityRules = [ 'name' => 'string|max:255', @@ -78,7 +77,7 @@ class DatabaseHost extends Model implements CleansAttributes, ValidableContract 'port' => 'numeric|between:1,65535', 'username' => 'string|max:32', 'password' => 'nullable|string', - 'node_id' => 'nullable|exists:nodes,id', + 'node_id' => 'nullable|integer|exists:nodes,id', ]; /** diff --git a/app/Services/Servers/StartupModificationService.php b/app/Services/Servers/StartupModificationService.php index 969d4310d..784b60a05 100644 --- a/app/Services/Servers/StartupModificationService.php +++ b/app/Services/Servers/StartupModificationService.php @@ -78,9 +78,10 @@ class StartupModificationService * @param \Pterodactyl\Models\Server $server * @param array $data * - * @throws \Pterodactyl\Exceptions\DisplayException + * @throws \Illuminate\Validation\ValidationException * @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + * @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException */ public function handle(Server $server, array $data) { diff --git a/app/Services/Servers/VariableValidatorService.php b/app/Services/Servers/VariableValidatorService.php index b4f722c79..31ca3728b 100644 --- a/app/Services/Servers/VariableValidatorService.php +++ b/app/Services/Servers/VariableValidatorService.php @@ -11,8 +11,8 @@ namespace Pterodactyl\Services\Servers; use Pterodactyl\Models\User; use Illuminate\Support\Collection; +use Illuminate\Validation\ValidationException; use Pterodactyl\Traits\Services\HasUserLevels; -use Pterodactyl\Exceptions\DisplayValidationException; use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; use Illuminate\Contracts\Validation\Factory as ValidationFactory; use Pterodactyl\Contracts\Repository\EggVariableRepositoryInterface; @@ -25,22 +25,22 @@ class VariableValidatorService /** * @var \Pterodactyl\Contracts\Repository\EggVariableRepositoryInterface */ - protected $optionVariableRepository; + private $optionVariableRepository; /** * @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface */ - protected $serverRepository; + private $serverRepository; /** * @var \Pterodactyl\Contracts\Repository\ServerVariableRepositoryInterface */ - protected $serverVariableRepository; + private $serverVariableRepository; /** * @var \Illuminate\Contracts\Validation\Factory */ - protected $validator; + private $validator; /** * VariableValidatorService constructor. @@ -68,32 +68,32 @@ class VariableValidatorService * @param int $egg * @param array $fields * @return \Illuminate\Support\Collection + * @throws \Illuminate\Validation\ValidationException */ public function handle(int $egg, array $fields = []): Collection { $variables = $this->optionVariableRepository->findWhere([['egg_id', '=', $egg]]); + $messages = $this->validator->make([], []); - return $variables->map(function ($item) use ($fields) { + $response = $variables->map(function ($item) use ($fields, $messages) { // Skip doing anything if user is not an admin and // variable is not user viewable or editable. if (! $this->isUserLevel(User::USER_LEVEL_ADMIN) && (! $item->user_editable || ! $item->user_viewable)) { return false; } - $validator = $this->validator->make([ + $v = $this->validator->make([ 'variable_value' => array_get($fields, $item->env_variable), ], [ 'variable_value' => $item->rules, + ], [], [ + 'variable_value' => trans('validation.internal.variable_value', ['env' => $item->name]), ]); - if ($validator->fails()) { - throw new DisplayValidationException(json_encode( - collect([ - 'notice' => [ - trans('admin/server.exceptions.bad_variable', ['name' => $item->name]), - ], - ])->merge($validator->errors()->toArray()) - )); + if ($v->fails()) { + foreach ($v->getMessageBag()->all() as $message) { + $messages->getMessageBag()->add($item->env_variable, $message); + } } return (object) [ @@ -104,5 +104,11 @@ class VariableValidatorService })->filter(function ($item) { return is_object($item); }); + + if (! empty($messages->getMessageBag()->all())) { + throw new ValidationException($messages); + } + + return $response; } } diff --git a/app/Traits/Controllers/JavascriptInjection.php b/app/Traits/Controllers/JavascriptInjection.php index 8b41fca9d..bbda917d1 100644 --- a/app/Traits/Controllers/JavascriptInjection.php +++ b/app/Traits/Controllers/JavascriptInjection.php @@ -45,7 +45,7 @@ trait JavascriptInjection $server = $request->attributes->get('server'); $token = $request->attributes->get('server_token'); - $response = array_merge([ + $response = array_merge_recursive([ 'server' => [ 'uuid' => $server->uuid, 'uuidShort' => $server->uuidShort, diff --git a/database/seeds/eggs/rust/egg-rust.json b/database/seeds/eggs/rust/egg-rust.json index c3d4901f7..074b14421 100644 --- a/database/seeds/eggs/rust/egg-rust.json +++ b/database/seeds/eggs/rust/egg-rust.json @@ -36,7 +36,7 @@ "name": "OxideMod", "description": "Set whether you want the server to use and auto update OxideMod or not. Valid options are \"1\" for true and \"0\" for false.", "env_variable": "OXIDE", - "default_value": "false", + "default_value": "0", "user_viewable": 1, "user_editable": 1, "rules": "required|boolean" diff --git a/resources/lang/en/admin/server.php b/resources/lang/en/admin/server.php index e93459a99..e0ccdba77 100644 --- a/resources/lang/en/admin/server.php +++ b/resources/lang/en/admin/server.php @@ -16,7 +16,7 @@ return [ 'default_allocation_not_found' => 'The requested default allocation was not found in this server\'s allocations.', ], 'alerts' => [ - 'startup_changed' => 'The startup configuration for this server has been updated. If this server\'s service or option was changed a reinstall will be occuring now.', + 'startup_changed' => 'The startup configuration for this server has been updated. If this server\'s nest or egg was changed a reinstall will be occuring now.', 'server_deleted' => 'Server has successfully been deleted from the system.', 'server_created' => 'Server was successfully created on the panel. Please allow the daemon a few minutes to completely install this server.', 'build_updated' => 'The build details for this server have been updated. Some changes may require a restart to take effect.', diff --git a/resources/lang/en/command/messages.php b/resources/lang/en/command/messages.php index a6385abc4..ec092eee7 100644 --- a/resources/lang/en/command/messages.php +++ b/resources/lang/en/command/messages.php @@ -82,6 +82,7 @@ return [ 'timezone' => 'Application Timezone', 'cache_driver' => 'Cache Driver', 'session_driver' => 'Session Driver', + 'queue_driver' => 'Queue Driver', 'using_redis' => 'You\'ve selected the Redis driver for one or more options, please provide valid connection information below. In most cases you can use the defaults provided unless you have modified your setup.', 'redis_host' => 'Redis Host', 'redis_password' => 'Redis Password', diff --git a/resources/lang/en/validation.php b/resources/lang/en/validation.php index d6b784673..201880ec9 100644 --- a/resources/lang/en/validation.php +++ b/resources/lang/en/validation.php @@ -85,23 +85,6 @@ return [ 'uploaded' => 'The :attribute failed to upload.', 'url' => 'The :attribute format is invalid.', - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name the lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ - - 'custom' => [ - 'attribute-name' => [ - 'rule-name' => 'custom-message', - ], - ], - /* |-------------------------------------------------------------------------- | Custom Validation Attributes @@ -114,4 +97,9 @@ return [ */ 'attributes' => [], + + // Internal validation logic for Pterodactyl + 'internal' => [ + 'variable_value' => ':env variable', + ], ]; diff --git a/resources/themes/pterodactyl/admin/databases/index.blade.php b/resources/themes/pterodactyl/admin/databases/index.blade.php index 1b95960b0..df1d13bb7 100644 --- a/resources/themes/pterodactyl/admin/databases/index.blade.php +++ b/resources/themes/pterodactyl/admin/databases/index.blade.php @@ -103,7 +103,7 @@