Merge branch '1.0-develop' into develop

This commit is contained in:
Matthew Penner 2022-12-12 16:23:11 -07:00
commit 4138fb7497
No known key found for this signature in database
14 changed files with 149 additions and 46 deletions

View file

@ -41,4 +41,4 @@ MAIL_FROM_NAME="Pterodactyl Panel"
# mail servers such as Gmail to reject your mail. # mail servers such as Gmail to reject your mail.
# #
# @see: https://github.com/pterodactyl/panel/pull/3110 # @see: https://github.com/pterodactyl/panel/pull/3110
# SERVER_NAME=panel.example.com # MAIL_EHLO_DOMAIN=panel.example.com

View file

@ -3,6 +3,17 @@ 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.
## v1.11.2
### Changed
* Telemetry no longer sends a map of Egg and Nest UUIDs to the number of servers using them.
* Increased the timeout for the decompress files endpoint in the client API from 15 seconds to 15 minutes.
### Fixed
* Fixed Panel Docker image having a `v` prefix in the version displayed in the admin area.
* Fixed emails using the wrong queue name, causing them to not be sent.
* Fixed the settings keys used for configuring SMTP settings, causing settings to not save properly.
* Fixed the `MAIL_EHLO_DOMAIN` environment variable not being properly backwards compatible with the old `SERVER_NAME` variable.
## v1.11.1 ## v1.11.1
### Fixed ### Fixed
* Fixed Panel Docker image showing `canary` as it's version. * Fixed Panel Docker image showing `canary` as it's version.

View file

@ -1,11 +1,13 @@
# Security Policy # Security Policy
## Supported Versions ## Supported Versions
The following versions of Pterodactyl are receiving active support and maintenance. Any security vulnerabilities discovered must be reproducible in supported versions. The following versions of Pterodactyl are receiving active support and maintenance. Any security vulnerabilities discovered must be reproducible in supported versions.
| Panel | Daemon | Supported | | Panel | Daemon | Supported |
|--------|--------------|--------------------| |--------|--------------|--------------------|
| 1.10.x | wings@1.7.x | :white_check_mark: | | 1.10.x | wings@1.7.x | :white_check_mark: |
| 1.11.x | wings@1.11.x | :white_check_mark: |
| 0.7.x | daemon@0.6.x | :x: | | 0.7.x | daemon@0.6.x | :x: |

View file

@ -67,12 +67,6 @@ class EmailSettingsCommand extends Command
$this->config->get('mail.from.name') $this->config->get('mail.from.name')
); );
$this->variables['MAIL_ENCRYPTION'] = $this->option('encryption') ?? $this->choice(
trans('command/messages.environment.mail.ask_encryption'),
['tls' => 'TLS', 'ssl' => 'SSL', '' => 'None'],
$this->config->get('mail.encryption', 'tls')
);
$this->writeToEnvironment($this->variables); $this->writeToEnvironment($this->variables);
$this->line('Updating stored environment configuration file.'); $this->line('Updating stored environment configuration file.');
@ -102,6 +96,12 @@ class EmailSettingsCommand extends Command
$this->variables['MAIL_PASSWORD'] = $this->option('password') ?? $this->secret( $this->variables['MAIL_PASSWORD'] = $this->option('password') ?? $this->secret(
trans('command/messages.environment.mail.ask_smtp_password') trans('command/messages.environment.mail.ask_smtp_password')
); );
$this->variables['MAIL_ENCRYPTION'] = $this->option('encryption') ?? $this->choice(
trans('command/messages.environment.mail.ask_encryption'),
['tls' => 'TLS', 'ssl' => 'SSL', '' => 'None'],
$this->config->get('mail.mailers.smtp.encryption', 'tls')
);
} }
/** /**

View file

@ -54,8 +54,8 @@ class MailController extends Controller
} }
$values = $request->normalize(); $values = $request->normalize();
if (array_get($values, 'mail:password') === '!e') { if (array_get($values, 'mail:mailers:smtp:password') === '!e') {
$values['mail:password'] = ''; $values['mail:mailers:smtp:password'] = '';
} }
foreach ($values as $key => $value) { foreach ($values as $key => $value) {

View file

@ -13,11 +13,11 @@ class MailSettingsFormRequest extends AdminFormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'mail:host' => 'required|string', 'mail:mailers:smtp:host' => 'required|string',
'mail:port' => 'required|integer|between:1,65535', 'mail:mailers:smtp:port' => 'required|integer|between:1,65535',
'mail:encryption' => ['present', Rule::in([null, 'tls', 'ssl'])], 'mail:mailers:smtp:encryption' => ['present', Rule::in([null, 'tls', 'ssl'])],
'mail:username' => 'nullable|string|max:191', 'mail:mailers:smtp:username' => 'nullable|string|max:191',
'mail:password' => 'nullable|string|max:191', 'mail:mailers:smtp:password' => 'nullable|string|max:191',
'mail:from:address' => 'required|string|email', 'mail:from:address' => 'required|string|email',
'mail:from:name' => 'nullable|string|max:191', 'mail:from:name' => 'nullable|string|max:191',
]; ];
@ -31,8 +31,8 @@ class MailSettingsFormRequest extends AdminFormRequest
{ {
$keys = array_flip(array_keys($this->rules())); $keys = array_flip(array_keys($this->rules()));
if (empty($this->input('mail:password'))) { if (empty($this->input('mail:mailers:smtp:password'))) {
unset($keys['mail:password']); unset($keys['mail:mailers:smtp:password']);
} }
return $this->only(array_flip($keys)); return $this->only(array_flip($keys));

View file

@ -2,7 +2,13 @@
namespace Pterodactyl\Models; namespace Pterodactyl\Models;
/** @property string $value */ /**
* Pterodactyl\Models\Setting.
*
* @property int $id
* @property string $key
* @property string $value
*/
class Setting extends Model class Setting extends Model
{ {
/** /**

View file

@ -37,13 +37,13 @@ class SettingsServiceProvider extends ServiceProvider
* when using the SMTP driver. * when using the SMTP driver.
*/ */
protected array $emailKeys = [ protected array $emailKeys = [
'mail:host', 'mail:mailers:smtp:host',
'mail:port', 'mail:mailers:smtp:port',
'mail:mailers:smtp:encryption',
'mail:mailers:smtp:username',
'mail:mailers:smtp:password',
'mail:from:address', 'mail:from:address',
'mail:from:name', 'mail:from:name',
'mail:encryption',
'mail:username',
'mail:password',
]; ];
/** /**
@ -51,7 +51,7 @@ class SettingsServiceProvider extends ServiceProvider
* configuration array. * configuration array.
*/ */
protected static array $encrypted = [ protected static array $encrypted = [
'mail:password', 'mail:mailers:smtp:password',
]; ];
/** /**

View file

@ -231,6 +231,9 @@ class DaemonFileRepository extends DaemonRepository
'root' => $root ?? '/', 'root' => $root ?? '/',
'file' => $file, 'file' => $file,
], ],
// Wait for up to 15 minutes for the decompress to be completed when calling this endpoint
// since it will likely take quite awhile for large directories.
'timeout' => 60 * 15,
] ]
); );
} catch (TransferException $exception) { } catch (TransferException $exception) {

View file

@ -140,10 +140,12 @@ class TelemetryCollectionService
'eggs' => [ 'eggs' => [
'count' => Egg::count(), 'count' => Egg::count(),
'server_usage' => Egg::all() // Egg UUIDs are generated randomly on import, so there is not a consistent way to
->flatMap(fn (Egg $egg) => [$egg->uuid => $egg->servers->count()]) // determine if servers are using default eggs or not.
->filter(fn (int $count) => $count > 0) // 'server_usage' => Egg::all()
->toArray(), // ->flatMap(fn (Egg $egg) => [$egg->uuid => $egg->servers->count()])
// ->filter(fn (int $count) => $count > 0)
// ->toArray(),
], ],
'locations' => [ 'locations' => [
@ -156,10 +158,12 @@ class TelemetryCollectionService
'nests' => [ 'nests' => [
'count' => Nest::count(), 'count' => Nest::count(),
'server_usage' => Nest::all() // Nest UUIDs are generated randomly on import, so there is not a consistent way to
->flatMap(fn (Nest $nest) => [$nest->uuid => $nest->eggs->sum(fn (Egg $egg) => $egg->servers->count())]) // determine if servers are using default eggs or not.
->filter(fn (int $count) => $count > 0) // 'server_usage' => Nest::all()
->toArray(), // ->flatMap(fn (Nest $nest) => [$nest->uuid => $nest->eggs->sum(fn (Egg $egg) => $egg->servers->count())])
// ->filter(fn (int $count) => $count > 0)
// ->toArray(),
], ],
'nodes' => [ 'nodes' => [

View file

@ -41,7 +41,7 @@ return [
'username' => env('MAIL_USERNAME'), 'username' => env('MAIL_USERNAME'),
'password' => env('MAIL_PASSWORD'), 'password' => env('MAIL_PASSWORD'),
'timeout' => null, 'timeout' => null,
'local_domain' => env('MAIL_EHLO_DOMAIN'), 'local_domain' => env('MAIL_EHLO_DOMAIN', env('SERVER_NAME')),
], ],
'ses' => [ 'ses' => [

View file

@ -33,7 +33,7 @@ return [
'database' => [ 'database' => [
'driver' => 'database', 'driver' => 'database',
'table' => 'jobs', 'table' => 'jobs',
'queue' => env('QUEUE_STANDARD', 'default'), 'queue' => env('QUEUE_STANDARD', 'standard'),
'retry_after' => 90, 'retry_after' => 90,
'after_commit' => false, 'after_commit' => false,
], ],
@ -43,7 +43,7 @@ return [
'key' => env('AWS_ACCESS_KEY_ID'), 'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'), 'secret' => env('AWS_SECRET_ACCESS_KEY'),
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'), 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
'queue' => env('SQS_QUEUE', env('QUEUE_STANDARD', 'default')), 'queue' => env('SQS_QUEUE', env('QUEUE_STANDARD', 'standard')),
'suffix' => env('SQS_SUFFIX'), 'suffix' => env('SQS_SUFFIX'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'after_commit' => false, 'after_commit' => false,
@ -52,7 +52,7 @@ return [
'redis' => [ 'redis' => [
'driver' => 'redis', 'driver' => 'redis',
'connection' => 'default', 'connection' => 'default',
'queue' => env('REDIS_QUEUE', env('QUEUE_STANDARD', 'default')), 'queue' => env('REDIS_QUEUE', env('QUEUE_STANDARD', 'standard')),
'retry_after' => 90, 'retry_after' => 90,
'block_for' => null, 'block_for' => null,
'after_commit' => false, 'after_commit' => false,

View file

@ -0,0 +1,77 @@
<?php
use Pterodactyl\Models\Setting;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Migrations\Migration;
return new class () extends Migration {
private array $keys = [
['mail:host', 'mail:mailers:smtp:host'],
['mail:port', 'mail:mailers:smtp:port'],
['mail:encryption', 'mail:mailers:smtp:encryption'],
['mail:username', 'mail:mailers:smtp:username'],
['mail:password', 'mail:mailers:smtp:password'],
];
/**
* Run the migrations.
*/
public function up(): void
{
$settings = Setting::all();
// Gets the first column in our key table and gets all matching settings.
$oldKeys = array_column($this->keys, 0);
$oldSettings = $settings->filter(fn (Setting $setting) => in_array($setting->key, $oldKeys));
// Gets the second column in our key table and gets all matching settings.
$newKeys = array_column($this->keys, 1);
$newSettings = $settings->filter(fn (Setting $setting) => in_array($setting->key, $newKeys));
// Map all the old settings to their new key.
$oldSettings->map(function (Setting $setting) use ($oldKeys) {
$row = array_search($setting->key, $oldKeys, true);
$setting->key = $this->keys[$row][1];
return $setting;
// Check if any settings with the new key already exist.
})->filter(function (Setting $setting) use ($newSettings) {
if ($newSettings->contains('key', $setting->key)) {
return false;
}
return true;
// Update the settings to use their new keys if they don't already exist.
})->each(fn (Setting $setting) => $setting->save());
}
/**
* Reverse the migrations.
*/
public function down(): void
{
DB::transaction(function () {
$settings = Setting::all();
// Gets the second column in our key table and gets all matching settings.
$newKeys = array_column($this->keys, 0);
$newSettings = $settings->filter(fn (Setting $setting) => in_array($setting->key, $newKeys));
// Delete all settings that already have the new key.
$newSettings->each(fn (Setting $setting) => $setting->delete());
// Gets the first column in our key table and gets all matching settings.
$oldKeys = array_column($this->keys, 1);
$oldSettings = $settings->filter(fn (Setting $setting) => in_array($setting->key, $oldKeys));
// Map all the old settings to their new key.
$oldSettings->map(function (Setting $setting) use ($oldKeys) {
$row = array_search($setting->key, $oldKeys, true);
$setting->key = $this->keys[$row][0];
return $setting;
// Update the settings to use their new keys if they don't already exist.
})->each(fn (Setting $setting) => $setting->save());
});
}
};

View file

@ -38,14 +38,14 @@
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label class="control-label">SMTP Host</label> <label class="control-label">SMTP Host</label>
<div> <div>
<input required type="text" class="form-control" name="mail:host" value="{{ old('mail:host', config('mail.mailers.smtp.host')) }}" /> <input required type="text" class="form-control" name="mail:mailers:smtp:host" value="{{ old('mail:mailers:smtp:host', config('mail.mailers.smtp.host')) }}" />
<p class="text-muted small">Enter the SMTP server address that mail should be sent through.</p> <p class="text-muted small">Enter the SMTP server address that mail should be sent through.</p>
</div> </div>
</div> </div>
<div class="form-group col-md-2"> <div class="form-group col-md-2">
<label class="control-label">SMTP Port</label> <label class="control-label">SMTP Port</label>
<div> <div>
<input required type="number" class="form-control" name="mail:port" value="{{ old('mail:port', config('mail.mailers.smtp.port')) }}" /> <input required type="number" class="form-control" name="mail:mailers:smtp:port" value="{{ old('mail:mailers:smtp:port', config('mail.mailers.smtp.port')) }}" />
<p class="text-muted small">Enter the SMTP server port that mail should be sent through.</p> <p class="text-muted small">Enter the SMTP server port that mail should be sent through.</p>
</div> </div>
</div> </div>
@ -53,9 +53,9 @@
<label class="control-label">Encryption</label> <label class="control-label">Encryption</label>
<div> <div>
@php @php
$encryption = old('mail:encryption', config('mail.mailers.smtp.encryption')); $encryption = old('mail:mailers:smtp:encryption', config('mail.mailers.smtp.encryption'));
@endphp @endphp
<select name="mail:encryption" class="form-control"> <select name="mail:mailers:smtp:encryption" class="form-control">
<option value="" @if($encryption === '') selected @endif>None</option> <option value="" @if($encryption === '') selected @endif>None</option>
<option value="tls" @if($encryption === 'tls') selected @endif>Transport Layer Security (TLS)</option> <option value="tls" @if($encryption === 'tls') selected @endif>Transport Layer Security (TLS)</option>
<option value="ssl" @if($encryption === 'ssl') selected @endif>Secure Sockets Layer (SSL)</option> <option value="ssl" @if($encryption === 'ssl') selected @endif>Secure Sockets Layer (SSL)</option>
@ -66,14 +66,14 @@
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label class="control-label">Username <span class="field-optional"></span></label> <label class="control-label">Username <span class="field-optional"></span></label>
<div> <div>
<input type="text" class="form-control" name="mail:username" value="{{ old('mail:username', config('mail.mailers.smtp.username')) }}" /> <input type="text" class="form-control" name="mail:mailers:smtp:username" value="{{ old('mail:mailers:smtp:username', config('mail.mailers.smtp.username')) }}" />
<p class="text-muted small">The username to use when connecting to the SMTP server.</p> <p class="text-muted small">The username to use when connecting to the SMTP server.</p>
</div> </div>
</div> </div>
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label class="control-label">Password <span class="field-optional"></span></label> <label class="control-label">Password <span class="field-optional"></span></label>
<div> <div>
<input type="password" class="form-control" name="mail:password"/> <input type="password" class="form-control" name="mail:mailers:smtp:password"/>
<p class="text-muted small">The password to use in conjunction with the SMTP username. Leave blank to continue using the existing password. To set the password to an empty value enter <code>!e</code> into the field.</p> <p class="text-muted small">The password to use in conjunction with the SMTP username. Leave blank to continue using the existing password. To set the password to an empty value enter <code>!e</code> into the field.</p>
</div> </div>
</div> </div>
@ -120,11 +120,11 @@
url: '/admin/settings/mail', url: '/admin/settings/mail',
contentType: 'application/json', contentType: 'application/json',
data: JSON.stringify({ data: JSON.stringify({
'mail:host': $('input[name="mail:host"]').val(), 'mail:mailers:smtp:host': $('input[name="mail:mailers:smtp:host"]').val(),
'mail:port': $('input[name="mail:port"]').val(), 'mail:mailers:smtp:port': $('input[name="mail:mailers:smtp:port"]').val(),
'mail:encryption': $('select[name="mail:encryption"]').val(), 'mail:mailers:smtp:encryption': $('select[name="mail:mailers:smtp:encryption"]').val(),
'mail:username': $('input[name="mail:username"]').val(), 'mail:mailers:smtp:username': $('input[name="mail:mailers:smtp:username"]').val(),
'mail:password': $('input[name="mail:password"]').val(), 'mail:mailers:smtp:password': $('input[name="mail:mailers:smtp:password"]').val(),
'mail:from:address': $('input[name="mail:from:address"]').val(), 'mail:from:address': $('input[name="mail:from:address"]').val(),
'mail:from:name': $('input[name="mail:from:name"]').val() 'mail:from:name': $('input[name="mail:from:name"]').val()
}), }),