mirror of
https://github.com/pterodactyl/panel.git
synced 2024-11-22 17:12:30 +01:00
Merge branch 'develop' into lancepioch-patch-3
This commit is contained in:
commit
e6008d6392
@ -1,109 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Console\Commands\Server;
|
||||
|
||||
use Webmozart\Assert\Assert;
|
||||
use Illuminate\Console\Command;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Pterodactyl\Repositories\Wings\DaemonServerRepository;
|
||||
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
||||
use Pterodactyl\Services\Servers\ServerConfigurationStructureService;
|
||||
|
||||
class RebuildServerCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Servers\ServerConfigurationStructureService
|
||||
*/
|
||||
protected $configurationStructureService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Wings\DaemonServerRepository
|
||||
*/
|
||||
protected $daemonRepository;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Rebuild a single server, all servers on a node, or all servers on the panel.';
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
|
||||
*/
|
||||
protected $repository;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'p:server:rebuild
|
||||
{server? : The ID of the server to rebuild.}
|
||||
{--node= : ID of the node to rebuild all servers on. Ignored if server is passed.}';
|
||||
|
||||
/**
|
||||
* RebuildServerCommand constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Repositories\Wings\DaemonServerRepository $daemonRepository
|
||||
* @param \Pterodactyl\Services\Servers\ServerConfigurationStructureService $configurationStructureService
|
||||
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
|
||||
*/
|
||||
public function __construct(
|
||||
DaemonServerRepository $daemonRepository,
|
||||
ServerConfigurationStructureService $configurationStructureService,
|
||||
ServerRepositoryInterface $repository
|
||||
) {
|
||||
parent::__construct();
|
||||
|
||||
$this->configurationStructureService = $configurationStructureService;
|
||||
$this->daemonRepository = $daemonRepository;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle command execution.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$servers = $this->getServersToProcess();
|
||||
$bar = $this->output->createProgressBar(count($servers));
|
||||
|
||||
$servers->each(function ($server) use ($bar) {
|
||||
$bar->clear();
|
||||
$json = array_merge($this->configurationStructureService->handle($server), ['rebuild' => true]);
|
||||
|
||||
try {
|
||||
$this->daemonRepository->setServer($server)->update($json);
|
||||
} catch (RequestException $exception) {
|
||||
$this->output->error(trans('command/messages.server.rebuild_failed', [
|
||||
'name' => $server->name,
|
||||
'id' => $server->id,
|
||||
'node' => $server->node->name,
|
||||
'message' => $exception->getMessage(),
|
||||
]));
|
||||
}
|
||||
|
||||
$bar->advance();
|
||||
$bar->display();
|
||||
});
|
||||
|
||||
$this->line('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the servers to be rebuilt.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
private function getServersToProcess()
|
||||
{
|
||||
Assert::nullOrIntegerish($this->argument('server'), 'Value passed in server argument must be null or an integer, received %s.');
|
||||
Assert::nullOrIntegerish($this->option('node'), 'Value passed in node option must be null or integer, received %s.');
|
||||
|
||||
return $this->repository->getDataForRebuild($this->argument('server'), $this->option('node'));
|
||||
}
|
||||
}
|
@ -1,16 +1,9 @@
|
||||
<?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\Exceptions\Service\User;
|
||||
|
||||
use Exception;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
|
||||
class TwoFactorAuthenticationTokenInvalid extends Exception
|
||||
class TwoFactorAuthenticationTokenInvalid extends DisplayException
|
||||
{
|
||||
}
|
||||
|
48
app/Http/Controllers/Admin/Nodes/NodeController.php
Normal file
48
app/Http/Controllers/Admin/Nodes/NodeController.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin\Nodes;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Repositories\Eloquent\NodeRepository;
|
||||
|
||||
class NodeController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var \Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
private $view;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\NodeRepository
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* NodeController constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Repositories\Eloquent\NodeRepository $repository
|
||||
* @param \Illuminate\Contracts\View\Factory $view
|
||||
*/
|
||||
public function __construct(NodeRepository $repository, Factory $view)
|
||||
{
|
||||
$this->view = $view;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a listing of nodes on the system.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$nodes = $this->repository
|
||||
->setSearchTerm($request->input('query'))
|
||||
->getNodeListingData();
|
||||
|
||||
return $this->view->make('admin.nodes.index', compact('nodes'));
|
||||
}
|
||||
}
|
160
app/Http/Controllers/Admin/Nodes/NodeViewController.php
Normal file
160
app/Http/Controllers/Admin/Nodes/NodeViewController.php
Normal file
@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin\Nodes;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Pterodactyl\Models\Node;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Repositories\Eloquent\NodeRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||
use Pterodactyl\Traits\Controllers\JavascriptInjection;
|
||||
use Pterodactyl\Services\Helpers\SoftwareVersionService;
|
||||
use Pterodactyl\Repositories\Eloquent\LocationRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\AllocationRepository;
|
||||
|
||||
class NodeViewController extends Controller
|
||||
{
|
||||
use JavascriptInjection;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\NodeRepository
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
private $view;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Helpers\SoftwareVersionService
|
||||
*/
|
||||
private $versionService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\LocationRepository
|
||||
*/
|
||||
private $locationRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\AllocationRepository
|
||||
*/
|
||||
private $allocationRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\ServerRepository
|
||||
*/
|
||||
private $serverRepository;
|
||||
|
||||
/**
|
||||
* NodeViewController constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Repositories\Eloquent\AllocationRepository $allocationRepository
|
||||
* @param \Pterodactyl\Repositories\Eloquent\LocationRepository $locationRepository
|
||||
* @param \Pterodactyl\Repositories\Eloquent\NodeRepository $repository
|
||||
* @param \Pterodactyl\Repositories\Eloquent\ServerRepository $serverRepository
|
||||
* @param \Pterodactyl\Services\Helpers\SoftwareVersionService $versionService
|
||||
* @param \Illuminate\Contracts\View\Factory $view
|
||||
*/
|
||||
public function __construct(
|
||||
AllocationRepository $allocationRepository,
|
||||
LocationRepository $locationRepository,
|
||||
NodeRepository $repository,
|
||||
ServerRepository $serverRepository,
|
||||
SoftwareVersionService $versionService,
|
||||
Factory $view
|
||||
) {
|
||||
$this->repository = $repository;
|
||||
$this->view = $view;
|
||||
$this->versionService = $versionService;
|
||||
$this->locationRepository = $locationRepository;
|
||||
$this->allocationRepository = $allocationRepository;
|
||||
$this->serverRepository = $serverRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns index view for a specific node on the system.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Pterodactyl\Models\Node $node
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index(Request $request, Node $node)
|
||||
{
|
||||
$node = $this->repository->loadLocationAndServerCount($node);
|
||||
|
||||
return $this->view->make('admin.nodes.view.index', [
|
||||
'node' => $node,
|
||||
'stats' => $this->repository->getUsageStats($node),
|
||||
'version' => $this->versionService,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the settings page for a specific node.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Pterodactyl\Models\Node $node
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function settings(Request $request, Node $node)
|
||||
{
|
||||
return $this->view->make('admin.nodes.view.settings', [
|
||||
'node' => $node,
|
||||
'locations' => $this->locationRepository->all(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the node configuration page for a specific node.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Pterodactyl\Models\Node $node
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function configuration(Request $request, Node $node)
|
||||
{
|
||||
return $this->view->make('admin.nodes.view.configuration', compact('node'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the node allocation management page.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Pterodactyl\Models\Node $node
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function allocations(Request $request, Node $node)
|
||||
{
|
||||
$node = $this->repository->loadNodeAllocations($node);
|
||||
|
||||
$this->plainInject(['node' => Collection::wrap($node)->only(['id'])]);
|
||||
|
||||
return $this->view->make('admin.nodes.view.allocation', [
|
||||
'node' => $node,
|
||||
'allocations' => $this->allocationRepository->setColumns(['ip'])->getUniqueAllocationIpsForNode($node->id),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a listing of servers that exist for this specific node.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Pterodactyl\Models\Node $node
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function servers(Request $request, Node $node)
|
||||
{
|
||||
$this->plainInject([
|
||||
'node' => Collection::wrap($node->makeVisible('daemonSecret'))
|
||||
->only(['scheme', 'fqdn', 'daemonListen', 'daemonSecret']),
|
||||
]);
|
||||
|
||||
return $this->view->make('admin.nodes.view.servers', [
|
||||
'node' => $node,
|
||||
'servers' => $this->serverRepository->loadAllServersForNode($node->id, 25),
|
||||
]);
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin\Nodes;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Http\Request;
|
||||
use Pterodactyl\Models\Node;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Repositories\Wings\DaemonConfigurationRepository;
|
||||
|
||||
class SystemInformationController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Wings\DaemonConfigurationRepository
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* SystemInformationController constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Repositories\Wings\DaemonConfigurationRepository $repository
|
||||
*/
|
||||
public function __construct(DaemonConfigurationRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns system information from the Daemon.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Pterodactyl\Models\Node $node
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function __invoke(Request $request, Node $node)
|
||||
{
|
||||
$data = $this->repository->setNode($node)->getSystemInformation();
|
||||
|
||||
return JsonResponse::create([
|
||||
'version' => $data['version'] ?? '',
|
||||
'system' => [
|
||||
'type' => Str::title($data['os'] ?? 'Unknown'),
|
||||
'arch' => $data['architecture'] ?? '--',
|
||||
'release' => $data['kernel_version'] ?? '--',
|
||||
'cpus' => $data['cpu_count'] ?? 0,
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
@ -9,7 +9,6 @@
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin;
|
||||
|
||||
use Javascript;
|
||||
use Cake\Chronos\Chronos;
|
||||
use Illuminate\Http\Request;
|
||||
use Pterodactyl\Models\Node;
|
||||
@ -138,19 +137,6 @@ class NodesController extends Controller
|
||||
$this->versionService = $versionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the index page listing all nodes on the panel.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
return view('admin.nodes.index', [
|
||||
'nodes' => $this->repository->setSearchTerm($request->input('query'))->getNodeListingData(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays create new node page.
|
||||
*
|
||||
@ -184,79 +170,6 @@ class NodesController extends Controller
|
||||
return redirect()->route('admin.nodes.view.allocation', $node->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the index overview page for a specific node.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Node $node
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function viewIndex(Node $node)
|
||||
{
|
||||
return view('admin.nodes.view.index', [
|
||||
'node' => $this->repository->loadLocationAndServerCount($node),
|
||||
'stats' => $this->repository->getUsageStats($node),
|
||||
'version' => $this->versionService,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the settings page for a specific node.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Node $node
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function viewSettings(Node $node)
|
||||
{
|
||||
return view('admin.nodes.view.settings', [
|
||||
'node' => $node,
|
||||
'locations' => $this->locationRepository->all(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the configuration page for a specific node.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Node $node
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function viewConfiguration(Node $node)
|
||||
{
|
||||
return view('admin.nodes.view.configuration', ['node' => $node]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the allocation page for a specific node.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Node $node
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function viewAllocation(Node $node)
|
||||
{
|
||||
$this->repository->loadNodeAllocations($node);
|
||||
Javascript::put(['node' => collect($node)->only(['id'])]);
|
||||
|
||||
return view('admin.nodes.view.allocation', [
|
||||
'allocations' => $this->allocationRepository->setColumns(['ip'])->getUniqueAllocationIpsForNode($node->id),
|
||||
'node' => $node,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the server listing page for a specific node.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Node $node
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function viewServers(Node $node)
|
||||
{
|
||||
$servers = $this->serverRepository->loadAllServersForNode($node->id, 25);
|
||||
Javascript::put([
|
||||
'node' => collect($node->makeVisible('daemonSecret'))->only(['scheme', 'fqdn', 'daemonListen', 'daemonSecret']),
|
||||
]);
|
||||
|
||||
return view('admin.nodes.view.servers', ['node' => $node, 'servers' => $servers]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates settings for a node.
|
||||
*
|
||||
|
132
app/Http/Controllers/Admin/Servers/CreateServerController.php
Normal file
132
app/Http/Controllers/Admin/Servers/CreateServerController.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin\Servers;
|
||||
|
||||
use JavaScript;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Prologue\Alerts\AlertsMessageBag;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Repositories\Eloquent\NestRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\NodeRepository;
|
||||
use Pterodactyl\Http\Requests\Admin\ServerFormRequest;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||
use Pterodactyl\Services\Servers\ServerCreationService;
|
||||
use Pterodactyl\Repositories\Eloquent\LocationRepository;
|
||||
|
||||
class CreateServerController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\ServerRepository
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\NodeRepository
|
||||
*/
|
||||
private $nodeRepository;
|
||||
|
||||
/**
|
||||
* @var \Prologue\Alerts\AlertsMessageBag
|
||||
*/
|
||||
private $alert;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\NestRepository
|
||||
*/
|
||||
private $nestRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\LocationRepository
|
||||
*/
|
||||
private $locationRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Servers\ServerCreationService
|
||||
*/
|
||||
private $creationService;
|
||||
|
||||
/**
|
||||
* CreateServerController constructor.
|
||||
*
|
||||
* @param \Prologue\Alerts\AlertsMessageBag $alert
|
||||
* @param \Pterodactyl\Repositories\Eloquent\NestRepository $nestRepository
|
||||
* @param \Pterodactyl\Repositories\Eloquent\LocationRepository $locationRepository
|
||||
* @param \Pterodactyl\Repositories\Eloquent\NodeRepository $nodeRepository
|
||||
* @param \Pterodactyl\Repositories\Eloquent\ServerRepository $repository
|
||||
* @param \Pterodactyl\Services\Servers\ServerCreationService $creationService
|
||||
*/
|
||||
public function __construct(
|
||||
AlertsMessageBag $alert,
|
||||
NestRepository $nestRepository,
|
||||
LocationRepository $locationRepository,
|
||||
NodeRepository $nodeRepository,
|
||||
ServerRepository $repository,
|
||||
ServerCreationService $creationService
|
||||
) {
|
||||
$this->repository = $repository;
|
||||
$this->nodeRepository = $nodeRepository;
|
||||
$this->alert = $alert;
|
||||
$this->nestRepository = $nestRepository;
|
||||
$this->locationRepository = $locationRepository;
|
||||
$this->creationService = $creationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the create server page.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$nodes = $this->nodeRepository->all();
|
||||
if (count($nodes) < 1) {
|
||||
$this->alert->warning(trans('admin/server.alerts.node_required'))->flash();
|
||||
|
||||
return redirect()->route('admin.nodes');
|
||||
}
|
||||
|
||||
$nests = $this->nestRepository->getWithEggs();
|
||||
|
||||
Javascript::put([
|
||||
'nodeData' => $this->nodeRepository->getNodesForServerCreation(),
|
||||
'nests' => $nests->map(function ($item) {
|
||||
return array_merge($item->toArray(), [
|
||||
'eggs' => $item->eggs->keyBy('id')->toArray(),
|
||||
]);
|
||||
})->keyBy('id'),
|
||||
]);
|
||||
|
||||
return view('admin.servers.new', [
|
||||
'locations' => $this->locationRepository->all(),
|
||||
'nests' => $nests,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new server on the remote system.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Admin\ServerFormRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Deployment\NoViableAllocationException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Deployment\NoViableNodeException
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function store(ServerFormRequest $request)
|
||||
{
|
||||
$server = $this->creationService->handle(
|
||||
$request->except(['_token'])
|
||||
);
|
||||
|
||||
$this->alert->success(
|
||||
trans('admin/server.alerts.server_created')
|
||||
)->flash();
|
||||
|
||||
return RedirectResponse::create('/admin/servers/view/' . $server->id);
|
||||
}
|
||||
}
|
51
app/Http/Controllers/Admin/Servers/ServerController.php
Normal file
51
app/Http/Controllers/Admin/Servers/ServerController.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin\Servers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||
|
||||
class ServerController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var \Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
private $view;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\ServerRepository
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* ServerController constructor.
|
||||
*
|
||||
* @param \Illuminate\Contracts\View\Factory $view
|
||||
* @param \Pterodactyl\Repositories\Eloquent\ServerRepository $repository
|
||||
*/
|
||||
public function __construct(
|
||||
Factory $view,
|
||||
ServerRepository $repository
|
||||
) {
|
||||
$this->view = $view;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all of the servers that exist on the system using a paginated result set. If
|
||||
* a query is passed along in the request it is also passed to the repository function.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
return $this->view->make('admin.servers.index', [
|
||||
'servers' => $this->repository->setSearchTerm($request->input('query'))->getAllServers(
|
||||
config()->get('pterodactyl.paginate.admin.servers')
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
176
app/Http/Controllers/Admin/Servers/ServerViewController.php
Normal file
176
app/Http/Controllers/Admin/Servers/ServerViewController.php
Normal file
@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin\Servers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Pterodactyl\Models\Nest;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Repositories\Eloquent\NestRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||
use Pterodactyl\Traits\Controllers\JavascriptInjection;
|
||||
use Pterodactyl\Repositories\Eloquent\DatabaseHostRepository;
|
||||
|
||||
class ServerViewController extends Controller
|
||||
{
|
||||
use JavascriptInjection;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
private $view;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\DatabaseHostRepository
|
||||
*/
|
||||
private $databaseHostRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\ServerRepository
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\NestRepository
|
||||
*/
|
||||
private $nestRepository;
|
||||
|
||||
/**
|
||||
* ServerViewController constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Repositories\Eloquent\DatabaseHostRepository $databaseHostRepository
|
||||
* @param \Pterodactyl\Repositories\Eloquent\NestRepository $nestRepository
|
||||
* @param \Pterodactyl\Repositories\Eloquent\ServerRepository $repository
|
||||
* @param \Illuminate\Contracts\View\Factory $view
|
||||
*/
|
||||
public function __construct(
|
||||
DatabaseHostRepository $databaseHostRepository,
|
||||
NestRepository $nestRepository,
|
||||
ServerRepository $repository,
|
||||
Factory $view
|
||||
) {
|
||||
$this->view = $view;
|
||||
$this->databaseHostRepository = $databaseHostRepository;
|
||||
$this->repository = $repository;
|
||||
$this->nestRepository = $nestRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index view for a server.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index(Request $request, Server $server)
|
||||
{
|
||||
return $this->view->make('admin.servers.view.index', compact('server'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the server details page.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function details(Request $request, Server $server)
|
||||
{
|
||||
return $this->view->make('admin.servers.view.details', compact('server'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view of server build settings.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function build(Request $request, Server $server)
|
||||
{
|
||||
$allocations = $server->node->allocations->toBase();
|
||||
|
||||
return $this->view->make('admin.servers.view.build', [
|
||||
'server' => $server,
|
||||
'assigned' => $allocations->where('server_id', $server->id)->sortBy('port')->sortBy('ip'),
|
||||
'unassigned' => $allocations->where('server_id', null)->sortBy('port')->sortBy('ip'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the server startup management page.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function startup(Request $request, Server $server)
|
||||
{
|
||||
$parameters = $this->repository->getVariablesWithValues($server->id, true);
|
||||
$nests = $this->nestRepository->getWithEggs();
|
||||
|
||||
$this->plainInject([
|
||||
'server' => $server,
|
||||
'server_variables' => $parameters->data,
|
||||
'nests' => $nests->map(function (Nest $item) {
|
||||
return array_merge($item->toArray(), [
|
||||
'eggs' => $item->eggs->keyBy('id')->toArray(),
|
||||
]);
|
||||
})->keyBy('id'),
|
||||
]);
|
||||
|
||||
return $this->view->make('admin.servers.view.startup', compact('server', 'nests'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all of the databases that exist for the server.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function database(Request $request, Server $server)
|
||||
{
|
||||
return $this->view->make('admin.servers.view.database', [
|
||||
'hosts' => $this->databaseHostRepository->all(),
|
||||
'server' => $server,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base server management page, or an exception if the server
|
||||
* is in a state that cannot be recovered from.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
*/
|
||||
public function manage(Request $request, Server $server)
|
||||
{
|
||||
if ($server->installed > 1) {
|
||||
throw new DisplayException(
|
||||
'This server is in a failed install state and cannot be recovered. Please delete and re-create the server.'
|
||||
);
|
||||
}
|
||||
|
||||
return $this->view->make('admin.servers.view.manage', compact('server'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the server deletion page.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function delete(Request $request, Server $server)
|
||||
{
|
||||
return $this->view->make('admin.servers.view.delete', compact('server'));
|
||||
}
|
||||
}
|
@ -9,7 +9,6 @@
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin;
|
||||
|
||||
use Javascript;
|
||||
use Illuminate\Http\Request;
|
||||
use Pterodactyl\Models\User;
|
||||
use Pterodactyl\Models\Server;
|
||||
@ -17,23 +16,18 @@ use Prologue\Alerts\AlertsMessageBag;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Services\Servers\SuspensionService;
|
||||
use Pterodactyl\Http\Requests\Admin\ServerFormRequest;
|
||||
use Pterodactyl\Services\Servers\ServerCreationService;
|
||||
use Pterodactyl\Services\Servers\ServerDeletionService;
|
||||
use Pterodactyl\Services\Servers\ReinstallServerService;
|
||||
use Pterodactyl\Services\Servers\ContainerRebuildService;
|
||||
use Pterodactyl\Services\Servers\BuildModificationService;
|
||||
use Pterodactyl\Services\Databases\DatabasePasswordService;
|
||||
use Pterodactyl\Services\Servers\DetailsModificationService;
|
||||
use Pterodactyl\Services\Servers\StartupModificationService;
|
||||
use Pterodactyl\Contracts\Repository\NestRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\NodeRepositoryInterface;
|
||||
use Pterodactyl\Repositories\Eloquent\DatabaseHostRepository;
|
||||
use Pterodactyl\Services\Databases\DatabaseManagementService;
|
||||
use Illuminate\Contracts\Config\Repository as ConfigRepository;
|
||||
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\LocationRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
|
||||
use Pterodactyl\Http\Requests\Admin\Servers\Databases\StoreServerDatabaseRequest;
|
||||
|
||||
@ -59,11 +53,6 @@ class ServersController extends Controller
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Servers\ContainerRebuildService
|
||||
*/
|
||||
protected $containerRebuildService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface
|
||||
*/
|
||||
@ -94,21 +83,11 @@ class ServersController extends Controller
|
||||
*/
|
||||
protected $detailsModificationService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\LocationRepositoryInterface
|
||||
*/
|
||||
protected $locationRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\NestRepositoryInterface
|
||||
*/
|
||||
protected $nestRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\NodeRepositoryInterface
|
||||
*/
|
||||
protected $nodeRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Servers\ReinstallServerService
|
||||
*/
|
||||
@ -119,11 +98,6 @@ class ServersController extends Controller
|
||||
*/
|
||||
protected $repository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Servers\ServerCreationService
|
||||
*/
|
||||
protected $service;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Servers\StartupModificationService
|
||||
*/
|
||||
@ -141,16 +115,12 @@ class ServersController extends Controller
|
||||
* @param \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface $allocationRepository
|
||||
* @param \Pterodactyl\Services\Servers\BuildModificationService $buildModificationService
|
||||
* @param \Illuminate\Contracts\Config\Repository $config
|
||||
* @param \Pterodactyl\Services\Servers\ContainerRebuildService $containerRebuildService
|
||||
* @param \Pterodactyl\Services\Servers\ServerCreationService $service
|
||||
* @param \Pterodactyl\Services\Databases\DatabaseManagementService $databaseManagementService
|
||||
* @param \Pterodactyl\Services\Databases\DatabasePasswordService $databasePasswordService
|
||||
* @param \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface $databaseRepository
|
||||
* @param \Pterodactyl\Repositories\Eloquent\DatabaseHostRepository $databaseHostRepository
|
||||
* @param \Pterodactyl\Services\Servers\ServerDeletionService $deletionService
|
||||
* @param \Pterodactyl\Services\Servers\DetailsModificationService $detailsModificationService
|
||||
* @param \Pterodactyl\Contracts\Repository\LocationRepositoryInterface $locationRepository
|
||||
* @param \Pterodactyl\Contracts\Repository\NodeRepositoryInterface $nodeRepository
|
||||
* @param \Pterodactyl\Services\Servers\ReinstallServerService $reinstallService
|
||||
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
|
||||
* @param \Pterodactyl\Contracts\Repository\NestRepositoryInterface $nestRepository
|
||||
@ -162,16 +132,12 @@ class ServersController extends Controller
|
||||
AllocationRepositoryInterface $allocationRepository,
|
||||
BuildModificationService $buildModificationService,
|
||||
ConfigRepository $config,
|
||||
ContainerRebuildService $containerRebuildService,
|
||||
ServerCreationService $service,
|
||||
DatabaseManagementService $databaseManagementService,
|
||||
DatabasePasswordService $databasePasswordService,
|
||||
DatabaseRepositoryInterface $databaseRepository,
|
||||
DatabaseHostRepository $databaseHostRepository,
|
||||
ServerDeletionService $deletionService,
|
||||
DetailsModificationService $detailsModificationService,
|
||||
LocationRepositoryInterface $locationRepository,
|
||||
NodeRepositoryInterface $nodeRepository,
|
||||
ReinstallServerService $reinstallService,
|
||||
ServerRepositoryInterface $repository,
|
||||
NestRepositoryInterface $nestRepository,
|
||||
@ -182,223 +148,19 @@ class ServersController extends Controller
|
||||
$this->allocationRepository = $allocationRepository;
|
||||
$this->buildModificationService = $buildModificationService;
|
||||
$this->config = $config;
|
||||
$this->containerRebuildService = $containerRebuildService;
|
||||
$this->databaseHostRepository = $databaseHostRepository;
|
||||
$this->databaseManagementService = $databaseManagementService;
|
||||
$this->databasePasswordService = $databasePasswordService;
|
||||
$this->databaseRepository = $databaseRepository;
|
||||
$this->detailsModificationService = $detailsModificationService;
|
||||
$this->deletionService = $deletionService;
|
||||
$this->locationRepository = $locationRepository;
|
||||
$this->nestRepository = $nestRepository;
|
||||
$this->nodeRepository = $nodeRepository;
|
||||
$this->reinstallService = $reinstallService;
|
||||
$this->repository = $repository;
|
||||
$this->service = $service;
|
||||
$this->startupModificationService = $startupModificationService;
|
||||
$this->suspensionService = $suspensionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the index page with all servers currently on the system.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
return view('admin.servers.index', [
|
||||
'servers' => $this->repository->setSearchTerm($request->input('query'))->getAllServers(
|
||||
$this->config->get('pterodactyl.paginate.admin.servers')
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display create new server page.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$nodes = $this->nodeRepository->all();
|
||||
if (count($nodes) < 1) {
|
||||
$this->alert->warning(trans('admin/server.alerts.node_required'))->flash();
|
||||
|
||||
return redirect()->route('admin.nodes');
|
||||
}
|
||||
|
||||
$nests = $this->nestRepository->getWithEggs();
|
||||
|
||||
Javascript::put([
|
||||
'nodeData' => $this->nodeRepository->getNodesForServerCreation(),
|
||||
'nests' => $nests->map(function ($item) {
|
||||
return array_merge($item->toArray(), [
|
||||
'eggs' => $item->eggs->keyBy('id')->toArray(),
|
||||
]);
|
||||
})->keyBy('id'),
|
||||
]);
|
||||
|
||||
return view('admin.servers.new', [
|
||||
'locations' => $this->locationRepository->all(),
|
||||
'nests' => $nests,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle POST of server creation form.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Admin\ServerFormRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Deployment\NoViableAllocationException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Deployment\NoViableNodeException
|
||||
*/
|
||||
public function store(ServerFormRequest $request)
|
||||
{
|
||||
$server = $this->service->handle($request->except('_token'));
|
||||
$this->alert->success(trans('admin/server.alerts.server_created'))->flash();
|
||||
|
||||
return redirect()->route('admin.servers.view', $server->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the index when viewing a specific server.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function viewIndex(Server $server)
|
||||
{
|
||||
return view('admin.servers.view.index', ['server' => $server]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the details page when viewing a specific server.
|
||||
*
|
||||
* @param int $server
|
||||
* @return \Illuminate\View\View
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function viewDetails($server)
|
||||
{
|
||||
return view('admin.servers.view.details', [
|
||||
'server' => $this->repository->findFirstWhere([
|
||||
['id', '=', $server],
|
||||
['installed', '=', 1],
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the build details page when viewing a specific server.
|
||||
*
|
||||
* @param int $server
|
||||
* @return \Illuminate\View\View
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function viewBuild($server)
|
||||
{
|
||||
$server = $this->repository->findFirstWhere([
|
||||
['id', '=', $server],
|
||||
['installed', '=', 1],
|
||||
]);
|
||||
|
||||
$allocations = $this->allocationRepository->getAllocationsForNode($server->node_id);
|
||||
|
||||
return view('admin.servers.view.build', [
|
||||
'server' => $server,
|
||||
'assigned' => $allocations->where('server_id', $server->id)->sortBy('port')->sortBy('ip'),
|
||||
'unassigned' => $allocations->where('server_id', null)->sortBy('port')->sortBy('ip'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display startup configuration page for a server.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\View\View
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function viewStartup(Server $server)
|
||||
{
|
||||
$parameters = $this->repository->getVariablesWithValues($server->id, true);
|
||||
if (! $parameters->server->installed) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$nests = $this->nestRepository->getWithEggs();
|
||||
|
||||
Javascript::put([
|
||||
'server' => $server,
|
||||
'nests' => $nests->map(function ($item) {
|
||||
return array_merge($item->toArray(), [
|
||||
'eggs' => $item->eggs->keyBy('id')->toArray(),
|
||||
]);
|
||||
})->keyBy('id'),
|
||||
'server_variables' => $parameters->data,
|
||||
]);
|
||||
|
||||
return view('admin.servers.view.startup', [
|
||||
'server' => $parameters->server,
|
||||
'nests' => $nests,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the database management page for a specific server.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function viewDatabase(Server $server)
|
||||
{
|
||||
$this->repository->loadDatabaseRelations($server);
|
||||
|
||||
return view('admin.servers.view.database', [
|
||||
'hosts' => $this->databaseHostRepository->all(),
|
||||
'server' => $server,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the management page when viewing a specific server.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\View\View
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
*/
|
||||
public function viewManage(Server $server)
|
||||
{
|
||||
if ($server->installed > 1) {
|
||||
throw new DisplayException('This server is in a failed installation state and must be deleted and recreated.');
|
||||
}
|
||||
|
||||
return view('admin.servers.view.manage', ['server' => $server]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the deletion page for a server.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function viewDelete(Server $server)
|
||||
{
|
||||
return view('admin.servers.view.delete', ['server' => $server]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the details for a server.
|
||||
*
|
||||
@ -464,21 +226,6 @@ class ServersController extends Controller
|
||||
return redirect()->route('admin.servers.view.manage', $server->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup a server to have a container rebuild.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function rebuildContainer(Server $server)
|
||||
{
|
||||
$this->containerRebuildService->handle($server);
|
||||
$this->alert->success(trans('admin/server.alerts.rebuild_on_boot'))->flash();
|
||||
|
||||
return redirect()->route('admin.servers.view.manage', $server->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the suspension status for a server.
|
||||
*
|
||||
@ -531,7 +278,7 @@ class ServersController extends Controller
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function delete(Request $request, Server $server)
|
||||
{
|
||||
@ -549,7 +296,6 @@ class ServersController extends Controller
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
|
@ -147,7 +147,7 @@ class UserController extends Controller
|
||||
public function store(UserFormRequest $request)
|
||||
{
|
||||
$user = $this->creationService->handle($request->normalize());
|
||||
$this->alert->success($this->translator->trans('admin/user.notices.account_created'))->flash();
|
||||
$this->alert->success($this->translator->get('admin/user.notices.account_created'))->flash();
|
||||
|
||||
return redirect()->route('admin.users.view', $user->id);
|
||||
}
|
||||
@ -164,27 +164,11 @@ class UserController extends Controller
|
||||
*/
|
||||
public function update(UserFormRequest $request, User $user)
|
||||
{
|
||||
$this->updateService->setUserLevel(User::USER_LEVEL_ADMIN);
|
||||
$data = $this->updateService->handle($user, $request->normalize());
|
||||
$this->updateService
|
||||
->setUserLevel(User::USER_LEVEL_ADMIN)
|
||||
->handle($user, $request->normalize());
|
||||
|
||||
if (! empty($data->get('exceptions'))) {
|
||||
foreach ($data->get('exceptions') as $node => $exception) {
|
||||
/** @var \GuzzleHttp\Exception\RequestException $exception */
|
||||
/** @var \GuzzleHttp\Psr7\Response|null $response */
|
||||
$response = method_exists($exception, 'getResponse') ? $exception->getResponse() : null;
|
||||
$message = trans('admin/server.exceptions.daemon_exception', [
|
||||
'code' => is_null($response) ? 'E_CONN_REFUSED' : $response->getStatusCode(),
|
||||
]);
|
||||
|
||||
$this->alert->danger(trans('exceptions.users.node_revocation_failed', [
|
||||
'node' => $node,
|
||||
'error' => $message,
|
||||
'link' => route('admin.nodes.view', $node),
|
||||
]))->flash();
|
||||
}
|
||||
}
|
||||
|
||||
$this->alert->success($this->translator->trans('admin/user.notices.account_updated'))->flash();
|
||||
$this->alert->success(trans('admin/user.notices.account_updated'))->flash();
|
||||
|
||||
return redirect()->route('admin.users.view', $user->id);
|
||||
}
|
||||
@ -193,7 +177,7 @@ class UserController extends Controller
|
||||
* Get a JSON response of users on the system.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function json(Request $request)
|
||||
{
|
||||
|
@ -72,9 +72,9 @@ class ServerController extends ApplicationApiController
|
||||
* @param \Pterodactyl\Http\Requests\Api\Application\Servers\StoreServerRequest $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Throwable
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Deployment\NoViableAllocationException
|
||||
|
@ -63,15 +63,16 @@ class ServerDetailsController extends ApplicationApiController
|
||||
* Update the build details for a specific server.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Application\Servers\UpdateServerBuildConfigurationRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return array
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function build(UpdateServerBuildConfigurationRequest $request): array
|
||||
public function build(UpdateServerBuildConfigurationRequest $request, Server $server): array
|
||||
{
|
||||
$server = $this->buildModificationService->handle($request->getModel(Server::class), $request->validated());
|
||||
$server = $this->buildModificationService->handle($server, $request->validated());
|
||||
|
||||
return $this->fractal->item($server)
|
||||
->transformWith($this->getTransformer(ServerTransformer::class))
|
||||
|
@ -6,17 +6,11 @@ use Illuminate\Http\Response;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Services\Servers\SuspensionService;
|
||||
use Pterodactyl\Services\Servers\ReinstallServerService;
|
||||
use Pterodactyl\Services\Servers\ContainerRebuildService;
|
||||
use Pterodactyl\Http\Requests\Api\Application\Servers\ServerWriteRequest;
|
||||
use Pterodactyl\Http\Controllers\Api\Application\ApplicationApiController;
|
||||
|
||||
class ServerManagementController extends ApplicationApiController
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Servers\ContainerRebuildService
|
||||
*/
|
||||
private $rebuildService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Servers\ReinstallServerService
|
||||
*/
|
||||
@ -30,18 +24,15 @@ class ServerManagementController extends ApplicationApiController
|
||||
/**
|
||||
* SuspensionController constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Services\Servers\ContainerRebuildService $rebuildService
|
||||
* @param \Pterodactyl\Services\Servers\ReinstallServerService $reinstallServerService
|
||||
* @param \Pterodactyl\Services\Servers\SuspensionService $suspensionService
|
||||
*/
|
||||
public function __construct(
|
||||
ContainerRebuildService $rebuildService,
|
||||
ReinstallServerService $reinstallServerService,
|
||||
SuspensionService $suspensionService
|
||||
) {
|
||||
parent::__construct();
|
||||
|
||||
$this->rebuildService = $rebuildService;
|
||||
$this->reinstallServerService = $reinstallServerService;
|
||||
$this->suspensionService = $suspensionService;
|
||||
}
|
||||
@ -50,15 +41,14 @@ class ServerManagementController extends ApplicationApiController
|
||||
* Suspend a server on the Panel.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Application\Servers\ServerWriteRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Http\Response
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function suspend(ServerWriteRequest $request): Response
|
||||
public function suspend(ServerWriteRequest $request, Server $server): Response
|
||||
{
|
||||
$this->suspensionService->toggle($request->getModel(Server::class), SuspensionService::ACTION_SUSPEND);
|
||||
$this->suspensionService->toggle($server, SuspensionService::ACTION_SUSPEND);
|
||||
|
||||
return $this->returnNoContent();
|
||||
}
|
||||
@ -67,15 +57,14 @@ class ServerManagementController extends ApplicationApiController
|
||||
* Unsuspend a server on the Panel.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Application\Servers\ServerWriteRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Http\Response
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function unsuspend(ServerWriteRequest $request): Response
|
||||
public function unsuspend(ServerWriteRequest $request, Server $server): Response
|
||||
{
|
||||
$this->suspensionService->toggle($request->getModel(Server::class), SuspensionService::ACTION_UNSUSPEND);
|
||||
$this->suspensionService->toggle($server, SuspensionService::ACTION_UNSUSPEND);
|
||||
|
||||
return $this->returnNoContent();
|
||||
}
|
||||
@ -84,30 +73,16 @@ class ServerManagementController extends ApplicationApiController
|
||||
* Mark a server as needing to be reinstalled.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Application\Servers\ServerWriteRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Http\Response
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function reinstall(ServerWriteRequest $request): Response
|
||||
public function reinstall(ServerWriteRequest $request, Server $server): Response
|
||||
{
|
||||
$this->reinstallServerService->reinstall($request->getModel(Server::class));
|
||||
|
||||
return $this->returnNoContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a server as needing its container rebuilt the next time it is started.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Application\Servers\ServerWriteRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function rebuild(ServerWriteRequest $request): Response
|
||||
{
|
||||
$this->rebuildService->handle($request->getModel(Server::class));
|
||||
$this->reinstallServerService->reinstall($server);
|
||||
|
||||
return $this->returnNoContent();
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
namespace Pterodactyl\Http\Controllers\Api\Client;
|
||||
|
||||
use Pterodactyl\Models\User;
|
||||
use Illuminate\Support\Collection;
|
||||
use Pterodactyl\Models\Permission;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||
use Pterodactyl\Transformers\Api\Client\ServerTransformer;
|
||||
use Pterodactyl\Http\Requests\Api\Client\GetServersRequest;
|
||||
@ -62,4 +64,25 @@ class ClientController extends ClientApiController
|
||||
->transformWith($this->getTransformer(ServerTransformer::class))
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all of the subuser permissions available on the system.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function permissions()
|
||||
{
|
||||
$permissions = Permission::permissions()->map(function ($values, $key) {
|
||||
return Collection::make($values)->map(function ($permission) use ($key) {
|
||||
return $key . '.' . $permission;
|
||||
})->values()->toArray();
|
||||
})->flatten();
|
||||
|
||||
return [
|
||||
'object' => 'system_permissions',
|
||||
'attributes' => [
|
||||
'permissions' => $permissions,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -2,15 +2,12 @@
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Illuminate\Http\Response;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use GuzzleHttp\Exception\TransferException;
|
||||
use Illuminate\Contracts\Routing\ResponseFactory;
|
||||
use Pterodactyl\Repositories\Wings\DaemonFileRepository;
|
||||
use Pterodactyl\Transformers\Daemon\FileObjectTransformer;
|
||||
use Illuminate\Contracts\Cache\Repository as CacheRepository;
|
||||
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
|
||||
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\CopyFileRequest;
|
||||
@ -18,34 +15,35 @@ use Pterodactyl\Http\Requests\Api\Client\Servers\Files\ListFilesRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\DeleteFileRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\RenameFileRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\CreateFolderRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\DownloadFileRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\GetFileContentsRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\WriteFileContentRequest;
|
||||
|
||||
class FileController extends ClientApiController
|
||||
{
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Cache\Factory
|
||||
*/
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Wings\DaemonFileRepository
|
||||
*/
|
||||
private $fileRepository;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Routing\ResponseFactory
|
||||
*/
|
||||
private $responseFactory;
|
||||
|
||||
/**
|
||||
* FileController constructor.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Routing\ResponseFactory $responseFactory
|
||||
* @param \Pterodactyl\Repositories\Wings\DaemonFileRepository $fileRepository
|
||||
* @param \Illuminate\Contracts\Cache\Repository $cache
|
||||
*/
|
||||
public function __construct(DaemonFileRepository $fileRepository, CacheRepository $cache)
|
||||
{
|
||||
public function __construct(
|
||||
ResponseFactory $responseFactory,
|
||||
DaemonFileRepository $fileRepository
|
||||
) {
|
||||
parent::__construct();
|
||||
|
||||
$this->cache = $cache;
|
||||
$this->fileRepository = $fileRepository;
|
||||
$this->responseFactory = $responseFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -85,7 +83,42 @@ class FileController extends ClientApiController
|
||||
return Response::create(
|
||||
$this->fileRepository->setServer($server)->getContent(
|
||||
$request->get('file'), config('pterodactyl.files.max_edit_size')
|
||||
)
|
||||
),
|
||||
Response::HTTP_OK,
|
||||
['Content-Type' => 'text/plain']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Files\GetFileContentsRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Symfony\Component\HttpFoundation\StreamedResponse
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function download(GetFileContentsRequest $request, Server $server)
|
||||
{
|
||||
set_time_limit(0);
|
||||
|
||||
$request = $this->fileRepository->setServer($server)->streamContent(
|
||||
$request->get('file')
|
||||
);
|
||||
|
||||
$body = $request->getBody();
|
||||
|
||||
preg_match('/filename=(?<name>.*)$/', $request->getHeaderLine('Content-Disposition'), $matches);
|
||||
|
||||
return $this->responseFactory->streamDownload(
|
||||
function () use ($body) {
|
||||
while (! $body->eof()) {
|
||||
echo $body->read(128);
|
||||
}
|
||||
},
|
||||
$matches['name'] ?? 'download',
|
||||
[
|
||||
'Content-Type' => $request->getHeaderLine('Content-Type'),
|
||||
'Content-Length' => $request->getHeaderLine('Content-Length'),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@ -169,27 +202,4 @@ class FileController extends ClientApiController
|
||||
|
||||
return Response::create('', Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a reference to a file to download in the cache so that when the
|
||||
* user hits the Daemon and it verifies with the Panel they'll actually be able
|
||||
* to download that file.
|
||||
*
|
||||
* Returns the token that needs to be used when downloading the file.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Files\DownloadFileRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function download(DownloadFileRequest $request, Server $server): JsonResponse
|
||||
{
|
||||
$token = Uuid::uuid4()->toString();
|
||||
|
||||
$this->cache->put(
|
||||
'Server:Downloads:' . $token, ['server' => $server->uuid, 'path' => $request->route()->parameter('file')], Carbon::now()->addMinutes(5)
|
||||
);
|
||||
|
||||
return JsonResponse::create(['token' => $token]);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
|
||||
|
||||
use Illuminate\Http\Response;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Settings\RenameServerRequest;
|
||||
|
||||
class SettingsController extends ClientApiController
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\ServerRepository
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* SettingsController constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Repositories\Eloquent\ServerRepository $repository
|
||||
*/
|
||||
public function __construct(ServerRepository $repository)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames a server.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Settings\RenameServerRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Http\Response
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function rename(RenameServerRequest $request, Server $server)
|
||||
{
|
||||
$this->repository->update($server->id, [
|
||||
'name' => $request->input('name'),
|
||||
]);
|
||||
|
||||
return Response::create('', Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
|
||||
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Repositories\Eloquent\SubuserRepository;
|
||||
use Pterodactyl\Transformers\Api\Client\SubuserTransformer;
|
||||
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Subusers\GetSubuserRequest;
|
||||
|
||||
class SubuserController extends ClientApiController
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\SubuserRepository
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* SubuserController constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Repositories\Eloquent\SubuserRepository $repository
|
||||
*/
|
||||
public function __construct(SubuserRepository $repository)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the users associated with this server instance.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Subusers\GetSubuserRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return array
|
||||
*/
|
||||
public function index(GetSubuserRequest $request, Server $server)
|
||||
{
|
||||
$users = $this->repository->getSubusersForServer($server->id);
|
||||
|
||||
return $this->fractal->collection($users)
|
||||
->transformWith($this->getTransformer(SubuserTransformer::class))
|
||||
->toArray();
|
||||
}
|
||||
}
|
@ -45,7 +45,7 @@ class WebsocketController extends ClientApiController
|
||||
*/
|
||||
public function __invoke(Request $request, Server $server)
|
||||
{
|
||||
if (! $request->user()->can('connect-to-ws', $server)) {
|
||||
if (! $request->user()->can('websocket.*', $server)) {
|
||||
throw new HttpException(
|
||||
Response::HTTP_FORBIDDEN, 'You do not have permission to connect to this server\'s websocket.'
|
||||
);
|
||||
@ -63,7 +63,11 @@ class WebsocketController extends ClientApiController
|
||||
->expiresAt($now->addMinutes(15)->getTimestamp())
|
||||
->withClaim('user_id', $request->user()->id)
|
||||
->withClaim('server_uuid', $server->uuid)
|
||||
->withClaim('permissions', ['connect', 'send-command', 'send-power'])
|
||||
->withClaim('permissions', array_merge([
|
||||
'connect',
|
||||
'send-command',
|
||||
'send-power',
|
||||
], $request->user()->root_admin ? ['receive-errors'] : []))
|
||||
->getToken($signer, new Key($server->node->daemonSecret));
|
||||
|
||||
$socket = str_replace(['https://', 'http://'], ['wss://', 'ws://'], $server->node->getConnectionAddress());
|
||||
|
129
app/Http/Controllers/Api/Client/TwoFactorController.php
Normal file
129
app/Http/Controllers/Api/Client/TwoFactorController.php
Normal file
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Api\Client;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Contracts\Validation\Factory;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Pterodactyl\Services\Users\TwoFactorSetupService;
|
||||
use Pterodactyl\Services\Users\ToggleTwoFactorService;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
|
||||
class TwoFactorController extends ClientApiController
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Users\TwoFactorSetupService
|
||||
*/
|
||||
private $setupService;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Validation\Factory
|
||||
*/
|
||||
private $validation;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Users\ToggleTwoFactorService
|
||||
*/
|
||||
private $toggleTwoFactorService;
|
||||
|
||||
/**
|
||||
* TwoFactorController constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Services\Users\ToggleTwoFactorService $toggleTwoFactorService
|
||||
* @param \Pterodactyl\Services\Users\TwoFactorSetupService $setupService
|
||||
* @param \Illuminate\Contracts\Validation\Factory $validation
|
||||
*/
|
||||
public function __construct(
|
||||
ToggleTwoFactorService $toggleTwoFactorService,
|
||||
TwoFactorSetupService $setupService,
|
||||
Factory $validation
|
||||
) {
|
||||
parent::__construct();
|
||||
|
||||
$this->setupService = $setupService;
|
||||
$this->validation = $validation;
|
||||
$this->toggleTwoFactorService = $toggleTwoFactorService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns two-factor token credentials that allow a user to configure
|
||||
* it on their account. If two-factor is already enabled this endpoint
|
||||
* will return a 400 error.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
if ($request->user()->totp_enabled) {
|
||||
throw new BadRequestHttpException('Two-factor authentication is already enabled on this account.');
|
||||
}
|
||||
|
||||
return JsonResponse::create([
|
||||
'data' => [
|
||||
'image_url_data' => $this->setupService->handle($request->user()),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a user's account to have two-factor enabled.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws \PragmaRX\Google2FA\Exceptions\IncompatibleWithGoogleAuthenticatorException
|
||||
* @throws \PragmaRX\Google2FA\Exceptions\InvalidCharactersException
|
||||
* @throws \PragmaRX\Google2FA\Exceptions\SecretKeyTooShortException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Pterodactyl\Exceptions\Service\User\TwoFactorAuthenticationTokenInvalid
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validator = $this->validation->make($request->all(), [
|
||||
'code' => 'required|string',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
throw new ValidationException($validator);
|
||||
}
|
||||
|
||||
$this->toggleTwoFactorService->handle($request->user(), $request->input('code'), true);
|
||||
|
||||
return JsonResponse::create([], Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables two-factor authentication on an account if the password provided
|
||||
* is valid.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function delete(Request $request)
|
||||
{
|
||||
if (! password_verify($request->input('password') ?? '', $request->user()->password)) {
|
||||
throw new BadRequestHttpException(
|
||||
'The password provided was not valid.'
|
||||
);
|
||||
}
|
||||
|
||||
/** @var \Pterodactyl\Models\User $user */
|
||||
$user = $request->user();
|
||||
|
||||
$user->update([
|
||||
'totp_authenticated_at' => Carbon::now(),
|
||||
'use_totp' => false,
|
||||
]);
|
||||
|
||||
return JsonResponse::create([], Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
}
|
@ -7,8 +7,9 @@ use Illuminate\Http\JsonResponse;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Services\Eggs\EggConfigurationService;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||
use Pterodactyl\Services\Servers\ServerConfigurationStructureService;
|
||||
|
||||
class ServerConfigurationController extends Controller
|
||||
class ServerDetailsController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Eggs\EggConfigurationService
|
||||
@ -20,21 +21,34 @@ class ServerConfigurationController extends Controller
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Servers\ServerConfigurationStructureService
|
||||
*/
|
||||
private $configurationStructureService;
|
||||
|
||||
/**
|
||||
* ServerConfigurationController constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Repositories\Eloquent\ServerRepository $repository
|
||||
* @param \Pterodactyl\Services\Servers\ServerConfigurationStructureService $configurationStructureService
|
||||
* @param \Pterodactyl\Services\Eggs\EggConfigurationService $eggConfigurationService
|
||||
*/
|
||||
public function __construct(ServerRepository $repository, EggConfigurationService $eggConfigurationService)
|
||||
{
|
||||
public function __construct(
|
||||
ServerRepository $repository,
|
||||
ServerConfigurationStructureService $configurationStructureService,
|
||||
EggConfigurationService $eggConfigurationService
|
||||
) {
|
||||
$this->eggConfigurationService = $eggConfigurationService;
|
||||
$this->repository = $repository;
|
||||
$this->configurationStructureService = $configurationStructureService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns details about the server that allows Wings to self-recover and ensure
|
||||
* that the state of the server matches the Panel at all times.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param $uuid
|
||||
* @param string $uuid
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
@ -43,8 +57,9 @@ class ServerConfigurationController extends Controller
|
||||
{
|
||||
$server = $this->repository->getByUuid($uuid);
|
||||
|
||||
return JsonResponse::create(
|
||||
$this->eggConfigurationService->handle($server)
|
||||
);
|
||||
return JsonResponse::create([
|
||||
'settings' => $this->configurationStructureService->handle($server),
|
||||
'process_configuration' => $this->eggConfigurationService->handle($server),
|
||||
]);
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ use Pterodactyl\Services\Sftp\AuthenticateUsingPasswordService;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Pterodactyl\Http\Requests\Api\Remote\SftpAuthenticationFormRequest;
|
||||
|
||||
class SftpController extends Controller
|
||||
class SftpAuthenticationController extends Controller
|
||||
{
|
||||
use ThrottlesLogins;
|
||||
|
||||
@ -40,9 +40,12 @@ class SftpController extends Controller
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
*/
|
||||
public function index(SftpAuthenticationFormRequest $request): JsonResponse
|
||||
public function __invoke(SftpAuthenticationFormRequest $request): JsonResponse
|
||||
{
|
||||
// Reverse the string to avoid issues with usernames that contain periods.
|
||||
$parts = explode('.', strrev($request->input('username')), 2);
|
||||
|
||||
// Unreverse the strings after parsing them apart.
|
||||
$connection = [
|
||||
'username' => strrev(array_get($parts, 1)),
|
||||
'server' => strrev(array_get($parts, 0)),
|
||||
@ -86,6 +89,8 @@ class SftpController extends Controller
|
||||
*/
|
||||
protected function throttleKey(Request $request)
|
||||
{
|
||||
return strtolower(array_get(explode('.', $request->input('username')), 0) . '|' . $request->ip());
|
||||
$username = explode('.', strrev($request->input('username', '')));
|
||||
|
||||
return strtolower(strrev($username[0] ?? '') . '|' . $request->ip());
|
||||
}
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Base;
|
||||
|
||||
use Illuminate\View\View;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Pterodactyl\Models\ApiKey;
|
||||
use Prologue\Alerts\AlertsMessageBag;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Services\Api\KeyCreationService;
|
||||
use Pterodactyl\Http\Requests\Base\StoreAccountKeyRequest;
|
||||
use Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface;
|
||||
|
||||
class AccountKeyController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var \Prologue\Alerts\AlertsMessageBag
|
||||
*/
|
||||
protected $alert;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Api\KeyCreationService
|
||||
*/
|
||||
protected $keyService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface
|
||||
*/
|
||||
protected $repository;
|
||||
|
||||
/**
|
||||
* APIController constructor.
|
||||
*
|
||||
* @param \Prologue\Alerts\AlertsMessageBag $alert
|
||||
* @param \Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface $repository
|
||||
* @param \Pterodactyl\Services\Api\KeyCreationService $keyService
|
||||
*/
|
||||
public function __construct(
|
||||
AlertsMessageBag $alert,
|
||||
ApiKeyRepositoryInterface $repository,
|
||||
KeyCreationService $keyService
|
||||
) {
|
||||
$this->alert = $alert;
|
||||
$this->keyService = $keyService;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of all account API keys.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(Request $request): View
|
||||
{
|
||||
return view('base.api.index', [
|
||||
'keys' => $this->repository->getAccountKeys($request->user()),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display account API key creation page.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create(Request $request): View
|
||||
{
|
||||
return view('base.api.new');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle saving new account API key.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Base\StoreAccountKeyRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
*/
|
||||
public function store(StoreAccountKeyRequest $request)
|
||||
{
|
||||
$this->keyService->setKeyType(ApiKey::TYPE_ACCOUNT)->handle([
|
||||
'user_id' => $request->user()->id,
|
||||
'allowed_ips' => $request->input('allowed_ips'),
|
||||
'memo' => $request->input('memo'),
|
||||
]);
|
||||
|
||||
$this->alert->success(trans('base.api.index.keypair_created'))->flash();
|
||||
|
||||
return redirect()->route('account.api');
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an account API key from the Panel via an AJAX request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $identifier
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function revoke(Request $request, string $identifier): Response
|
||||
{
|
||||
$this->repository->deleteAccountKey($request->user(), $identifier);
|
||||
|
||||
return response('', 204);
|
||||
}
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Base;
|
||||
|
||||
use Illuminate\View\View;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Pterodactyl\Models\ApiKey;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Prologue\Alerts\AlertsMessageBag;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Services\Api\KeyCreationService;
|
||||
use Pterodactyl\Http\Requests\Base\CreateClientApiKeyRequest;
|
||||
use Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface;
|
||||
|
||||
class ClientApiController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var \Prologue\Alerts\AlertsMessageBag
|
||||
*/
|
||||
private $alert;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Api\KeyCreationService
|
||||
*/
|
||||
private $creationService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* ClientApiController constructor.
|
||||
*
|
||||
* @param \Prologue\Alerts\AlertsMessageBag $alert
|
||||
* @param \Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface $repository
|
||||
* @param \Pterodactyl\Services\Api\KeyCreationService $creationService
|
||||
*/
|
||||
public function __construct(AlertsMessageBag $alert, ApiKeyRepositoryInterface $repository, KeyCreationService $creationService)
|
||||
{
|
||||
$this->alert = $alert;
|
||||
$this->creationService = $creationService;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all of the API keys available to this user.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(Request $request): View
|
||||
{
|
||||
return view('base.api.index', [
|
||||
'keys' => $this->repository->getAccountKeys($request->user()),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render UI to allow creation of an API key.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
return view('base.api.new');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the API key and return the user to the key listing page.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Base\CreateClientApiKeyRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
*/
|
||||
public function store(CreateClientApiKeyRequest $request): RedirectResponse
|
||||
{
|
||||
$allowedIps = null;
|
||||
if (! is_null($request->input('allowed_ips'))) {
|
||||
$allowedIps = json_encode(explode(PHP_EOL, $request->input('allowed_ips')));
|
||||
}
|
||||
|
||||
$this->creationService->setKeyType(ApiKey::TYPE_ACCOUNT)->handle([
|
||||
'memo' => $request->input('memo'),
|
||||
'allowed_ips' => $allowedIps,
|
||||
'user_id' => $request->user()->id,
|
||||
]);
|
||||
|
||||
$this->alert->success('A new client API key has been generated for your account.')->flash();
|
||||
|
||||
return redirect()->route('account.api');
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a client's API key from the panel.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param $identifier
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function delete(Request $request, $identifier): Response
|
||||
{
|
||||
$this->repository->deleteAccountKey($request->user(), $identifier);
|
||||
|
||||
return response('', 204);
|
||||
}
|
||||
}
|
43
app/Http/Controllers/Base/LocaleController.php
Normal file
43
app/Http/Controllers/Base/LocaleController.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Base;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Translation\Translator;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
|
||||
class LocaleController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var \Illuminate\Translation\Translator
|
||||
*/
|
||||
private $translator;
|
||||
|
||||
/**
|
||||
* LocaleController constructor.
|
||||
*
|
||||
* @param \Illuminate\Translation\Translator $translator
|
||||
*/
|
||||
public function __construct(Translator $translator)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns translation data given a specific locale and namespace.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $locale
|
||||
* @param string $namespace
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function __invoke(Request $request, string $locale, string $namespace)
|
||||
{
|
||||
$data = $this->translator->getLoader()->load($locale, str_replace('.', '/', $namespace));
|
||||
|
||||
return JsonResponse::create($data, 200, [
|
||||
'E-Tag' => md5(json_encode($data)),
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,134 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Base;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Prologue\Alerts\AlertsMessageBag;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Services\Users\TwoFactorSetupService;
|
||||
use Pterodactyl\Services\Users\ToggleTwoFactorService;
|
||||
use Illuminate\Contracts\Config\Repository as ConfigRepository;
|
||||
use Pterodactyl\Contracts\Repository\SessionRepositoryInterface;
|
||||
use Pterodactyl\Exceptions\Service\User\TwoFactorAuthenticationTokenInvalid;
|
||||
|
||||
class SecurityController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var \Prologue\Alerts\AlertsMessageBag
|
||||
*/
|
||||
protected $alert;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Config\Repository
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\SessionRepositoryInterface
|
||||
*/
|
||||
protected $repository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Users\ToggleTwoFactorService
|
||||
*/
|
||||
protected $toggleTwoFactorService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Users\TwoFactorSetupService
|
||||
*/
|
||||
protected $twoFactorSetupService;
|
||||
|
||||
/**
|
||||
* SecurityController constructor.
|
||||
*
|
||||
* @param \Prologue\Alerts\AlertsMessageBag $alert
|
||||
* @param \Illuminate\Contracts\Config\Repository $config
|
||||
* @param \Pterodactyl\Contracts\Repository\SessionRepositoryInterface $repository
|
||||
* @param \Pterodactyl\Services\Users\ToggleTwoFactorService $toggleTwoFactorService
|
||||
* @param \Pterodactyl\Services\Users\TwoFactorSetupService $twoFactorSetupService
|
||||
*/
|
||||
public function __construct(
|
||||
AlertsMessageBag $alert,
|
||||
ConfigRepository $config,
|
||||
SessionRepositoryInterface $repository,
|
||||
ToggleTwoFactorService $toggleTwoFactorService,
|
||||
TwoFactorSetupService $twoFactorSetupService
|
||||
) {
|
||||
$this->alert = $alert;
|
||||
$this->config = $config;
|
||||
$this->repository = $repository;
|
||||
$this->toggleTwoFactorService = $toggleTwoFactorService;
|
||||
$this->twoFactorSetupService = $twoFactorSetupService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return information about the user's two-factor authentication status. If not enabled setup their
|
||||
* secret and return information to allow the user to proceede with setup.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
if ($request->user()->use_totp) {
|
||||
return JsonResponse::create([
|
||||
'enabled' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
$response = $this->twoFactorSetupService->handle($request->user());
|
||||
|
||||
return JsonResponse::create([
|
||||
'enabled' => false,
|
||||
'qr_image' => $response,
|
||||
'secret' => '',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that 2FA token received is valid and will work on the account.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$this->toggleTwoFactorService->handle($request->user(), $request->input('token') ?? '');
|
||||
} catch (TwoFactorAuthenticationTokenInvalid $exception) {
|
||||
$error = true;
|
||||
}
|
||||
|
||||
return JsonResponse::create([
|
||||
'success' => ! isset($error),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables TOTP on an account.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function delete(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$this->toggleTwoFactorService->handle($request->user(), $request->input('token') ?? '', false);
|
||||
} catch (TwoFactorAuthenticationTokenInvalid $exception) {
|
||||
$error = true;
|
||||
}
|
||||
|
||||
return JsonResponse::create([
|
||||
'success' => ! isset($error),
|
||||
]);
|
||||
}
|
||||
}
|
@ -102,6 +102,6 @@ class ActionController extends Controller
|
||||
$node = Node::findOrFail($nodeId);
|
||||
|
||||
// Manually as getConfigurationAsJson() returns it in correct format already
|
||||
return response($node->getConfigurationAsJson())->header('Content-Type', 'text/json');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
40
app/Http/Middleware/Admin/Servers/ServerInstalled.php
Normal file
40
app/Http/Middleware/Admin/Servers/ServerInstalled.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Middleware\Admin\Servers;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
class ServerInstalled
|
||||
{
|
||||
/**
|
||||
* Checks that the server is installed before allowing access through the route.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
/** @var \Pterodactyl\Models\Server|null $server */
|
||||
$server = $request->route()->parameter('server');
|
||||
|
||||
if (! $server instanceof Server) {
|
||||
throw new NotFoundHttpException(
|
||||
'No server resource was located in the request parameters.'
|
||||
);
|
||||
}
|
||||
|
||||
if ($server->installed !== 1) {
|
||||
throw new HttpException(
|
||||
Response::HTTP_FORBIDDEN, 'Access to this resource is not allowed due to the current installation state.'
|
||||
);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
@ -6,8 +6,11 @@ use Closure;
|
||||
use stdClass;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Pterodactyl\Events\Auth\FailedCaptcha;
|
||||
use Illuminate\Contracts\Config\Repository;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class VerifyReCaptcha
|
||||
{
|
||||
@ -16,14 +19,21 @@ class VerifyReCaptcha
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Events\Dispatcher
|
||||
*/
|
||||
private $dispatcher;
|
||||
|
||||
/**
|
||||
* VerifyReCaptcha constructor.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Events\Dispatcher $dispatcher
|
||||
* @param \Illuminate\Contracts\Config\Repository $config
|
||||
*/
|
||||
public function __construct(Repository $config)
|
||||
public function __construct(Dispatcher $dispatcher, Repository $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->dispatcher = $dispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,10 +67,15 @@ class VerifyReCaptcha
|
||||
}
|
||||
}
|
||||
|
||||
// Emit an event and return to the previous view with an error (only the captcha error will be shown!)
|
||||
event(new FailedCaptcha($request->ip(), (! isset($result) ?: object_get($result, 'hostname'))));
|
||||
$this->dispatcher->dispatch(
|
||||
new FailedCaptcha(
|
||||
$request->ip(), ! empty($result) ? ($result->hostname ?? null) : null
|
||||
)
|
||||
);
|
||||
|
||||
return redirect()->back()->withErrors(['g-recaptcha-response' => trans('strings.captcha_invalid')])->withInput();
|
||||
throw new HttpException(
|
||||
Response::HTTP_BAD_REQUEST, 'Failed to validate reCAPTCHA data.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace Pterodactyl\Http\Requests\Admin;
|
||||
|
||||
use Pterodactyl\Models\User;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class UserFormRequest extends AdminFormRequest
|
||||
{
|
||||
@ -12,16 +13,16 @@ class UserFormRequest extends AdminFormRequest
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = collect(User::getRules());
|
||||
if ($this->method() === 'PATCH') {
|
||||
$rules = collect(User::getRulesForUpdate($this->route()->parameter('user')))->merge([
|
||||
'ignore_connection_error' => ['sometimes', 'nullable', 'boolean'],
|
||||
]);
|
||||
}
|
||||
|
||||
return $rules->only([
|
||||
'email', 'username', 'name_first', 'name_last', 'password',
|
||||
'language', 'ignore_connection_error', 'root_admin',
|
||||
return Collection::make(
|
||||
User::getRulesForUpdate($this->route()->parameter('user'))
|
||||
)->only([
|
||||
'email',
|
||||
'username',
|
||||
'name_first',
|
||||
'name_last',
|
||||
'password',
|
||||
'language',
|
||||
'root_admin',
|
||||
])->toArray();
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ class DeleteDatabaseRequest extends ClientApiRequest implements ClientPermission
|
||||
*/
|
||||
public function permission(): string
|
||||
{
|
||||
return 'delete-database';
|
||||
return 'database.delete';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -12,6 +12,6 @@ class GetDatabasesRequest extends ClientApiRequest implements ClientPermissionsR
|
||||
*/
|
||||
public function permission(): string
|
||||
{
|
||||
return 'view-databases';
|
||||
return 'database.read';
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,6 @@ class RotatePasswordRequest extends ClientApiRequest
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return $this->user()->can('reset-db-password', $this->getModel(Server::class));
|
||||
return $this->user()->can('database.update', $this->getModel(Server::class));
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ class StoreDatabaseRequest extends ClientApiRequest implements ClientPermissions
|
||||
*/
|
||||
public function permission(): string
|
||||
{
|
||||
return 'create-database';
|
||||
return 'database.create';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -12,7 +12,7 @@ class CopyFileRequest extends ClientApiRequest implements ClientPermissionsReque
|
||||
*/
|
||||
public function permission(): string
|
||||
{
|
||||
return 'copy-files';
|
||||
return 'file.create';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,7 +14,7 @@ class CreateFolderRequest extends ClientApiRequest
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return $this->user()->can('create-files', $this->getModel(Server::class));
|
||||
return $this->user()->can('file.create', $this->getModel(Server::class));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -12,7 +12,7 @@ class DeleteFileRequest extends ClientApiRequest implements ClientPermissionsReq
|
||||
*/
|
||||
public function permission(): string
|
||||
{
|
||||
return 'delete-files';
|
||||
return 'file.delete';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,6 +15,6 @@ class DownloadFileRequest extends ClientApiRequest
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return $this->user()->can('download-files', $this->getModel(Server::class));
|
||||
return $this->user()->can('file.read', $this->getModel(Server::class));
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ class GetFileContentsRequest extends ClientApiRequest implements ClientPermissio
|
||||
*/
|
||||
public function permission(): string
|
||||
{
|
||||
return 'edit-files';
|
||||
return 'file.read';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,7 +15,7 @@ class ListFilesRequest extends ClientApiRequest
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return $this->user()->can('list-files', $this->getModel(Server::class));
|
||||
return $this->user()->can('file.read', $this->getModel(Server::class));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,7 +15,7 @@ class RenameFileRequest extends ClientApiRequest implements ClientPermissionsReq
|
||||
*/
|
||||
public function permission(): string
|
||||
{
|
||||
return 'move-files';
|
||||
return 'file.update';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,7 +16,7 @@ class WriteFileContentRequest extends ClientApiRequest implements ClientPermissi
|
||||
*/
|
||||
public function permission(): string
|
||||
{
|
||||
return 'save-files';
|
||||
return 'file.create';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,6 +15,6 @@ class GetNetworkRequest extends ClientApiRequest
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return $this->user()->can('view-allocations', $this->getModel(Server::class));
|
||||
return $this->user()->can('allocation.read', $this->getModel(Server::class));
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ class SendCommandRequest extends GetServerRequest
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return $this->user()->can('send-command', $this->getModel(Server::class));
|
||||
return $this->user()->can('control.console', $this->getModel(Server::class));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,7 +14,7 @@ class SendPowerRequest extends ClientApiRequest
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return $this->user()->can('power-' . $this->input('signal', '_undefined'), $this->getModel(Server::class));
|
||||
return $this->user()->can('control.' . $this->input('signal', ''), $this->getModel(Server::class));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Api\Client\Servers\Settings;
|
||||
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Contracts\Http\ClientPermissionsRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
|
||||
|
||||
class RenameServerRequest extends ClientApiRequest implements ClientPermissionsRequest
|
||||
{
|
||||
/**
|
||||
* Returns the permissions string indicating which permission should be used to
|
||||
* validate that the authenticated user has permission to perform this action aganist
|
||||
* the given resource (server).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function permission(): string
|
||||
{
|
||||
return 'settings.rename';
|
||||
}
|
||||
|
||||
/**
|
||||
* The rules to apply when validating this request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => Server::getRules()['name'],
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Api\Client\Servers\Subusers;
|
||||
|
||||
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
|
||||
|
||||
class GetSubuserRequest extends ClientApiRequest
|
||||
{
|
||||
/**
|
||||
* Confirm that a user is able to view subusers for the specified server.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return $this->user()->can('user.read', $this->route()->parameter('server'));
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Base;
|
||||
|
||||
use Pterodactyl\Models\User;
|
||||
use Pterodactyl\Http\Requests\FrontendUserFormRequest;
|
||||
use Pterodactyl\Exceptions\Http\Base\InvalidPasswordProvidedException;
|
||||
|
||||
class AccountDataFormRequest extends FrontendUserFormRequest
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
* @throws \Pterodactyl\Exceptions\Http\Base\InvalidPasswordProvidedException
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
if (! parent::authorize()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify password matches when changing password or email.
|
||||
if (in_array($this->input('do_action'), ['password', 'email'])) {
|
||||
if (! password_verify($this->input('current_password'), $this->user()->password)) {
|
||||
throw new InvalidPasswordProvidedException(trans('validation.internal.invalid_password'));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$modelRules = User::getRulesForUpdate($this->user());
|
||||
|
||||
switch ($this->input('do_action')) {
|
||||
case 'email':
|
||||
$rules = [
|
||||
'new_email' => array_get($modelRules, 'email'),
|
||||
];
|
||||
break;
|
||||
case 'password':
|
||||
$rules = [
|
||||
'new_password' => 'required|confirmed|string|min:8',
|
||||
'new_password_confirmation' => 'required',
|
||||
];
|
||||
break;
|
||||
case 'identity':
|
||||
$rules = [
|
||||
'name_first' => array_get($modelRules, 'name_first'),
|
||||
'name_last' => array_get($modelRules, 'name_last'),
|
||||
'username' => array_get($modelRules, 'username'),
|
||||
'language' => array_get($modelRules, 'language'),
|
||||
];
|
||||
break;
|
||||
default:
|
||||
abort(422);
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Base;
|
||||
|
||||
use Exception;
|
||||
use IPTools\Network;
|
||||
use Pterodactyl\Http\Requests\FrontendUserFormRequest;
|
||||
|
||||
class ApiKeyFormRequest extends FrontendUserFormRequest
|
||||
{
|
||||
/**
|
||||
* Rules applied to data passed in this request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$this->parseAllowedIntoArray();
|
||||
|
||||
return [
|
||||
'memo' => 'required|nullable|string|max:500',
|
||||
'permissions' => 'sometimes|present|array',
|
||||
'admin_permissions' => 'sometimes|present|array',
|
||||
'allowed_ips' => 'present',
|
||||
'allowed_ips.*' => 'sometimes|string',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the string of allowed IPs into an array.
|
||||
*/
|
||||
protected function parseAllowedIntoArray()
|
||||
{
|
||||
$loop = [];
|
||||
if (! empty($this->input('allowed_ips'))) {
|
||||
foreach (explode(PHP_EOL, $this->input('allowed_ips')) as $ip) {
|
||||
$loop[] = trim($ip);
|
||||
}
|
||||
}
|
||||
|
||||
$this->merge(['allowed_ips' => $loop]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run additional validation rules on the request to ensure all of the data is good.
|
||||
*
|
||||
* @param \Illuminate\Validation\Validator $validator
|
||||
*/
|
||||
public function withValidator($validator)
|
||||
{
|
||||
$validator->after(function ($validator) {
|
||||
/* @var \Illuminate\Validation\Validator $validator */
|
||||
if (empty($this->input('permissions')) && empty($this->input('admin_permissions'))) {
|
||||
$validator->errors()->add('permissions', 'At least one permission must be selected.');
|
||||
}
|
||||
|
||||
foreach ($this->input('allowed_ips') as $ip) {
|
||||
$ip = trim($ip);
|
||||
|
||||
try {
|
||||
Network::parse($ip);
|
||||
} catch (Exception $ex) {
|
||||
$validator->errors()->add('allowed_ips', 'Could not parse IP ' . $ip . ' because it is in an invalid format.');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Base;
|
||||
|
||||
use Pterodactyl\Http\Requests\FrontendUserFormRequest;
|
||||
|
||||
class CreateClientApiKeyRequest extends FrontendUserFormRequest
|
||||
{
|
||||
/**
|
||||
* Validate the data being provided.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'memo' => 'required|string|max:255',
|
||||
'allowed_ips' => 'nullable|string',
|
||||
];
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Base;
|
||||
|
||||
use Pterodactyl\Http\Requests\FrontendUserFormRequest;
|
||||
|
||||
class StoreAccountKeyRequest extends FrontendUserFormRequest
|
||||
{
|
||||
/**
|
||||
* Rules to validate the request input against before storing
|
||||
* an account API key.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'memo' => 'required|nullable|string|max:500',
|
||||
'allowed_ips' => 'present',
|
||||
'allowed_ips.*' => 'sometimes|string',
|
||||
];
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Server\Database;
|
||||
|
||||
use Pterodactyl\Http\Requests\Server\ServerFormRequest;
|
||||
|
||||
class DeleteServerDatabaseRequest extends ServerFormRequest
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
if (! parent::authorize()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return config('pterodactyl.client_features.databases.enabled');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the user permission to validate this request against.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function permission(): string
|
||||
{
|
||||
return 'delete-database';
|
||||
}
|
||||
|
||||
/**
|
||||
* Rules to validate this request against.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Server\Database;
|
||||
|
||||
use Pterodactyl\Http\Requests\Server\ServerFormRequest;
|
||||
|
||||
class StoreServerDatabaseRequest extends ServerFormRequest
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
if (! parent::authorize()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return config('pterodactyl.client_features.databases.enabled');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the user permission to validate this request against.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function permission(): string
|
||||
{
|
||||
return 'create-database';
|
||||
}
|
||||
|
||||
/**
|
||||
* Rules to validate this request against.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'database' => 'required|string|min:1',
|
||||
'remote' => 'required|string|regex:/^[0-9%.]{1,15}$/',
|
||||
];
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Server;
|
||||
|
||||
class ScheduleCreationFormRequest extends ServerFormRequest
|
||||
{
|
||||
/**
|
||||
* Permission to validate this request against.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function permission(): string
|
||||
{
|
||||
if ($this->method() === 'PATCH') {
|
||||
return 'edit-schedule';
|
||||
}
|
||||
|
||||
return 'create-schedule';
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation rules to apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'name' => 'nullable|string|max:255',
|
||||
'cron_day_of_week' => 'required|string',
|
||||
'cron_day_of_month' => 'required|string',
|
||||
'cron_hour' => 'required|string',
|
||||
'cron_minute' => 'required|string',
|
||||
'tasks' => 'sometimes|array|size:4',
|
||||
'tasks.time_value' => 'required_with:tasks|max:5',
|
||||
'tasks.time_interval' => 'required_with:tasks|max:5',
|
||||
'tasks.action' => 'required_with:tasks|max:5',
|
||||
'tasks.payload' => 'required_with:tasks|max:5',
|
||||
'tasks.time_value.*' => 'numeric|between:0,59',
|
||||
'tasks.time_interval.*' => 'string|in:s,m',
|
||||
'tasks.action.*' => 'string|in:power,command',
|
||||
'tasks.payload.*' => 'string',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the request into a format that can be used by the application.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function normalize()
|
||||
{
|
||||
return $this->only('name', 'cron_day_of_week', 'cron_day_of_month', 'cron_hour', 'cron_minute');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tasks provided in the request that are associated with this schedule.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function getTasks()
|
||||
{
|
||||
$restructured = [];
|
||||
foreach (array_get($this->all(), 'tasks', []) as $key => $values) {
|
||||
for ($i = 0; $i < count($values); $i++) {
|
||||
$restructured[$i][$key] = $values[$i];
|
||||
}
|
||||
}
|
||||
|
||||
return empty($restructured) ? null : $restructured;
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Server;
|
||||
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Http\Requests\FrontendUserFormRequest;
|
||||
|
||||
abstract class ServerFormRequest extends FrontendUserFormRequest
|
||||
{
|
||||
/**
|
||||
* Return the user permission to validate this request against.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function permission(): string;
|
||||
|
||||
/**
|
||||
* Determine if a user has permission to access this resource.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
if (! parent::authorize()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->user()->can($this->permission(), $this->getServer());
|
||||
}
|
||||
|
||||
public function getServer(): Server
|
||||
{
|
||||
return $this->attributes->get('server');
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
<?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::getRules()['name'],
|
||||
];
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Server\Subuser;
|
||||
|
||||
use Pterodactyl\Http\Requests\Server\ServerFormRequest;
|
||||
|
||||
class SubuserStoreFormRequest extends ServerFormRequest
|
||||
{
|
||||
/**
|
||||
* Return the user permission to validate this request against.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function permission(): string
|
||||
{
|
||||
return 'create-subuser';
|
||||
}
|
||||
|
||||
/**
|
||||
* The rules to validate this request submission against.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'email' => 'required|email',
|
||||
'permissions' => 'sometimes|array',
|
||||
];
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Server\Subuser;
|
||||
|
||||
use Pterodactyl\Http\Requests\Server\ServerFormRequest;
|
||||
|
||||
class SubuserUpdateFormRequest extends ServerFormRequest
|
||||
{
|
||||
/**
|
||||
* Return the user permission to validate this request against.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function permission(): string
|
||||
{
|
||||
return 'edit-subuser';
|
||||
}
|
||||
|
||||
/**
|
||||
* The rules to validate this request submission against.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'permissions' => 'present|array',
|
||||
];
|
||||
}
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Server;
|
||||
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Illuminate\Contracts\Config\Repository;
|
||||
use Pterodactyl\Exceptions\Http\Server\FileSizeTooLargeException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Pterodactyl\Contracts\Repository\Daemon\FileRepositoryInterface;
|
||||
use Pterodactyl\Exceptions\Http\Server\FileTypeNotEditableException;
|
||||
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
|
||||
class UpdateFileContentsFormRequest extends ServerFormRequest
|
||||
{
|
||||
/**
|
||||
* Return the permission string to validate this request against.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function permission(): string
|
||||
{
|
||||
return 'edit-files';
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize a request to edit a file.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Http\Server\FileSizeTooLargeException
|
||||
* @throws \Pterodactyl\Exceptions\Http\Server\FileTypeNotEditableException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
if (! parent::authorize()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$server = $this->attributes->get('server');
|
||||
$token = $this->attributes->get('server_token');
|
||||
|
||||
return $this->checkFileCanBeEdited($server, $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given file can be edited by a user on this server.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @param string $token
|
||||
* @return bool
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Http\Server\FileSizeTooLargeException
|
||||
* @throws \Pterodactyl\Exceptions\Http\Server\FileTypeNotEditableException
|
||||
*/
|
||||
private function checkFileCanBeEdited($server, $token)
|
||||
{
|
||||
$config = app()->make(Repository::class);
|
||||
$repository = app()->make(FileRepositoryInterface::class);
|
||||
|
||||
try {
|
||||
$stats = $repository->setServer($server)->setToken($token)->getFileStat($this->route()->parameter('file'));
|
||||
} catch (RequestException $exception) {
|
||||
switch ($exception->getCode()) {
|
||||
case 404:
|
||||
throw new NotFoundHttpException;
|
||||
default:
|
||||
throw new DaemonConnectionException($exception);
|
||||
}
|
||||
}
|
||||
|
||||
if ((! $stats->file && ! $stats->symlink) || ! in_array($stats->mime, $config->get('pterodactyl.files.editable'))) {
|
||||
throw new FileTypeNotEditableException(trans('server.files.exceptions.invalid_mime'));
|
||||
}
|
||||
|
||||
if ($stats->size > $config->get('pterodactyl.files.max_edit_size')) {
|
||||
throw new FileSizeTooLargeException(trans('server.files.exceptions.max_size'));
|
||||
}
|
||||
|
||||
$this->attributes->set('file_stats', $stats);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Server;
|
||||
|
||||
use Pterodactyl\Http\Requests\FrontendUserFormRequest;
|
||||
use Pterodactyl\Contracts\Repository\EggVariableRepositoryInterface;
|
||||
|
||||
class UpdateStartupParametersFormRequest extends FrontendUserFormRequest
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $validationAttributes = [];
|
||||
|
||||
/**
|
||||
* Determine if the user has permission to update the startup parameters
|
||||
* for this server.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
if (! parent::authorize()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->user()->can('edit-startup', $this->attributes->get('server'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that all of the required fields were passed and that the environment
|
||||
* variable values meet the defined criteria for those fields.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$repository = $this->container->make(EggVariableRepositoryInterface::class);
|
||||
|
||||
$variables = $repository->getEditableVariables($this->attributes->get('server')->egg_id);
|
||||
$rules = $variables->mapWithKeys(function ($variable) {
|
||||
$this->validationAttributes['environment.' . $variable->env_variable] = $variable->name;
|
||||
|
||||
return ['environment.' . $variable->env_variable => $variable->rules];
|
||||
})->toArray();
|
||||
|
||||
return array_merge($rules, [
|
||||
'environment' => 'required|array',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return attributes to provide better naming conventions for error messages.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes()
|
||||
{
|
||||
return $this->validationAttributes;
|
||||
}
|
||||
}
|
@ -30,5 +30,13 @@ class AssetComposer
|
||||
public function compose(View $view)
|
||||
{
|
||||
$view->with('asset', $this->assetHashService);
|
||||
$view->with('siteConfiguration', [
|
||||
'name' => config('app.name') ?? 'Pterodactyl',
|
||||
'locale' => config('app.locale') ?? 'en',
|
||||
'recaptcha' => [
|
||||
'enabled' => config('recaptcha.enabled', false),
|
||||
'siteKey' => config('recaptcha.website_key') ?? '',
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,22 @@
|
||||
|
||||
namespace Pterodactyl\Models;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $node_id
|
||||
* @property string $ip
|
||||
* @property string|null $ip_alias
|
||||
* @property int $port
|
||||
* @property int|null $server_id
|
||||
* @property \Carbon\Carbon|null $created_at
|
||||
* @property \Carbon\Carbon|null $updated_at
|
||||
*
|
||||
* @property string $alias
|
||||
* @property bool $has_alias
|
||||
*
|
||||
* @property \Pterodactyl\Models\Server|null $server
|
||||
* @property \Pterodactyl\Models\Node $node
|
||||
*/
|
||||
class Allocation extends Validable
|
||||
{
|
||||
/**
|
||||
|
@ -2,6 +2,19 @@
|
||||
|
||||
namespace Pterodactyl\Models;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $uuid
|
||||
* @property string $author
|
||||
* @property string $name
|
||||
* @property string $description
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
*
|
||||
* @property \Illuminate\Support\Collection|\Pterodactyl\Models\Server[] $servers
|
||||
* @property \Illuminate\Support\Collection|\Pterodactyl\Models\Egg[] $eggs
|
||||
* @property \Illuminate\Support\Collection|\Pterodactyl\Models\Pack[] $packs
|
||||
*/
|
||||
class Nest extends Validable
|
||||
{
|
||||
/**
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pterodactyl\Models;
|
||||
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Pterodactyl\Models\Traits\Searchable;
|
||||
|
||||
@ -151,71 +152,58 @@ class Node extends Validable
|
||||
/**
|
||||
* Returns the configuration in JSON format.
|
||||
*
|
||||
* @param bool $pretty
|
||||
* @return string
|
||||
*/
|
||||
public function getConfigurationAsJson($pretty = false)
|
||||
public function getYamlConfiguration()
|
||||
{
|
||||
$config = [
|
||||
'web' => [
|
||||
'debug' => false,
|
||||
'api' => [
|
||||
'host' => '0.0.0.0',
|
||||
'listen' => $this->daemonListen,
|
||||
'port' => $this->daemonListen,
|
||||
'ssl' => [
|
||||
'enabled' => (! $this->behind_proxy && $this->scheme === 'https'),
|
||||
'certificate' => '/etc/letsencrypt/live/' . $this->fqdn . '/fullchain.pem',
|
||||
'cert' => '/etc/letsencrypt/live/' . $this->fqdn . '/fullchain.pem',
|
||||
'key' => '/etc/letsencrypt/live/' . $this->fqdn . '/privkey.pem',
|
||||
],
|
||||
'upload_limit' => $this->upload_size,
|
||||
],
|
||||
'system' => [
|
||||
'data' => $this->daemonBase,
|
||||
'username' => 'pterodactyl',
|
||||
'timezone_path' => '/etc/timezone',
|
||||
'set_permissions_on_boot' => true,
|
||||
'detect_clean_exit_as_crash' => false,
|
||||
'sftp' => [
|
||||
'use_internal' => true,
|
||||
'disable_disk_checking' => false,
|
||||
'bind_address' => '0.0.0.0',
|
||||
'bind_port' => $this->daemonSFTP,
|
||||
'read_only' => false,
|
||||
],
|
||||
],
|
||||
'docker' => [
|
||||
'container' => [
|
||||
'user' => null,
|
||||
],
|
||||
'network' => [
|
||||
'interface' => '172.18.0.1',
|
||||
'name' => 'pterodactyl_nw',
|
||||
'driver' => 'bridge',
|
||||
],
|
||||
'update_images' => true,
|
||||
'socket' => '/var/run/docker.sock',
|
||||
'autoupdate_images' => true,
|
||||
'timezone_path' => '/etc/timezone',
|
||||
],
|
||||
'filesystem' => [
|
||||
'server_logs' => '/tmp/pterodactyl',
|
||||
'disk_check_timeout' => 30,
|
||||
'throttles' => [
|
||||
'kill_at_count' => 5,
|
||||
'decay' => 10,
|
||||
'bytes' => 4096,
|
||||
'check_interval' => 100,
|
||||
],
|
||||
'internals' => [
|
||||
'disk_use_seconds' => 30,
|
||||
'set_permissions_on_boot' => true,
|
||||
'throttle' => [
|
||||
'enabled' => true,
|
||||
'kill_at_count' => 5,
|
||||
'decay' => 10,
|
||||
'lines' => 1000,
|
||||
'check_interval_ms' => 100,
|
||||
],
|
||||
],
|
||||
'sftp' => [
|
||||
'path' => $this->daemonBase,
|
||||
'ip' => '0.0.0.0',
|
||||
'port' => $this->daemonSFTP,
|
||||
'keypair' => [
|
||||
'bits' => 2048,
|
||||
'e' => 65537,
|
||||
],
|
||||
],
|
||||
'logger' => [
|
||||
'path' => 'logs/',
|
||||
'src' => false,
|
||||
'level' => 'info',
|
||||
'period' => '1d',
|
||||
'count' => 3,
|
||||
],
|
||||
'remote' => [
|
||||
'base' => route('index'),
|
||||
],
|
||||
'uploads' => [
|
||||
'size_limit' => $this->upload_size,
|
||||
],
|
||||
'keys' => [$this->daemonSecret],
|
||||
'remote' => route('index'),
|
||||
'token' => $this->daemonSecret,
|
||||
];
|
||||
|
||||
return json_encode($config, ($pretty) ? JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT : JSON_UNESCAPED_SLASHES);
|
||||
return Yaml::dump($config, 4, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace Pterodactyl\Models;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class Permission extends Validable
|
||||
{
|
||||
/**
|
||||
@ -48,12 +50,130 @@ class Permission extends Validable
|
||||
'permission' => 'required|string',
|
||||
];
|
||||
|
||||
/**
|
||||
* All of the permissions available on the system. You should use self::permissions()
|
||||
* to retrieve them, and not directly access this array as it is subject to change.
|
||||
*
|
||||
* @var array
|
||||
* @see \Pterodactyl\Models\Permission::permissions()
|
||||
*/
|
||||
protected static $permissions = [
|
||||
'websocket' => [
|
||||
// Allows the user to connect to the server websocket, this will give them
|
||||
// access to view the console output as well as realtime server stats (CPU
|
||||
// and Memory usage).
|
||||
'*',
|
||||
],
|
||||
|
||||
'control' => [
|
||||
// Allows the user to send data to the server console process. A user with this
|
||||
// permission will not be able to stop the server directly by issuing the specified
|
||||
// stop command for the Egg, however depending on plugins and server configuration
|
||||
// they may still be able to control the server power state.
|
||||
'console', // power.send-command
|
||||
|
||||
// Allows the user to start/stop/restart/kill the server process.
|
||||
'start', // power.power-start
|
||||
'stop', // power.power-stop
|
||||
'restart', // power.power-restart
|
||||
'kill', // power.power-kill
|
||||
],
|
||||
|
||||
'user' => [
|
||||
// Allows a user to create a new user assigned to the server. They will not be able
|
||||
// to assign any permissions they do not already have on their account as well.
|
||||
'create', // subuser.create-subuser
|
||||
'read', // subuser.list-subusers, subuser.view-subuser
|
||||
'update', // subuser.edit-subuser
|
||||
'delete', // subuser.delete-subuser
|
||||
],
|
||||
|
||||
'file' => [
|
||||
// Allows a user to create additional files and folders either via the Panel,
|
||||
// or via a direct upload.
|
||||
'create', // files.create-files, files.upload-files, files.copy-files, files.move-files
|
||||
|
||||
// Allows a user to view the contents of a directory as well as read the contents
|
||||
// of a given file. A user with this permission will be able to download files
|
||||
// as well.
|
||||
'read', // files.list-files, files.download-files
|
||||
|
||||
// Allows a user to update the contents of an existing file or directory.
|
||||
'update', // files.edit-files, files.save-files
|
||||
|
||||
// Allows a user to delete a file or directory.
|
||||
'delete', // files.delete-files
|
||||
|
||||
// Allows a user to archive the contents of a directory as well as decompress existing
|
||||
// archives on the system.
|
||||
'archive', // files.compress-files, files.decompress-files
|
||||
|
||||
// Allows the user to connect and manage server files using their account
|
||||
// credentials and a SFTP client.
|
||||
'sftp', // files.access-sftp
|
||||
],
|
||||
|
||||
// Controls permissions for editing or viewing a server's allocations.
|
||||
'allocation' => [
|
||||
'read', // server.view-allocations
|
||||
'update', // server.edit-allocation
|
||||
],
|
||||
|
||||
// Controls permissions for editing or viewing a server's startup parameters.
|
||||
'startup' => [
|
||||
'read', // server.view-startup
|
||||
'update', // server.edit-startup
|
||||
],
|
||||
|
||||
'database' => [
|
||||
// Allows a user to create a new database for a server.
|
||||
'create', // database.create-database
|
||||
|
||||
// Allows a user to view the databases associated with the server. If they do not also
|
||||
// have the view_password permission they will only be able to see the connection address
|
||||
// and the name of the user.
|
||||
'read', // database.view-databases
|
||||
|
||||
// Allows a user to rotate the password on a database instance. If the user does not
|
||||
// alow have the view_password permission they will not be able to see the updated password
|
||||
// anywhere, but it will still be rotated.
|
||||
'update', // database.reset-db-password
|
||||
|
||||
// Allows a user to delete a database instance.
|
||||
'delete', // database.delete-database
|
||||
|
||||
// Allows a user to view the password associated with a database instance for the
|
||||
// server. Note that a user without this permission may still be able to access these
|
||||
// credentials by viewing files or the console.
|
||||
'view_password', // database.reset-db-password
|
||||
],
|
||||
|
||||
'schedule' => [
|
||||
'create', // task.create-schedule
|
||||
'read', // task.view-schedule, task.list-schedules
|
||||
'update', // task.edit-schedule, task.queue-schedule, task.toggle-schedule
|
||||
'delete', // task.delete-schedule
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns all of the permissions available on the system for a user to
|
||||
* have when controlling a server.
|
||||
*
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public static function permissions(): Collection
|
||||
{
|
||||
return Collection::make(self::$permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of all permissions available for a user.
|
||||
*
|
||||
* @var array
|
||||
* @deprecated
|
||||
*/
|
||||
protected static $permissions = [
|
||||
protected static $deprecatedPermissions = [
|
||||
'power' => [
|
||||
'power-start' => 's:power:start',
|
||||
'power-stop' => 's:power:stop',
|
||||
@ -110,16 +230,17 @@ class Permission extends Validable
|
||||
*
|
||||
* @param bool $array
|
||||
* @return array|\Illuminate\Support\Collection
|
||||
* @deprecated
|
||||
*/
|
||||
public static function getPermissions($array = false)
|
||||
{
|
||||
if ($array) {
|
||||
return collect(self::$permissions)->mapWithKeys(function ($item) {
|
||||
return collect(self::$deprecatedPermissions)->mapWithKeys(function ($item) {
|
||||
return $item;
|
||||
})->all();
|
||||
}
|
||||
|
||||
return collect(self::$permissions);
|
||||
return collect(self::$deprecatedPermissions);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,7 +16,7 @@ use Znck\Eloquent\Traits\BelongsToThrough;
|
||||
* @property string $name
|
||||
* @property string $description
|
||||
* @property bool $skip_scripts
|
||||
* @property bool $suspended
|
||||
* @property int $suspended
|
||||
* @property int $owner_id
|
||||
* @property int $memory
|
||||
* @property int $swap
|
||||
@ -44,7 +44,7 @@ use Znck\Eloquent\Traits\BelongsToThrough;
|
||||
* @property \Pterodactyl\Models\Node $node
|
||||
* @property \Pterodactyl\Models\Nest $nest
|
||||
* @property \Pterodactyl\Models\Egg $egg
|
||||
* @property \Pterodactyl\Models\EggVariable[]|\Illuminate\Support\Collection $variables
|
||||
* @property \Pterodactyl\Models\ServerVariable[]|\Illuminate\Support\Collection $variables
|
||||
* @property \Pterodactyl\Models\Schedule[]|\Illuminate\Support\Collection $schedule
|
||||
* @property \Pterodactyl\Models\Database[]|\Illuminate\Support\Collection $databases
|
||||
* @property \Pterodactyl\Models\Location $location
|
||||
@ -170,6 +170,18 @@ class Server extends Validable
|
||||
return Schema::getColumnListing($this->getTable());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the format for server allocations when communicating with the Daemon.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAllocationMappings(): array
|
||||
{
|
||||
return $this->allocations->groupBy('ip')->map(function ($item) {
|
||||
return $item->pluck('port');
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
|
@ -4,6 +4,17 @@ namespace Pterodactyl\Models;
|
||||
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $user_id
|
||||
* @property int $server_id
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
*
|
||||
* @property \Pterodactyl\Models\User $user
|
||||
* @property \Pterodactyl\Models\Server $server
|
||||
* @property \Pterodactyl\Models\Permission[]|\Illuminate\Support\Collection $permissions
|
||||
*/
|
||||
class Subuser extends Validable
|
||||
{
|
||||
use Notifiable;
|
||||
|
@ -158,7 +158,7 @@ class User extends Validable implements
|
||||
'username' => 'required|between:1,255|unique:users,username',
|
||||
'name_first' => 'required|string|between:1,255',
|
||||
'name_last' => 'required|string|between:1,255',
|
||||
'password' => 'required|nullable|string',
|
||||
'password' => 'sometimes|nullable|string',
|
||||
'root_admin' => 'boolean',
|
||||
'language' => 'required|string',
|
||||
'use_totp' => 'boolean',
|
||||
@ -171,7 +171,7 @@ class User extends Validable implements
|
||||
*/
|
||||
public static function getRules()
|
||||
{
|
||||
$rules = self::getRules();
|
||||
$rules = parent::getRules();
|
||||
|
||||
$rules['language'][] = new In(array_keys((new self)->getAvailableLanguages()));
|
||||
$rules['username'][] = new Username;
|
||||
@ -216,7 +216,7 @@ class User extends Validable implements
|
||||
*/
|
||||
public function getNameAttribute()
|
||||
{
|
||||
return $this->name_first . ' ' . $this->name_last;
|
||||
return trim($this->name_first . ' ' . $this->name_last);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -31,27 +31,31 @@ class NodeRepository extends EloquentRepository implements NodeRepositoryInterfa
|
||||
*/
|
||||
public function getUsageStats(Node $node): array
|
||||
{
|
||||
$stats = $this->getBuilder()->select(
|
||||
$this->getBuilder()->raw('IFNULL(SUM(servers.memory), 0) as sum_memory, IFNULL(SUM(servers.disk), 0) as sum_disk')
|
||||
)->join('servers', 'servers.node_id', '=', 'nodes.id')->where('node_id', $node->id)->first();
|
||||
$stats = $this->getBuilder()
|
||||
->selectRaw('IFNULL(SUM(servers.memory), 0) as sum_memory, IFNULL(SUM(servers.disk), 0) as sum_disk')
|
||||
->join('servers', 'servers.node_id', '=', 'nodes.id')
|
||||
->where('node_id', '=', $node->id)
|
||||
->first();
|
||||
|
||||
return collect(['disk' => $stats->sum_disk, 'memory' => $stats->sum_memory])->mapWithKeys(function ($value, $key) use ($node) {
|
||||
$maxUsage = $node->{$key};
|
||||
if ($node->{$key . '_overallocate'} > 0) {
|
||||
$maxUsage = $node->{$key} * (1 + ($node->{$key . '_overallocate'} / 100));
|
||||
}
|
||||
return Collection::make(['disk' => $stats->sum_disk, 'memory' => $stats->sum_memory])
|
||||
->mapWithKeys(function ($value, $key) use ($node) {
|
||||
$maxUsage = $node->{$key};
|
||||
if ($node->{$key . '_overallocate'} > 0) {
|
||||
$maxUsage = $node->{$key} * (1 + ($node->{$key . '_overallocate'} / 100));
|
||||
}
|
||||
|
||||
$percent = ($value / $maxUsage) * 100;
|
||||
$percent = ($value / $maxUsage) * 100;
|
||||
|
||||
return [
|
||||
$key => [
|
||||
'value' => number_format($value),
|
||||
'max' => number_format($maxUsage),
|
||||
'percent' => $percent,
|
||||
'css' => ($percent <= self::THRESHOLD_PERCENTAGE_LOW) ? 'green' : (($percent > self::THRESHOLD_PERCENTAGE_MEDIUM) ? 'red' : 'yellow'),
|
||||
],
|
||||
];
|
||||
})->toArray();
|
||||
return [
|
||||
$key => [
|
||||
'value' => number_format($value),
|
||||
'max' => number_format($maxUsage),
|
||||
'percent' => $percent,
|
||||
'css' => ($percent <= self::THRESHOLD_PERCENTAGE_LOW) ? 'green' : (($percent > self::THRESHOLD_PERCENTAGE_MEDIUM) ? 'red' : 'yellow'),
|
||||
],
|
||||
];
|
||||
})
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -132,7 +136,12 @@ class NodeRepository extends EloquentRepository implements NodeRepositoryInterfa
|
||||
public function loadNodeAllocations(Node $node, bool $refresh = false): Node
|
||||
{
|
||||
$node->setRelation('allocations',
|
||||
$node->allocations()->orderByRaw('server_id IS NOT NULL DESC, server_id IS NULL')->orderByRaw('INET_ATON(ip) ASC')->orderBy('port', 'asc')->with('server:id,name')->paginate(50)
|
||||
$node->allocations()
|
||||
->orderByRaw('server_id IS NOT NULL DESC, server_id IS NULL')
|
||||
->orderByRaw('INET_ATON(ip) ASC')
|
||||
->orderBy('port', 'asc')
|
||||
->with('server:id,name')
|
||||
->paginate(50)
|
||||
);
|
||||
|
||||
return $node;
|
||||
|
@ -3,9 +3,9 @@
|
||||
namespace Pterodactyl\Repositories\Eloquent;
|
||||
|
||||
use Pterodactyl\Models\User;
|
||||
use Webmozart\Assert\Assert;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Pterodactyl\Repositories\Concerns\Searchable;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
@ -273,12 +273,16 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt
|
||||
*/
|
||||
public function getByUuid(string $uuid): Server
|
||||
{
|
||||
Assert::notEmpty($uuid, 'Expected non-empty string as first argument passed to ' . __METHOD__);
|
||||
|
||||
try {
|
||||
return $this->getBuilder()->with('nest', 'node')->where(function ($query) use ($uuid) {
|
||||
$query->where('uuidShort', $uuid)->orWhere('uuid', $uuid);
|
||||
})->firstOrFail($this->getColumns());
|
||||
/** @var \Pterodactyl\Models\Server $model */
|
||||
$model = $this->getBuilder()
|
||||
->with('nest', 'node')
|
||||
->where(function (Builder $query) use ($uuid) {
|
||||
$query->where('uuidShort', $uuid)->orWhere('uuid', $uuid);
|
||||
})
|
||||
->firstOrFail($this->getColumns());
|
||||
|
||||
return $model;
|
||||
} catch (ModelNotFoundException $exception) {
|
||||
throw new RecordNotFoundException;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace Pterodactyl\Repositories\Eloquent;
|
||||
|
||||
use Pterodactyl\Models\Subuser;
|
||||
use Illuminate\Support\Collection;
|
||||
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
|
||||
use Pterodactyl\Contracts\Repository\SubuserRepositoryInterface;
|
||||
|
||||
@ -18,6 +19,22 @@ class SubuserRepository extends EloquentRepository implements SubuserRepositoryI
|
||||
return Subuser::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subusers for the given server instance with the associated user
|
||||
* and permission relationships pre-loaded.
|
||||
*
|
||||
* @param int $server
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getSubusersForServer(int $server): Collection
|
||||
{
|
||||
return $this->getBuilder()
|
||||
->with('user', 'permissions')
|
||||
->where('server_id', $server)
|
||||
->get()
|
||||
->toBase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a subuser with the associated server relationship.
|
||||
*
|
||||
|
@ -2,6 +2,25 @@
|
||||
|
||||
namespace Pterodactyl\Repositories\Wings;
|
||||
|
||||
use GuzzleHttp\Exception\TransferException;
|
||||
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
|
||||
class DaemonConfigurationRepository extends DaemonRepository
|
||||
{
|
||||
/**
|
||||
* Returns system information from the wings instance.
|
||||
*
|
||||
* @return array
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function getSystemInformation(): array
|
||||
{
|
||||
try {
|
||||
$response = $this->getHttpClient()->get('/api/system');
|
||||
} catch (TransferException $exception) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
}
|
||||
|
||||
return json_decode($response->getBody()->__toString(), true);
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,29 @@ class DaemonFileRepository extends DaemonRepository
|
||||
return $response->getBody()->__toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stream of a file's contents back to the calling function to allow
|
||||
* proxying the request through the Panel rather than needing a direct call to
|
||||
* the Daemon in order to work.
|
||||
*
|
||||
* @param string $path
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function streamContent(string $path): ResponseInterface
|
||||
{
|
||||
Assert::isInstanceOf($this->server, Server::class);
|
||||
|
||||
$response = $this->getHttpClient()->get(
|
||||
sprintf('/api/servers/%s/files/contents', $this->server->uuid),
|
||||
[
|
||||
'query' => ['file' => $path, 'download' => true],
|
||||
'stream' => true,
|
||||
]
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save new contents to a given file. This works for both creating and updating
|
||||
* a file.
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pterodactyl\Repositories\Wings;
|
||||
|
||||
use BadMethodCallException;
|
||||
use Webmozart\Assert\Assert;
|
||||
use Pterodactyl\Models\Server;
|
||||
use GuzzleHttp\Exception\TransferException;
|
||||
@ -29,4 +30,90 @@ class DaemonServerRepository extends DaemonRepository
|
||||
|
||||
return json_decode($response->getBody()->__toString(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new server on the Wings daemon.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function create(array $data): void
|
||||
{
|
||||
Assert::isInstanceOf($this->server, Server::class);
|
||||
|
||||
try {
|
||||
$this->getHttpClient()->post(
|
||||
'/api/servers', [
|
||||
'json' => $data,
|
||||
]
|
||||
);
|
||||
} catch (TransferException $exception) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates details about a server on the Daemon.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function update(array $data): void
|
||||
{
|
||||
Assert::isInstanceOf($this->server, Server::class);
|
||||
|
||||
try {
|
||||
$this->getHttpClient()->patch('/api/servers/' . $this->server->uuid, ['json' => $data]);
|
||||
} catch (TransferException $exception) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a server from the daemon, forcibly if passed.
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function delete(): void
|
||||
{
|
||||
Assert::isInstanceOf($this->server, Server::class);
|
||||
|
||||
try {
|
||||
$this->getHttpClient()->delete('/api/servers/' . $this->server->uuid);
|
||||
} catch (TransferException $exception) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reinstall a server on the daemon.
|
||||
*/
|
||||
public function reinstall(): void
|
||||
{
|
||||
throw new BadMethodCallException('Method is not implemented.');
|
||||
}
|
||||
|
||||
/**
|
||||
* By default this function will suspend a server instance on the daemon. However, passing
|
||||
* "true" as the first argument will unsuspend the server.
|
||||
*
|
||||
* @param bool $unsuspend
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function suspend(bool $unsuspend = false): void
|
||||
{
|
||||
Assert::isInstanceOf($this->server, Server::class);
|
||||
|
||||
try {
|
||||
$this->getHttpClient()->patch(
|
||||
'/api/servers/' . $this->server->uuid,
|
||||
['json' => ['suspended' => ! $unsuspend]]
|
||||
);
|
||||
} catch (TransferException $exception) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,124 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Services\DaemonKeys;
|
||||
|
||||
use Webmozart\Assert\Assert;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Psr\Log\LoggerInterface as Writer;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface as DaemonServerRepositoryInterface;
|
||||
|
||||
class DaemonKeyDeletionService
|
||||
{
|
||||
/**
|
||||
* @var \Illuminate\Database\ConnectionInterface
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface
|
||||
*/
|
||||
protected $daemonRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface
|
||||
*/
|
||||
protected $repository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
|
||||
*/
|
||||
protected $serverRepository;
|
||||
|
||||
/**
|
||||
* @var \Psr\Log\LoggerInterface
|
||||
*/
|
||||
protected $writer;
|
||||
|
||||
/**
|
||||
* DaemonKeyDeletionService constructor.
|
||||
*
|
||||
* @param \Illuminate\Database\ConnectionInterface $connection
|
||||
* @param \Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface $repository
|
||||
* @param \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface $daemonRepository
|
||||
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $serverRepository
|
||||
* @param \Psr\Log\LoggerInterface $writer
|
||||
*/
|
||||
public function __construct(
|
||||
ConnectionInterface $connection,
|
||||
DaemonKeyRepositoryInterface $repository,
|
||||
DaemonServerRepositoryInterface $daemonRepository,
|
||||
ServerRepositoryInterface $serverRepository,
|
||||
Writer $writer
|
||||
) {
|
||||
$this->connection = $connection;
|
||||
$this->daemonRepository = $daemonRepository;
|
||||
$this->repository = $repository;
|
||||
$this->serverRepository = $serverRepository;
|
||||
$this->writer = $writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Pterodactyl\Models\Server|int $server
|
||||
* @param int $user
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function handle($server, $user)
|
||||
{
|
||||
Assert::integerish($user, 'Second argument passed to handle must be an integer, received %s.');
|
||||
|
||||
if (! $server instanceof Server) {
|
||||
$server = $this->serverRepository->find($server);
|
||||
}
|
||||
|
||||
$this->connection->beginTransaction();
|
||||
$key = $this->repository->findFirstWhere([
|
||||
['user_id', '=', $user],
|
||||
['server_id', '=', $server->id],
|
||||
]);
|
||||
|
||||
$this->repository->delete($key->id);
|
||||
|
||||
try {
|
||||
$this->daemonRepository->setServer($server)->revokeAccessKey($key->secret);
|
||||
} catch (RequestException $exception) {
|
||||
$response = $exception->getResponse();
|
||||
$this->connection->rollBack();
|
||||
$this->writer->warning($exception);
|
||||
|
||||
throw new DisplayException(trans('admin/server.exceptions.daemon_exception', [
|
||||
'code' => is_null($response) ? 'E_CONN_REFUSED' : $response->getStatusCode(),
|
||||
]));
|
||||
}
|
||||
|
||||
$this->connection->commit();
|
||||
}
|
||||
}
|
@ -107,7 +107,7 @@ class EggConfigurationService
|
||||
{
|
||||
// Get the legacy configuration structure for the server so that we
|
||||
// can property map the egg placeholders to values.
|
||||
$structure = $this->configurationStructureService->handle($server);
|
||||
$structure = $this->configurationStructureService->handle($server, true);
|
||||
|
||||
foreach ($configs as $file => $data) {
|
||||
foreach ($data->find ?? [] as &$value) {
|
||||
|
@ -2,10 +2,9 @@
|
||||
|
||||
namespace Pterodactyl\Services\Helpers;
|
||||
|
||||
use Cake\Chronos\Chronos;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Filesystem\FilesystemManager;
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use Illuminate\Contracts\Cache\Repository as CacheRepository;
|
||||
|
||||
class AssetHashService
|
||||
{
|
||||
@ -14,11 +13,6 @@ class AssetHashService
|
||||
*/
|
||||
public const MANIFEST_PATH = './assets/manifest.json';
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Cache\Repository
|
||||
*/
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Filesystem\Filesystem
|
||||
*/
|
||||
@ -38,13 +32,11 @@ class AssetHashService
|
||||
* AssetHashService constructor.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Foundation\Application $application
|
||||
* @param \Illuminate\Contracts\Cache\Repository $cache
|
||||
* @param \Illuminate\Filesystem\FilesystemManager $filesystem
|
||||
*/
|
||||
public function __construct(Application $application, CacheRepository $cache, FilesystemManager $filesystem)
|
||||
public function __construct(Application $application, FilesystemManager $filesystem)
|
||||
{
|
||||
$this->application = $application;
|
||||
$this->cache = $cache;
|
||||
$this->filesystem = $filesystem->createLocalDriver(['root' => public_path()]);
|
||||
}
|
||||
|
||||
@ -59,9 +51,9 @@ class AssetHashService
|
||||
public function url(string $resource): string
|
||||
{
|
||||
$file = last(explode('/', $resource));
|
||||
$data = array_get($this->manifest(), $file, $file);
|
||||
$data = Arr::get($this->manifest(), $file) ?? $file;
|
||||
|
||||
return str_replace($file, array_get($data, 'src', $file), $resource);
|
||||
return str_replace($file, Arr::get($data, 'src') ?? $file, $resource);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,7 +69,7 @@ class AssetHashService
|
||||
$file = last(explode('/', $resource));
|
||||
$data = array_get($this->manifest(), $file, $file);
|
||||
|
||||
return array_get($data, 'integrity', '');
|
||||
return Arr::get($data, 'integrity') ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -122,21 +114,8 @@ class AssetHashService
|
||||
*/
|
||||
protected function manifest(): array
|
||||
{
|
||||
if (! is_null(self::$manifest)) {
|
||||
return self::$manifest;
|
||||
}
|
||||
|
||||
// Skip checking the cache if we are not in production.
|
||||
if ($this->application->environment() === 'production') {
|
||||
$stored = $this->cache->get('Core:AssetManifest');
|
||||
if (! is_null($stored)) {
|
||||
return self::$manifest = $stored;
|
||||
}
|
||||
}
|
||||
|
||||
$contents = json_decode($this->filesystem->get(self::MANIFEST_PATH), true);
|
||||
$this->cache->put('Core:AssetManifest', $contents, Chronos::now()->addMinutes(1440));
|
||||
|
||||
return self::$manifest = $contents;
|
||||
return self::$manifest ?: self::$manifest = json_decode(
|
||||
$this->filesystem->get(self::MANIFEST_PATH), true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,22 @@
|
||||
<?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\Helpers;
|
||||
|
||||
use stdClass;
|
||||
use Exception;
|
||||
use GuzzleHttp\Client;
|
||||
use Cake\Chronos\Chronos;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Contracts\Cache\Repository as CacheRepository;
|
||||
use Illuminate\Contracts\Config\Repository as ConfigRepository;
|
||||
use Pterodactyl\Exceptions\Service\Helper\CdnVersionFetchingException;
|
||||
|
||||
class SoftwareVersionService
|
||||
{
|
||||
const VERSION_CACHE_KEY = 'pterodactyl:versions';
|
||||
const VERSION_CACHE_KEY = 'pterodactyl:versioning_data';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $result;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Cache\Repository
|
||||
@ -31,28 +28,20 @@ class SoftwareVersionService
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Config\Repository
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* SoftwareVersionService constructor.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Cache\Repository $cache
|
||||
* @param \GuzzleHttp\Client $client
|
||||
* @param \Illuminate\Contracts\Config\Repository $config
|
||||
*/
|
||||
public function __construct(
|
||||
CacheRepository $cache,
|
||||
Client $client,
|
||||
ConfigRepository $config
|
||||
Client $client
|
||||
) {
|
||||
$this->cache = $cache;
|
||||
$this->client = $client;
|
||||
$this->config = $config;
|
||||
|
||||
$this->cacheVersionData();
|
||||
self::$result = $this->cacheVersionData();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -62,7 +51,7 @@ class SoftwareVersionService
|
||||
*/
|
||||
public function getPanel()
|
||||
{
|
||||
return object_get($this->cache->get(self::VERSION_CACHE_KEY), 'panel', 'error');
|
||||
return Arr::get(self::$result, 'panel') ?? 'error';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,7 +61,7 @@ class SoftwareVersionService
|
||||
*/
|
||||
public function getDaemon()
|
||||
{
|
||||
return object_get($this->cache->get(self::VERSION_CACHE_KEY), 'daemon', 'error');
|
||||
return Arr::get(self::$result, 'daemon') ?? 'error';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,7 +71,17 @@ class SoftwareVersionService
|
||||
*/
|
||||
public function getDiscord()
|
||||
{
|
||||
return object_get($this->cache->get(self::VERSION_CACHE_KEY), 'discord', 'https://pterodactyl.io/discord');
|
||||
return Arr::get(self::$result, 'discord') ?? 'https://pterodactyl.io/discord';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL for donations.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDonations()
|
||||
{
|
||||
return Arr::get(self::$result, 'donations') ?? 'https://paypal.me/PterodactylSoftware';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -92,11 +91,11 @@ class SoftwareVersionService
|
||||
*/
|
||||
public function isLatestPanel()
|
||||
{
|
||||
if ($this->config->get('app.version') === 'canary') {
|
||||
if (config()->get('app.version') === 'canary') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return version_compare($this->config->get('app.version'), $this->getPanel()) >= 0;
|
||||
return version_compare(config()->get('app.version'), $this->getPanel()) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -116,20 +115,22 @@ class SoftwareVersionService
|
||||
|
||||
/**
|
||||
* Keeps the versioning cache up-to-date with the latest results from the CDN.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function cacheVersionData()
|
||||
{
|
||||
$this->cache->remember(self::VERSION_CACHE_KEY, Chronos::now()->addMinutes(config('pterodactyl.cdn.cache_time')), function () {
|
||||
return $this->cache->remember(self::VERSION_CACHE_KEY, Chronos::now()->addMinutes(config()->get('pterodactyl.cdn.cache_time', 60)), function () {
|
||||
try {
|
||||
$response = $this->client->request('GET', $this->config->get('pterodactyl.cdn.url'));
|
||||
$response = $this->client->request('GET', config()->get('pterodactyl.cdn.url'));
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
return json_decode($response->getBody());
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
throw new CdnVersionFetchingException;
|
||||
} catch (Exception $exception) {
|
||||
return new stdClass();
|
||||
return [];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -6,10 +6,10 @@ use Pterodactyl\Models\Node;
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Pterodactyl\Repositories\Daemon\ConfigurationRepository;
|
||||
use Pterodactyl\Contracts\Repository\NodeRepositoryInterface;
|
||||
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
use Pterodactyl\Exceptions\Service\Node\ConfigurationNotPersistedException;
|
||||
use Pterodactyl\Contracts\Repository\Daemon\ConfigurationRepositoryInterface;
|
||||
|
||||
class NodeUpdateService
|
||||
{
|
||||
@ -32,12 +32,12 @@ class NodeUpdateService
|
||||
* UpdateService constructor.
|
||||
*
|
||||
* @param \Illuminate\Database\ConnectionInterface $connection
|
||||
* @param \Pterodactyl\Contracts\Repository\Daemon\ConfigurationRepositoryInterface $configurationRepository
|
||||
* @param \Pterodactyl\Repositories\Daemon\ConfigurationRepository $configurationRepository
|
||||
* @param \Pterodactyl\Contracts\Repository\NodeRepositoryInterface $repository
|
||||
*/
|
||||
public function __construct(
|
||||
ConnectionInterface $connection,
|
||||
ConfigurationRepositoryInterface $configurationRepository,
|
||||
ConfigurationRepository $configurationRepository,
|
||||
NodeRepositoryInterface $repository
|
||||
) {
|
||||
$this->connection = $connection;
|
||||
@ -58,6 +58,8 @@ class NodeUpdateService
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Node\ConfigurationNotPersistedException
|
||||
*
|
||||
* @throws \GuzzleHttp\Exception\GuzzleException
|
||||
*/
|
||||
public function handle(Node $node, array $data, bool $resetToken = false)
|
||||
{
|
||||
|
@ -2,15 +2,16 @@
|
||||
|
||||
namespace Pterodactyl\Services\Servers;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Pterodactyl\Models\Server;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Repositories\Wings\DaemonServerRepository;
|
||||
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
|
||||
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
|
||||
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
use Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface as DaemonServerRepositoryInterface;
|
||||
|
||||
class BuildModificationService
|
||||
{
|
||||
@ -25,7 +26,7 @@ class BuildModificationService
|
||||
private $connection;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface
|
||||
* @var \Pterodactyl\Repositories\Wings\DaemonServerRepository
|
||||
*/
|
||||
private $daemonServerRepository;
|
||||
|
||||
@ -34,24 +35,32 @@ class BuildModificationService
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Servers\ServerConfigurationStructureService
|
||||
*/
|
||||
private $structureService;
|
||||
|
||||
/**
|
||||
* BuildModificationService constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface $allocationRepository
|
||||
* @param \Pterodactyl\Services\Servers\ServerConfigurationStructureService $structureService
|
||||
* @param \Illuminate\Database\ConnectionInterface $connection
|
||||
* @param \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface $daemonServerRepository
|
||||
* @param \Pterodactyl\Repositories\Wings\DaemonServerRepository $daemonServerRepository
|
||||
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
|
||||
*/
|
||||
public function __construct(
|
||||
AllocationRepositoryInterface $allocationRepository,
|
||||
ServerConfigurationStructureService $structureService,
|
||||
ConnectionInterface $connection,
|
||||
DaemonServerRepositoryInterface $daemonServerRepository,
|
||||
DaemonServerRepository $daemonServerRepository,
|
||||
ServerRepositoryInterface $repository
|
||||
) {
|
||||
$this->allocationRepository = $allocationRepository;
|
||||
$this->daemonServerRepository = $daemonServerRepository;
|
||||
$this->connection = $connection;
|
||||
$this->repository = $repository;
|
||||
$this->structureService = $structureService;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -67,23 +76,22 @@ class BuildModificationService
|
||||
*/
|
||||
public function handle(Server $server, array $data)
|
||||
{
|
||||
$build = [];
|
||||
$this->connection->beginTransaction();
|
||||
|
||||
$this->processAllocations($server, $data);
|
||||
|
||||
if (isset($data['allocation_id']) && $data['allocation_id'] != $server->allocation_id) {
|
||||
try {
|
||||
$allocation = $this->allocationRepository->findFirstWhere([
|
||||
$this->allocationRepository->findFirstWhere([
|
||||
['id', '=', $data['allocation_id']],
|
||||
['server_id', '=', $server->id],
|
||||
]);
|
||||
} catch (RecordNotFoundException $ex) {
|
||||
throw new DisplayException(trans('admin/server.exceptions.default_allocation_not_found'));
|
||||
}
|
||||
|
||||
$build['default'] = ['ip' => $allocation->ip, 'port' => $allocation->port];
|
||||
}
|
||||
|
||||
/** @var \Pterodactyl\Models\Server $server */
|
||||
$server = $this->repository->withFreshModel()->update($server->id, [
|
||||
'oom_disabled' => array_get($data, 'oom_disabled'),
|
||||
'memory' => array_get($data, 'memory'),
|
||||
@ -96,20 +104,13 @@ class BuildModificationService
|
||||
'allocation_limit' => array_get($data, 'allocation_limit'),
|
||||
]);
|
||||
|
||||
$allocations = $this->allocationRepository->findWhere([['server_id', '=', $server->id]]);
|
||||
|
||||
$build['oom_disabled'] = $server->oom_disabled;
|
||||
$build['memory'] = (int) $server->memory;
|
||||
$build['swap'] = (int) $server->swap;
|
||||
$build['io'] = (int) $server->io;
|
||||
$build['cpu'] = (int) $server->cpu;
|
||||
$build['disk'] = (int) $server->disk;
|
||||
$build['ports|overwrite'] = $allocations->groupBy('ip')->map(function ($item) {
|
||||
return $item->pluck('port');
|
||||
})->toArray();
|
||||
$updateData = $this->structureService->handle($server);
|
||||
|
||||
try {
|
||||
$this->daemonServerRepository->setServer($server)->update(['build' => $build]);
|
||||
$this->daemonServerRepository
|
||||
->setServer($server)
|
||||
->update(Arr::only($updateData, ['build']));
|
||||
|
||||
$this->connection->commit();
|
||||
} catch (RequestException $exception) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
|
@ -1,42 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Services\Servers;
|
||||
|
||||
use Pterodactyl\Models\Server;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
use Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface;
|
||||
|
||||
class ContainerRebuildService
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* ContainerRebuildService constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface $repository
|
||||
*/
|
||||
public function __construct(ServerRepositoryInterface $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a server for rebuild on next boot cycle.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function handle(Server $server)
|
||||
{
|
||||
try {
|
||||
$this->repository->setServer($server)->rebuild();
|
||||
} catch (RequestException $exception) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,8 +6,6 @@ use Pterodactyl\Models\Server;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Pterodactyl\Traits\Services\ReturnsUpdatedModels;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||
use Pterodactyl\Services\DaemonKeys\DaemonKeyCreationService;
|
||||
use Pterodactyl\Services\DaemonKeys\DaemonKeyDeletionService;
|
||||
|
||||
class DetailsModificationService
|
||||
{
|
||||
@ -18,16 +16,6 @@ class DetailsModificationService
|
||||
*/
|
||||
private $connection;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\DaemonKeys\DaemonKeyCreationService
|
||||
*/
|
||||
private $keyCreationService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\DaemonKeys\DaemonKeyDeletionService
|
||||
*/
|
||||
private $keyDeletionService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\ServerRepository
|
||||
*/
|
||||
@ -37,19 +25,13 @@ class DetailsModificationService
|
||||
* DetailsModificationService constructor.
|
||||
*
|
||||
* @param \Illuminate\Database\ConnectionInterface $connection
|
||||
* @param \Pterodactyl\Services\DaemonKeys\DaemonKeyCreationService $keyCreationService
|
||||
* @param \Pterodactyl\Services\DaemonKeys\DaemonKeyDeletionService $keyDeletionService
|
||||
* @param \Pterodactyl\Repositories\Eloquent\ServerRepository $repository
|
||||
*/
|
||||
public function __construct(
|
||||
ConnectionInterface $connection,
|
||||
DaemonKeyCreationService $keyCreationService,
|
||||
DaemonKeyDeletionService $keyDeletionService,
|
||||
ServerRepository $repository
|
||||
) {
|
||||
$this->connection = $connection;
|
||||
$this->keyCreationService = $keyCreationService;
|
||||
$this->keyDeletionService = $keyDeletionService;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
@ -60,7 +42,6 @@ class DetailsModificationService
|
||||
* @param array $data
|
||||
* @return bool|\Pterodactyl\Models\Server
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
@ -75,11 +56,6 @@ class DetailsModificationService
|
||||
'description' => array_get($data, 'description') ?? '',
|
||||
], true, true);
|
||||
|
||||
if ((int) array_get($data, 'owner_id', 0) !== (int) $server->owner_id) {
|
||||
$this->keyDeletionService->handle($server, $server->owner_id);
|
||||
$this->keyCreationService->handle($server->id, array_get($data, 'owner_id'));
|
||||
}
|
||||
|
||||
$this->connection->commit();
|
||||
|
||||
return $response;
|
||||
|
@ -1,48 +1,41 @@
|
||||
<?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\Servers;
|
||||
|
||||
use Pterodactyl\Models\Server;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Pterodactyl\Repositories\Wings\DaemonServerRepository;
|
||||
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
||||
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
use Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface as DaemonServerRepositoryInterface;
|
||||
|
||||
class ReinstallServerService
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface
|
||||
* @var \Pterodactyl\Repositories\Wings\DaemonServerRepository
|
||||
*/
|
||||
protected $daemonServerRepository;
|
||||
private $daemonServerRepository;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Database\ConnectionInterface
|
||||
*/
|
||||
protected $database;
|
||||
private $database;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
|
||||
*/
|
||||
protected $repository;
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* ReinstallService constructor.
|
||||
*
|
||||
* @param \Illuminate\Database\ConnectionInterface $database
|
||||
* @param \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface $daemonServerRepository
|
||||
* @param \Pterodactyl\Repositories\Wings\DaemonServerRepository $daemonServerRepository
|
||||
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
|
||||
*/
|
||||
public function __construct(
|
||||
ConnectionInterface $database,
|
||||
DaemonServerRepositoryInterface $daemonServerRepository,
|
||||
DaemonServerRepository $daemonServerRepository,
|
||||
ServerRepositoryInterface $repository
|
||||
) {
|
||||
$this->daemonServerRepository = $daemonServerRepository;
|
||||
|
@ -47,14 +47,73 @@ class ServerConfigurationStructureService
|
||||
* daemon, if you modify the structure eggs will break unexpectedly.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @param bool $legacy
|
||||
* @return array
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function handle(Server $server): array
|
||||
public function handle(Server $server, bool $legacy = false): array
|
||||
{
|
||||
$server->loadMissing(self::REQUIRED_RELATIONS);
|
||||
|
||||
return $legacy ?
|
||||
$this->returnLegacyFormat($server)
|
||||
: $this->returnCurrentFormat($server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the new data format used for the Wings daemon.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return array
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
protected function returnCurrentFormat(Server $server)
|
||||
{
|
||||
return [
|
||||
'uuid' => $server->uuid,
|
||||
'suspended' => (bool) $server->suspended,
|
||||
'environment' => $this->environment->handle($server),
|
||||
'invocation' => $server->startup,
|
||||
'build' => [
|
||||
'memory_limit' => $server->memory,
|
||||
'swap' => $server->swap,
|
||||
'io_weight' => $server->io,
|
||||
'cpu_limit' => $server->cpu,
|
||||
'disk_space' => $server->disk,
|
||||
],
|
||||
'service' => [
|
||||
'egg' => $server->egg->uuid,
|
||||
'pack' => $server->pack ? $server->pack->uuid : null,
|
||||
'skip_scripts' => $server->skip_scripts,
|
||||
],
|
||||
'container' => [
|
||||
'image' => $server->image,
|
||||
'oom_disabled' => $server->oom_disabled,
|
||||
'requires_rebuild' => false,
|
||||
],
|
||||
'allocations' => [
|
||||
'default' => [
|
||||
'ip' => $server->allocation->ip,
|
||||
'port' => $server->allocation->port,
|
||||
],
|
||||
'mappings' => $server->getAllocationMappings(),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the legacy server data format to continue support for old egg configurations
|
||||
* that have not yet been updated.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return array
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
protected function returnLegacyFormat(Server $server)
|
||||
{
|
||||
return [
|
||||
'uuid' => $server->uuid,
|
||||
'build' => [
|
||||
|
@ -3,27 +3,27 @@
|
||||
namespace Pterodactyl\Services\Servers;
|
||||
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Illuminate\Support\Arr;
|
||||
use Pterodactyl\Models\Node;
|
||||
use Pterodactyl\Models\User;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Illuminate\Support\Collection;
|
||||
use Pterodactyl\Models\Allocation;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Pterodactyl\Models\Objects\DeploymentObject;
|
||||
use Pterodactyl\Repositories\Eloquent\EggRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||
use Pterodactyl\Repositories\Wings\DaemonServerRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\AllocationRepository;
|
||||
use Pterodactyl\Services\Deployment\FindViableNodesService;
|
||||
use Pterodactyl\Contracts\Repository\EggRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerVariableRepository;
|
||||
use Pterodactyl\Services\Deployment\AllocationSelectionService;
|
||||
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
|
||||
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
use Pterodactyl\Contracts\Repository\ServerVariableRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface as DaemonServerRepositoryInterface;
|
||||
|
||||
class ServerCreationService
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface
|
||||
* @var \Pterodactyl\Repositories\Eloquent\AllocationRepository
|
||||
*/
|
||||
private $allocationRepository;
|
||||
|
||||
@ -42,72 +42,80 @@ class ServerCreationService
|
||||
*/
|
||||
private $connection;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface
|
||||
*/
|
||||
private $daemonServerRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\EggRepositoryInterface
|
||||
*/
|
||||
private $eggRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Deployment\FindViableNodesService
|
||||
*/
|
||||
private $findViableNodesService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\ServerVariableRepositoryInterface
|
||||
*/
|
||||
private $serverVariableRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Servers\VariableValidatorService
|
||||
*/
|
||||
private $validatorService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\EggRepository
|
||||
*/
|
||||
private $eggRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\ServerRepository
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\ServerVariableRepository
|
||||
*/
|
||||
private $serverVariableRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Wings\DaemonServerRepository
|
||||
*/
|
||||
private $daemonServerRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Servers\ServerDeletionService
|
||||
*/
|
||||
private $serverDeletionService;
|
||||
|
||||
/**
|
||||
* CreationService constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface $allocationRepository
|
||||
* @param \Pterodactyl\Repositories\Eloquent\AllocationRepository $allocationRepository
|
||||
* @param \Pterodactyl\Services\Deployment\AllocationSelectionService $allocationSelectionService
|
||||
* @param \Illuminate\Database\ConnectionInterface $connection
|
||||
* @param \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface $daemonServerRepository
|
||||
* @param \Pterodactyl\Contracts\Repository\EggRepositoryInterface $eggRepository
|
||||
* @param \Pterodactyl\Repositories\Wings\DaemonServerRepository $daemonServerRepository
|
||||
* @param \Pterodactyl\Repositories\Eloquent\EggRepository $eggRepository
|
||||
* @param \Pterodactyl\Services\Deployment\FindViableNodesService $findViableNodesService
|
||||
* @param \Pterodactyl\Services\Servers\ServerConfigurationStructureService $configurationStructureService
|
||||
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
|
||||
* @param \Pterodactyl\Contracts\Repository\ServerVariableRepositoryInterface $serverVariableRepository
|
||||
* @param \Pterodactyl\Services\Servers\ServerDeletionService $serverDeletionService
|
||||
* @param \Pterodactyl\Repositories\Eloquent\ServerRepository $repository
|
||||
* @param \Pterodactyl\Repositories\Eloquent\ServerVariableRepository $serverVariableRepository
|
||||
* @param \Pterodactyl\Services\Servers\VariableValidatorService $validatorService
|
||||
*/
|
||||
public function __construct(
|
||||
AllocationRepositoryInterface $allocationRepository,
|
||||
AllocationRepository $allocationRepository,
|
||||
AllocationSelectionService $allocationSelectionService,
|
||||
ConnectionInterface $connection,
|
||||
DaemonServerRepositoryInterface $daemonServerRepository,
|
||||
EggRepositoryInterface $eggRepository,
|
||||
DaemonServerRepository $daemonServerRepository,
|
||||
EggRepository $eggRepository,
|
||||
FindViableNodesService $findViableNodesService,
|
||||
ServerConfigurationStructureService $configurationStructureService,
|
||||
ServerRepositoryInterface $repository,
|
||||
ServerVariableRepositoryInterface $serverVariableRepository,
|
||||
ServerDeletionService $serverDeletionService,
|
||||
ServerRepository $repository,
|
||||
ServerVariableRepository $serverVariableRepository,
|
||||
VariableValidatorService $validatorService
|
||||
) {
|
||||
$this->allocationSelectionService = $allocationSelectionService;
|
||||
$this->allocationRepository = $allocationRepository;
|
||||
$this->configurationStructureService = $configurationStructureService;
|
||||
$this->connection = $connection;
|
||||
$this->daemonServerRepository = $daemonServerRepository;
|
||||
$this->eggRepository = $eggRepository;
|
||||
$this->findViableNodesService = $findViableNodesService;
|
||||
$this->validatorService = $validatorService;
|
||||
$this->eggRepository = $eggRepository;
|
||||
$this->repository = $repository;
|
||||
$this->serverVariableRepository = $serverVariableRepository;
|
||||
$this->validatorService = $validatorService;
|
||||
$this->daemonServerRepository = $daemonServerRepository;
|
||||
$this->serverDeletionService = $serverDeletionService;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -120,12 +128,12 @@ class ServerCreationService
|
||||
* @param \Pterodactyl\Models\Objects\DeploymentObject|null $deployment
|
||||
* @return \Pterodactyl\Models\Server
|
||||
*
|
||||
* @throws \Throwable
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Deployment\NoViableNodeException
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Deployment\NoViableAllocationException
|
||||
*/
|
||||
public function handle(array $data, DeploymentObject $deployment = null): Server
|
||||
@ -142,35 +150,41 @@ class ServerCreationService
|
||||
|
||||
// Auto-configure the node based on the selected allocation
|
||||
// if no node was defined.
|
||||
if (is_null(array_get($data, 'node_id'))) {
|
||||
if (is_null(Arr::get($data, 'node_id'))) {
|
||||
$data['node_id'] = $this->getNodeFromAllocation($data['allocation_id']);
|
||||
}
|
||||
|
||||
if (is_null(array_get($data, 'nest_id'))) {
|
||||
$egg = $this->eggRepository->setColumns(['id', 'nest_id'])->find(array_get($data, 'egg_id'));
|
||||
if (is_null(Arr::get($data, 'nest_id'))) {
|
||||
/** @var \Pterodactyl\Models\Egg $egg */
|
||||
$egg = $this->eggRepository->setColumns(['id', 'nest_id'])->find(Arr::get($data, 'egg_id'));
|
||||
$data['nest_id'] = $egg->nest_id;
|
||||
}
|
||||
|
||||
$eggVariableData = $this->validatorService
|
||||
->setUserLevel(User::USER_LEVEL_ADMIN)
|
||||
->handle(array_get($data, 'egg_id'), array_get($data, 'environment', []));
|
||||
->handle(Arr::get($data, 'egg_id'), Arr::get($data, 'environment', []));
|
||||
|
||||
// Create the server and assign any additional allocations to it.
|
||||
$server = $this->createModel($data);
|
||||
|
||||
$this->storeAssignedAllocations($server, $data);
|
||||
$this->storeEggVariables($server, $eggVariableData);
|
||||
|
||||
// Due to the design of the Daemon, we need to persist this server to the disk
|
||||
// before we can actually create it on the Daemon.
|
||||
//
|
||||
// If that connection fails out we will attempt to perform a cleanup by just
|
||||
// deleting the server itself from the system.
|
||||
$this->connection->commit();
|
||||
|
||||
$structure = $this->configurationStructureService->handle($server);
|
||||
|
||||
try {
|
||||
$this->daemonServerRepository->setServer($server)->create($structure, [
|
||||
'start_on_completion' => (bool) array_get($data, 'start_on_completion', false),
|
||||
]);
|
||||
$this->daemonServerRepository->setServer($server)->create($structure);
|
||||
} catch (DaemonConnectionException $exception) {
|
||||
$this->serverDeletionService->withForce(true)->handle($server);
|
||||
|
||||
$this->connection->commit();
|
||||
} catch (RequestException $exception) {
|
||||
$this->connection->rollBack();
|
||||
throw new DaemonConnectionException($exception);
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
return $server;
|
||||
@ -190,8 +204,8 @@ class ServerCreationService
|
||||
private function configureDeployment(array $data, DeploymentObject $deployment): Allocation
|
||||
{
|
||||
$nodes = $this->findViableNodesService->setLocations($deployment->getLocations())
|
||||
->setDisk(array_get($data, 'disk'))
|
||||
->setMemory(array_get($data, 'memory'))
|
||||
->setDisk(Arr::get($data, 'disk'))
|
||||
->setMemory(Arr::get($data, 'memory'))
|
||||
->handle();
|
||||
|
||||
return $this->allocationSelectionService->setDedicated($deployment->isDedicated())
|
||||
@ -212,32 +226,34 @@ class ServerCreationService
|
||||
{
|
||||
$uuid = $this->generateUniqueUuidCombo();
|
||||
|
||||
return $this->repository->create([
|
||||
'external_id' => array_get($data, 'external_id'),
|
||||
/** @var \Pterodactyl\Models\Server $model */
|
||||
$model = $this->repository->create([
|
||||
'external_id' => Arr::get($data, 'external_id'),
|
||||
'uuid' => $uuid,
|
||||
'uuidShort' => substr($uuid, 0, 8),
|
||||
'node_id' => array_get($data, 'node_id'),
|
||||
'name' => array_get($data, 'name'),
|
||||
'description' => array_get($data, 'description') ?? '',
|
||||
'skip_scripts' => array_get($data, 'skip_scripts') ?? isset($data['skip_scripts']),
|
||||
'node_id' => Arr::get($data, 'node_id'),
|
||||
'name' => Arr::get($data, 'name'),
|
||||
'description' => Arr::get($data, 'description') ?? '',
|
||||
'skip_scripts' => Arr::get($data, 'skip_scripts') ?? isset($data['skip_scripts']),
|
||||
'suspended' => false,
|
||||
'owner_id' => array_get($data, 'owner_id'),
|
||||
'memory' => array_get($data, 'memory'),
|
||||
'swap' => array_get($data, 'swap'),
|
||||
'disk' => array_get($data, 'disk'),
|
||||
'io' => array_get($data, 'io'),
|
||||
'cpu' => array_get($data, 'cpu'),
|
||||
'oom_disabled' => array_get($data, 'oom_disabled', true),
|
||||
'allocation_id' => array_get($data, 'allocation_id'),
|
||||
'nest_id' => array_get($data, 'nest_id'),
|
||||
'egg_id' => array_get($data, 'egg_id'),
|
||||
'pack_id' => (! isset($data['pack_id']) || $data['pack_id'] == 0) ? null : $data['pack_id'],
|
||||
'startup' => array_get($data, 'startup'),
|
||||
'daemonSecret' => str_random(Node::DAEMON_SECRET_LENGTH),
|
||||
'image' => array_get($data, 'image'),
|
||||
'database_limit' => array_get($data, 'database_limit'),
|
||||
'allocation_limit' => array_get($data, 'allocation_limit'),
|
||||
'owner_id' => Arr::get($data, 'owner_id'),
|
||||
'memory' => Arr::get($data, 'memory'),
|
||||
'swap' => Arr::get($data, 'swap'),
|
||||
'disk' => Arr::get($data, 'disk'),
|
||||
'io' => Arr::get($data, 'io'),
|
||||
'cpu' => Arr::get($data, 'cpu'),
|
||||
'oom_disabled' => Arr::get($data, 'oom_disabled', true),
|
||||
'allocation_id' => Arr::get($data, 'allocation_id'),
|
||||
'nest_id' => Arr::get($data, 'nest_id'),
|
||||
'egg_id' => Arr::get($data, 'egg_id'),
|
||||
'pack_id' => empty($data['pack_id']) ? null : $data['pack_id'],
|
||||
'startup' => Arr::get($data, 'startup'),
|
||||
'image' => Arr::get($data, 'image'),
|
||||
'database_limit' => Arr::get($data, 'database_limit'),
|
||||
'allocation_limit' => Arr::get($data, 'allocation_limit'),
|
||||
]);
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -280,18 +296,21 @@ class ServerCreationService
|
||||
/**
|
||||
* Get the node that an allocation belongs to.
|
||||
*
|
||||
* @param int $allocation
|
||||
* @param int $id
|
||||
* @return int
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
private function getNodeFromAllocation(int $allocation): int
|
||||
private function getNodeFromAllocation(int $id): int
|
||||
{
|
||||
$allocation = $this->allocationRepository->setColumns(['id', 'node_id'])->find($allocation);
|
||||
/** @var \Pterodactyl\Models\Allocation $allocation */
|
||||
$allocation = $this->allocationRepository->setColumns(['id', 'node_id'])->find($id);
|
||||
|
||||
return $allocation->node_id;
|
||||
}
|
||||
|
||||
/** @noinspection PhpDocMissingThrowsInspection */
|
||||
|
||||
/**
|
||||
* Create a unique UUID and UUID-Short combo for a server.
|
||||
*
|
||||
@ -299,6 +318,7 @@ class ServerCreationService
|
||||
*/
|
||||
private function generateUniqueUuidCombo(): string
|
||||
{
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
$uuid = Uuid::uuid4()->toString();
|
||||
|
||||
if (! $this->repository->isUniqueUuidCombo($uuid, substr($uuid, 0, 8))) {
|
||||
|
@ -1,82 +1,75 @@
|
||||
<?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\Servers;
|
||||
|
||||
use Psr\Log\LoggerInterface as Writer;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\DatabaseRepository;
|
||||
use Pterodactyl\Repositories\Wings\DaemonServerRepository;
|
||||
use Pterodactyl\Services\Databases\DatabaseManagementService;
|
||||
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
|
||||
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
use Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface as DaemonServerRepositoryInterface;
|
||||
|
||||
class ServerDeletionService
|
||||
{
|
||||
/**
|
||||
* @var \Illuminate\Database\ConnectionInterface
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface
|
||||
*/
|
||||
protected $daemonServerRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Databases\DatabaseManagementService
|
||||
*/
|
||||
protected $databaseManagementService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface
|
||||
*/
|
||||
protected $databaseRepository;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $force = false;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
|
||||
* @var \Illuminate\Database\ConnectionInterface
|
||||
*/
|
||||
protected $repository;
|
||||
private $connection;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Wings\DaemonServerRepository
|
||||
*/
|
||||
private $daemonServerRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\DatabaseRepository
|
||||
*/
|
||||
private $databaseRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Databases\DatabaseManagementService
|
||||
*/
|
||||
private $databaseManagementService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\ServerRepository
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* @var \Psr\Log\LoggerInterface
|
||||
*/
|
||||
protected $writer;
|
||||
private $writer;
|
||||
|
||||
/**
|
||||
* DeletionService constructor.
|
||||
*
|
||||
* @param \Illuminate\Database\ConnectionInterface $connection
|
||||
* @param \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface $daemonServerRepository
|
||||
* @param \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface $databaseRepository
|
||||
* @param \Pterodactyl\Repositories\Wings\DaemonServerRepository $daemonServerRepository
|
||||
* @param \Pterodactyl\Repositories\Eloquent\DatabaseRepository $databaseRepository
|
||||
* @param \Pterodactyl\Services\Databases\DatabaseManagementService $databaseManagementService
|
||||
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
|
||||
* @param \Pterodactyl\Repositories\Eloquent\ServerRepository $repository
|
||||
* @param \Psr\Log\LoggerInterface $writer
|
||||
*/
|
||||
public function __construct(
|
||||
ConnectionInterface $connection,
|
||||
DaemonServerRepositoryInterface $daemonServerRepository,
|
||||
DatabaseRepositoryInterface $databaseRepository,
|
||||
DaemonServerRepository $daemonServerRepository,
|
||||
DatabaseRepository $databaseRepository,
|
||||
DatabaseManagementService $databaseManagementService,
|
||||
ServerRepositoryInterface $repository,
|
||||
Writer $writer
|
||||
ServerRepository $repository,
|
||||
LoggerInterface $writer
|
||||
) {
|
||||
$this->daemonServerRepository = $daemonServerRepository;
|
||||
$this->connection = $connection;
|
||||
$this->databaseManagementService = $databaseManagementService;
|
||||
$this->daemonServerRepository = $daemonServerRepository;
|
||||
$this->databaseRepository = $databaseRepository;
|
||||
$this->databaseManagementService = $databaseManagementService;
|
||||
$this->repository = $repository;
|
||||
$this->writer = $writer;
|
||||
}
|
||||
@ -97,34 +90,29 @@ class ServerDeletionService
|
||||
/**
|
||||
* Delete a server from the panel and remove any associated databases from hosts.
|
||||
*
|
||||
* @param int|\Pterodactyl\Models\Server $server
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
*
|
||||
* @throws \Throwable
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
*/
|
||||
public function handle($server)
|
||||
public function handle(Server $server)
|
||||
{
|
||||
try {
|
||||
$this->daemonServerRepository->setServer($server)->delete();
|
||||
} catch (RequestException $exception) {
|
||||
$response = $exception->getResponse();
|
||||
|
||||
if (is_null($response) || (! is_null($response) && $response->getStatusCode() !== 404)) {
|
||||
// If not forcing the deletion, throw an exception, otherwise just log it and
|
||||
// continue with server deletion process in the panel.
|
||||
if (! $this->force) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
} else {
|
||||
$this->writer->warning($exception);
|
||||
}
|
||||
} catch (DaemonConnectionException $exception) {
|
||||
if ($this->force) {
|
||||
$this->writer->warning($exception);
|
||||
} else {
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
$this->connection->beginTransaction();
|
||||
$this->databaseRepository->setColumns('id')->findWhere([['server_id', '=', $server->id]])->each(function ($item) {
|
||||
$this->databaseManagementService->delete($item->id);
|
||||
});
|
||||
$this->connection->transaction(function () use ($server) {
|
||||
$this->databaseRepository->setColumns('id')->findWhere([['server_id', '=', $server->id]])->each(function ($item) {
|
||||
$this->databaseManagementService->delete($item->id);
|
||||
});
|
||||
|
||||
$this->repository->delete($server->id);
|
||||
$this->connection->commit();
|
||||
$this->repository->delete($server->id);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -4,24 +4,16 @@ namespace Pterodactyl\Services\Servers;
|
||||
|
||||
use Pterodactyl\Models\User;
|
||||
use Pterodactyl\Models\Server;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Pterodactyl\Traits\Services\HasUserLevels;
|
||||
use Pterodactyl\Contracts\Repository\EggRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
||||
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
use Pterodactyl\Contracts\Repository\ServerVariableRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface as DaemonServerRepositoryInterface;
|
||||
|
||||
class StartupModificationService
|
||||
{
|
||||
use HasUserLevels;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface
|
||||
*/
|
||||
private $daemonServerRepository;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Database\ConnectionInterface
|
||||
*/
|
||||
@ -52,33 +44,38 @@ class StartupModificationService
|
||||
*/
|
||||
private $validatorService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Servers\ServerConfigurationStructureService
|
||||
*/
|
||||
private $structureService;
|
||||
|
||||
/**
|
||||
* StartupModificationService constructor.
|
||||
*
|
||||
* @param \Illuminate\Database\ConnectionInterface $connection
|
||||
* @param \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface $daemonServerRepository
|
||||
* @param \Pterodactyl\Contracts\Repository\EggRepositoryInterface $eggRepository
|
||||
* @param \Pterodactyl\Services\Servers\EnvironmentService $environmentService
|
||||
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
|
||||
* @param \Pterodactyl\Services\Servers\ServerConfigurationStructureService $structureService
|
||||
* @param \Pterodactyl\Contracts\Repository\ServerVariableRepositoryInterface $serverVariableRepository
|
||||
* @param \Pterodactyl\Services\Servers\VariableValidatorService $validatorService
|
||||
*/
|
||||
public function __construct(
|
||||
ConnectionInterface $connection,
|
||||
DaemonServerRepositoryInterface $daemonServerRepository,
|
||||
EggRepositoryInterface $eggRepository,
|
||||
EnvironmentService $environmentService,
|
||||
ServerRepositoryInterface $repository,
|
||||
ServerConfigurationStructureService $structureService,
|
||||
ServerVariableRepositoryInterface $serverVariableRepository,
|
||||
VariableValidatorService $validatorService
|
||||
) {
|
||||
$this->daemonServerRepository = $daemonServerRepository;
|
||||
$this->connection = $connection;
|
||||
$this->eggRepository = $eggRepository;
|
||||
$this->environmentService = $environmentService;
|
||||
$this->repository = $repository;
|
||||
$this->serverVariableRepository = $serverVariableRepository;
|
||||
$this->validatorService = $validatorService;
|
||||
$this->structureService = $structureService;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -89,7 +86,6 @@ class StartupModificationService
|
||||
* @return \Pterodactyl\Models\Server
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
@ -110,22 +106,8 @@ class StartupModificationService
|
||||
});
|
||||
}
|
||||
|
||||
$daemonData = [];
|
||||
if ($this->isUserLevel(User::USER_LEVEL_ADMIN)) {
|
||||
$this->updateAdministrativeSettings($data, $server, $daemonData);
|
||||
}
|
||||
|
||||
$daemonData = array_merge_recursive($daemonData, [
|
||||
'build' => [
|
||||
'env|overwrite' => $this->environmentService->handle($server),
|
||||
],
|
||||
]);
|
||||
|
||||
try {
|
||||
$this->daemonServerRepository->setServer($server)->update($daemonData);
|
||||
} catch (RequestException $exception) {
|
||||
$this->connection->rollBack();
|
||||
throw new DaemonConnectionException($exception);
|
||||
$this->updateAdministrativeSettings($data, $server);
|
||||
}
|
||||
|
||||
$this->connection->commit();
|
||||
@ -138,12 +120,11 @@ class StartupModificationService
|
||||
*
|
||||
* @param array $data
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @param array $daemonData
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
private function updateAdministrativeSettings(array $data, Server &$server, array &$daemonData)
|
||||
private function updateAdministrativeSettings(array $data, Server &$server)
|
||||
{
|
||||
if (
|
||||
is_digit(array_get($data, 'egg_id'))
|
||||
@ -163,13 +144,5 @@ class StartupModificationService
|
||||
'skip_scripts' => array_get($data, 'skip_scripts') ?? isset($data['skip_scripts']),
|
||||
'image' => array_get($data, 'docker_image', $server->image),
|
||||
]);
|
||||
|
||||
$daemonData = array_merge($daemonData, [
|
||||
'build' => ['image' => $server->image],
|
||||
'service' => array_merge(
|
||||
$this->repository->getDaemonServiceData($server, true),
|
||||
['skip_scripts' => $server->skip_scripts]
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -1,66 +1,57 @@
|
||||
<?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\Servers;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Webmozart\Assert\Assert;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Psr\Log\LoggerInterface as Writer;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Repositories\Wings\DaemonServerRepository;
|
||||
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface as DaemonServerRepositoryInterface;
|
||||
|
||||
class SuspensionService
|
||||
{
|
||||
const ACTION_SUSPEND = 'suspend';
|
||||
const ACTION_UNSUSPEND = 'unsuspend';
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface
|
||||
*/
|
||||
protected $daemonServerRepository;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Database\ConnectionInterface
|
||||
*/
|
||||
protected $database;
|
||||
private $connection;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
|
||||
*/
|
||||
protected $repository;
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* @var \Psr\Log\LoggerInterface
|
||||
*/
|
||||
protected $writer;
|
||||
private $writer;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Wings\DaemonServerRepository
|
||||
*/
|
||||
private $daemonServerRepository;
|
||||
|
||||
/**
|
||||
* SuspensionService constructor.
|
||||
*
|
||||
* @param \Illuminate\Database\ConnectionInterface $database
|
||||
* @param \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface $daemonServerRepository
|
||||
* @param \Illuminate\Database\ConnectionInterface $connection
|
||||
* @param \Pterodactyl\Repositories\Wings\DaemonServerRepository $daemonServerRepository
|
||||
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
|
||||
* @param \Psr\Log\LoggerInterface $writer
|
||||
*/
|
||||
public function __construct(
|
||||
ConnectionInterface $database,
|
||||
DaemonServerRepositoryInterface $daemonServerRepository,
|
||||
ConnectionInterface $connection,
|
||||
DaemonServerRepository $daemonServerRepository,
|
||||
ServerRepositoryInterface $repository,
|
||||
Writer $writer
|
||||
LoggerInterface $writer
|
||||
) {
|
||||
$this->daemonServerRepository = $daemonServerRepository;
|
||||
$this->database = $database;
|
||||
$this->connection = $connection;
|
||||
$this->repository = $repository;
|
||||
$this->writer = $writer;
|
||||
$this->daemonServerRepository = $daemonServerRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,49 +59,26 @@ class SuspensionService
|
||||
*
|
||||
* @param int|\Pterodactyl\Models\Server $server
|
||||
* @param string $action
|
||||
* @return bool
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function toggle($server, $action = self::ACTION_SUSPEND)
|
||||
public function toggle(Server $server, $action = self::ACTION_SUSPEND)
|
||||
{
|
||||
if (! $server instanceof Server) {
|
||||
$server = $this->repository->find($server);
|
||||
}
|
||||
|
||||
if (! in_array($action, [self::ACTION_SUSPEND, self::ACTION_UNSUSPEND])) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Action must be either ' . self::ACTION_SUSPEND . ' or ' . self::ACTION_UNSUSPEND . ', %s passed.',
|
||||
$action
|
||||
));
|
||||
}
|
||||
Assert::oneOf($action, [self::ACTION_SUSPEND, self::ACTION_UNSUSPEND]);
|
||||
|
||||
if (
|
||||
$action === self::ACTION_SUSPEND && $server->suspended ||
|
||||
$action === self::ACTION_UNSUSPEND && ! $server->suspended
|
||||
) {
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->database->beginTransaction();
|
||||
$this->repository->withoutFreshModel()->update($server->id, [
|
||||
'suspended' => $action === self::ACTION_SUSPEND,
|
||||
]);
|
||||
$this->connection->transaction(function () use ($action, $server) {
|
||||
$this->repository->withoutFreshModel()->update($server->id, [
|
||||
'suspended' => $action === self::ACTION_SUSPEND,
|
||||
]);
|
||||
|
||||
try {
|
||||
$this->daemonServerRepository->setServer($server)->$action();
|
||||
$this->database->commit();
|
||||
|
||||
return true;
|
||||
} catch (RequestException $exception) {
|
||||
$response = $exception->getResponse();
|
||||
$this->writer->warning($exception);
|
||||
|
||||
throw new DisplayException(trans('admin/server.exceptions.daemon_exception', [
|
||||
'code' => is_null($response) ? 'E_CONN_REFUSED' : $response->getStatusCode(),
|
||||
]));
|
||||
}
|
||||
$this->daemonServerRepository->setServer($server)->suspend($action === self::ACTION_UNSUSPEND);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +1,12 @@
|
||||
<?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\Subusers;
|
||||
|
||||
use Pterodactyl\Models\Subuser;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Pterodactyl\Services\DaemonKeys\DaemonKeyDeletionService;
|
||||
use Pterodactyl\Contracts\Repository\SubuserRepositoryInterface;
|
||||
|
||||
class SubuserDeletionService
|
||||
{
|
||||
/**
|
||||
* @var \Illuminate\Database\ConnectionInterface
|
||||
*/
|
||||
private $connection;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\DaemonKeys\DaemonKeyDeletionService
|
||||
*/
|
||||
private $keyDeletionService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\SubuserRepositoryInterface
|
||||
*/
|
||||
@ -34,17 +15,11 @@ class SubuserDeletionService
|
||||
/**
|
||||
* SubuserDeletionService constructor.
|
||||
*
|
||||
* @param \Illuminate\Database\ConnectionInterface $connection
|
||||
* @param \Pterodactyl\Services\DaemonKeys\DaemonKeyDeletionService $keyDeletionService
|
||||
* @param \Pterodactyl\Contracts\Repository\SubuserRepositoryInterface $repository
|
||||
*/
|
||||
public function __construct(
|
||||
ConnectionInterface $connection,
|
||||
DaemonKeyDeletionService $keyDeletionService,
|
||||
SubuserRepositoryInterface $repository
|
||||
) {
|
||||
$this->connection = $connection;
|
||||
$this->keyDeletionService = $keyDeletionService;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
@ -52,15 +27,9 @@ class SubuserDeletionService
|
||||
* Delete a subuser and their associated permissions from the Panel and Daemon.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Subuser $subuser
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function handle(Subuser $subuser)
|
||||
{
|
||||
$this->connection->beginTransaction();
|
||||
$this->keyDeletionService->handle($subuser->server_id, $subuser->user_id);
|
||||
$this->repository->delete($subuser->id);
|
||||
$this->connection->commit();
|
||||
}
|
||||
}
|
||||
|
@ -5,18 +5,12 @@ namespace Pterodactyl\Services\Users;
|
||||
use Carbon\Carbon;
|
||||
use Pterodactyl\Models\User;
|
||||
use PragmaRX\Google2FA\Google2FA;
|
||||
use Illuminate\Contracts\Config\Repository;
|
||||
use Illuminate\Contracts\Encryption\Encrypter;
|
||||
use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
|
||||
use Pterodactyl\Exceptions\Service\User\TwoFactorAuthenticationTokenInvalid;
|
||||
|
||||
class ToggleTwoFactorService
|
||||
{
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Config\Repository
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Encryption\Encrypter
|
||||
*/
|
||||
@ -37,16 +31,13 @@ class ToggleTwoFactorService
|
||||
*
|
||||
* @param \Illuminate\Contracts\Encryption\Encrypter $encrypter
|
||||
* @param \PragmaRX\Google2FA\Google2FA $google2FA
|
||||
* @param \Illuminate\Contracts\Config\Repository $config
|
||||
* @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $repository
|
||||
*/
|
||||
public function __construct(
|
||||
Encrypter $encrypter,
|
||||
Google2FA $google2FA,
|
||||
Repository $config,
|
||||
UserRepositoryInterface $repository
|
||||
) {
|
||||
$this->config = $config;
|
||||
$this->encrypter = $encrypter;
|
||||
$this->google2FA = $google2FA;
|
||||
$this->repository = $repository;
|
||||
@ -60,19 +51,23 @@ class ToggleTwoFactorService
|
||||
* @param bool|null $toggleState
|
||||
* @return bool
|
||||
*
|
||||
* @throws \PragmaRX\Google2FA\Exceptions\IncompatibleWithGoogleAuthenticatorException
|
||||
* @throws \PragmaRX\Google2FA\Exceptions\InvalidCharactersException
|
||||
* @throws \PragmaRX\Google2FA\Exceptions\SecretKeyTooShortException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Pterodactyl\Exceptions\Service\User\TwoFactorAuthenticationTokenInvalid
|
||||
*/
|
||||
public function handle(User $user, string $token, bool $toggleState = null): bool
|
||||
{
|
||||
$window = $this->config->get('pterodactyl.auth.2fa.window');
|
||||
$secret = $this->encrypter->decrypt($user->totp_secret);
|
||||
|
||||
$isValidToken = $this->google2FA->verifyKey($secret, $token, $window);
|
||||
$isValidToken = $this->google2FA->verifyKey($secret, $token, config()->get('pterodactyl.auth.2fa.window'));
|
||||
|
||||
if (! $isValidToken) {
|
||||
throw new TwoFactorAuthenticationTokenInvalid;
|
||||
throw new TwoFactorAuthenticationTokenInvalid(
|
||||
'The token provided is not valid.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->repository->withoutFreshModel()->update($user->id, [
|
||||
|
@ -3,11 +3,9 @@
|
||||
namespace Pterodactyl\Services\Users;
|
||||
|
||||
use Pterodactyl\Models\User;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Contracts\Hashing\Hasher;
|
||||
use Pterodactyl\Traits\Services\HasUserLevels;
|
||||
use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
|
||||
use Pterodactyl\Services\DaemonKeys\RevokeMultipleDaemonKeysService;
|
||||
use Pterodactyl\Repositories\Eloquent\UserRepository;
|
||||
|
||||
class UserUpdateService
|
||||
{
|
||||
@ -19,44 +17,33 @@ class UserUpdateService
|
||||
private $hasher;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\UserRepositoryInterface
|
||||
* @var \Pterodactyl\Repositories\Eloquent\UserRepository
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\DaemonKeys\RevokeMultipleDaemonKeysService
|
||||
*/
|
||||
private $revocationService;
|
||||
|
||||
/**
|
||||
* UpdateService constructor.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Hashing\Hasher $hasher
|
||||
* @param \Pterodactyl\Services\DaemonKeys\RevokeMultipleDaemonKeysService $revocationService
|
||||
* @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $repository
|
||||
* @param \Pterodactyl\Repositories\Eloquent\UserRepository $repository
|
||||
*/
|
||||
public function __construct(
|
||||
Hasher $hasher,
|
||||
RevokeMultipleDaemonKeysService $revocationService,
|
||||
UserRepositoryInterface $repository
|
||||
) {
|
||||
public function __construct(Hasher $hasher, UserRepository $repository)
|
||||
{
|
||||
$this->hasher = $hasher;
|
||||
$this->repository = $repository;
|
||||
$this->revocationService = $revocationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the user model instance. If the user has been removed as an administrator
|
||||
* revoke all of the authentication tokens that have been assigned to their account.
|
||||
* Update the user model instance.
|
||||
*
|
||||
* @param \Pterodactyl\Models\User $user
|
||||
* @param array $data
|
||||
* @return \Illuminate\Support\Collection
|
||||
* @return \Pterodactyl\Models\User
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function handle(User $user, array $data): Collection
|
||||
public function handle(User $user, array $data)
|
||||
{
|
||||
if (! empty(array_get($data, 'password'))) {
|
||||
$data['password'] = $this->hasher->make($data['password']);
|
||||
@ -64,17 +51,9 @@ class UserUpdateService
|
||||
unset($data['password']);
|
||||
}
|
||||
|
||||
if ($this->isUserLevel(User::USER_LEVEL_ADMIN)) {
|
||||
if (array_get($data, 'root_admin', 0) == 0 && $user->root_admin) {
|
||||
$this->revocationService->handle($user, array_get($data, 'ignore_connection_error', false));
|
||||
}
|
||||
} else {
|
||||
unset($data['root_admin']);
|
||||
}
|
||||
/** @var \Pterodactyl\Models\User $response */
|
||||
$response = $this->repository->update($user->id, $data);
|
||||
|
||||
return collect([
|
||||
'model' => $this->repository->update($user->id, $data),
|
||||
'exceptions' => $this->revocationService->getExceptions(),
|
||||
]);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
@ -33,32 +33,13 @@ trait JavascriptInjection
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects server javascript into the page to be used by other services.
|
||||
* Injects the exact array passed in, nothing more.
|
||||
*
|
||||
* @param array $args
|
||||
* @param bool $overwrite
|
||||
* @return array
|
||||
*/
|
||||
public function injectJavascript($args = [], $overwrite = false)
|
||||
public function plainInject($args = [])
|
||||
{
|
||||
$request = $this->request ?? app()->make(Request::class);
|
||||
$server = $request->attributes->get('server');
|
||||
$token = $request->attributes->get('server_token');
|
||||
|
||||
$response = array_merge_recursive([
|
||||
'server' => [
|
||||
'uuid' => $server->uuid,
|
||||
'uuidShort' => $server->uuidShort,
|
||||
'daemonSecret' => $token,
|
||||
],
|
||||
'server_token' => $token,
|
||||
'node' => [
|
||||
'fqdn' => $server->node->fqdn,
|
||||
'scheme' => $server->node->scheme,
|
||||
'daemonListen' => $server->node->daemonListen,
|
||||
],
|
||||
], $args);
|
||||
|
||||
return Javascript::put($overwrite ? $args : $response);
|
||||
return Javascript::put($args);
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,10 @@ class ServerTransformer extends BaseClientTransformer
|
||||
'uuid' => $server->uuid,
|
||||
'name' => $server->name,
|
||||
'node' => $server->node->name,
|
||||
'sftp_details' => [
|
||||
'ip' => $server->node->fqdn,
|
||||
'port' => $server->node->daemonSFTP,
|
||||
],
|
||||
'description' => $server->description,
|
||||
'allocation' => [
|
||||
'ip' => $server->allocation->alias,
|
||||
|
55
app/Transformers/Api/Client/SubuserTransformer.php
Normal file
55
app/Transformers/Api/Client/SubuserTransformer.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Transformers\Api\Client;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Pterodactyl\Models\Subuser;
|
||||
|
||||
class SubuserTransformer extends BaseClientTransformer
|
||||
{
|
||||
protected $availableIncludes = ['permissions'];
|
||||
|
||||
/**
|
||||
* Return the resource name for the JSONAPI output.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getResourceName(): string
|
||||
{
|
||||
return Subuser::RESOURCE_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a User model into a representation that can be shown to regular
|
||||
* users of the API.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Subuser $model
|
||||
* @return array
|
||||
*/
|
||||
public function transform(Subuser $model)
|
||||
{
|
||||
$user = $model->user;
|
||||
|
||||
return [
|
||||
'uuid' => $user->uuid,
|
||||
'username' => $user->username,
|
||||
'email' => $user->email,
|
||||
'image' => 'https://gravatar.com/avatar/' . md5(Str::lower($user->email)),
|
||||
'2fa_enabled' => $user->use_totp,
|
||||
'created_at' => $model->created_at->toIso8601String(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Include the permissions associated with this subuser.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Subuser $model
|
||||
* @return \League\Fractal\Resource\Item
|
||||
*/
|
||||
public function includePermissions(Subuser $model)
|
||||
{
|
||||
return $this->item($model, function (Subuser $model) {
|
||||
return ['permissions' => $model->permissions->pluck('permission')];
|
||||
});
|
||||
}
|
||||
}
|
@ -34,12 +34,13 @@
|
||||
"s1lentium/iptools": "^1.1",
|
||||
"spatie/laravel-fractal": "^5.6",
|
||||
"staudenmeir/belongs-to-through": "^2.6",
|
||||
"symfony/yaml": "^4.0",
|
||||
"webmozart/assert": "^1.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-debugbar": "^3.2",
|
||||
"barryvdh/laravel-ide-helper": "^2.6",
|
||||
"codedungeon/phpunit-result-printer": "^0.26",
|
||||
"codedungeon/phpunit-result-printer": "0.25.1",
|
||||
"friendsofphp/php-cs-fixer": "^2.15.1",
|
||||
"laravel/dusk": "^5.5",
|
||||
"php-mock/php-mock-phpunit": "^2.4",
|
||||
|
132
composer.lock
generated
132
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "54a69da316f2921ebcae63ec6b054468",
|
||||
"content-hash": "39fbdca3eac026ce6a99684706ffa03b",
|
||||
"packages": [
|
||||
{
|
||||
"name": "appstract/laravel-blade-directives",
|
||||
@ -4441,6 +4441,65 @@
|
||||
],
|
||||
"time": "2019-08-26T08:26:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v4.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "76de473358fe802578a415d5bb43c296cf09d211"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/76de473358fe802578a415d5bb43c296cf09d211",
|
||||
"reference": "76de473358fe802578a415d5bb43c296cf09d211",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3",
|
||||
"symfony/polyfill-ctype": "~1.8"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/console": "<3.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/console": "^3.4|^4.0|^5.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/console": "For validating YAML files using the lint command"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.4-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Yaml\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2019-11-12T14:51:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "tijsverkoyen/css-to-inline-styles",
|
||||
"version": "2.2.1",
|
||||
@ -4879,16 +4938,16 @@
|
||||
},
|
||||
{
|
||||
"name": "codedungeon/phpunit-result-printer",
|
||||
"version": "0.26.1",
|
||||
"version": "0.25.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mikeerickson/phpunit-pretty-result-printer.git",
|
||||
"reference": "70efe139f174954392582103355a1b4a3d9022e5"
|
||||
"reference": "4a689ac40366eb4adf166cf4676da7ef30d82315"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mikeerickson/phpunit-pretty-result-printer/zipball/70efe139f174954392582103355a1b4a3d9022e5",
|
||||
"reference": "70efe139f174954392582103355a1b4a3d9022e5",
|
||||
"url": "https://api.github.com/repos/mikeerickson/phpunit-pretty-result-printer/zipball/4a689ac40366eb4adf166cf4676da7ef30d82315",
|
||||
"reference": "4a689ac40366eb4adf166cf4676da7ef30d82315",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -4899,7 +4958,7 @@
|
||||
"symfony/yaml": "^2.7|^3.0|^4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "8.0.*",
|
||||
"phpunit/phpunit": "7.5.*",
|
||||
"spatie/phpunit-watcher": "^1.6"
|
||||
},
|
||||
"type": "library",
|
||||
@ -4928,7 +4987,7 @@
|
||||
"result-printer",
|
||||
"testing"
|
||||
],
|
||||
"time": "2019-02-28T18:52:43+00:00"
|
||||
"time": "2019-02-01T19:13:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/ca-bundle",
|
||||
@ -7546,65 +7605,6 @@
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2019-08-07T11:52:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v4.3.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "5a0b7c32dc3ec56fd4abae8a4a71b0cf05013686"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/5a0b7c32dc3ec56fd4abae8a4a71b0cf05013686",
|
||||
"reference": "5a0b7c32dc3ec56fd4abae8a4a71b0cf05013686",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3",
|
||||
"symfony/polyfill-ctype": "~1.8"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/console": "<3.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/console": "~3.4|~4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/console": "For validating YAML files using the lint command"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Yaml\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2019-08-20T14:27:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
"version": "1.1.3",
|
||||
|
@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
* The destination path for the javascript file.
|
||||
*/
|
||||
'path' => 'public/js',
|
||||
|
||||
/*
|
||||
* The destination filename for the javascript file.
|
||||
*/
|
||||
'filename' => 'laroute',
|
||||
|
||||
/*
|
||||
* The namespace for the helper functions. By default this will bind them to
|
||||
* `window.laroute`.
|
||||
*/
|
||||
'namespace' => 'Router',
|
||||
|
||||
/*
|
||||
* Generate absolute URLs
|
||||
*
|
||||
* Set the Application URL in config/app.php
|
||||
*/
|
||||
'absolute' => false,
|
||||
|
||||
/*
|
||||
* The Filter Method
|
||||
*
|
||||
* 'all' => All routes except "'laroute' => false"
|
||||
* 'only' => Only "'laroute' => true" routes
|
||||
* 'force' => All routes, ignored "laroute" route parameter
|
||||
*/
|
||||
'filter' => 'all',
|
||||
|
||||
/*
|
||||
* Controller Namespace
|
||||
*
|
||||
* Set here your controller namespace (see RouteServiceProvider -> $namespace) for cleaner action calls
|
||||
* e.g. 'App\Http\Controllers'
|
||||
*/
|
||||
'action_namespace' => '',
|
||||
|
||||
/*
|
||||
* The path to the template `laroute.js` file. This is the file that contains
|
||||
* the ported helper Laravel url/route functions and the route data to go
|
||||
* with them.
|
||||
*/
|
||||
'template' => 'vendor/lord/laroute/src/templates/laroute.js',
|
||||
|
||||
/*
|
||||
* Appends a prefix to URLs. By default the prefix is an empty string.
|
||||
*
|
||||
*/
|
||||
'prefix' => '',
|
||||
];
|
90
package.json
90
package.json
@ -4,24 +4,35 @@
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.19",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.9.0",
|
||||
"@fortawesome/react-fontawesome": "^0.1.4",
|
||||
"@hot-loader/react-dom": "^16.8.6",
|
||||
"axios": "^0.18.0",
|
||||
"@types/react-google-recaptcha": "^1.1.1",
|
||||
"axios": "^0.19.0",
|
||||
"ayu-ace": "^2.0.4",
|
||||
"brace": "^0.11.1",
|
||||
"chart.js": "^2.8.0",
|
||||
"classnames": "^2.2.6",
|
||||
"date-fns": "^1.29.0",
|
||||
"easy-peasy": "^3.0.2",
|
||||
"easy-peasy": "^3.2.3",
|
||||
"events": "^3.0.0",
|
||||
"formik": "^1.5.7",
|
||||
"i18next": "^19.0.0",
|
||||
"i18next-chained-backend": "^2.0.0",
|
||||
"i18next-localstorage-backend": "^3.0.0",
|
||||
"i18next-xhr-backend": "^3.2.2",
|
||||
"jquery": "^3.3.1",
|
||||
"lodash-es": "^4.17.15",
|
||||
"path": "^0.12.7",
|
||||
"query-string": "^6.7.0",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-hot-loader": "^4.12.13",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "npm:@hot-loader/react-dom",
|
||||
"react-google-recaptcha": "^2.0.1",
|
||||
"react-hot-loader": "^4.12.18",
|
||||
"react-i18next": "^11.2.1",
|
||||
"react-redux": "^7.1.0",
|
||||
"react-router-dom": "^5.0.1",
|
||||
"react-transition-group": "^4.1.0",
|
||||
"react-router-dom": "^5.1.2",
|
||||
"react-transition-group": "^4.3.0",
|
||||
"sockette": "^2.0.6",
|
||||
"styled-components": "^4.3.2",
|
||||
"styled-components": "^4.4.1",
|
||||
"styled-components-breakpoint": "^3.0.0-preview.20",
|
||||
"use-react-router": "^1.0.7",
|
||||
"uuid": "^3.3.2",
|
||||
"xterm": "^3.14.4",
|
||||
@ -30,27 +41,30 @@
|
||||
"yup": "^0.27.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.6.0",
|
||||
"@babel/plugin-proposal-class-properties": "^7.5.5",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.5.5",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
||||
"@babel/plugin-transform-runtime": "^7.6.0",
|
||||
"@babel/preset-env": "^7.6.0",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@babel/preset-typescript": "^7.6.0",
|
||||
"@babel/runtime": "^7.6.0",
|
||||
"@babel/core": "^7.7.5",
|
||||
"@babel/plugin-proposal-class-properties": "^7.7.4",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.7.4",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.7.4",
|
||||
"@babel/plugin-transform-runtime": "^7.7.5",
|
||||
"@babel/preset-env": "^7.7.5",
|
||||
"@babel/preset-react": "^7.7.4",
|
||||
"@babel/preset-typescript": "^7.7.4",
|
||||
"@babel/runtime": "^7.7.5",
|
||||
"@types/chart.js": "^2.8.5",
|
||||
"@types/classnames": "^2.2.8",
|
||||
"@types/events": "^3.0.0",
|
||||
"@types/feather-icons": "^4.7.0",
|
||||
"@types/lodash": "^4.14.119",
|
||||
"@types/lodash-es": "^4.17.3",
|
||||
"@types/node": "^12.6.9",
|
||||
"@types/query-string": "^6.3.0",
|
||||
"@types/react": "^16.8.19",
|
||||
"@types/react-dom": "^16.8.4",
|
||||
"@types/react": "^16.9.15",
|
||||
"@types/react-dom": "^16.9.4",
|
||||
"@types/react-redux": "^7.1.1",
|
||||
"@types/react-router-dom": "^4.3.3",
|
||||
"@types/react-router": "^5.1.3",
|
||||
"@types/react-router-dom": "^5.1.3",
|
||||
"@types/react-transition-group": "^2.9.2",
|
||||
"@types/styled-components": "^4.1.18",
|
||||
"@types/styled-components": "^4.4.0",
|
||||
"@types/uuid": "^3.4.5",
|
||||
"@types/webpack-env": "^1.13.6",
|
||||
"@types/yup": "^0.26.17",
|
||||
@ -59,24 +73,26 @@
|
||||
"babel-loader": "^8.0.6",
|
||||
"babel-plugin-styled-components": "^1.10.6",
|
||||
"babel-plugin-tailwind-components": "^0.5.10",
|
||||
"css-loader": "^3.2.0",
|
||||
"css-loader": "^3.2.1",
|
||||
"cssnano": "^4.1.10",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-config-standard": "^12.0.0",
|
||||
"eslint-plugin-import": "^2.17.3",
|
||||
"eslint-plugin-node": "^9.1.0",
|
||||
"eslint-plugin-promise": "^4.1.1",
|
||||
"eslint-plugin-react-hooks": "^2.1.2",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"fork-ts-checker-webpack-plugin": "^1.5.0",
|
||||
"glob-all": "^3.1.0",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"mini-css-extract-plugin": "^0.8.0",
|
||||
"postcss": "^6.0.21",
|
||||
"postcss-import": "^11.1.0",
|
||||
"postcss": "^7.0.24",
|
||||
"postcss-import": "^12.0.1",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"postcss-preset-env": "^3.4.0",
|
||||
"precss": "^3.1.2",
|
||||
"purgecss-webpack-plugin": "^1.1.0",
|
||||
"postcss-preset-env": "^6.7.0",
|
||||
"precss": "^4.0.0",
|
||||
"purgecss-webpack-plugin": "^1.6.0",
|
||||
"redux-devtools-extension": "^2.13.8",
|
||||
"resolve-url-loader": "^3.0.0",
|
||||
"source-map-loader": "^0.2.4",
|
||||
"style-loader": "^0.23.1",
|
||||
@ -84,20 +100,24 @@
|
||||
"terser-webpack-plugin": "^1.3.0",
|
||||
"ts-loader": "^5.3.3",
|
||||
"typescript": "^3.6.3",
|
||||
"webpack": "^4.40.2",
|
||||
"webpack": "^4.41.2",
|
||||
"webpack-assets-manifest": "^3.1.1",
|
||||
"webpack-cli": "^3.3.9",
|
||||
"webpack-dev-server": "^3.8.1",
|
||||
"webpack-manifest-plugin": "^2.0.3"
|
||||
"webpack-cli": "^3.3.10",
|
||||
"webpack-dev-server": "^3.9.0",
|
||||
"webpack-manifest-plugin": "^2.0.3",
|
||||
"yarn-deduplicate": "^1.1.1"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rm -rf public/assets/*.js && rm -rf public/assets/*.css",
|
||||
"clean": "rm -rf public/assets/*.{js,css,map}",
|
||||
"watch": "NODE_ENV=development ./node_modules/.bin/webpack --watch --progress",
|
||||
"build": "NODE_ENV=development ./node_modules/.bin/webpack --progress",
|
||||
"build:production": "NODE_ENV=production ./node_modules/.bin/webpack",
|
||||
"build:production": "yarn run clean && NODE_ENV=production ./node_modules/.bin/webpack --mode production",
|
||||
"serve": "yarn run clean && PUBLIC_PATH=https://pterodactyl.test:8080 NODE_ENV=development webpack-dev-server --host 0.0.0.0 --hot --https --key /etc/ssl/private/pterodactyl.test-key.pem --cert /etc/ssl/private/pterodactyl.test.pem"
|
||||
},
|
||||
"browserslist": [
|
||||
"defaults"
|
||||
"> 0.5%",
|
||||
"last 2 versions",
|
||||
"firefox esr",
|
||||
"not dead"
|
||||
]
|
||||
}
|
||||
|
2
public/.gitignore
vendored
Normal file
2
public/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
assets/*
|
||||
!assets/*.svg
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user