Merge branch 'release/v0.7.6'
This commit is contained in:
commit
41e27a6612
48 changed files with 638 additions and 287 deletions
22
CHANGELOG.md
22
CHANGELOG.md
|
@ -3,6 +3,28 @@ 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.6 (Derelict Dermodactylus)
|
||||
### Fixed
|
||||
* Fixes a UI error when attempting to change the default Nest and Egg for an existing server.
|
||||
* Correct permissions check in UI to allow subusers with permission to `view-allocations` the ability to actually see the sidebar link.
|
||||
* Fixes improper behavior when marking an egg as copying the configuration from another.
|
||||
* Debug bar is only checked when the app is set to debug mode in the API session handler, rather than when it is in local mode to match the plugin settings.
|
||||
* Added validation to port allocations to prevent allocation of restricted or invalid ports.
|
||||
* Fix data integrity exception thrown when attempting to store updated server egg variables.
|
||||
* Added missing permissions check on 'SFTP Configuration' page to ensure user has permission to access a server's SFTP server before showing a user credentials.
|
||||
|
||||
### Added
|
||||
* Added ability for end users to change the name of their server through the UI. This option is only open to the server owner or an admin.
|
||||
* Added giant warning message if you attempt to change an encryption key once one has been set.
|
||||
|
||||
### Changed
|
||||
* Panel now throws proper 504: Gateway Timeout errors on server listing when daemon is offline.
|
||||
* Sessions handled through redis now use a seperate database (default `1`) to store session database to avoid logging users out when flushing the cache.
|
||||
* File manager UI improved to be clearer with buttons and cleaner on mobile.
|
||||
* reCAPTCHA's secret key position swapped with website key in advanced panel settings to be consistent with Google's reCAPTCHA dashboard.
|
||||
* Changed DisplayException to handle its own logging correctly and check if the previous exception is marked as one that should not be logged.
|
||||
* Changed 'New Folder' modal in file manager to include a trailing slash.
|
||||
|
||||
## v0.7.5 (Derelict Dermodactylus)
|
||||
### Fixed
|
||||
* Fixes application API keys being created as a client API key.
|
||||
|
|
10
Vagrantfile
vendored
10
Vagrantfile
vendored
|
@ -1,13 +1,9 @@
|
|||
Vagrant.configure("2") do |config|
|
||||
config.vm.box = "ubuntu/xenial64"
|
||||
config.vm.box = "bento/ubuntu-16.04"
|
||||
|
||||
config.vm.synced_folder "./", "/var/www/html/pterodactyl",
|
||||
owner: "www-data", group: "www-data"
|
||||
|
||||
#config.vm.provision :file, source: ".dev/vagrant/pterdactyl.conf", destination: "/etc/nginx/sites-available/pterodactyl.conf"
|
||||
#config.vm.provision :file, source: ".dev/vagrant/pteroq.service", destination: "/etc/systemd/system/pteroq.service"
|
||||
#config.vm.provision :file, source: ".dev/vagrant/mailhog.service", destination: "/etc/systemd/system/mailhog.service"
|
||||
#config.vm.provision :file, source: ".dev/vagrant/.env", destination: "/var/www/html/pterodactyl/.env"
|
||||
config.vm.provision :shell, path: ".dev/vagrant/provision.sh"
|
||||
|
||||
config.vm.network :private_network, ip: "192.168.50.2"
|
||||
|
@ -16,6 +12,6 @@ Vagrant.configure("2") do |config|
|
|||
config.vm.network :forwarded_port, guest: 3306, host: 53306
|
||||
|
||||
# Config for the vagrant-dns plugin (https://github.com/BerlinVagrant/vagrant-dns)
|
||||
config.dns.tld = "app"
|
||||
config.dns.patterns = [/^pterodactyl.app$/]
|
||||
config.dns.tld = "test"
|
||||
config.dns.patterns = [/^pterodactyl.test$/]
|
||||
end
|
||||
|
|
28
app/Console/Commands/Overrides/KeyGenerateCommand.php
Normal file
28
app/Console/Commands/Overrides/KeyGenerateCommand.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Console\Commands\Overrides;
|
||||
|
||||
use Illuminate\Foundation\Console\KeyGenerateCommand as BaseKeyGenerateCommand;
|
||||
|
||||
class KeyGenerateCommand extends BaseKeyGenerateCommand
|
||||
{
|
||||
/**
|
||||
* Override the default Laravel key generation command to throw a warning to the user
|
||||
* if it appears that they have already generated an application encryption key.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if (! empty(config('app.key')) && $this->input->isInteractive()) {
|
||||
$this->output->warning(trans('command/messages.key.warning'));
|
||||
if (! $this->confirm(trans('command/messages.key.confirm'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $this->confirm(trans('command/messages.key.final_confirm'))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
parent::handle();
|
||||
}
|
||||
}
|
|
@ -2,9 +2,11 @@
|
|||
|
||||
namespace Pterodactyl\Exceptions;
|
||||
|
||||
use Log;
|
||||
use Exception;
|
||||
use Throwable;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Container\Container;
|
||||
use Prologue\Alerts\AlertsMessageBag;
|
||||
|
||||
class DisplayException extends PterodactylException
|
||||
|
@ -31,10 +33,6 @@ class DisplayException extends PterodactylException
|
|||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
|
||||
if (! is_null($previous)) {
|
||||
Log::{$level}($previous);
|
||||
}
|
||||
|
||||
$this->level = $level;
|
||||
}
|
||||
|
||||
|
@ -70,8 +68,31 @@ class DisplayException extends PterodactylException
|
|||
]), method_exists($this, 'getStatusCode') ? $this->getStatusCode() : Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
app()->make(AlertsMessageBag::class)->danger($this->getMessage())->flash();
|
||||
Container::getInstance()->make(AlertsMessageBag::class)->danger($this->getMessage())->flash();
|
||||
|
||||
return redirect()->back()->withInput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the exception to the logs using the defined error level only if the previous
|
||||
* exception is set.
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function report()
|
||||
{
|
||||
if (! $this->getPrevious() instanceof Exception || ! Handler::isReportable($this->getPrevious())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$logger = Container::getInstance()->make(LoggerInterface::class);
|
||||
} catch (Exception $ex) {
|
||||
throw $this->getPrevious();
|
||||
}
|
||||
|
||||
return $logger->{$this->getErrorLevel()}($this->getPrevious());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace Pterodactyl\Exceptions;
|
|||
use Exception;
|
||||
use PDOException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Auth\AuthenticationException;
|
||||
use Illuminate\Session\TokenMismatchException;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
@ -24,7 +25,6 @@ class Handler extends ExceptionHandler
|
|||
protected $dontReport = [
|
||||
AuthenticationException::class,
|
||||
AuthorizationException::class,
|
||||
DisplayException::class,
|
||||
HttpException::class,
|
||||
ModelNotFoundException::class,
|
||||
RecordNotFoundException::class,
|
||||
|
@ -201,6 +201,17 @@ class Handler extends ExceptionHandler
|
|||
return ['errors' => [array_merge($error, $override)]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of exceptions that should not be reported.
|
||||
*
|
||||
* @param \Exception $exception
|
||||
* @return bool
|
||||
*/
|
||||
public static function isReportable(Exception $exception): bool
|
||||
{
|
||||
return (new static(Container::getInstance()))->shouldReport($exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an authentication exception into an unauthenticated response.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Exceptions\Service\Allocation;
|
||||
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
|
||||
class CidrOutOfRangeException extends DisplayException
|
||||
{
|
||||
/**
|
||||
* CidrOutOfRangeException constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(trans('exceptions.allocations.cidr_out_of_range'));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Exceptions\Service\Allocation;
|
||||
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
|
||||
class InvalidPortMappingException extends DisplayException
|
||||
{
|
||||
/**
|
||||
* InvalidPortMappingException constructor.
|
||||
*
|
||||
* @param mixed $port
|
||||
*/
|
||||
public function __construct($port)
|
||||
{
|
||||
parent::__construct(trans('exceptions.allocations.invalid_mapping', ['port' => $port]));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Exceptions\Service\Allocation;
|
||||
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
|
||||
class PortOutOfRangeException extends DisplayException
|
||||
{
|
||||
/**
|
||||
* PortOutOfRangeException constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(trans('exceptions.allocations.port_out_of_range'));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Exceptions\Service\Allocation;
|
||||
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
|
||||
class TooManyPortsInRangeException extends DisplayException
|
||||
{
|
||||
/**
|
||||
* TooManyPortsInRangeException constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(trans('exceptions.allocations.too_many_ports'));
|
||||
}
|
||||
}
|
|
@ -331,7 +331,10 @@ class NodesController extends Controller
|
|||
* @param int|\Pterodactyl\Models\Node $node
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Allocation\CidrOutOfRangeException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Allocation\InvalidPortMappingException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Allocation\PortOutOfRangeException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Allocation\TooManyPortsInRangeException
|
||||
*/
|
||||
public function createAllocation(AllocationFormRequest $request, Node $node)
|
||||
{
|
||||
|
|
|
@ -73,7 +73,10 @@ class AllocationController extends ApplicationApiController
|
|||
* @param \Pterodactyl\Http\Requests\Api\Application\Allocations\StoreAllocationRequest $request
|
||||
* @return array
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Allocation\CidrOutOfRangeException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Allocation\InvalidPortMappingException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Allocation\PortOutOfRangeException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Allocation\TooManyPortsInRangeException
|
||||
*/
|
||||
public function store(StoreAllocationRequest $request): array
|
||||
{
|
||||
|
|
|
@ -4,6 +4,8 @@ namespace Pterodactyl\Http\Controllers\Base;
|
|||
|
||||
use Illuminate\Http\Request;
|
||||
use Pterodactyl\Models\User;
|
||||
use Illuminate\Http\Response;
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
@ -81,6 +83,8 @@ class IndexController extends Controller
|
|||
|
||||
try {
|
||||
$response = $this->daemonRepository->setServer($server)->setToken($token)->details();
|
||||
} catch (ConnectException $exception) {
|
||||
throw new HttpException(Response::HTTP_GATEWAY_TIMEOUT, $exception->getMessage());
|
||||
} catch (RequestException $exception) {
|
||||
throw new HttpException(500, $exception->getMessage());
|
||||
}
|
||||
|
|
59
app/Http/Controllers/Server/Settings/NameController.php
Normal file
59
app/Http/Controllers/Server/Settings/NameController.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Server\Settings;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Traits\Controllers\JavascriptInjection;
|
||||
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
||||
use Pterodactyl\Http\Requests\Server\Settings\ChangeServerNameRequest;
|
||||
|
||||
class NameController extends Controller
|
||||
{
|
||||
use JavascriptInjection;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* NameController constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
|
||||
*/
|
||||
public function __construct(ServerRepositoryInterface $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('view-name', $request->attributes->get('server'));
|
||||
$this->setRequest($request)->injectJavascript();
|
||||
|
||||
return view('server.settings.name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the stored name for a specific server.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Server\Settings\ChangeServerNameRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function update(ChangeServerNameRequest $request): RedirectResponse
|
||||
{
|
||||
$this->repository->update($request->getServer()->id, $request->validated());
|
||||
|
||||
return redirect()->route('server.settings.name', $request->getServer()->uuidShort);
|
||||
}
|
||||
}
|
|
@ -16,9 +16,12 @@ class SftpController extends Controller
|
|||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$this->authorize('access-sftp', $request->attributes->get('server'));
|
||||
$this->setRequest($request)->injectJavascript();
|
||||
|
||||
return view('server.settings.sftp');
|
||||
|
|
|
@ -41,7 +41,7 @@ class SetSessionDriver
|
|||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if ($this->app->environment() !== 'production') {
|
||||
if ($this->config->get('app.debug')) {
|
||||
$this->app->make(LaravelDebugbar::class)->disable();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Server\Settings;
|
||||
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Http\Requests\Server\ServerFormRequest;
|
||||
|
||||
class ChangeServerNameRequest extends ServerFormRequest
|
||||
{
|
||||
/**
|
||||
* Permission to use when checking if a user can access this resource.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function permission(): string
|
||||
{
|
||||
return 'edit-name';
|
||||
}
|
||||
|
||||
/**
|
||||
* Rules to use when validating the submitted data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'name' => Server::getCreateRules()['name'],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -113,7 +113,11 @@ class Egg extends Model implements CleansAttributes, ValidableContract
|
|||
*/
|
||||
public function getCopyScriptInstallAttribute()
|
||||
{
|
||||
return (is_null($this->copy_script_from)) ? $this->script_install : $this->scriptFrom->script_install;
|
||||
if (! is_null($this->script_install) || is_null($this->copy_script_from)) {
|
||||
return $this->script_install;
|
||||
}
|
||||
|
||||
return $this->scriptFrom->script_install;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,7 +128,11 @@ class Egg extends Model implements CleansAttributes, ValidableContract
|
|||
*/
|
||||
public function getCopyScriptEntryAttribute()
|
||||
{
|
||||
return (is_null($this->copy_script_from)) ? $this->script_entry : $this->scriptFrom->script_entry;
|
||||
if (! is_null($this->script_entry) || is_null($this->copy_script_from)) {
|
||||
return $this->script_entry;
|
||||
}
|
||||
|
||||
return $this->scriptFrom->script_entry;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,7 +143,11 @@ class Egg extends Model implements CleansAttributes, ValidableContract
|
|||
*/
|
||||
public function getCopyScriptContainerAttribute()
|
||||
{
|
||||
return (is_null($this->copy_script_from)) ? $this->script_container : $this->scriptFrom->script_container;
|
||||
if (! is_null($this->script_container) || is_null($this->copy_script_from)) {
|
||||
return $this->script_container;
|
||||
}
|
||||
|
||||
return $this->scriptFrom->script_container;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -145,7 +157,11 @@ class Egg extends Model implements CleansAttributes, ValidableContract
|
|||
*/
|
||||
public function getInheritConfigFilesAttribute()
|
||||
{
|
||||
return is_null($this->config_from) ? $this->config_files : $this->configFrom->config_files;
|
||||
if (! is_null($this->config_files) || is_null($this->config_from)) {
|
||||
return $this->config_files;
|
||||
}
|
||||
|
||||
return $this->configFrom->config_files;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,7 +171,11 @@ class Egg extends Model implements CleansAttributes, ValidableContract
|
|||
*/
|
||||
public function getInheritConfigStartupAttribute()
|
||||
{
|
||||
return is_null($this->config_from) ? $this->config_startup : $this->configFrom->config_startup;
|
||||
if (! is_null($this->config_startup) || is_null($this->config_from)) {
|
||||
return $this->config_startup;
|
||||
}
|
||||
|
||||
return $this->configFrom->config_startup;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -165,7 +185,11 @@ class Egg extends Model implements CleansAttributes, ValidableContract
|
|||
*/
|
||||
public function getInheritConfigLogsAttribute()
|
||||
{
|
||||
return is_null($this->config_from) ? $this->config_logs : $this->configFrom->config_logs;
|
||||
if (! is_null($this->config_logs) || is_null($this->config_from)) {
|
||||
return $this->config_logs;
|
||||
}
|
||||
|
||||
return $this->configFrom->config_logs;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -175,7 +199,11 @@ class Egg extends Model implements CleansAttributes, ValidableContract
|
|||
*/
|
||||
public function getInheritConfigStopAttribute()
|
||||
{
|
||||
return is_null($this->config_from) ? $this->config_stop : $this->configFrom->config_stop;
|
||||
if (! is_null($this->config_stop) || is_null($this->config_from)) {
|
||||
return $this->config_stop;
|
||||
}
|
||||
|
||||
return $this->configFrom->config_stop;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -164,7 +164,7 @@ class Node extends Model implements CleansAttributes, ValidableContract
|
|||
'enabled' => true,
|
||||
'kill_at_count' => 5,
|
||||
'decay' => 10,
|
||||
'bytes' => 30720,
|
||||
'lines' => 1000,
|
||||
'check_interval_ms' => 100,
|
||||
],
|
||||
],
|
||||
|
|
|
@ -1,26 +1,24 @@
|
|||
<?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\Allocations;
|
||||
|
||||
use IPTools\Network;
|
||||
use Pterodactyl\Models\Node;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
|
||||
use Pterodactyl\Exceptions\Service\Allocation\CidrOutOfRangeException;
|
||||
use Pterodactyl\Exceptions\Service\Allocation\PortOutOfRangeException;
|
||||
use Pterodactyl\Exceptions\Service\Allocation\InvalidPortMappingException;
|
||||
use Pterodactyl\Exceptions\Service\Allocation\TooManyPortsInRangeException;
|
||||
|
||||
class AssignmentService
|
||||
{
|
||||
const CIDR_MAX_BITS = 27;
|
||||
const CIDR_MIN_BITS = 32;
|
||||
const PORT_FLOOR = 1024;
|
||||
const PORT_CEIL = 65535;
|
||||
const PORT_RANGE_LIMIT = 1000;
|
||||
const PORT_RANGE_REGEX = '/^(\d{1,5})-(\d{1,5})$/';
|
||||
const PORT_RANGE_REGEX = '/^(\d{4,5})-(\d{4,5})$/';
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Database\ConnectionInterface
|
||||
|
@ -38,10 +36,8 @@ class AssignmentService
|
|||
* @param \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface $repository
|
||||
* @param \Illuminate\Database\ConnectionInterface $connection
|
||||
*/
|
||||
public function __construct(
|
||||
AllocationRepositoryInterface $repository,
|
||||
ConnectionInterface $connection
|
||||
) {
|
||||
public function __construct(AllocationRepositoryInterface $repository, ConnectionInterface $connection)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
@ -49,21 +45,20 @@ class AssignmentService
|
|||
/**
|
||||
* Insert allocations into the database and link them to a specific node.
|
||||
*
|
||||
* @param int|\Pterodactyl\Models\Node $node
|
||||
* @param array $data
|
||||
* @param \Pterodactyl\Models\Node $node
|
||||
* @param array $data
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Allocation\CidrOutOfRangeException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Allocation\PortOutOfRangeException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Allocation\InvalidPortMappingException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Allocation\TooManyPortsInRangeException
|
||||
*/
|
||||
public function handle($node, array $data)
|
||||
public function handle(Node $node, array $data)
|
||||
{
|
||||
if ($node instanceof Node) {
|
||||
$node = $node->id;
|
||||
}
|
||||
|
||||
$explode = explode('/', $data['allocation_ip']);
|
||||
if (count($explode) !== 1) {
|
||||
if (! ctype_digit($explode[1]) || ($explode[1] > self::CIDR_MIN_BITS || $explode[1] < self::CIDR_MAX_BITS)) {
|
||||
throw new DisplayException(trans('exceptions.allocations.cidr_out_of_range'));
|
||||
throw new CidrOutOfRangeException;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,7 +66,7 @@ class AssignmentService
|
|||
foreach (Network::parse(gethostbyname($data['allocation_ip'])) as $ip) {
|
||||
foreach ($data['allocation_ports'] as $port) {
|
||||
if (! is_digit($port) && ! preg_match(self::PORT_RANGE_REGEX, $port)) {
|
||||
throw new DisplayException(trans('exceptions.allocations.invalid_mapping', ['port' => $port]));
|
||||
throw new InvalidPortMappingException($port);
|
||||
}
|
||||
|
||||
$insertData = [];
|
||||
|
@ -79,12 +74,16 @@ class AssignmentService
|
|||
$block = range($matches[1], $matches[2]);
|
||||
|
||||
if (count($block) > self::PORT_RANGE_LIMIT) {
|
||||
throw new DisplayException(trans('exceptions.allocations.too_many_ports'));
|
||||
throw new TooManyPortsInRangeException;
|
||||
}
|
||||
|
||||
if ((int) $matches[1] <= self::PORT_FLOOR || (int) $matches[2] > self::PORT_CEIL) {
|
||||
throw new PortOutOfRangeException;
|
||||
}
|
||||
|
||||
foreach ($block as $unit) {
|
||||
$insertData[] = [
|
||||
'node_id' => $node,
|
||||
'node_id' => $node->id,
|
||||
'ip' => $ip->__toString(),
|
||||
'port' => (int) $unit,
|
||||
'ip_alias' => array_get($data, 'allocation_alias'),
|
||||
|
@ -92,8 +91,12 @@ class AssignmentService
|
|||
];
|
||||
}
|
||||
} else {
|
||||
if ((int) $port <= self::PORT_FLOOR || (int) $port > self::PORT_CEIL) {
|
||||
throw new PortOutOfRangeException;
|
||||
}
|
||||
|
||||
$insertData[] = [
|
||||
'node_id' => $node,
|
||||
'node_id' => $node->id,
|
||||
'ip' => $ip->__toString(),
|
||||
'port' => (int) $port,
|
||||
'ip_alias' => array_get($data, 'allocation_alias'),
|
||||
|
|
|
@ -105,7 +105,7 @@ class StartupModificationService
|
|||
'server_id' => $server->id,
|
||||
'variable_id' => $result->id,
|
||||
], [
|
||||
'variable_value' => $result->value,
|
||||
'variable_value' => $result->value ?? '',
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
|
6
artisan
6
artisan
|
@ -1,6 +1,8 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
define('LARAVEL_START', microtime(true));
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Register The Auto Loader
|
||||
|
@ -13,7 +15,7 @@
|
|||
|
|
||||
*/
|
||||
|
||||
require __DIR__.'/bootstrap/autoload.php';
|
||||
require __DIR__.'/vendor/autoload.php';
|
||||
|
||||
$app = require_once __DIR__.'/bootstrap/app.php';
|
||||
|
||||
|
@ -40,7 +42,7 @@ $status = $kernel->handle(
|
|||
| Shutdown The Application
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Once Artisan has finished running. We will fire off the shutdown events
|
||||
| Once Artisan has finished running, we will fire off the shutdown events
|
||||
| so that any final work may be done by the application before we shut
|
||||
| down the process. This is the last thing to happen to the request.
|
||||
|
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
<?php
|
||||
|
||||
define('LARAVEL_START', microtime(true));
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Register The Composer Auto Loader
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Composer provides a convenient, automatically generated class loader
|
||||
| for our application. We just need to utilize it! We'll require it
|
||||
| into the script here so that we do not have to worry about the
|
||||
| loading of any our classes "manually". Feels great to relax.
|
||||
|
|
||||
*/
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
|
@ -9,7 +9,7 @@ return [
|
|||
| change this value if you are not maintaining your own internal versions.
|
||||
*/
|
||||
|
||||
'version' => '0.7.5',
|
||||
'version' => '0.7.6',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
|
@ -70,6 +70,12 @@ return [
|
|||
'driver' => 'redis',
|
||||
'connection' => 'default',
|
||||
],
|
||||
|
||||
'sessions' => [
|
||||
'driver' => env('SESSION_DRIVER', 'database'),
|
||||
'table' => 'sessions',
|
||||
'connection' => env('SESSION_DRIVER') === 'redis' ? 'sessions' : null,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|
|
|
@ -71,11 +71,19 @@ return [
|
|||
|
||||
'redis' => [
|
||||
'client' => 'predis',
|
||||
|
||||
'default' => [
|
||||
'host' => env('REDIS_HOST', 'localhost'),
|
||||
'password' => env('REDIS_PASSWORD', null),
|
||||
'port' => env('REDIS_PORT', 6379),
|
||||
'database' => env('REDIS_DATBASE', 0),
|
||||
],
|
||||
|
||||
'sessions' => [
|
||||
'host' => env('REDIS_HOST', 'localhost'),
|
||||
'password' => env('REDIS_PASSWORD', null),
|
||||
'port' => env('REDIS_PORT', 6379),
|
||||
'database' => env('REDIS_DATBASE_SESSIONS', 1),
|
||||
],
|
||||
],
|
||||
];
|
||||
|
|
|
@ -69,7 +69,7 @@ return [
|
|||
|
|
||||
*/
|
||||
|
||||
'connection' => null,
|
||||
'connection' => env('SESSION_DRIVER') === 'redis' ? 'sessions' : null,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"meta": {
|
||||
"version": "PTDL_v1"
|
||||
},
|
||||
"exported_at": "2017-11-03T22:15:10-05:00",
|
||||
"exported_at": "2018-02-27T00:57:04-06:00",
|
||||
"name": "Forge Minecraft",
|
||||
"author": "support@pterodactyl.io",
|
||||
"description": "Minecraft Forge Server. Minecraft Forge is a modding API (Application Programming Interface), which makes it easier to create mods, and also make sure mods are compatible with each other.",
|
||||
|
@ -17,7 +17,7 @@
|
|||
},
|
||||
"scripts": {
|
||||
"installation": {
|
||||
"script": "#!\/bin\/ash\n# Forge Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add curl\n\nGET_VERSIONS=$(curl -sl http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/ | grep -A1 Latest | grep -o -e '[1]\\.[0-9][0-9] - [0-9][0-9]\\.[0-9][0-9]\\.[0-9]\\.[0-9][0-9][0-9][0-9]')\nLATEST_VERSION=$(echo $GET_VERSIONS | sed 's\/ \/\/g')\n\ncd \/mnt\/server\n\ncurl -sS http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/$LATEST_VERSION\/forge-$LATEST_VERSION-installer.jar -o installer.jar\ncurl -sS http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/$LATEST_VERSION\/forge-$LATEST_VERSION-universal.jar -o server.jar\n\njava -jar installer.jar --installServer\nrm -rf installer.jar",
|
||||
"script": "#!\/bin\/ash\r\n# Forge Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\napk update\r\napk add curl\r\n\r\nGET_VERSIONS=$(curl -sl http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/ | grep -A1 Latest | grep -o -e '[1]\\.[0-9][0-9]]\\?\\.\\?[0-9]\\?[0-9] - [0-9][0-9]\\.[0-9][0-9]\\.[0-9]\\?[0-9]\\.[0-9][0-9][0-9][0-9]')\r\nLATEST_VERSION=$(echo $GET_VERSIONS | sed 's\/ \/\/g')\r\n\r\ncd \/mnt\/server\r\n\r\ncurl -sS http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/$LATEST_VERSION\/forge-$LATEST_VERSION-installer.jar -o installer.jar\r\ncurl -sS http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/$LATEST_VERSION\/forge-$LATEST_VERSION-universal.jar -o server.jar\r\n\r\njava -jar installer.jar --installServer\r\nrm -rf installer.jar",
|
||||
"container": "frolvlad\/alpine-oraclejdk8:cleaned",
|
||||
"entrypoint": "ash"
|
||||
}
|
||||
|
@ -33,4 +33,4 @@
|
|||
"rules": "required|regex:\/^([\\w\\d._-]+)(\\.jar)$\/"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
},
|
||||
"scripts": {
|
||||
"installation": {
|
||||
"script": "#!\/bin\/ash\n# TS3 Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add tar curl\n\ncd \/tmp\n\ncurl -sSLO http:\/\/dl.4players.de\/ts\/releases\/${TS_VERSION}\/teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2\n\ntar -xjvf teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2\ncp -r teamspeak3-server_linux_amd64\/* \/mnt\/server\n\necho \"machine_id=\ndefault_voice_port=${SERVER_PORT}\nvoice_ip=0.0.0.0\nlicensepath=\nfiletransfer_port=30033\nfiletransfer_ip=\nquery_port=${SERVER_PORT}\nquery_ip=0.0.0.0\nquery_ip_whitelist=query_ip_whitelist.txt\nquery_ip_blacklist=query_ip_blacklist.txt\ndbplugin=ts3db_sqlite3\ndbpluginparameter=\ndbsqlpath=sql\/\ndbsqlcreatepath=create_sqlite\/\ndbconnections=10\nlogpath=logs\nlogquerycommands=0\ndbclientkeepdays=30\nlogappend=0\nquery_skipbruteforcecheck=0\" > \/mnt\/server\/ts3server.ini",
|
||||
"script": "#!\/bin\/ash\n# TS3 Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add tar curl\n\ncd \/tmp\n\ncurl -sSLO http:\/\/dl.4players.de\/ts\/releases\/${TS_VERSION}\/teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2\n\ntar -xjvf teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2\ncp -r teamspeak3-server_linux_amd64\/* \/mnt\/server\n\necho \"machine_id=\ndefault_voice_port=${SERVER_PORT}\nvoice_ip=0.0.0.0\nlicensepath=\nfiletransfer_port=30033\nfiletransfer_ip=\nquery_port=${SERVER_PORT}\nquery_ip=0.0.0.0\nquery_ip_whitelist=query_ip_whitelist.txt\nquery_ip_blacklist=query_ip_blacklist.txt\ndbplugin=ts3db_sqlite3\ndbpluginparameter=\ndbsqlpath=sql\/\ndbsqlcreatepath=create_sqlite\/\ndbconnections=10\nlogpath=logs\nlogquerycommands=0\ndbclientkeepdays=30\nlogappend=0\nquery_skipbruteforcecheck=0\" > \/mnt\/server\/ts3server.ini\n\ntouch \/mnt\/server\/.ts3server_license_accepted",
|
||||
"container": "alpine:3.4",
|
||||
"entrypoint": "ash"
|
||||
}
|
||||
|
@ -27,10 +27,10 @@
|
|||
"name": "Server Version",
|
||||
"description": "The version of Teamspeak 3 to use when running the server.",
|
||||
"env_variable": "TS_VERSION",
|
||||
"default_value": "3.0.13.8",
|
||||
"default_value": "3.1.1",
|
||||
"user_viewable": 1,
|
||||
"user_editable": 1,
|
||||
"rules": "required|regex:\/^([0-9_\\.-]{5,10})$\/"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,6 +145,18 @@ p.small {
|
|||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
.table .min-size {
|
||||
width:1px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@media (max-width:767px) {
|
||||
.box-header > .box-tools {
|
||||
position: relative !important;
|
||||
padding: 0px 10px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.middle, .align-middle {
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -284,7 +284,7 @@ class ActionsClass {
|
|||
swal({
|
||||
type: 'warning',
|
||||
title: '',
|
||||
text: 'Are you sure you want to delete <code>' + delName + '</code>? There is <strong>no</strong> reversing this action.',
|
||||
text: 'Are you sure you want to delete <code>' + delName + '</code>?',
|
||||
html: true,
|
||||
showCancelButton: true,
|
||||
showConfirmButton: true,
|
||||
|
@ -380,16 +380,22 @@ class ActionsClass {
|
|||
if (selectedItems.length != 0)
|
||||
{
|
||||
let formattedItems = "";
|
||||
let i = 0;
|
||||
$.each(selectedItems, function(key, value) {
|
||||
formattedItems += ("<code>" + value + "</code>, ");
|
||||
})
|
||||
formattedItems += ("<code>" + value + "</code>, ");
|
||||
i++;
|
||||
return i < 5;
|
||||
});
|
||||
|
||||
formattedItems = formattedItems.slice(0, -2);
|
||||
if (selectedItems.length > 5) {
|
||||
formattedItems += ', and ' + (selectedItems.length - 5) + ' other(s)';
|
||||
}
|
||||
|
||||
swal({
|
||||
type: 'warning',
|
||||
title: '',
|
||||
text: 'Are you sure you want to delete:' + formattedItems + '? There is <strong>no</strong> reversing this action.',
|
||||
text: 'Are you sure you want to delete the following files: ' + formattedItems + '?',
|
||||
html: true,
|
||||
showCancelButton: true,
|
||||
showConfirmButton: true,
|
||||
|
|
|
@ -80,8 +80,11 @@
|
|||
}
|
||||
}
|
||||
}).fail(function (jqXHR) {
|
||||
console.error(jqXHR);
|
||||
element.find('[data-action="status"]').html('<span class="label label-default">Error</span>');
|
||||
if (jqXHR.status === 504) {
|
||||
element.find('[data-action="status"]').html('<span class="label label-default">Gateway Timeout</span>');
|
||||
} else {
|
||||
element.find('[data-action="status"]').html('<span class="label label-default">Error</span>');
|
||||
}
|
||||
});
|
||||
}).promise().done(function () {
|
||||
setTimeout(updateServerStatus, 10000);
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'key' => [
|
||||
'warning' => 'It appears you have already configured an application encryption key. Continuing with this process with overwrite that key and cause data corruption for any existing encrypted data. DO NOT CONTINUE UNLESS YOU KNOW WHAT YOU ARE DOING.',
|
||||
'confirm' => 'I understand the consequences of performing this command and accept all responsibility for the loss of encrypted data.',
|
||||
'final_confirm' => 'Are you sure you wish to continue? Changing the application encryption key WILL CAUSE DATA LOSS.',
|
||||
],
|
||||
'location' => [
|
||||
'no_location_found' => 'Could not locate a record matching the provided short code.',
|
||||
'ask_short' => 'Location Short Code',
|
||||
|
|
|
@ -8,9 +8,10 @@ return [
|
|||
],
|
||||
'allocations' => [
|
||||
'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.',
|
||||
'too_many_ports' => 'Adding more than 1000 ports at a single time is not supported. Please use a smaller range.',
|
||||
'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.',
|
||||
'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.',
|
||||
'cidr_out_of_range' => 'CIDR notation only allows masks between /25 and /32.',
|
||||
'port_out_of_range' => 'Ports in an allocation must be greater than 1024 and less than or equal to 65535.',
|
||||
],
|
||||
'nest' => [
|
||||
'delete_has_servers' => 'A Nest with active servers attached to it cannot be deleted from the Panel.',
|
||||
|
|
|
@ -27,5 +27,6 @@ return [
|
|||
'edit_file' => 'Edit File',
|
||||
'admin_header' => 'ADMINISTRATIVE',
|
||||
'admin' => 'Server Configuration',
|
||||
'server_name' => 'Server Name',
|
||||
],
|
||||
];
|
||||
|
|
|
@ -273,8 +273,8 @@ return [
|
|||
'last_modified' => 'Last Modified',
|
||||
'add_new' => 'Add New File',
|
||||
'add_folder' => 'Add New Folder',
|
||||
'mass_actions' => 'Mass actions',
|
||||
'delete' => 'Delete',
|
||||
'mass_actions' => 'Mass Actions',
|
||||
'delete' => 'Delete Files',
|
||||
'edit' => [
|
||||
'header' => 'Edit File',
|
||||
'header_sub' => 'Make modifications to a file from the web.',
|
||||
|
@ -289,6 +289,11 @@ return [
|
|||
],
|
||||
],
|
||||
'config' => [
|
||||
'name' => [
|
||||
'header' => 'Server Name',
|
||||
'header_sub' => 'Change this server\'s name.',
|
||||
'details' => 'The server name is only a reference to this server on the panel, and will not affect any server specific configurations that may display to users in games.',
|
||||
],
|
||||
'startup' => [
|
||||
'header' => 'Start Configuration',
|
||||
'header_sub' => 'Control server startup arguments.',
|
||||
|
|
|
@ -134,26 +134,11 @@
|
|||
{!! Theme::js('vendor/lodash/lodash.js') !!}
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('#pNestId').select2({placeholder: 'Select a Nest'}).change();
|
||||
$('#pEggId').select2({placeholder: 'Select a Nest Egg'});
|
||||
$('#pPackId').select2({placeholder: 'Select a Service Pack'});
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
$('#pNestId').on('change', function (event) {
|
||||
$('#pEggId').html('').select2({
|
||||
data: $.map(_.get(Pterodactyl.nests, $(this).val() + '.eggs', []), function (item) {
|
||||
return {
|
||||
id: item.id,
|
||||
text: item.name,
|
||||
};
|
||||
}),
|
||||
}).val(Pterodactyl.server.egg_id).change();
|
||||
});
|
||||
|
||||
$('#pEggId').on('change', function (event) {
|
||||
var parentChain = _.get(Pterodactyl.nests, $('#pNestId').val(), null);
|
||||
var objectChain = _.get(parentChain, 'eggs.' + $(this).val(), null);
|
||||
$('#pEggId').select2({placeholder: 'Select a Nest Egg'}).on('change', function () {
|
||||
var selectedEgg = _.isNull($(this).val()) ? $(this).find('option').first().val() : $(this).val();
|
||||
var parentChain = _.get(Pterodactyl.nests, $("#pNestId").val());
|
||||
var objectChain = _.get(parentChain, 'eggs.' + selectedEgg);
|
||||
|
||||
$('#setDefaultImage').html(_.get(objectChain, 'docker_image', 'undefined'));
|
||||
$('#pDockerImage').val(_.get(objectChain, 'docker_image', 'undefined'));
|
||||
|
@ -168,7 +153,7 @@
|
|||
}
|
||||
|
||||
$('#pPackId').html('').select2({
|
||||
data: [{ id: '0', text: 'No Service Pack' }].concat(
|
||||
data: [{id: '0', text: 'No Service Pack'}].concat(
|
||||
$.map(_.get(objectChain, 'packs', []), function (item, i) {
|
||||
return {
|
||||
id: item.id,
|
||||
|
@ -202,9 +187,26 @@
|
|||
</div> \
|
||||
</div> \
|
||||
</div>';
|
||||
$('#appendVariablesTo').append(dataAppend);
|
||||
$('#appendVariablesTo').find('#egg_variable_' + item.env_variable).val(setValue);
|
||||
$('#appendVariablesTo').append(dataAppend).find('#egg_variable_' + item.env_variable).val(setValue);
|
||||
});
|
||||
});
|
||||
|
||||
$('#pNestId').select2({placeholder: 'Select a Nest'}).on('change', function () {
|
||||
$('#pEggId').html('').select2({
|
||||
data: $.map(_.get(Pterodactyl.nests, $(this).val() + '.eggs', []), function (item) {
|
||||
return {
|
||||
id: item.id,
|
||||
text: item.name,
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
||||
if (_.isObject(_.get(Pterodactyl.nests, $(this).val() + '.eggs.' + Pterodactyl.server.egg_id))) {
|
||||
$('#pEggId').val(Pterodactyl.server.egg_id);
|
||||
}
|
||||
|
||||
$('#pEggId').change();
|
||||
}).change();
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
|
|
@ -34,6 +34,12 @@
|
|||
<p class="text-muted small">If enabled, login forms and password reset forms will do a silent captcha check and display a visible captcha if needed.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-4">
|
||||
<label class="control-label">Site Key</label>
|
||||
<div>
|
||||
<input type="text" required class="form-control" name="recaptcha:website_key" value="{{ old('recaptcha:website_key', config('recaptcha.website_key')) }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-4">
|
||||
<label class="control-label">Secret Key</label>
|
||||
<div>
|
||||
|
@ -41,12 +47,6 @@
|
|||
<p class="text-muted small">Used for communication between your site and Google. Be sure to keep it a secret.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-4">
|
||||
<label class="control-label">Website Key</label>
|
||||
<div>
|
||||
<input type="text" required class="form-control" name="recaptcha:website_key" value="{{ old('recaptcha:website_key', config('recaptcha.website_key')) }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@if($showRecaptchaWarning)
|
||||
<div class="row">
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<link rel="mask-icon" href="/favicons/safari-pinned-tab.svg" color="#bc6e3c">
|
||||
<link rel="shortcut icon" href="/favicons/favicon.ico">
|
||||
<meta name="msapplication-config" content="/favicons/browserconfig.xml">
|
||||
<meta name="theme-color" content="#367fa9">
|
||||
<meta name="theme-color" content="#0e4688">
|
||||
|
||||
@include('layouts.scripts')
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<link rel="mask-icon" href="/favicons/safari-pinned-tab.svg" color="#bc6e3c">
|
||||
<link rel="shortcut icon" href="/favicons/favicon.ico">
|
||||
<meta name="msapplication-config" content="/favicons/browserconfig.xml">
|
||||
<meta name="theme-color" content="#367fa9">
|
||||
<meta name="theme-color" content="#0e4688">
|
||||
|
||||
@section('scripts')
|
||||
{!! Theme::css('vendor/bootstrap/bootstrap.min.css?t={cache-version}') !!}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<link rel="mask-icon" href="/favicons/safari-pinned-tab.svg" color="#bc6e3c">
|
||||
<link rel="shortcut icon" href="/favicons/favicon.ico">
|
||||
<meta name="msapplication-config" content="/favicons/browserconfig.xml">
|
||||
<meta name="theme-color" content="#367fa9">
|
||||
<meta name="theme-color" content="#0e4688">
|
||||
|
||||
@section('scripts')
|
||||
{!! Theme::css('vendor/bootstrap/bootstrap.min.css?t={cache-version}') !!}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<link rel="mask-icon" href="/favicons/safari-pinned-tab.svg" color="#bc6e3c">
|
||||
<link rel="shortcut icon" href="/favicons/favicon.ico">
|
||||
<meta name="msapplication-config" content="/favicons/browserconfig.xml">
|
||||
<meta name="theme-color" content="#367fa9">
|
||||
<meta name="theme-color" content="#0e4688">
|
||||
|
||||
@include('layouts.scripts')
|
||||
|
||||
|
@ -170,7 +170,7 @@
|
|||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
@if(Gate::allows('view-startup', $server) || Gate::allows('access-sftp', $server) || Gate::allows('view-allocation', $server))
|
||||
@if(Gate::allows('view-startup', $server) || Gate::allows('access-sftp', $server) || Gate::allows('view-allocations', $server))
|
||||
<li class="treeview
|
||||
@if(starts_with(Route::currentRouteName(), 'server.settings'))
|
||||
active
|
||||
|
@ -184,7 +184,10 @@
|
|||
</span>
|
||||
</a>
|
||||
<ul class="treeview-menu">
|
||||
@can('view-allocation', $server)
|
||||
@can('view-name', $server)
|
||||
<li class="{{ Route::currentRouteName() !== 'server.settings.name' ?: 'active' }}"><a href="{{ route('server.settings.name', $server->uuidShort) }}"><i class="fa fa-angle-right"></i> @lang('navigation.server.server_name')</a></li>
|
||||
@endcan
|
||||
@can('view-allocations', $server)
|
||||
<li class="{{ Route::currentRouteName() !== 'server.settings.allocation' ?: 'active' }}"><a href="{{ route('server.settings.allocation', $server->uuidShort) }}"><i class="fa fa-angle-right"></i> @lang('navigation.server.port_allocations')</a></li>
|
||||
@endcan
|
||||
@can('access-sftp', $server)
|
||||
|
|
|
@ -6,45 +6,45 @@
|
|||
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">/home/container{{ $directory['header'] }}</h3>
|
||||
<div class="box-tools pull-right">
|
||||
<div class="btn-group">
|
||||
<button type="button" id="mass_actions" class="btn btn-sm btn-info dropdown-toggle disabled" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
@lang('server.files.mass_actions') <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-massactions">
|
||||
<li><a href="#" id="selective-deletion" data-action="selective-deletion">@lang('server.files.delete') <i class="fa fa-fw fa-trash-o"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-success btn-icon" data-action="add-folder">
|
||||
<i class="fa fa-fw fa-folder-open-o"></i>
|
||||
</button>
|
||||
<div class="box-tools">
|
||||
<a href="/server/{{ $server->uuidShort }}/files/add/@if($directory['header'] !== '')?dir={{ $directory['header'] }}@endif">
|
||||
<button class="btn btn-success btn-sm btn-icon">
|
||||
<i class="fa fa-fw fa-file-text-o"></i>
|
||||
New File <i class="fa fa-fw fa-file-text-o"></i>
|
||||
</button>
|
||||
</a>
|
||||
<button class="btn btn-sm btn-success btn-icon" data-action="add-folder">
|
||||
New Folder <i class="fa fa-fw fa-folder-open-o"></i>
|
||||
</button>
|
||||
<label class="btn btn-primary btn-sm btn-icon">
|
||||
<i class="fa fa-fw fa-upload"></i><input type="file" id="files_touch_target" class="hidden">
|
||||
Upload <i class="fa fa-fw fa-upload"></i><input type="file" id="files_touch_target" class="hidden">
|
||||
</label>
|
||||
<div class="btn-group hidden-xs">
|
||||
<button type="button" id="mass_actions" class="btn btn-sm btn-default dropdown-toggle disabled" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
@lang('server.files.mass_actions') <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-massactions">
|
||||
<li><a href="#" id="selective-deletion" data-action="selective-deletion">@lang('server.files.delete') <i class="fa fa-fw fa-trash-o"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body table-responsive no-padding">
|
||||
<table class="table table-hover" id="file_listing" data-current-dir="{{ $directory['header'] }}">
|
||||
<table class="table table-hover" id="file_listing" data-current-dir="{{ rtrim($directory['header'], '/') . '/' }}">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:4%;" class="middle">
|
||||
<input type="checkbox" class="select-all-files" data-action="selectAll"><i class="fa fa-refresh muted muted-hover use-pointer" data-action="reload-files" style="font-size:14px;"></i>
|
||||
<th class="middle min-size">
|
||||
<input type="checkbox" class="select-all-files hidden-xs" data-action="selectAll"><i class="fa fa-refresh muted muted-hover use-pointer" data-action="reload-files" style="font-size:14px;"></i>
|
||||
</th>
|
||||
<th style="width:55%">@lang('server.files.file_name')</th>
|
||||
<th style="width:15%" class="hidden-xs">@lang('server.files.size')</th>
|
||||
<th style="width:20%" class="hidden-xs">@lang('server.files.last_modified')</th>
|
||||
<th style="width:6%"></th>
|
||||
<th>@lang('server.files.file_name')</th>
|
||||
<th class="hidden-xs">@lang('server.files.size')</th>
|
||||
<th class="hidden-xs">@lang('server.files.last_modified')</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="append_files_to">
|
||||
@if (isset($directory['first']) && $directory['first'] === true)
|
||||
<tr data-type="disabled">
|
||||
<td><i class="fa fa-folder" style="margin-left: 0.859px;"></i></td>
|
||||
<td class="middle min-size"><i class="fa fa-folder" style="margin-left: 0.859px;"></i></td>
|
||||
<td><a href="/server/{{ $server->uuidShort }}/files" data-action="directory-view">←</a></a></td>
|
||||
<td class="hidden-xs"></td>
|
||||
<td class="hidden-xs"></td>
|
||||
|
@ -53,7 +53,7 @@
|
|||
@endif
|
||||
@if (isset($directory['show']) && $directory['show'] === true)
|
||||
<tr data-type="disabled">
|
||||
<td><i class="fa fa-folder" style="margin-left: 0.859px;"></i></td>
|
||||
<td class="middle min-size"><i class="fa fa-folder" style="margin-left: 0.859px;"></i></td>
|
||||
<td data-name="{{ rawurlencode($directory['link']) }}">
|
||||
<a href="/server/{{ $server->uuidShort }}/files" data-action="directory-view">← {{ $directory['link_show'] }}</a>
|
||||
</td>
|
||||
|
@ -64,7 +64,9 @@
|
|||
@endif
|
||||
@foreach ($folders as $folder)
|
||||
<tr data-type="folder">
|
||||
<td data-identifier="type" class="middle"><input type="checkbox" class="select-folder" data-action="addSelection"><i class="fa fa-folder" style="margin-left: 0.859px;"></i></td>
|
||||
<td class="middle min-size" data-identifier="type">
|
||||
<input type="checkbox" class="select-folder hidden-xs" data-action="addSelection"><i class="fa fa-folder" style="margin-left: 0.859px;"></i>
|
||||
</td>
|
||||
<td data-identifier="name" data-name="{{ rawurlencode($folder['entry']) }}" data-path="@if($folder['directory'] !== ''){{ rawurlencode($folder['directory']) }}@endif/">
|
||||
<a href="/server/{{ $server->uuidShort }}/files" data-action="directory-view">{{ $folder['entry'] }}</a>
|
||||
</td>
|
||||
|
@ -79,12 +81,14 @@
|
|||
{{ $carbon->diffForHumans() }}
|
||||
@endif
|
||||
</td>
|
||||
<td><button class="btn btn-xxs btn-default disable-menu-hide" data-action="toggleMenu" style="padding:2px 6px 0px;"><i class="fa fa-ellipsis-h disable-menu-hide"></i></td>
|
||||
<td class="min-size">
|
||||
<button class="btn btn-xxs btn-default disable-menu-hide" data-action="toggleMenu" style="padding:2px 6px 0px;"><i class="fa fa-ellipsis-h disable-menu-hide"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@foreach ($files as $file)
|
||||
<tr data-type="file" data-mime="{{ $file['mime'] }}">
|
||||
<td data-identifier="type" class="middle"><input type="checkbox" class="select-file" data-action="addSelection">
|
||||
<td class="middle min-size" data-identifier="type"><input type="checkbox" class="select-file hidden-xs" data-action="addSelection">
|
||||
{{-- oh boy --}}
|
||||
@if(in_array($file['mime'], [
|
||||
'application/x-7z-compressed',
|
||||
|
@ -156,7 +160,9 @@
|
|||
{{ $carbon->diffForHumans() }}
|
||||
@endif
|
||||
</td>
|
||||
<td><button class="btn btn-xxs btn-default disable-menu-hide" data-action="toggleMenu" style="padding:2px 6px 0px;"><i class="fa fa-ellipsis-h disable-menu-hide"></i></td>
|
||||
<td class="min-size">
|
||||
<button class="btn btn-xxs btn-default disable-menu-hide" data-action="toggleMenu" style="padding:2px 6px 0px;"><i class="fa fa-ellipsis-h disable-menu-hide"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
|
|
50
resources/themes/pterodactyl/server/settings/name.blade.php
Normal file
50
resources/themes/pterodactyl/server/settings/name.blade.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
{{-- 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 --}}
|
||||
@extends('layouts.master')
|
||||
|
||||
@section('title')
|
||||
@lang('server.config.name.header')
|
||||
@endsection
|
||||
|
||||
@section('content-header')
|
||||
<h1>@lang('server.config.name.header')<small>@lang('server.config.name.header_sub')</small></h1>
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="{{ route('index') }}">@lang('strings.home')</a></li>
|
||||
<li><a href="{{ route('server.index', $server->uuidShort) }}">{{ $server->name }}</a></li>
|
||||
<li>@lang('navigation.server.configuration')</li>
|
||||
<li class="active">@lang('navigation.server.server_name')</li>
|
||||
</ol>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<form action="{{ route('server.settings.name', $server->uuidShort) }}" method="POST">
|
||||
<div class="box">
|
||||
<div class="box-body">
|
||||
<div class="form-group no-margin-bottom">
|
||||
<label class="control-label" for="pServerName">@lang('server.config.name.header')</label>
|
||||
<div>
|
||||
<input type="text" name="name" id="pServerName" class="form-control" value="{{ $server->name }}" />
|
||||
<p class="small text-muted no-margin-bottom">@lang('server.config.name.details')</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
{{ method_field('PATCH') }}
|
||||
{{ csrf_field() }}
|
||||
<input type="submit" class="btn btn-sm btn-primary pull-right" value="@lang('strings.submit')" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('footer-scripts')
|
||||
@parent
|
||||
{!! Theme::js('js/frontend/server.socket.js') !!}
|
||||
@endsection
|
|
@ -19,11 +19,12 @@ Route::get('/console', 'ConsoleController@console')->name('server.console');
|
|||
*/
|
||||
Route::group(['prefix' => 'settings'], function () {
|
||||
Route::get('/allocation', 'Settings\AllocationController@index')->name('server.settings.allocation');
|
||||
Route::patch('/allocation', 'Settings\AllocationController@update');
|
||||
|
||||
Route::get('/name', 'Settings\NameController@index')->name('server.settings.name');
|
||||
Route::get('/sftp', 'Settings\SftpController@index')->name('server.settings.sftp');
|
||||
|
||||
Route::get('/startup', 'Settings\StartupController@index')->name('server.settings.startup');
|
||||
|
||||
Route::patch('/allocation', 'Settings\AllocationController@update');
|
||||
Route::patch('/name', 'Settings\NameController@update');
|
||||
Route::patch('/startup', 'Settings\StartupController@update');
|
||||
});
|
||||
|
||||
|
|
|
@ -37,8 +37,8 @@ class SetSessionDriverTest extends MiddlewareTestCase
|
|||
*/
|
||||
public function testProductionEnvironment()
|
||||
{
|
||||
$this->appMock->shouldReceive('environment')->withNoArgs()->once()->andReturn('production');
|
||||
$this->config->shouldReceive('set')->with('session.driver', 'array')->once()->andReturnNull();
|
||||
$this->config->shouldReceive('get')->once()->with('app.debug')->andReturn(false);
|
||||
$this->config->shouldReceive('set')->once()->with('session.driver', 'array')->andReturnNull();
|
||||
|
||||
$this->getMiddleware()->handle($this->request, $this->getClosureAssertions());
|
||||
}
|
||||
|
@ -48,11 +48,10 @@ class SetSessionDriverTest extends MiddlewareTestCase
|
|||
*/
|
||||
public function testLocalEnvironment()
|
||||
{
|
||||
$this->appMock->shouldReceive('environment')->withNoArgs()->once()->andReturn('local');
|
||||
$this->appMock->shouldReceive('make')->with(LaravelDebugbar::class)->once()->andReturnSelf();
|
||||
$this->appMock->shouldReceive('disable')->withNoArgs()->once()->andReturnNull();
|
||||
|
||||
$this->config->shouldReceive('set')->with('session.driver', 'array')->once()->andReturnNull();
|
||||
$this->config->shouldReceive('get')->once()->with('app.debug')->andReturn(true);
|
||||
$this->appMock->shouldReceive('make')->once()->with(LaravelDebugbar::class)->andReturnSelf();
|
||||
$this->appMock->shouldReceive('disable')->once()->withNoArgs()->andReturnNull();
|
||||
$this->config->shouldReceive('set')->once()->with('session.driver', 'array')->andReturnNull();
|
||||
|
||||
$this->getMiddleware()->handle($this->request, $this->getClosureAssertions());
|
||||
}
|
||||
|
|
|
@ -1,30 +1,19 @@
|
|||
<?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\Allocations;
|
||||
|
||||
use Exception;
|
||||
use Mockery as m;
|
||||
use Tests\TestCase;
|
||||
use phpmock\phpunit\PHPMock;
|
||||
use Pterodactyl\Models\Node;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Services\Allocations\AssignmentService;
|
||||
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
|
||||
|
||||
class AssignmentServiceTest extends TestCase
|
||||
{
|
||||
use PHPMock;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Database\ConnectionInterface
|
||||
* @var \Illuminate\Database\ConnectionInterface|\Mockery\Mock
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
|
@ -34,15 +23,10 @@ class AssignmentServiceTest extends TestCase
|
|||
protected $node;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface
|
||||
* @var \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface|\Mockery\Mock
|
||||
*/
|
||||
protected $repository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Allocations\AssignmentService
|
||||
*/
|
||||
protected $service;
|
||||
|
||||
/**
|
||||
* Setup tests.
|
||||
*/
|
||||
|
@ -50,19 +34,9 @@ class AssignmentServiceTest extends TestCase
|
|||
{
|
||||
parent::setUp();
|
||||
|
||||
// Due to a bug in PHP, this is necessary since we only have a single test
|
||||
// that relies on this mock. If this does not exist the test will fail to register
|
||||
// correctly.
|
||||
//
|
||||
// This can also be avoided if tests were run in isolated processes, or if that test
|
||||
// came first, but neither of those are good solutions, so this is the next best option.
|
||||
PHPMock::defineFunctionMock('\\Pterodactyl\\Services\\Allocations', 'gethostbyname');
|
||||
|
||||
$this->node = factory(Node::class)->make();
|
||||
$this->connection = m::mock(ConnectionInterface::class);
|
||||
$this->repository = m::mock(AllocationRepositoryInterface::class);
|
||||
|
||||
$this->service = new AssignmentService($this->repository, $this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,22 +46,22 @@ class AssignmentServiceTest extends TestCase
|
|||
{
|
||||
$data = [
|
||||
'allocation_ip' => '192.168.1.1',
|
||||
'allocation_ports' => ['1024'],
|
||||
'allocation_ports' => ['2222'],
|
||||
];
|
||||
|
||||
$this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull();
|
||||
$this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull();
|
||||
$this->repository->shouldReceive('insertIgnore')->with([
|
||||
[
|
||||
'node_id' => $this->node->id,
|
||||
'ip' => '192.168.1.1',
|
||||
'port' => 1024,
|
||||
'port' => 2222,
|
||||
'ip_alias' => null,
|
||||
'server_id' => null,
|
||||
],
|
||||
])->once()->andReturn(true);
|
||||
$this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull();
|
||||
$this->connection->shouldReceive('commit')->once()->withNoArgs()->andReturnNull();
|
||||
|
||||
$this->service->handle($this->node->id, $data);
|
||||
$this->getService()->handle($this->node, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,18 +71,11 @@ class AssignmentServiceTest extends TestCase
|
|||
{
|
||||
$data = [
|
||||
'allocation_ip' => '192.168.1.1',
|
||||
'allocation_ports' => ['1024-1026'],
|
||||
'allocation_ports' => ['1025-1027'],
|
||||
];
|
||||
|
||||
$this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull();
|
||||
$this->repository->shouldReceive('insertIgnore')->with([
|
||||
[
|
||||
'node_id' => $this->node->id,
|
||||
'ip' => '192.168.1.1',
|
||||
'port' => 1024,
|
||||
'ip_alias' => null,
|
||||
'server_id' => null,
|
||||
],
|
||||
$this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull();
|
||||
$this->repository->shouldReceive('insertIgnore')->once()->with([
|
||||
[
|
||||
'node_id' => $this->node->id,
|
||||
'ip' => '192.168.1.1',
|
||||
|
@ -123,10 +90,17 @@ class AssignmentServiceTest extends TestCase
|
|||
'ip_alias' => null,
|
||||
'server_id' => null,
|
||||
],
|
||||
])->once()->andReturn(true);
|
||||
$this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull();
|
||||
[
|
||||
'node_id' => $this->node->id,
|
||||
'ip' => '192.168.1.1',
|
||||
'port' => 1027,
|
||||
'ip_alias' => null,
|
||||
'server_id' => null,
|
||||
],
|
||||
])->andReturn(true);
|
||||
$this->connection->shouldReceive('commit')->once()->withNoArgs()->andReturnNull();
|
||||
|
||||
$this->service->handle($this->node->id, $data);
|
||||
$this->getService()->handle($this->node, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -136,23 +110,23 @@ class AssignmentServiceTest extends TestCase
|
|||
{
|
||||
$data = [
|
||||
'allocation_ip' => '192.168.1.1',
|
||||
'allocation_ports' => ['1024'],
|
||||
'allocation_ports' => ['2222'],
|
||||
'allocation_alias' => 'my.alias.net',
|
||||
];
|
||||
|
||||
$this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull();
|
||||
$this->repository->shouldReceive('insertIgnore')->with([
|
||||
$this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull();
|
||||
$this->repository->shouldReceive('insertIgnore')->once()->with([
|
||||
[
|
||||
'node_id' => $this->node->id,
|
||||
'ip' => '192.168.1.1',
|
||||
'port' => 1024,
|
||||
'port' => 2222,
|
||||
'ip_alias' => 'my.alias.net',
|
||||
'server_id' => null,
|
||||
],
|
||||
])->once()->andReturn(true);
|
||||
$this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull();
|
||||
])->andReturn(true);
|
||||
$this->connection->shouldReceive('commit')->once()->withNoArgs()->andReturnNull();
|
||||
|
||||
$this->service->handle($this->node->id, $data);
|
||||
$this->getService()->handle($this->node, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,26 +135,23 @@ class AssignmentServiceTest extends TestCase
|
|||
public function testDomainNamePassedInPlaceOfIPAddress()
|
||||
{
|
||||
$data = [
|
||||
'allocation_ip' => 'test-domain.com',
|
||||
'allocation_ports' => ['1024'],
|
||||
'allocation_ip' => 'unit-test-static.pterodactyl.io',
|
||||
'allocation_ports' => ['2222'],
|
||||
];
|
||||
|
||||
$this->getFunctionMock('\\Pterodactyl\\Services\\Allocations', 'gethostbyname')
|
||||
->expects($this->once())->willReturn('192.168.1.1');
|
||||
|
||||
$this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull();
|
||||
$this->repository->shouldReceive('insertIgnore')->with([
|
||||
$this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull();
|
||||
$this->repository->shouldReceive('insertIgnore')->once()->with([
|
||||
[
|
||||
'node_id' => $this->node->id,
|
||||
'ip' => '192.168.1.1',
|
||||
'port' => 1024,
|
||||
'ip' => '127.0.0.1',
|
||||
'port' => 2222,
|
||||
'ip_alias' => null,
|
||||
'server_id' => null,
|
||||
],
|
||||
])->once()->andReturn(true);
|
||||
$this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull();
|
||||
])->andReturn(true);
|
||||
$this->connection->shouldReceive('commit')->once()->withNoArgs()->andReturnNull();
|
||||
|
||||
$this->service->handle($this->node->id, $data);
|
||||
$this->getService()->handle($this->node, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -190,54 +161,55 @@ class AssignmentServiceTest extends TestCase
|
|||
{
|
||||
$data = [
|
||||
'allocation_ip' => '192.168.1.100/31',
|
||||
'allocation_ports' => ['1024'],
|
||||
'allocation_ports' => ['2222'],
|
||||
];
|
||||
|
||||
$this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull();
|
||||
$this->repository->shouldReceive('insertIgnore')->with([
|
||||
$this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull();
|
||||
$this->repository->shouldReceive('insertIgnore')->once()->with([
|
||||
[
|
||||
'node_id' => $this->node->id,
|
||||
'ip' => '192.168.1.100',
|
||||
'port' => 1024,
|
||||
'port' => 2222,
|
||||
'ip_alias' => null,
|
||||
'server_id' => null,
|
||||
],
|
||||
])->once()->andReturn(true);
|
||||
])->andReturn(true);
|
||||
|
||||
$this->repository->shouldReceive('insertIgnore')->with([
|
||||
$this->repository->shouldReceive('insertIgnore')->once()->with([
|
||||
[
|
||||
'node_id' => $this->node->id,
|
||||
'ip' => '192.168.1.101',
|
||||
'port' => 1024,
|
||||
'port' => 2222,
|
||||
'ip_alias' => null,
|
||||
'server_id' => null,
|
||||
],
|
||||
])->once()->andReturn(true);
|
||||
$this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull();
|
||||
])->andReturn(true);
|
||||
$this->connection->shouldReceive('commit')->once()->withNoArgs()->andReturnNull();
|
||||
|
||||
$this->service->handle($this->node->id, $data);
|
||||
$this->getService()->handle($this->node, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a CIDR IP address with a range works properly.
|
||||
*
|
||||
* @expectedException \Pterodactyl\Exceptions\Service\Allocation\CidrOutOfRangeException
|
||||
* @expectedExceptionMessage CIDR notation only allows masks between /25 and /32.
|
||||
*/
|
||||
public function testCIDRNotatedIPAddressOutsideRangeLimit()
|
||||
{
|
||||
$data = [
|
||||
'allocation_ip' => '192.168.1.100/20',
|
||||
'allocation_ports' => ['1024'],
|
||||
'allocation_ports' => ['2222'],
|
||||
];
|
||||
|
||||
try {
|
||||
$this->service->handle($this->node->id, $data);
|
||||
} catch (Exception $exception) {
|
||||
$this->assertInstanceOf(DisplayException::class, $exception);
|
||||
$this->assertEquals(trans('exceptions.allocations.cidr_out_of_range'), $exception->getMessage());
|
||||
}
|
||||
$this->getService()->handle($this->node, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that an exception is thrown if there are too many ports.
|
||||
*
|
||||
* @expectedException \Pterodactyl\Exceptions\Service\Allocation\TooManyPortsInRangeException
|
||||
* @expectedExceptionMessage Adding more than 1000 ports in a single range at once is not supported.
|
||||
*/
|
||||
public function testAllocationWithPortsExceedingLimit()
|
||||
{
|
||||
|
@ -246,22 +218,16 @@ class AssignmentServiceTest extends TestCase
|
|||
'allocation_ports' => ['5000-7000'],
|
||||
];
|
||||
|
||||
$this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull();
|
||||
$this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull();
|
||||
|
||||
try {
|
||||
$this->service->handle($this->node->id, $data);
|
||||
} catch (Exception $exception) {
|
||||
if (! $exception instanceof DisplayException) {
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
$this->assertInstanceOf(DisplayException::class, $exception);
|
||||
$this->assertEquals(trans('exceptions.allocations.too_many_ports'), $exception->getMessage());
|
||||
}
|
||||
$this->getService()->handle($this->node, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that an exception is thrown if an invalid port is provided.
|
||||
*
|
||||
* @expectedException \Pterodactyl\Exceptions\Service\Allocation\InvalidPortMappingException
|
||||
* @expectedExceptionMessage The mapping provided for test123 was invalid and could not be processed.
|
||||
*/
|
||||
public function testInvalidPortProvided()
|
||||
{
|
||||
|
@ -270,42 +236,52 @@ class AssignmentServiceTest extends TestCase
|
|||
'allocation_ports' => ['test123'],
|
||||
];
|
||||
|
||||
$this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull();
|
||||
|
||||
try {
|
||||
$this->service->handle($this->node->id, $data);
|
||||
} catch (Exception $exception) {
|
||||
if (! $exception instanceof DisplayException) {
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
$this->assertInstanceOf(DisplayException::class, $exception);
|
||||
$this->assertEquals(trans('exceptions.allocations.invalid_mapping', ['port' => 'test123']), $exception->getMessage());
|
||||
}
|
||||
$this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull();
|
||||
$this->getService()->handle($this->node, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a model can be passed in place of an ID.
|
||||
* Test that ports outside of defined limits throw an error.
|
||||
*
|
||||
* @param array $ports
|
||||
*
|
||||
* @dataProvider invalidPortsDataProvider
|
||||
* @expectedException \Pterodactyl\Exceptions\Service\Allocation\PortOutOfRangeException
|
||||
* @expectedExceptionMessage Ports in an allocation must be greater than 1024 and less than or equal to 65535.
|
||||
*/
|
||||
public function testModelCanBePassedInPlaceOfNodeModel()
|
||||
public function testPortRangeOutsideOfRangeLimits(array $ports)
|
||||
{
|
||||
$data = [
|
||||
'allocation_ip' => '192.168.1.1',
|
||||
'allocation_ports' => ['1024'],
|
||||
$data = ['allocation_ip' => '192.168.1.1', 'allocation_ports' => $ports];
|
||||
|
||||
$this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull();
|
||||
$this->getService()->handle($this->node, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide ports and ranges of ports that exceed the viable port limits for the software.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function invalidPortsDataProvider(): array
|
||||
{
|
||||
return [
|
||||
[['65536']],
|
||||
[['1024']],
|
||||
[['1000']],
|
||||
[['0']],
|
||||
[['65530-65540']],
|
||||
[['65540-65560']],
|
||||
[[PHP_INT_MAX]],
|
||||
];
|
||||
}
|
||||
|
||||
$this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull();
|
||||
$this->repository->shouldReceive('insertIgnore')->with([
|
||||
[
|
||||
'node_id' => $this->node->id,
|
||||
'ip' => '192.168.1.1',
|
||||
'port' => 1024,
|
||||
'ip_alias' => null,
|
||||
'server_id' => null,
|
||||
],
|
||||
])->once()->andReturn(true);
|
||||
$this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull();
|
||||
|
||||
$this->service->handle($this->node, $data);
|
||||
/**
|
||||
* Returns an instance of the service with mocked dependencies for testing.
|
||||
*
|
||||
* @return \Pterodactyl\Services\Allocations\AssignmentService
|
||||
*/
|
||||
private function getService(): AssignmentService
|
||||
{
|
||||
return new AssignmentService($this->repository, $this->connection);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,14 +121,18 @@ class StartupModificationServiceTest extends TestCase
|
|||
$this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull();
|
||||
$this->validatorService->shouldReceive('setUserLevel')->with(User::USER_LEVEL_ADMIN)->once()->andReturnNull();
|
||||
$this->validatorService->shouldReceive('handle')->with(456, ['test' => 'abcd1234'])->once()->andReturn(
|
||||
collect([(object) ['id' => 1, 'value' => 'stored-value']])
|
||||
collect([(object) ['id' => 1, 'value' => 'stored-value'], (object) ['id' => 2, 'value' => null]])
|
||||
);
|
||||
|
||||
$this->serverVariableRepository->shouldReceive('withoutFreshModel')->withNoArgs()->once()->andReturnSelf();
|
||||
$this->serverVariableRepository->shouldReceive('updateOrCreate')->with([
|
||||
$this->serverVariableRepository->shouldReceive('withoutFreshModel->updateOrCreate')->once()->with([
|
||||
'server_id' => $model->id,
|
||||
'variable_id' => 1,
|
||||
], ['variable_value' => 'stored-value'])->once()->andReturnNull();
|
||||
], ['variable_value' => 'stored-value'])->andReturnNull();
|
||||
|
||||
$this->serverVariableRepository->shouldReceive('withoutFreshModel->updateOrCreate')->once()->with([
|
||||
'server_id' => $model->id,
|
||||
'variable_id' => 2,
|
||||
], ['variable_value' => ''])->andReturnNull();
|
||||
|
||||
$this->eggRepository->shouldReceive('setColumns->find')->once()->with($eggModel->id)->andReturn($eggModel);
|
||||
|
||||
|
|
Loading…
Reference in a new issue