Cleanup FQDN validation logic, fallback to old hostname check (#4409)
Co-authored-by: DaneEveritt <dane@daneeveritt.com>
This commit is contained in:
parent
c748fa9842
commit
95e15d2c8a
3 changed files with 87 additions and 49 deletions
|
@ -58,29 +58,13 @@ class MakeNodeCommand extends Command
|
||||||
$data['name'] = $this->option('name') ?? $this->ask('Enter a short identifier used to distinguish this node from others');
|
$data['name'] = $this->option('name') ?? $this->ask('Enter a short identifier used to distinguish this node from others');
|
||||||
$data['description'] = $this->option('description') ?? $this->ask('Enter a description to identify the node');
|
$data['description'] = $this->option('description') ?? $this->ask('Enter a description to identify the node');
|
||||||
$data['location_id'] = $this->option('locationId') ?? $this->ask('Enter a valid location id');
|
$data['location_id'] = $this->option('locationId') ?? $this->ask('Enter a valid location id');
|
||||||
$data['fqdn'] = $this->option('fqdn') ?? $this->ask('Enter a domain name (e.g node.example.com) to be used for connecting to the daemon. An IP address may only be used if you are not using SSL for this node');
|
|
||||||
|
|
||||||
// Note, this function will also resolve CNAMEs for us automatically,
|
|
||||||
// there is no need to manually resolve them here.
|
|
||||||
//
|
|
||||||
// Using @ as workaround to fix https://bugs.php.net/bug.php?id=73149
|
|
||||||
$records = @dns_get_record($data['fqdn'], DNS_A + DNS_AAAA);
|
|
||||||
if (empty($records)) {
|
|
||||||
$this->error('The FQDN or IP address provided does not resolve to a valid IP address.');
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$data['public'] = $this->option('public') ?? $this->confirm('Should this node be public? As a note, setting a node to private you will be denying the ability to auto-deploy to this node.', true);
|
|
||||||
$data['scheme'] = $this->option('scheme') ?? $this->anticipate(
|
$data['scheme'] = $this->option('scheme') ?? $this->anticipate(
|
||||||
'Please either enter https for SSL or http for a non-ssl connection',
|
'Please either enter https for SSL or http for a non-ssl connection',
|
||||||
['https', 'http'],
|
['https', 'http'],
|
||||||
'https'
|
'https'
|
||||||
);
|
);
|
||||||
if (filter_var($data['fqdn'], FILTER_VALIDATE_IP) && $data['scheme'] === 'https') {
|
$data['fqdn'] = $this->option('fqdn') ?? $this->ask('Enter a domain name (e.g node.example.com) to be used for connecting to the daemon. An IP address may only be used if you are not using SSL for this node');
|
||||||
$this->error('A fully qualified domain name that resolves to a public IP address is required in order to use SSL for this node.');
|
$data['public'] = $this->option('public') ?? $this->confirm('Should this node be public? As a note, setting a node to private you will be denying the ability to auto-deploy to this node.', true);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$data['behind_proxy'] = $this->option('proxy') ?? $this->confirm('Is your FQDN behind a proxy?');
|
$data['behind_proxy'] = $this->option('proxy') ?? $this->confirm('Is your FQDN behind a proxy?');
|
||||||
$data['maintenance_mode'] = $this->option('maintenance') ?? $this->confirm('Should maintenance mode be enabled?');
|
$data['maintenance_mode'] = $this->option('maintenance') ?? $this->confirm('Should maintenance mode be enabled?');
|
||||||
$data['memory'] = $this->option('maxMemory') ?? $this->ask('Enter the maximum amount of memory');
|
$data['memory'] = $this->option('maxMemory') ?? $this->ask('Enter the maximum amount of memory');
|
||||||
|
|
|
@ -1,14 +1,8 @@
|
||||||
<?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\Node;
|
namespace Pterodactyl\Http\Requests\Admin\Node;
|
||||||
|
|
||||||
|
use Pterodactyl\Rules\Fqdn;
|
||||||
use Pterodactyl\Models\Node;
|
use Pterodactyl\Models\Node;
|
||||||
use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
|
use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
|
||||||
|
|
||||||
|
@ -23,30 +17,9 @@ class NodeFormRequest extends AdminFormRequest
|
||||||
return Node::getRulesForUpdate($this->route()->parameter('node'));
|
return Node::getRulesForUpdate($this->route()->parameter('node'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Node::getRules();
|
$data = Node::getRules();
|
||||||
}
|
$data['fqdn'][] = Fqdn::make('scheme');
|
||||||
|
|
||||||
/**
|
return $data;
|
||||||
* Run validation after the rules above have been applied.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Validation\Validator $validator
|
|
||||||
*/
|
|
||||||
public function withValidator($validator)
|
|
||||||
{
|
|
||||||
$validator->after(function ($validator) {
|
|
||||||
// Note, this function will also resolve CNAMEs for us automatically,
|
|
||||||
// there is no need to manually resolve them here.
|
|
||||||
//
|
|
||||||
// Using @ as workaround to fix https://bugs.php.net/bug.php?id=73149
|
|
||||||
$records = @dns_get_record($this->input('fqdn'), DNS_A + DNS_AAAA);
|
|
||||||
if (empty($records)) {
|
|
||||||
$validator->errors()->add('fqdn', trans('admin/node.validation.fqdn_not_resolvable'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that if using HTTPS the FQDN is not an IP address.
|
|
||||||
if (filter_var($this->input('fqdn'), FILTER_VALIDATE_IP) && $this->input('scheme') === 'https') {
|
|
||||||
$validator->errors()->add('fqdn', trans('admin/node.validation.fqdn_required_for_ssl'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
81
app/Rules/Fqdn.php
Normal file
81
app/Rules/Fqdn.php
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pterodactyl\Rules;
|
||||||
|
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
|
use Illuminate\Contracts\Validation\Rule;
|
||||||
|
use Illuminate\Contracts\Validation\DataAwareRule;
|
||||||
|
|
||||||
|
class Fqdn implements Rule, DataAwareRule
|
||||||
|
{
|
||||||
|
protected array $data = [];
|
||||||
|
protected string $message = '';
|
||||||
|
protected ?string $schemeField = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
*/
|
||||||
|
public function setData($data): self
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates that the value provided resolves to an IP address. If a scheme is
|
||||||
|
* specified when this rule is created additional checks will be applied.
|
||||||
|
*
|
||||||
|
* @param string $attribute
|
||||||
|
* @param mixed $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function passes($attribute, $value)
|
||||||
|
{
|
||||||
|
if (filter_var($value, FILTER_VALIDATE_IP)) {
|
||||||
|
// Check if the scheme is set to HTTPS.
|
||||||
|
//
|
||||||
|
// Unless someone owns their IP blocks and decides to pay who knows how much for a
|
||||||
|
// custom SSL cert, IPs will not be able to use HTTPS. This should prevent most
|
||||||
|
// home users from making this mistake and wondering why their node is not working.
|
||||||
|
if ($this->schemeField && Arr::get($this->data, $this->schemeField) === 'https') {
|
||||||
|
$this->message = 'The :attribute must not be an IP address when HTTPS is enabled.';
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup A and AAAA DNS records for the FQDN. Note, this function will also resolve CNAMEs
|
||||||
|
// for us automatically, there is no need to manually resolve them here.
|
||||||
|
//
|
||||||
|
// The error suppression is intentional, see https://bugs.php.net/bug.php?id=73149
|
||||||
|
$records = @dns_get_record($value, DNS_A + DNS_AAAA);
|
||||||
|
// If no records were returned fall back to trying to resolve the value using the hosts DNS
|
||||||
|
// resolution. This will not work for IPv6 which is why we prefer to use `dns_get_record`
|
||||||
|
// first.
|
||||||
|
if (!empty($records) || filter_var(gethostbyname($value), FILTER_VALIDATE_IP)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->message = 'The :attribute could not be resolved to a valid IP address.';
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function message(): string
|
||||||
|
{
|
||||||
|
return $this->message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new instance of the rule with a defined scheme set.
|
||||||
|
*/
|
||||||
|
public static function make(string $schemeField = null): self
|
||||||
|
{
|
||||||
|
return tap(new static(), function ($fqdn) use ($schemeField) {
|
||||||
|
$fqdn->schemeField = $schemeField;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue