Merge branch 'develop' into feature/api-v1
This commit is contained in:
commit
a1da8a3c9d
68 changed files with 1785 additions and 524 deletions
|
@ -78,8 +78,10 @@ interface ServerRepositoryInterface extends BaseRepositoryInterface
|
|||
/**
|
||||
* Revoke an access key on the daemon before the time is expired.
|
||||
*
|
||||
* @param string $key
|
||||
* @param string|array $key
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*
|
||||
* @throws \GuzzleHttp\Exception\RequestException
|
||||
*/
|
||||
public function revokeAccessKey($key);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,9 @@
|
|||
|
||||
namespace Pterodactyl\Contracts\Repository;
|
||||
|
||||
use Pterodactyl\Models\User;
|
||||
use Pterodactyl\Models\DaemonKey;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
interface DaemonKeyRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
|
@ -59,4 +61,22 @@ interface DaemonKeyRepositoryInterface extends RepositoryInterface
|
|||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function getKeyWithServer($key);
|
||||
|
||||
/**
|
||||
* Get all of the keys for a specific user including the information needed
|
||||
* from their server relation for revocation on the daemon.
|
||||
*
|
||||
* @param \Pterodactyl\Models\User $user
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getKeysForRevocation(User $user): Collection;
|
||||
|
||||
/**
|
||||
* Delete an array of daemon keys from the database. Used primarily in
|
||||
* conjunction with getKeysForRevocation.
|
||||
*
|
||||
* @param array $ids
|
||||
* @return bool|int
|
||||
*/
|
||||
public function deleteKeys(array $ids);
|
||||
}
|
||||
|
|
32
app/Contracts/Repository/SettingsRepositoryInterface.php
Normal file
32
app/Contracts/Repository/SettingsRepositoryInterface.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Contracts\Repository;
|
||||
|
||||
interface SettingsRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Store a new persistent setting in the database.
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function set(string $key, string $value);
|
||||
|
||||
/**
|
||||
* Retrieve a persistent setting from the database.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $key, $default);
|
||||
|
||||
/**
|
||||
* Remove a key from the database cache.
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function forget(string $key);
|
||||
}
|
|
@ -1,11 +1,4 @@
|
|||
<?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\Http\Connection;
|
||||
|
||||
|
|
|
@ -1,51 +1,25 @@
|
|||
<?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\Controllers\Admin;
|
||||
|
||||
use Krucas\Settings\Settings;
|
||||
use Prologue\Alerts\AlertsMessageBag;
|
||||
use Illuminate\View\View;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Http\Requests\Admin\BaseFormRequest;
|
||||
use Pterodactyl\Services\Helpers\SoftwareVersionService;
|
||||
|
||||
class BaseController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var \Prologue\Alerts\AlertsMessageBag
|
||||
*/
|
||||
protected $alert;
|
||||
|
||||
/**
|
||||
* @var \Krucas\Settings\Settings
|
||||
*/
|
||||
protected $settings;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Helpers\SoftwareVersionService
|
||||
*/
|
||||
protected $version;
|
||||
private $version;
|
||||
|
||||
/**
|
||||
* BaseController constructor.
|
||||
*
|
||||
* @param \Prologue\Alerts\AlertsMessageBag $alert
|
||||
* @param \Krucas\Settings\Settings $settings
|
||||
* @param \Pterodactyl\Services\Helpers\SoftwareVersionService $version
|
||||
*/
|
||||
public function __construct(
|
||||
AlertsMessageBag $alert,
|
||||
Settings $settings,
|
||||
SoftwareVersionService $version
|
||||
) {
|
||||
$this->alert = $alert;
|
||||
$this->settings = $settings;
|
||||
public function __construct(SoftwareVersionService $version)
|
||||
{
|
||||
$this->version = $version;
|
||||
}
|
||||
|
||||
|
@ -54,34 +28,8 @@ class BaseController extends Controller
|
|||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function getIndex()
|
||||
public function index(): View
|
||||
{
|
||||
return view('admin.index', ['version' => $this->version]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the admin settings view.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function getSettings()
|
||||
{
|
||||
return view('admin.settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle settings post request.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Admin\BaseFormRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function postSettings(BaseFormRequest $request)
|
||||
{
|
||||
$this->settings->set('company', $request->input('company'));
|
||||
$this->settings->set('2fa', $request->input('2fa'));
|
||||
|
||||
$this->alert->success('Settings have been successfully updated.')->flash();
|
||||
|
||||
return redirect()->route('admin.settings');
|
||||
}
|
||||
}
|
||||
|
|
91
app/Http/Controllers/Admin/Settings/AdvancedController.php
Normal file
91
app/Http/Controllers/Admin/Settings/AdvancedController.php
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin\Settings;
|
||||
|
||||
use Illuminate\View\View;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Prologue\Alerts\AlertsMessageBag;
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Illuminate\Contracts\Config\Repository as ConfigRepository;
|
||||
use Pterodactyl\Contracts\Repository\SettingsRepositoryInterface;
|
||||
use Pterodactyl\Http\Requests\Admin\Settings\AdvancedSettingsFormRequest;
|
||||
|
||||
class AdvancedController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var \Prologue\Alerts\AlertsMessageBag
|
||||
*/
|
||||
private $alert;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Config\Repository
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Console\Kernel
|
||||
*/
|
||||
private $kernel;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\SettingsRepositoryInterface
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* AdvancedController constructor.
|
||||
*
|
||||
* @param \Prologue\Alerts\AlertsMessageBag $alert
|
||||
* @param \Illuminate\Contracts\Config\Repository $config
|
||||
* @param \Illuminate\Contracts\Console\Kernel $kernel
|
||||
* @param \Pterodactyl\Contracts\Repository\SettingsRepositoryInterface $settings
|
||||
*/
|
||||
public function __construct(
|
||||
AlertsMessageBag $alert,
|
||||
ConfigRepository $config,
|
||||
Kernel $kernel,
|
||||
SettingsRepositoryInterface $settings
|
||||
) {
|
||||
$this->alert = $alert;
|
||||
$this->config = $config;
|
||||
$this->kernel = $kernel;
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render advanced Panel settings UI.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(): View
|
||||
{
|
||||
$showRecaptchaWarning = false;
|
||||
if (
|
||||
$this->config->get('recaptcha._shipped_secret_key') === $this->config->get('recaptcha.secret_key')
|
||||
|| $this->config->get('recaptcha._shipped_website_key') === $this->config->get('recaptcha.website_key')
|
||||
) {
|
||||
$showRecaptchaWarning = true;
|
||||
}
|
||||
|
||||
return view('admin.settings.advanced', [
|
||||
'showRecaptchaWarning' => $showRecaptchaWarning,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Pterodactyl\Http\Requests\Admin\Settings\AdvancedSettingsFormRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(AdvancedSettingsFormRequest $request): RedirectResponse
|
||||
{
|
||||
foreach ($request->normalize() as $key => $value) {
|
||||
$this->settings->set('settings::' . $key, $value);
|
||||
}
|
||||
|
||||
$this->kernel->call('queue:restart');
|
||||
$this->alert->success('Advanced settings have been updated successfully and the queue worker was restarted to apply these changes.')->flash();
|
||||
|
||||
return redirect()->route('admin.settings.advanced');
|
||||
}
|
||||
}
|
89
app/Http/Controllers/Admin/Settings/IndexController.php
Normal file
89
app/Http/Controllers/Admin/Settings/IndexController.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin\Settings;
|
||||
|
||||
use Illuminate\View\View;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Prologue\Alerts\AlertsMessageBag;
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Traits\Helpers\AvailableLanguages;
|
||||
use Pterodactyl\Services\Helpers\SoftwareVersionService;
|
||||
use Pterodactyl\Contracts\Repository\SettingsRepositoryInterface;
|
||||
use Pterodactyl\Http\Requests\Admin\Settings\BaseSettingsFormRequest;
|
||||
|
||||
class IndexController extends Controller
|
||||
{
|
||||
use AvailableLanguages;
|
||||
|
||||
/**
|
||||
* @var \Prologue\Alerts\AlertsMessageBag
|
||||
*/
|
||||
private $alert;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Console\Kernel
|
||||
*/
|
||||
private $kernel;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\SettingsRepositoryInterface
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Helpers\SoftwareVersionService
|
||||
*/
|
||||
private $versionService;
|
||||
|
||||
/**
|
||||
* IndexController constructor.
|
||||
*
|
||||
* @param \Prologue\Alerts\AlertsMessageBag $alert
|
||||
* @param \Illuminate\Contracts\Console\Kernel $kernel
|
||||
* @param \Pterodactyl\Contracts\Repository\SettingsRepositoryInterface $settings
|
||||
* @param \Pterodactyl\Services\Helpers\SoftwareVersionService $versionService
|
||||
*/
|
||||
public function __construct(
|
||||
AlertsMessageBag $alert,
|
||||
Kernel $kernel,
|
||||
SettingsRepositoryInterface $settings,
|
||||
SoftwareVersionService $versionService)
|
||||
{
|
||||
$this->alert = $alert;
|
||||
$this->kernel = $kernel;
|
||||
$this->settings = $settings;
|
||||
$this->versionService = $versionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the UI for basic Panel settings.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(): View
|
||||
{
|
||||
return view('admin.settings.index', [
|
||||
'version' => $this->versionService,
|
||||
'languages' => $this->getAvailableLanguages(true),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle settings update.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Admin\Settings\BaseSettingsFormRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(BaseSettingsFormRequest $request): RedirectResponse
|
||||
{
|
||||
foreach ($request->normalize() as $key => $value) {
|
||||
$this->settings->set('settings::' . $key, $value);
|
||||
}
|
||||
|
||||
$this->kernel->call('queue:restart');
|
||||
$this->alert->success('Panel settings have been updated successfully and the queue worker was restarted to apply these changes.')->flash();
|
||||
|
||||
return redirect()->route('admin.settings');
|
||||
}
|
||||
}
|
112
app/Http/Controllers/Admin/Settings/MailController.php
Normal file
112
app/Http/Controllers/Admin/Settings/MailController.php
Normal file
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin\Settings;
|
||||
|
||||
use Illuminate\View\View;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Prologue\Alerts\AlertsMessageBag;
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Illuminate\Contracts\Encryption\Encrypter;
|
||||
use Pterodactyl\Providers\SettingsServiceProvider;
|
||||
use Illuminate\Contracts\Config\Repository as ConfigRepository;
|
||||
use Pterodactyl\Contracts\Repository\SettingsRepositoryInterface;
|
||||
use Pterodactyl\Http\Requests\Admin\Settings\MailSettingsFormRequest;
|
||||
|
||||
class MailController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var \Prologue\Alerts\AlertsMessageBag
|
||||
*/
|
||||
private $alert;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Config\Repository
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Encryption\Encrypter
|
||||
*/
|
||||
private $encrypter;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Console\Kernel
|
||||
*/
|
||||
private $kernel;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\SettingsRepositoryInterface
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* MailController constructor.
|
||||
*
|
||||
* @param \Prologue\Alerts\AlertsMessageBag $alert
|
||||
* @param \Illuminate\Contracts\Config\Repository $config
|
||||
* @param \Illuminate\Contracts\Encryption\Encrypter $encrypter
|
||||
* @param \Illuminate\Contracts\Console\Kernel $kernel
|
||||
* @param \Pterodactyl\Contracts\Repository\SettingsRepositoryInterface $settings
|
||||
*/
|
||||
public function __construct(
|
||||
AlertsMessageBag $alert,
|
||||
ConfigRepository $config,
|
||||
Encrypter $encrypter,
|
||||
Kernel $kernel,
|
||||
SettingsRepositoryInterface $settings
|
||||
) {
|
||||
$this->alert = $alert;
|
||||
$this->config = $config;
|
||||
$this->encrypter = $encrypter;
|
||||
$this->kernel = $kernel;
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render UI for editing mail settings. This UI should only display if
|
||||
* the server is configured to send mail using SMTP.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(): View
|
||||
{
|
||||
return view('admin.settings.mail', [
|
||||
'disabled' => $this->config->get('mail.driver') !== 'smtp',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle request to update SMTP mail settings.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Admin\Settings\MailSettingsFormRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
*/
|
||||
public function update(MailSettingsFormRequest $request): RedirectResponse
|
||||
{
|
||||
if ($this->config->get('mail.driver') !== 'smtp') {
|
||||
throw new DisplayException('This feature is only available if SMTP is the selected email driver for the Panel.');
|
||||
}
|
||||
|
||||
$values = $request->normalize();
|
||||
if (array_get($values, 'mail:password') === '!e') {
|
||||
$values['mail:password'] = '';
|
||||
}
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
if (in_array($key, SettingsServiceProvider::getEncryptedKeys()) && ! empty($value)) {
|
||||
$value = $this->encrypter->encrypt($value);
|
||||
}
|
||||
|
||||
$this->settings->set('settings::' . $key, $value);
|
||||
}
|
||||
|
||||
$this->kernel->call('queue:restart');
|
||||
$this->alert->success('Mail settings have been updated successfully and the queue worker was restarted to apply these changes.')->flash();
|
||||
|
||||
return redirect()->route('admin.settings.mail');
|
||||
}
|
||||
}
|
|
@ -1,11 +1,4 @@
|
|||
<?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\Controllers\Admin;
|
||||
|
||||
|
@ -160,10 +153,30 @@ class UserController extends Controller
|
|||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function update(UserFormRequest $request, User $user)
|
||||
{
|
||||
$this->updateService->handle($user->id, $request->normalize());
|
||||
$this->updateService->setUserLevel(User::USER_LEVEL_ADMIN);
|
||||
$data = $this->updateService->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();
|
||||
|
||||
return redirect()->route('admin.users.view', $user->id);
|
||||
|
|
|
@ -1,30 +1,8 @@
|
|||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>
|
||||
* Some Modifications (c) 2015 Dylan Seidt <dylan.seidt@gmail.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\Http\Controllers\Base;
|
||||
|
||||
use Pterodactyl\Models\User;
|
||||
use Prologue\Alerts\AlertsMessageBag;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Services\Users\UserUpdateService;
|
||||
|
@ -48,10 +26,8 @@ class AccountController extends Controller
|
|||
* @param \Prologue\Alerts\AlertsMessageBag $alert
|
||||
* @param \Pterodactyl\Services\Users\UserUpdateService $updateService
|
||||
*/
|
||||
public function __construct(
|
||||
AlertsMessageBag $alert,
|
||||
UserUpdateService $updateService
|
||||
) {
|
||||
public function __construct(AlertsMessageBag $alert, UserUpdateService $updateService)
|
||||
{
|
||||
$this->alert = $alert;
|
||||
$this->updateService = $updateService;
|
||||
}
|
||||
|
@ -74,6 +50,7 @@ class AccountController extends Controller
|
|||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function update(AccountDataFormRequest $request)
|
||||
{
|
||||
|
@ -86,7 +63,8 @@ class AccountController extends Controller
|
|||
$data = $request->only(['name_first', 'name_last', 'username']);
|
||||
}
|
||||
|
||||
$this->updateService->handle($request->user()->id, $data);
|
||||
$this->updateService->setUserLevel(User::USER_LEVEL_USER);
|
||||
$this->updateService->handle($request->user(), $data);
|
||||
$this->alert->success(trans('base.account.details_updated'))->flash();
|
||||
|
||||
return redirect()->route('account');
|
||||
|
|
|
@ -149,8 +149,6 @@ class TaskManagementController extends Controller
|
|||
*
|
||||
* @param \Pterodactyl\Http\Requests\Server\ScheduleCreationFormRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function update(ScheduleCreationFormRequest $request): RedirectResponse
|
||||
{
|
||||
|
@ -177,7 +175,7 @@ class TaskManagementController extends Controller
|
|||
*/
|
||||
public function delete(Request $request): Response
|
||||
{
|
||||
$server = $request->attributes->get('server_data.model');
|
||||
$server = $request->attributes->get('server');
|
||||
$schedule = $request->attributes->get('schedule');
|
||||
$this->authorize('delete-schedule', $server);
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ class AdminAuthenticate
|
|||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
|
|
|
@ -46,6 +46,8 @@ class DaemonAuthenticate
|
|||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
|
|
|
@ -11,7 +11,6 @@ namespace Pterodactyl\Http\Middleware;
|
|||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Krucas\Settings\Settings;
|
||||
use Prologue\Alerts\AlertsMessageBag;
|
||||
|
||||
class RequireTwoFactorAuthentication
|
||||
|
@ -25,11 +24,6 @@ class RequireTwoFactorAuthentication
|
|||
*/
|
||||
private $alert;
|
||||
|
||||
/**
|
||||
* @var \Krucas\Settings\Settings
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* The names of routes that should be accessable without 2FA enabled.
|
||||
*
|
||||
|
@ -56,12 +50,10 @@ class RequireTwoFactorAuthentication
|
|||
* RequireTwoFactorAuthentication constructor.
|
||||
*
|
||||
* @param \Prologue\Alerts\AlertsMessageBag $alert
|
||||
* @param \Krucas\Settings\Settings $settings
|
||||
*/
|
||||
public function __construct(AlertsMessageBag $alert, Settings $settings)
|
||||
public function __construct(AlertsMessageBag $alert)
|
||||
{
|
||||
$this->alert = $alert;
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -81,10 +73,7 @@ class RequireTwoFactorAuthentication
|
|||
return $next($request);
|
||||
}
|
||||
|
||||
switch ((int) $this->settings->get('2fa', 0)) {
|
||||
case self::LEVEL_NONE:
|
||||
return $next($request);
|
||||
break;
|
||||
switch ((int) config('pterodactyl.auth.2fa_required')) {
|
||||
case self::LEVEL_ADMIN:
|
||||
if (! $request->user()->root_admin || $request->user()->use_totp) {
|
||||
return $next($request);
|
||||
|
@ -95,6 +84,9 @@ class RequireTwoFactorAuthentication
|
|||
return $next($request);
|
||||
}
|
||||
break;
|
||||
case self::LEVEL_NONE:
|
||||
default:
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
$this->alert->danger(trans('auth.2fa_must_be_enabled'))->flash();
|
||||
|
|
|
@ -47,9 +47,8 @@ class AuthenticateAsSubuser
|
|||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Illuminate\Auth\AuthenticationException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
|
|
|
@ -49,7 +49,7 @@ class ScheduleBelongsToServer
|
|||
$scheduleId = $this->hashids->decodeFirst($request->route()->parameter('schedule'), 0);
|
||||
$schedule = $this->repository->getScheduleWithTasks($scheduleId);
|
||||
|
||||
if (object_get($schedule, 'server_id') !== $server->id) {
|
||||
if ($schedule->server_id !== $server->id) {
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Admin\Settings;
|
||||
|
||||
use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
|
||||
|
||||
class AdvancedSettingsFormRequest extends AdminFormRequest
|
||||
{
|
||||
/**
|
||||
* Return all of the rules to apply to this request's data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'recaptcha:enabled' => 'required|in:true,false',
|
||||
'recaptcha:secret_key' => 'required|string|max:255',
|
||||
'recaptcha:website_key' => 'required|string|max:255',
|
||||
'pterodactyl:guzzle:timeout' => 'required|integer|between:1,60',
|
||||
'pterodactyl:guzzle:connect_timeout' => 'required|integer|between:1,60',
|
||||
'pterodactyl:console:count' => 'required|integer|min:1',
|
||||
'pterodactyl:console:frequency' => 'required|integer|min:10',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function attributes()
|
||||
{
|
||||
return [
|
||||
'recaptcha:enabled' => 'reCAPTCHA Enabled',
|
||||
'recaptcha:secret_key' => 'reCAPTCHA Secret Key',
|
||||
'recaptcha:website_key' => 'reCAPTCHA Website Key',
|
||||
'pterodactyl:guzzle:timeout' => 'HTTP Request Timeout',
|
||||
'pterodactyl:guzzle:connect_timeout' => 'HTTP Connection Timeout',
|
||||
'pterodactyl:console:count' => 'Console Message Count',
|
||||
'pterodactyl:console:frequency' => 'Console Frequency Tick',
|
||||
];
|
||||
}
|
||||
}
|
36
app/Http/Requests/Admin/Settings/BaseSettingsFormRequest.php
Normal file
36
app/Http/Requests/Admin/Settings/BaseSettingsFormRequest.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Admin\Settings;
|
||||
|
||||
use Illuminate\Validation\Rule;
|
||||
use Pterodactyl\Traits\Helpers\AvailableLanguages;
|
||||
use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
|
||||
|
||||
class BaseSettingsFormRequest extends AdminFormRequest
|
||||
{
|
||||
use AvailableLanguages;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'app:name' => 'required|string|max:255',
|
||||
'pterodactyl:auth:2fa_required' => 'required|integer|in:0,1,2',
|
||||
'app:locale' => ['required', 'string', Rule::in(array_keys($this->getAvailableLanguages()))],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function attributes()
|
||||
{
|
||||
return [
|
||||
'app:name' => 'Company Name',
|
||||
'pterodactyl:auth:2fa_required' => 'Require 2-Factor Authentication',
|
||||
'app:locale' => 'Default Language',
|
||||
];
|
||||
}
|
||||
}
|
44
app/Http/Requests/Admin/Settings/MailSettingsFormRequest.php
Normal file
44
app/Http/Requests/Admin/Settings/MailSettingsFormRequest.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Admin\Settings;
|
||||
|
||||
use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
|
||||
|
||||
class MailSettingsFormRequest extends AdminFormRequest
|
||||
{
|
||||
/**
|
||||
* Return rules to validate mail settings POST data aganist.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'mail:host' => 'required|string',
|
||||
'mail:port' => 'required|integer|between:1,65535',
|
||||
'mail:encryption' => 'present|string|in:"",tls,ssl',
|
||||
'mail:username' => 'string|max:255',
|
||||
'mail:password' => 'string|max:255',
|
||||
'mail:from:address' => 'required|string|email',
|
||||
'mail:from:name' => 'string|max:255',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the default normalization function for this type of request
|
||||
* as we need to accept empty values on the keys.
|
||||
*
|
||||
* @param array $only
|
||||
* @return array
|
||||
*/
|
||||
public function normalize($only = [])
|
||||
{
|
||||
$keys = array_flip(array_keys($this->rules()));
|
||||
|
||||
if (empty($this->input('mail:password'))) {
|
||||
unset($keys['mail:password']);
|
||||
}
|
||||
|
||||
return $this->only(array_flip($keys));
|
||||
}
|
||||
}
|
|
@ -19,7 +19,11 @@ class UserFormRequest extends AdminFormRequest
|
|||
public function rules()
|
||||
{
|
||||
if ($this->method() === 'PATCH') {
|
||||
return User::getUpdateRulesForId($this->route()->parameter('user')->id);
|
||||
$rules = User::getUpdateRulesForId($this->route()->parameter('user')->id);
|
||||
|
||||
return array_merge($rules, [
|
||||
'ignore_connection_error' => 'sometimes|nullable|boolean',
|
||||
]);
|
||||
}
|
||||
|
||||
return User::getCreateRules();
|
||||
|
@ -30,7 +34,7 @@ class UserFormRequest extends AdminFormRequest
|
|||
if ($this->method === 'PATCH') {
|
||||
return array_merge(
|
||||
$this->intersect('password'),
|
||||
$this->only(['email', 'username', 'name_first', 'name_last', 'root_admin'])
|
||||
$this->only(['email', 'username', 'name_first', 'name_last', 'root_admin', 'ignore_connection_error'])
|
||||
);
|
||||
}
|
||||
|
||||
|
|
39
app/Models/Setting.php
Normal file
39
app/Models/Setting.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Models;
|
||||
|
||||
use Sofa\Eloquence\Eloquence;
|
||||
use Sofa\Eloquence\Validable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Sofa\Eloquence\Contracts\CleansAttributes;
|
||||
use Sofa\Eloquence\Contracts\Validable as ValidableContract;
|
||||
|
||||
class Setting extends Model implements CleansAttributes, ValidableContract
|
||||
{
|
||||
use Eloquence, Validable;
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'settings';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['key', 'value'];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $applicationRules = [
|
||||
'key' => 'required|string|between:1,255',
|
||||
'value' => 'string',
|
||||
];
|
||||
}
|
|
@ -13,7 +13,6 @@ use Pterodactyl\Observers\UserObserver;
|
|||
use Pterodactyl\Observers\ServerObserver;
|
||||
use Pterodactyl\Observers\SubuserObserver;
|
||||
use Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider;
|
||||
use DaneEveritt\LoginNotifications\NotificationServiceProvider;
|
||||
use Barryvdh\Debugbar\ServiceProvider as DebugbarServiceProvider;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
|
@ -42,10 +41,6 @@ class AppServiceProvider extends ServiceProvider
|
|||
$this->app->register(DebugbarServiceProvider::class);
|
||||
$this->app->register(IdeHelperServiceProvider::class);
|
||||
}
|
||||
|
||||
if (config('pterodactyl.auth.notifications')) {
|
||||
$this->app->register(NotificationServiceProvider::class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,6 +26,7 @@ use Pterodactyl\Repositories\Eloquent\SubuserRepository;
|
|||
use Pterodactyl\Repositories\Eloquent\DatabaseRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\LocationRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\ScheduleRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\SettingsRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\DaemonKeyRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\AllocationRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\PermissionRepository;
|
||||
|
@ -47,6 +48,7 @@ use Pterodactyl\Contracts\Repository\SubuserRepositoryInterface;
|
|||
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\LocationRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\SettingsRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\PermissionRepositoryInterface;
|
||||
|
@ -86,10 +88,13 @@ class RepositoryServiceProvider extends ServiceProvider
|
|||
$this->app->bind(ServerRepositoryInterface::class, ServerRepository::class);
|
||||
$this->app->bind(ServerVariableRepositoryInterface::class, ServerVariableRepository::class);
|
||||
$this->app->bind(SessionRepositoryInterface::class, SessionRepository::class);
|
||||
$this->app->bind(SettingsRepositoryInterface::class, SettingsRepository::class);
|
||||
$this->app->bind(SubuserRepositoryInterface::class, SubuserRepository::class);
|
||||
$this->app->bind(TaskRepositoryInterface::class, TaskRepository::class);
|
||||
$this->app->bind(UserRepositoryInterface::class, UserRepository::class);
|
||||
|
||||
$this->app->alias(SettingsRepositoryInterface::class, 'settings');
|
||||
|
||||
// Daemon Repositories
|
||||
if ($this->app->make('config')->get('pterodactyl.daemon.use_new_daemon')) {
|
||||
$this->app->bind(ConfigurationRepositoryInterface::class, \Pterodactyl\Repositories\Wings\ConfigurationRepository::class);
|
||||
|
|
101
app/Providers/SettingsServiceProvider.php
Normal file
101
app/Providers/SettingsServiceProvider.php
Normal file
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Contracts\Encryption\Encrypter;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Contracts\Config\Repository as ConfigRepository;
|
||||
use Pterodactyl\Contracts\Repository\SettingsRepositoryInterface;
|
||||
|
||||
class SettingsServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* An array of configuration keys to override with database values
|
||||
* if they exist.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $keys = [
|
||||
'app:name',
|
||||
'app:locale',
|
||||
'recaptcha:enabled',
|
||||
'recaptcha:secret_key',
|
||||
'recaptcha:website_key',
|
||||
'pterodactyl:guzzle:timeout',
|
||||
'pterodactyl:guzzle:connect_timeout',
|
||||
'pterodactyl:console:count',
|
||||
'pterodactyl:console:frequency',
|
||||
'pterodactyl:auth:2fa_required',
|
||||
];
|
||||
|
||||
/**
|
||||
* Keys specific to the mail driver that are only grabbed from the database
|
||||
* when using the SMTP driver.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $emailKeys = [
|
||||
'mail:host',
|
||||
'mail:port',
|
||||
'mail:from:address',
|
||||
'mail:from:name',
|
||||
'mail:encryption',
|
||||
'mail:username',
|
||||
'mail:password',
|
||||
];
|
||||
|
||||
/**
|
||||
* Keys that are encrypted and should be decrypted when set in the
|
||||
* configuration array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $encrypted = [
|
||||
'mail:password',
|
||||
];
|
||||
|
||||
/**
|
||||
* Boot the service provider.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Config\Repository $config
|
||||
* @param \Illuminate\Contracts\Encryption\Encrypter $encrypter
|
||||
* @param \Pterodactyl\Contracts\Repository\SettingsRepositoryInterface $settings
|
||||
*/
|
||||
public function boot(ConfigRepository $config, Encrypter $encrypter, SettingsRepositoryInterface $settings)
|
||||
{
|
||||
if ($config->get('pterodactyl.load_environment_only', false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only set the email driver settings from the database if we
|
||||
// are configured using SMTP as the driver.
|
||||
if ($config->get('mail.driver') === 'smtp') {
|
||||
$this->keys = array_merge($this->keys, $this->emailKeys);
|
||||
}
|
||||
|
||||
$values = $settings->all()->mapWithKeys(function ($setting) {
|
||||
return [$setting->key => $setting->value];
|
||||
})->toArray();
|
||||
|
||||
foreach ($this->keys as $key) {
|
||||
$value = array_get($values, 'settings::' . $key, $config->get(str_replace(':', '.', $key)));
|
||||
if (in_array($key, self::$encrypted)) {
|
||||
try {
|
||||
$value = $encrypter->decrypt($value);
|
||||
} catch (DecryptException $exception) {
|
||||
}
|
||||
}
|
||||
|
||||
$config->set(str_replace(':', '.', $key), $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getEncryptedKeys(): array
|
||||
{
|
||||
return self::$encrypted;
|
||||
}
|
||||
}
|
|
@ -107,7 +107,13 @@ class ServerRepository extends BaseRepository implements ServerRepositoryInterfa
|
|||
*/
|
||||
public function revokeAccessKey($key)
|
||||
{
|
||||
Assert::stringNotEmpty($key, 'First argument passed to revokeAccessKey must be a non-empty string, received %s.');
|
||||
if (is_array($key)) {
|
||||
return $this->getHttpClient()->request('POST', 'keys', [
|
||||
'json' => $key,
|
||||
]);
|
||||
}
|
||||
|
||||
Assert::stringNotEmpty($key, 'First argument passed to revokeAccessKey must be a non-empty string or array, received %s.');
|
||||
|
||||
return $this->getHttpClient()->request('DELETE', 'keys/' . $key);
|
||||
}
|
||||
|
|
|
@ -24,8 +24,10 @@
|
|||
|
||||
namespace Pterodactyl\Repositories\Eloquent;
|
||||
|
||||
use Pterodactyl\Models\User;
|
||||
use Webmozart\Assert\Assert;
|
||||
use Pterodactyl\Models\DaemonKey;
|
||||
use Illuminate\Support\Collection;
|
||||
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
|
||||
use Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface;
|
||||
|
||||
|
@ -83,4 +85,28 @@ class DaemonKeyRepository extends EloquentRepository implements DaemonKeyReposit
|
|||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the keys for a specific user including the information needed
|
||||
* from their server relation for revocation on the daemon.
|
||||
*
|
||||
* @param \Pterodactyl\Models\User $user
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getKeysForRevocation(User $user): Collection
|
||||
{
|
||||
return $this->getBuilder()->with('server:id,uuid,node_id')->where('user_id', $user->id)->get($this->getColumns());
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an array of daemon keys from the database. Used primarily in
|
||||
* conjunction with getKeysForRevocation.
|
||||
*
|
||||
* @param array $ids
|
||||
* @return bool|int
|
||||
*/
|
||||
public function deleteKeys(array $ids)
|
||||
{
|
||||
return $this->getBuilder()->whereIn('id', $ids)->delete();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,11 +18,6 @@ class LocationRepository extends EloquentRepository implements LocationRepositor
|
|||
{
|
||||
use Searchable;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $searchTerm;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
96
app/Repositories/Eloquent/SettingsRepository.php
Normal file
96
app/Repositories/Eloquent/SettingsRepository.php
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Repositories\Eloquent;
|
||||
|
||||
use Pterodactyl\Models\Setting;
|
||||
use Pterodactyl\Contracts\Repository\SettingsRepositoryInterface;
|
||||
|
||||
class SettingsRepository extends EloquentRepository implements SettingsRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $cache = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $databaseMiss = [];
|
||||
|
||||
/**
|
||||
* Return an instance of the model that acts as the base for
|
||||
* this repository.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return Setting::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new persistent setting in the database.
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
*/
|
||||
public function set(string $key, string $value)
|
||||
{
|
||||
// Clear item from the cache.
|
||||
$this->clearCache($key);
|
||||
$this->withoutFresh()->updateOrCreate(['key' => $key], ['value' => $value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a persistent setting from the database.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $key, $default = null)
|
||||
{
|
||||
// If item has already been requested return it from the cache. If
|
||||
// we already know it is missing, immediately return the default
|
||||
// value.
|
||||
if (array_key_exists($key, $this->cache)) {
|
||||
return $this->cache[$key];
|
||||
} elseif (array_key_exists($key, $this->databaseMiss)) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$instance = $this->getBuilder()->where('key', $key)->first();
|
||||
|
||||
if (is_null($instance)) {
|
||||
$this->databaseMiss[$key] = true;
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
$this->cache[$key] = $instance->value;
|
||||
|
||||
return $this->cache[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a key from the database cache.
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function forget(string $key)
|
||||
{
|
||||
$this->clearCache($key);
|
||||
$this->deleteWhere(['key' => $key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a key from the cache.
|
||||
*
|
||||
* @param string $key
|
||||
*/
|
||||
protected function clearCache(string $key)
|
||||
{
|
||||
unset($this->cache[$key], $this->databaseMiss[$key]);
|
||||
}
|
||||
}
|
91
app/Services/DaemonKeys/RevokeMultipleDaemonKeysService.php
Normal file
91
app/Services/DaemonKeys/RevokeMultipleDaemonKeysService.php
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Services\DaemonKeys;
|
||||
|
||||
use Pterodactyl\Models\User;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface;
|
||||
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
use Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface as DaemonServerRepository;
|
||||
|
||||
class RevokeMultipleDaemonKeysService
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $exceptions = [];
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface
|
||||
*/
|
||||
private $daemonRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* RevokeMultipleDaemonKeysService constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface $repository
|
||||
* @param \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface $daemonRepository
|
||||
*/
|
||||
public function __construct(
|
||||
DaemonKeyRepositoryInterface $repository,
|
||||
DaemonServerRepository $daemonRepository
|
||||
) {
|
||||
$this->daemonRepository = $daemonRepository;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grab all of the keys that exist for a single user and delete them from all
|
||||
* daemon's that they are assigned to. If connection fails, this function will
|
||||
* return an error.
|
||||
*
|
||||
* @param \Pterodactyl\Models\User $user
|
||||
* @param bool $ignoreConnectionErrors
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function handle(User $user, bool $ignoreConnectionErrors = false)
|
||||
{
|
||||
$keys = $this->repository->getKeysForRevocation($user);
|
||||
|
||||
$keys->groupBy('server.node_id')->each(function ($group, $node) use ($ignoreConnectionErrors) {
|
||||
try {
|
||||
$this->daemonRepository->setNode($node)->revokeAccessKey(collect($group)->pluck('secret')->toArray());
|
||||
} catch (RequestException $exception) {
|
||||
if (! $ignoreConnectionErrors) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
}
|
||||
|
||||
$this->setConnectionException($node, $exception);
|
||||
}
|
||||
|
||||
$this->repository->deleteKeys(collect($group)->pluck('id')->toArray());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of exceptions that were returned by the handle function.
|
||||
*
|
||||
* @return RequestException[]
|
||||
*/
|
||||
public function getExceptions()
|
||||
{
|
||||
return $this->exceptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an exception for a node to the array.
|
||||
*
|
||||
* @param int $node
|
||||
* @param \GuzzleHttp\Exception\RequestException $exception
|
||||
*/
|
||||
protected function setConnectionException(int $node, RequestException $exception)
|
||||
{
|
||||
$this->exceptions[$node] = $exception;
|
||||
}
|
||||
}
|
|
@ -1,59 +1,79 @@
|
|||
<?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\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;
|
||||
|
||||
class UserUpdateService
|
||||
{
|
||||
use HasUserLevels;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Hashing\Hasher
|
||||
*/
|
||||
protected $hasher;
|
||||
private $hasher;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\UserRepositoryInterface
|
||||
*/
|
||||
protected $repository;
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\DaemonKeys\RevokeMultipleDaemonKeysService
|
||||
*/
|
||||
private $revocationService;
|
||||
|
||||
/**
|
||||
* UpdateService constructor.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Hashing\Hasher $hasher
|
||||
* @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $repository
|
||||
* @param \Illuminate\Contracts\Hashing\Hasher $hasher
|
||||
* @param \Pterodactyl\Services\DaemonKeys\RevokeMultipleDaemonKeysService $revocationService
|
||||
* @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $repository
|
||||
*/
|
||||
public function __construct(
|
||||
Hasher $hasher,
|
||||
RevokeMultipleDaemonKeysService $revocationService,
|
||||
UserRepositoryInterface $repository
|
||||
) {
|
||||
$this->hasher = $hasher;
|
||||
$this->repository = $repository;
|
||||
$this->revocationService = $revocationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the user model instance.
|
||||
* Update the user model instance. If the user has been removed as an administrator
|
||||
* revoke all of the authentication tokens that have beenn assigned to their account.
|
||||
*
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
* @param \Pterodactyl\Models\User $user
|
||||
* @param array $data
|
||||
* @return \Illuminate\Support\Collection
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function handle($id, array $data)
|
||||
public function handle(User $user, array $data): Collection
|
||||
{
|
||||
if (isset($data['password'])) {
|
||||
if (array_has($data, 'password')) {
|
||||
$data['password'] = $this->hasher->make($data['password']);
|
||||
}
|
||||
|
||||
return $this->repository->update($id, $data);
|
||||
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']);
|
||||
}
|
||||
|
||||
return collect([
|
||||
'model' => $this->repository->update($user->id, $data),
|
||||
'exceptions' => $this->revocationService->getExceptions(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
56
app/Traits/Helpers/AvailableLanguages.php
Normal file
56
app/Traits/Helpers/AvailableLanguages.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Traits\Helpers;
|
||||
|
||||
use Matriphe\ISO639\ISO639;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
|
||||
trait AvailableLanguages
|
||||
{
|
||||
/**
|
||||
* @var \Illuminate\Filesystem\Filesystem
|
||||
*/
|
||||
private $filesystem;
|
||||
|
||||
/**
|
||||
* @var \Matriphe\ISO639\ISO639
|
||||
*/
|
||||
private $iso639;
|
||||
|
||||
/**
|
||||
* Return all of the available languages on the Panel based on those
|
||||
* that are present in the language folder.
|
||||
*
|
||||
* @param bool $localize
|
||||
* @return array
|
||||
*/
|
||||
public function getAvailableLanguages($localize = false): array
|
||||
{
|
||||
return collect($this->getFilesystemInstance()->directories(resource_path('lang')))->mapWithKeys(function ($path) use ($localize) {
|
||||
$code = basename($path);
|
||||
$value = $localize ? $this->getIsoInstance()->nativeByCode1($code) : $this->getIsoInstance()->languageByCode1($code);
|
||||
|
||||
return [$code => title_case($value)];
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance of the filesystem for getting a folder listing.
|
||||
*
|
||||
* @return \Illuminate\Filesystem\Filesystem
|
||||
*/
|
||||
private function getFilesystemInstance(): Filesystem
|
||||
{
|
||||
return $this->filesystem = $this->filesystem ?: app()->make(Filesystem::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance of the ISO639 class for generating names.
|
||||
*
|
||||
* @return \Matriphe\ISO639\ISO639
|
||||
*/
|
||||
private function getIsoInstance(): ISO639
|
||||
{
|
||||
return $this->iso639 = $this->iso639 ?: app()->make(ISO639::class);
|
||||
}
|
||||
}
|
Reference in a new issue