Merge branch 'develop' into feature/api-v1

This commit is contained in:
Dane Everitt 2017-12-31 10:32:28 -06:00
commit 46d7ba7585
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53
32 changed files with 247 additions and 201 deletions

View File

@ -1,11 +1,11 @@
APP_ENV=production APP_ENV=production
APP_DEBUG=false APP_DEBUG=false
APP_KEY=SomeRandomString3232RandomString APP_KEY=
APP_THEME=pterodactyl APP_THEME=pterodactyl
APP_TIMEZONE=America/New_York APP_TIMEZONE=America/New_York
APP_CLEAR_TASKLOG=720 APP_CLEAR_TASKLOG=720
APP_DELETE_MINUTES=10 APP_DELETE_MINUTES=10
APP_URL= APP_ENVIRONMENT_ONLY=true
DB_HOST=127.0.0.1 DB_HOST=127.0.0.1
DB_PORT=3306 DB_PORT=3306
@ -13,9 +13,6 @@ DB_DATABASE=panel
DB_USERNAME=pterodactyl DB_USERNAME=pterodactyl
DB_PASSWORD= DB_PASSWORD=
CACHE_DRIVER=
SESSION_DRIVER=
HASHIDS_SALT= HASHIDS_SALT=
HASHIDS_LENGTH=8 HASHIDS_LENGTH=8
@ -27,9 +24,6 @@ MAIL_PASSWORD=
MAIL_ENCRYPTION=tls MAIL_ENCRYPTION=tls
MAIL_FROM=no-reply@example.com MAIL_FROM=no-reply@example.com
QUEUE_DRIVER=
QUEUE_HIGH=high QUEUE_HIGH=high
QUEUE_STANDARD=standard QUEUE_STANDARD=standard
QUEUE_LOW=low QUEUE_LOW=low
APP_SERVICE_AUTHOR=undefined@unknown-author.com

View File

@ -3,6 +3,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. This project follows [Semantic Versioning](http://semver.org) guidelines.
## v0.7.0-beta.4 (Derelict Dermodactylus)
### Fixed
* `[beta.3]` — Fixes a bug with the default environment file that was causing an inability to perform a fresh install when running package discovery.
* `[beta.3]` — Fixes an edge case caused by the Laravel 5.5 upgrade that would try to perform an in_array check aganist a null value.
* `[beta.3]` — Fixes a bug that would cause an error when attempting to create a new user on the Panel.
* `[beta.3]` — Fixes error handling of the settings service provider when no migrations have been run.
## v0.7.0-beta.3 (Derelict Dermodactylus) ## v0.7.0-beta.3 (Derelict Dermodactylus)
### Fixed ### 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 that would cause an endless exception message stream in the console when attemping to setup environment settings in certain instances.
@ -12,15 +19,17 @@ This project follows [Semantic Versioning](http://semver.org) guidelines.
* `[beta.2]` — Fixes bug that caused incorrect rendering of CPU usage on server graphs due to missing variable. * `[beta.2]` — Fixes bug that caused incorrect rendering of CPU usage on server graphs due to missing variable.
* `[beta.2]` — Fixes bug causing schedules to be un-deletable. * `[beta.2]` — Fixes bug causing schedules to be un-deletable.
* `[beta.2]` — Fixes bug that prevented the deletion of nodes due to an allocation deletion cascade issue with the SQL schema. * `[beta.2]` — Fixes bug that prevented the deletion of nodes due to an allocation deletion cascade issue with the SQL schema.
* `[beta.2]` — Fixes a bug causing eggs not extending other eggs to fail validation.
### Changed ### Changed
* Revoking the administrative status for an admin will revoke all authentication tokens currently assigned to their account. * Revoking the administrative status for an admin will revoke all authentication tokens currently assigned to their account.
* Updated core framework to Laravel 5.5. This includes many dependency updates. * Updated core framework to Laravel 5.5. This includes many dependency updates.
* Certain AWS specific environment keys were changed, this should have minimal impact on users unless you specifically enabled AWS specific features. The renames are: `AWS_KEY -> AWS_ACCESS_KEY_ID`, `AWS_SECRET -> AWS_SECRET_ACCESS_KEY`, `AWS_REGION -> AWS_DEFAULT_REGION` * Certain AWS specific environment keys were changed, this should have minimal impact on users unless you specifically enabled AWS specific features. The renames are: `AWS_KEY -> AWS_ACCESS_KEY_ID`, `AWS_SECRET -> AWS_SECRET_ACCESS_KEY`, `AWS_REGION -> AWS_DEFAULT_REGION`
* 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.
### Added ### Added
* Added star indicators to user listing in Admin CP to indicate users who are set as a root admin. * Added star indicators to user listing in Admin CP to indicate users who are set as a root admin.
* Settings are now editable via the Admin CP and override config values where possible. * Creating a new node will now requires a SSL connection if the Panel is configured to use SSL as well.
## v0.7.0-beta.2 (Derelict Dermodactylus) ## v0.7.0-beta.2 (Derelict Dermodactylus)
### Fixed ### Fixed

View File

@ -66,7 +66,8 @@ class AppSettingsCommand extends Command
{--queue= : The queue driver backend to use.} {--queue= : The queue driver backend to use.}
{--redis-host= : Redis host to use for connections.} {--redis-host= : Redis host to use for connections.}
{--redis-pass= : Password used to connect to redis.} {--redis-pass= : Password used to connect to redis.}
{--redis-port= : Port to connect to redis over.}'; {--redis-port= : Port to connect to redis over.}
{--disable-settings-ui}';
/** /**
* @var array * @var array
@ -136,6 +137,12 @@ class AppSettingsCommand extends Command
array_key_exists($selected, self::ALLOWED_QUEUE_DRIVERS) ? $selected : null array_key_exists($selected, self::ALLOWED_QUEUE_DRIVERS) ? $selected : null
); );
if ($this->option('disable-settings-ui')) {
$this->variables['APP_ENVIRONMENT_ONLY'] = 'true';
} else {
$this->variables['APP_ENVIRONMENT_ONLY'] = $this->confirm(trans('command/messages.environment.app.settings'), true) ? 'false' : 'true';
}
$this->checkForRedis(); $this->checkForRedis();
$this->writeToEnvironment($this->variables); $this->writeToEnvironment($this->variables);

View File

@ -65,7 +65,7 @@ class DisplayException extends PterodactylException
if ($request->expectsJson()) { if ($request->expectsJson()) {
return response()->json(Handler::convertToArray($this, [ return response()->json(Handler::convertToArray($this, [
'detail' => $this->getMessage(), 'detail' => $this->getMessage(),
]), 500); ]), method_exists($this, 'getStatusCode') ? $this->getStatusCode() : 500);
} }
app()->make(AlertsMessageBag::class)->danger($this->getMessage())->flash(); app()->make(AlertsMessageBag::class)->danger($this->getMessage())->flash();

View File

@ -7,18 +7,38 @@ use Pterodactyl\Exceptions\DisplayException;
class DaemonConnectionException extends DisplayException class DaemonConnectionException extends DisplayException
{ {
/**
* @var int
*/
private $statusCode = 500;
/** /**
* Throw a displayable exception caused by a daemon connection error. * Throw a displayable exception caused by a daemon connection error.
* *
* @param \GuzzleHttp\Exception\GuzzleException $previous * @param \GuzzleHttp\Exception\GuzzleException $previous
* @param bool $useStatusCode
*/ */
public function __construct(GuzzleException $previous) public function __construct(GuzzleException $previous, bool $useStatusCode = false)
{ {
/** @var \GuzzleHttp\Psr7\Response|null $response */ /** @var \GuzzleHttp\Psr7\Response|null $response */
$response = method_exists($previous, 'getResponse') ? $previous->getResponse() : null; $response = method_exists($previous, 'getResponse') ? $previous->getResponse() : null;
if ($useStatusCode) {
$this->statusCode = is_null($response) ? 500 : $response->getStatusCode();
}
parent::__construct(trans('admin/server.exceptions.daemon_exception', [ parent::__construct(trans('admin/server.exceptions.daemon_exception', [
'code' => is_null($response) ? 'E_CONN_REFUSED' : $response->getStatusCode(), 'code' => is_null($response) ? 'E_CONN_REFUSED' : $response->getStatusCode(),
]), $previous, DisplayException::LEVEL_WARNING); ]), $previous, DisplayException::LEVEL_WARNING);
} }
/**
* Return the HTTP status code for this exception.
*
* @return int
*/
public function getStatusCode()
{
return $this->statusCode;
}
} }

View File

@ -9,6 +9,7 @@ use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Contracts\Translation\Translator; use Illuminate\Contracts\Translation\Translator;
use Pterodactyl\Services\Users\UserUpdateService; use Pterodactyl\Services\Users\UserUpdateService;
use Pterodactyl\Traits\Helpers\AvailableLanguages;
use Pterodactyl\Services\Users\UserCreationService; use Pterodactyl\Services\Users\UserCreationService;
use Pterodactyl\Services\Users\UserDeletionService; use Pterodactyl\Services\Users\UserDeletionService;
use Pterodactyl\Http\Requests\Admin\UserFormRequest; use Pterodactyl\Http\Requests\Admin\UserFormRequest;
@ -16,6 +17,8 @@ use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
class UserController extends Controller class UserController extends Controller
{ {
use AvailableLanguages;
/** /**
* @var \Prologue\Alerts\AlertsMessageBag * @var \Prologue\Alerts\AlertsMessageBag
*/ */
@ -92,7 +95,9 @@ class UserController extends Controller
*/ */
public function create() public function create()
{ {
return view('admin.users.new'); return view('admin.users.new', [
'languages' => $this->getAvailableLanguages(true),
]);
} }
/** /**
@ -103,7 +108,10 @@ class UserController extends Controller
*/ */
public function view(User $user) public function view(User $user)
{ {
return view('admin.users.view', ['user' => $user]); return view('admin.users.view', [
'user' => $user,
'languages' => $this->getAvailableLanguages(true),
]);
} }
/** /**

View File

@ -1,11 +1,4 @@
<?php <?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Http\Requests\Admin; namespace Pterodactyl\Http\Requests\Admin;
@ -39,11 +32,11 @@ abstract class AdminFormRequest extends FormRequest
* Return only the fields that we are interested in from the request. * Return only the fields that we are interested in from the request.
* This will include empty fields as a null value. * This will include empty fields as a null value.
* *
* @param array $only * @param array|null $only
* @return array * @return array
*/ */
public function normalize($only = []) public function normalize(array $only = null)
{ {
return $this->all(empty($only) ? array_keys($this->rules()) : $only); return $this->only($only ?? array_keys($this->rules()));
} }
} }

View File

@ -22,12 +22,16 @@ class UserFormRequest extends AdminFormRequest
return User::getCreateRules(); return User::getCreateRules();
} }
public function normalize($only = []) /**
* @param array|null $only
* @return array
*/
public function normalize(array $only = null)
{ {
if ($this->method === 'PATCH') { if ($this->method === 'PATCH') {
return array_merge( return array_merge(
$this->all(['password']), $this->all(['password']),
$this->only(['email', 'username', 'name_first', 'name_last', 'root_admin', 'ignore_connection_error']) $this->only(['email', 'username', 'name_first', 'name_last', 'root_admin', 'language', 'ignore_connection_error'])
); );
} }

View File

@ -1,11 +1,4 @@
<?php <?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Models; namespace Pterodactyl\Models;
@ -127,6 +120,8 @@ class User extends Model implements
'name_first' => 'required', 'name_first' => 'required',
'name_last' => 'required', 'name_last' => 'required',
'password' => 'sometimes', 'password' => 'sometimes',
'language' => 'sometimes',
'use_totp' => 'sometimes',
]; ];
/** /**

View File

@ -1,27 +1,14 @@
<?php <?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Observers; namespace Pterodactyl\Observers;
use Pterodactyl\Events; use Pterodactyl\Events;
use Pterodactyl\Models\User; use Pterodactyl\Models\User;
use Pterodactyl\Services\Components\UuidService;
class UserObserver class UserObserver
{ {
protected $uuid; protected $uuid;
public function __construct(UuidService $uuid)
{
$this->uuid = $uuid;
}
/** /**
* Listen to the User creating event. * Listen to the User creating event.
* *
@ -29,8 +16,6 @@ class UserObserver
*/ */
public function creating(User $user) public function creating(User $user)
{ {
$user->uuid = $this->uuid->generate('users', 'uuid');
event(new Events\User\Creating($user)); event(new Events\User\Creating($user));
} }

View File

@ -30,6 +30,18 @@ class AppServiceProvider extends ServiceProvider
View::share('appIsGit', $this->versionData()['is_git'] ?? false); View::share('appIsGit', $this->versionData()['is_git'] ?? false);
} }
/**
* Register application service providers.
*/
public function register()
{
// Only load the settings service provider if the environment
// is configured to allow it.
if (! config('pterodactyl.load_environment_only', false) && $this->app->environment() !== 'testing') {
$this->app->register(SettingsServiceProvider::class);
}
}
/** /**
* Return version information for the footer. * Return version information for the footer.
* *

View File

@ -2,6 +2,8 @@
namespace Pterodactyl\Providers; namespace Pterodactyl\Providers;
use Illuminate\Contracts\Logging\Log;
use Illuminate\Database\QueryException;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Encryption\Encrypter; use Illuminate\Contracts\Encryption\Encrypter;
use Illuminate\Contracts\Encryption\DecryptException; use Illuminate\Contracts\Encryption\DecryptException;
@ -60,23 +62,26 @@ class SettingsServiceProvider extends ServiceProvider
* *
* @param \Illuminate\Contracts\Config\Repository $config * @param \Illuminate\Contracts\Config\Repository $config
* @param \Illuminate\Contracts\Encryption\Encrypter $encrypter * @param \Illuminate\Contracts\Encryption\Encrypter $encrypter
* @param \Illuminate\Contracts\Logging\Log $log
* @param \Pterodactyl\Contracts\Repository\SettingsRepositoryInterface $settings * @param \Pterodactyl\Contracts\Repository\SettingsRepositoryInterface $settings
*/ */
public function boot(ConfigRepository $config, Encrypter $encrypter, SettingsRepositoryInterface $settings) public function boot(ConfigRepository $config, Encrypter $encrypter, Log $log, SettingsRepositoryInterface $settings)
{ {
if ($config->get('pterodactyl.load_environment_only', false)) {
return;
}
// Only set the email driver settings from the database if we // Only set the email driver settings from the database if we
// are configured using SMTP as the driver. // are configured using SMTP as the driver.
if ($config->get('mail.driver') === 'smtp') { if ($config->get('mail.driver') === 'smtp') {
$this->keys = array_merge($this->keys, $this->emailKeys); $this->keys = array_merge($this->keys, $this->emailKeys);
} }
$values = $settings->all()->mapWithKeys(function ($setting) { try {
return [$setting->key => $setting->value]; $values = $settings->all()->mapWithKeys(function ($setting) {
})->toArray(); return [$setting->key => $setting->value];
})->toArray();
} catch (QueryException $exception) {
$log->notice('A query exception was encountered while trying to load settings from the database.');
return;
}
foreach ($this->keys as $key) { foreach ($this->keys as $key) {
$value = array_get($values, 'settings::' . $key, $config->get(str_replace(':', '.', $key))); $value = array_get($values, 'settings::' . $key, $config->get(str_replace(':', '.', $key)));

View File

@ -1,63 +0,0 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Services\Components;
use DB;
use Uuid;
class UuidService
{
/**
* Generate a unique UUID validating against specified table and column.
* Defaults to `users.uuid`.
*
* @param string $table
* @param string $field
* @param int $type
* @return string
* @deprecated
*/
public function generate($table = 'users', $field = 'uuid', $type = 4)
{
$return = false;
do {
$uuid = Uuid::generate($type);
if (! DB::table($table)->where($field, $uuid)->exists()) {
$return = $uuid;
}
} while (! $return);
return (string) $return;
}
/**
* Generates a ShortUUID code which is 8 characters long and is used for identifying servers in the system.
*
* @param string $table
* @param string $field
* @param null|string $attachedUuid
* @return string
* @deprecated
*/
public function generateShort($table = 'servers', $field = 'uuidShort', $attachedUuid = null)
{
$return = false;
do {
$short = (is_null($attachedUuid)) ? substr(Uuid::generate(4), 0, 8) : substr($attachedUuid, 0, 8);
$attachedUuid = null;
if (! DB::table($table)->where($field, $short)->exists()) {
$return = $short;
}
} while (! $return);
return (string) $return;
}
}

View File

@ -1,11 +1,4 @@
<?php <?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Services\Eggs\Variables; namespace Pterodactyl\Services\Eggs\Variables;
@ -49,7 +42,7 @@ class VariableCreationService
)); ));
} }
$options = array_get($data, 'options', []); $options = array_get($data, 'options') ?? [];
return $this->repository->create(array_merge($data, [ return $this->repository->create(array_merge($data, [
'egg_id' => $egg, 'egg_id' => $egg,

View File

@ -1,11 +1,4 @@
<?php <?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Services\Eggs\Variables; namespace Pterodactyl\Services\Eggs\Variables;
@ -69,7 +62,7 @@ class VariableUpdateService
} }
} }
$options = array_get($data, 'options', []); $options = array_get($data, 'options') ?? [];
return $this->repository->withoutFresh()->update($variable->id, array_merge($data, [ return $this->repository->withoutFresh()->update($variable->id, array_merge($data, [
'user_viewable' => in_array('user_viewable', $options), 'user_viewable' => in_array('user_viewable', $options),

View File

@ -9,6 +9,7 @@
namespace Pterodactyl\Services\Users; namespace Pterodactyl\Services\Users;
use Ramsey\Uuid\Uuid;
use Illuminate\Foundation\Application; use Illuminate\Foundation\Application;
use Illuminate\Contracts\Hashing\Hasher; use Illuminate\Contracts\Hashing\Hasher;
use Illuminate\Database\ConnectionInterface; use Illuminate\Database\ConnectionInterface;
@ -96,7 +97,10 @@ class UserCreationService
$token = $this->passwordService->handle($data['email']); $token = $this->passwordService->handle($data['email']);
} }
$user = $this->repository->create($data); $user = $this->repository->create(array_merge($data, [
'uuid' => Uuid::uuid4()->toString(),
]));
$this->connection->commit(); $this->connection->commit();
// @todo fire event, handle notification there // @todo fire event, handle notification there

View File

@ -173,7 +173,6 @@ return [
/* /*
* Application Service Providers... * Application Service Providers...
*/ */
Pterodactyl\Providers\SettingsServiceProvider::class,
Pterodactyl\Providers\AppServiceProvider::class, Pterodactyl\Providers\AppServiceProvider::class,
Pterodactyl\Providers\AuthServiceProvider::class, Pterodactyl\Providers\AuthServiceProvider::class,
Pterodactyl\Providers\EventServiceProvider::class, Pterodactyl\Providers\EventServiceProvider::class,

View File

@ -32,6 +32,5 @@
<env name="SESSION_DRIVER" value="array"/> <env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/> <env name="QUEUE_DRIVER" value="sync"/>
<env name="MAIL_DRIVER" value="array"/> <env name="MAIL_DRIVER" value="array"/>
<env name="APP_ENVIRONMENT_ONLY" value="true"/>
</php> </php>
</phpunit> </phpunit>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -63,6 +63,11 @@ class FileManager {
if (_.isFunction(next)) { if (_.isFunction(next)) {
return next(new Error('Failed to load file listing.')); return next(new Error('Failed to load file listing.'));
} }
if ((path !== '' && path !== '/') && jqXHR.status === 404) {
return this.list('', next);
}
swal({ swal({
type: 'error', type: 'error',
title: 'File Error', title: 'File Error',

View File

@ -1,11 +1,4 @@
<?php <?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
return [ return [
'location' => [ 'location' => [
@ -74,6 +67,7 @@ return [
'try_again' => 'Go back and try again?', 'try_again' => 'Go back and try again?',
], ],
'app' => [ 'app' => [
'settings' => 'Enable UI based settings editor?',
'author' => 'Egg Author Email', 'author' => 'Egg Author Email',
'author_help' => 'Provide the email address that eggs exported by this Panel should be from. This should be a valid email address.', 'author_help' => 'Provide the email address that eggs exported by this Panel should be from. This should be a valid email address.',
'app_url_help' => 'The application URL MUST begin with https:// or http:// depending on if you are using SSL or not. If you do not include the scheme your emails and other content will link to the wrong location.', 'app_url_help' => 'The application URL MUST begin with https:// or http:// depending on if you are using SSL or not. If you do not include the scheme your emails and other content will link to the wrong location.',

View File

@ -83,7 +83,7 @@
<div class="form-group"> <div class="form-group">
<label for="pConfigFrom" class="form-label">Copy Settings From</label> <label for="pConfigFrom" class="form-label">Copy Settings From</label>
<select name="config_from" id="pConfigFrom" class="form-control"> <select name="config_from" id="pConfigFrom" class="form-control">
<option value="0">None</option> <option value="">None</option>
</select> </select>
<p class="text-muted small">If you would like to default to settings from another Egg select it from the dropdown above.</p> <p class="text-muted small">If you would like to default to settings from another Egg select it from the dropdown above.</p>
</div> </div>

View File

@ -125,7 +125,7 @@
<div class="form-group"> <div class="form-group">
<label for="pConfigFrom" class="form-label">Copy Settings From</label> <label for="pConfigFrom" class="form-label">Copy Settings From</label>
<select name="config_from" id="pConfigFrom" class="form-control"> <select name="config_from" id="pConfigFrom" class="form-control">
<option value="0">None</option> <option value="">None</option>
@foreach($egg->nest->eggs as $o) @foreach($egg->nest->eggs as $o)
<option value="{{ $o->id }}" {{ ($egg->config_from !== $o->id) ?: 'selected' }}>{{ $o->name }} &lt;{{ $o->author }}&gt;</option> <option value="{{ $o->id }}" {{ ($egg->config_from !== $o->id) ?: 'selected' }}>{{ $o->name }} &lt;{{ $o->author }}&gt;</option>
@endforeach @endforeach

View File

@ -72,11 +72,15 @@
<label for="pSSLTrue"> Use SSL Connection</label> <label for="pSSLTrue"> Use SSL Connection</label>
</div> </div>
<div class="radio radio-danger radio-inline"> <div class="radio radio-danger radio-inline">
<input type="radio" id="pSSLFalse" value="http" name="scheme"> <input type="radio" id="pSSLFalse" value="http" name="scheme" @if(request()->isSecure()) disabled @endif>
<label for="pSSLFalse"> Use HTTP Connection</label> <label for="pSSLFalse"> Use HTTP Connection</label>
</div> </div>
</div> </div>
<p class="text-muted small">In most cases you should select to use a SSL connection. If using an IP Address or you do not wish to use SSL at all, select a HTTP connection.</p> @if(request()->isSecure())
<p class="text-danger small">Your Panel is currently configured to use a secure connection. In order for browsers to connect to your node it <strong>must</strong> use a SSL connection.</p>
@else
<p class="text-muted small">In most cases you should select to use a SSL connection. If using an IP Address or you do not wish to use SSL at all, select a HTTP connection.</p>
@endif
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="form-label">Behind Proxy</label> <label class="form-label">Behind Proxy</label>

View File

@ -51,6 +51,17 @@
<input type="text" autocomplete="off" name="name_last" value="{{ old('name_last') }}" class="form-control" /> <input type="text" autocomplete="off" name="name_last" value="{{ old('name_last') }}" class="form-control" />
</div> </div>
</div> </div>
<div class="form-group">
<label class="control-label">Default Langauge</label>
<div>
<select name="language" class="form-control">
@foreach($languages as $key => $value)
<option value="{{ $key }}" @if(config('app.locale') === $key) selected @endif>{{ $value }}</option>
@endforeach
</select>
<p class="text-muted"><small>The default language to use when rendering the Panel for this user.</small></p>
</div>
</div>
</div> </div>
<div class="box-footer"> <div class="box-footer">
{!! csrf_field() !!} {!! csrf_field() !!}

View File

@ -51,6 +51,17 @@
<input readonly type="text" name="name_last" value="{{ $user->name_last }}" class="form-control form-autocomplete-stop"> <input readonly type="text" name="name_last" value="{{ $user->name_last }}" class="form-control form-autocomplete-stop">
</div> </div>
</div> </div>
<div class="form-group">
<label class="control-label">Default Langauge</label>
<div>
<select name="language" class="form-control">
@foreach($languages as $key => $value)
<option value="{{ $key }}" @if($user->language === $key) selected @endif>{{ $value }}</option>
@endforeach
</select>
<p class="text-muted"><small>The default language to use when rendering the Panel for this user.</small></p>
</div>
</div>
</div> </div>
<div class="box-footer"> <div class="box-footer">
{!! csrf_field() !!} {!! csrf_field() !!}
@ -101,25 +112,24 @@
</div> </div>
</div> </div>
</form> </form>
<div class="col-xs-12"> {{--<div class="col-xs-12">--}}
<div class="box"> {{--<div class="box">--}}
<div class="box-header with-border"> {{--<div class="box-header with-border">--}}
<h3 class="box-title">Associated Servers</h3> {{--<h3 class="box-title">Associated Servers</h3>--}}
</div> {{--</div>--}}
<div class="box-body table-responsive no-padding"> {{--<div class="box-body table-responsive no-padding">--}}
<table class="table table-hover"> {{--<table class="table table-hover">--}}
<thead> {{--<thead>--}}
<tr> {{--<tr>--}}
<th style="width:2%;"></th> {{--<th style="width:2%;"></th>--}}
<th>Identifier</th> {{--<th>Identifier</th>--}}
<th>Server Name</th> {{--<th>Server Name</th>--}}
<th>Access</th> {{--<th>Access</th>--}}
<th>Node</th> {{--<th>Node</th>--}}
<th style="width:10%;"></th> {{--<th style="width:10%;"></th>--}}
</tr> {{--</tr>--}}
</thead> {{--</thead>--}}
<tbody> {{--<tbody>--}}
Oh dear, this hasn't been fixed yet?
{{--@foreach($user->setAccessLevel('subuser')->access()->get() as $server)--}} {{--@foreach($user->setAccessLevel('subuser')->access()->get() as $server)--}}
{{--<tr>--}} {{--<tr>--}}
{{--<td><a href="{{ route('server.index', $server->uuidShort) }}/"><i class="fa fa-tachometer"></i></a></td>--}} {{--<td><a href="{{ route('server.index', $server->uuidShort) }}/"><i class="fa fa-tachometer"></i></a></td>--}}
@ -136,12 +146,11 @@
{{--<td class="centered">@if($server->suspended === 0)<span class="label muted muted-hover label-success">Active</span>@else<span class="label label-warning">Suspended</span>@endif</td>--}} {{--<td class="centered">@if($server->suspended === 0)<span class="label muted muted-hover label-success">Active</span>@else<span class="label label-warning">Suspended</span>@endif</td>--}}
{{--</td>--}} {{--</td>--}}
{{--@endforeach--}} {{--@endforeach--}}
</tbody> {{--</tbody>--}}
</table> {{--</table>--}}
</div> {{--</div>--}}
</form> {{--</div>--}}
</div> {{--</div>--}}
</div>
<div class="col-xs-12"> <div class="col-xs-12">
<div class="box box-danger"> <div class="box box-danger">
<div class="box-header with-border"> <div class="box-header with-border">

View File

@ -1,4 +1,7 @@
@include('partials/admin.settings.notice')
@section('settings::nav') @section('settings::nav')
@yield('settings::notice')
<div class="row"> <div class="row">
<div class="col-xs-12"> <div class="col-xs-12">
<div class="nav-tabs-custom nav-tabs-floating"> <div class="nav-tabs-custom nav-tabs-floating">

View File

@ -0,0 +1,11 @@
@section('settings::notice')
@if(config('pterodactyl.load_environment_only', false))
<div class="row">
<div class="col-xs-12">
<div class="alert alert-danger">
Your Panel is currently configured to read settings from the environment only. You will need to set <code>LOAD_ENVIRONMENT_ONLY=false</code> in your environment file in order to load settings dynamically.
</div>
</div>
</div>
@endif
@endsection

View File

@ -1,17 +1,9 @@
<?php <?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Tests\Unit\Services\Eggs\Variables; namespace Tests\Unit\Services\Eggs\Variables;
use Mockery as m; use Mockery as m;
use Tests\TestCase; use Tests\TestCase;
use Pterodactyl\Models\Egg;
use Pterodactyl\Models\EggVariable; use Pterodactyl\Models\EggVariable;
use Pterodactyl\Services\Eggs\Variables\VariableCreationService; use Pterodactyl\Services\Eggs\Variables\VariableCreationService;
use Pterodactyl\Contracts\Repository\EggVariableRepositoryInterface; use Pterodactyl\Contracts\Repository\EggVariableRepositoryInterface;
@ -73,6 +65,26 @@ class VariableCreationServiceTest extends TestCase
$this->assertInstanceOf(EggVariable::class, $this->service->handle(1, $data)); $this->assertInstanceOf(EggVariable::class, $this->service->handle(1, $data));
} }
/**
* Test that an empty (null) value passed in the option key is handled
* properly as an array.
*
* @see https://github.com/Pterodactyl/Panel/issues/841
*/
public function testNullOptionValueIsPassedAsArray()
{
$data = ['env_variable' => 'TEST_VAR_123', 'options' => null];
$this->repository->shouldReceive('create')->with([
'egg_id' => 1,
'user_viewable' => false,
'user_editable' => false,
'env_variable' => 'TEST_VAR_123',
'options' => null,
])->once()->andReturn(new EggVariable);
$this->assertInstanceOf(EggVariable::class, $this->service->handle(1, $data));
}
/** /**
* Test that all of the reserved variables defined in the model trigger an exception. * Test that all of the reserved variables defined in the model trigger an exception.
* *

View File

@ -1,11 +1,4 @@
<?php <?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Tests\Unit\Services\Eggs\Variables; namespace Tests\Unit\Services\Eggs\Variables;
@ -100,6 +93,24 @@ class VariableUpdateServiceTest extends TestCase
$this->assertTrue($this->service->handle($this->model, ['env_variable' => 'TEST_VAR_123'])); $this->assertTrue($this->service->handle($this->model, ['env_variable' => 'TEST_VAR_123']));
} }
/**
* Test that an empty (null) value passed in the option key is handled
* properly as an array.
*
* @see https://github.com/Pterodactyl/Panel/issues/841
*/
public function testNullOptionValueIsPassedAsArray()
{
$this->repository->shouldReceive('withoutFresh')->withNoArgs()->once()->andReturnSelf()
->shouldReceive('update')->with($this->model->id, [
'user_viewable' => false,
'user_editable' => false,
'options' => null,
])->once()->andReturn(true);
$this->assertTrue($this->service->handle($this->model, ['options' => null]));
}
/** /**
* Test that data passed into the handler is overwritten inside the handler. * Test that data passed into the handler is overwritten inside the handler.
*/ */

View File

@ -1,16 +1,10 @@
<?php <?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Tests\Unit\Services; namespace Tests\Unit\Services;
use Mockery as m; use Mockery as m;
use Tests\TestCase; use Tests\TestCase;
use Tests\Traits\MocksUuids;
use Illuminate\Foundation\Application; use Illuminate\Foundation\Application;
use Illuminate\Contracts\Hashing\Hasher; use Illuminate\Contracts\Hashing\Hasher;
use Illuminate\Database\ConnectionInterface; use Illuminate\Database\ConnectionInterface;
@ -22,6 +16,8 @@ use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
class UserCreationServiceTest extends TestCase class UserCreationServiceTest extends TestCase
{ {
use MocksUuids;
/** /**
* @var \Illuminate\Foundation\Application * @var \Illuminate\Foundation\Application
*/ */
@ -93,9 +89,10 @@ class UserCreationServiceTest extends TestCase
$this->hasher->shouldReceive('make')->with('raw-password')->once()->andReturn('enc-password'); $this->hasher->shouldReceive('make')->with('raw-password')->once()->andReturn('enc-password');
$this->database->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); $this->database->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull();
$this->hasher->shouldNotReceive('make'); $this->repository->shouldReceive('create')->with([
$this->passwordService->shouldNotReceive('handle'); 'password' => 'enc-password',
$this->repository->shouldReceive('create')->with(['password' => 'enc-password'])->once()->andReturn($user); 'uuid' => $this->getKnownUuid(),
])->once()->andReturn($user);
$this->database->shouldReceive('commit')->withNoArgs()->once()->andReturnNull(); $this->database->shouldReceive('commit')->withNoArgs()->once()->andReturnNull();
$this->appMock->shouldReceive('makeWith')->with(AccountCreated::class, [ $this->appMock->shouldReceive('makeWith')->with(AccountCreated::class, [
'user' => [ 'user' => [
@ -116,6 +113,37 @@ class UserCreationServiceTest extends TestCase
$this->assertEquals($user->name_first, 'FirstName'); $this->assertEquals($user->name_first, 'FirstName');
} }
/**
* Test that a UUID passed in the submission data is not used when
* creating the user.
*/
public function testUuidPassedInDataIsIgnored()
{
$user = (object) [
'name_first' => 'FirstName',
'username' => 'user_name',
];
$this->hasher->shouldReceive('make')->andReturn('enc-password');
$this->database->shouldReceive('beginTransaction')->andReturnNull();
$this->repository->shouldReceive('create')->with([
'password' => 'enc-password',
'uuid' => $this->getKnownUuid(),
])->once()->andReturn($user);
$this->database->shouldReceive('commit')->andReturnNull();
$this->appMock->shouldReceive('makeWith')->andReturnNull();
$this->notification->shouldReceive('send')->andReturnNull();
$response = $this->service->handle([
'password' => 'raw-password',
'uuid' => 'test-uuid',
]);
$this->assertNotNull($response);
$this->assertEquals($user->username, $response->username);
$this->assertEquals($user->name_first, 'FirstName');
}
/** /**
* Test that a user is created with a random password when no password is provided. * Test that a user is created with a random password when no password is provided.
*/ */
@ -138,6 +166,7 @@ class UserCreationServiceTest extends TestCase
$this->repository->shouldReceive('create')->with([ $this->repository->shouldReceive('create')->with([
'password' => 'created-enc-password', 'password' => 'created-enc-password',
'email' => 'user@example.com', 'email' => 'user@example.com',
'uuid' => $this->getKnownUuid(),
])->once()->andReturn($user); ])->once()->andReturn($user);
$this->database->shouldReceive('commit')->withNoArgs()->once()->andReturnNull(); $this->database->shouldReceive('commit')->withNoArgs()->once()->andReturnNull();