Temporary patch to get user management pages displaying correctly

This commit is contained in:
Dane Everitt 2019-12-08 11:02:59 -08:00
parent 06e5a05f22
commit c087f6429f
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
6 changed files with 32 additions and 119 deletions

View file

@ -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)
{

View file

@ -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();
}
}

View file

@ -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',

View file

@ -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,16 +51,18 @@ 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;

View file

@ -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;
}
}

View file

@ -102,55 +102,11 @@
</select>
<p class="text-muted"><small>Setting this to 'Yes' gives a user full administrative access.</small></p>
</div>
<div class="checkbox checkbox-primary">
<input type="checkbox" id="pIgnoreConnectionError" value="1" name="ignore_connection_error">
<label for="pIgnoreConnectionError"> Ignore exceptions raised while revoking keys.</label>
<p class="text-muted small">If checked, any errors thrown while revoking keys across nodes will be ignored. You should avoid this checkbox if possible as any non-revoked keys could continue to be active for up to 24 hours after this account is changed. If you are needing to revoke account permissions immediately and are facing node issues, you should check this box and then restart any nodes that failed to be updated to clear out any stored keys.</p>
</div>
</div>
</div>
</div>
</div>
</form>
{{--<div class="col-xs-12">--}}
{{--<div class="box">--}}
{{--<div class="box-header with-border">--}}
{{--<h3 class="box-title">Associated Servers</h3>--}}
{{--</div>--}}
{{--<div class="box-body table-responsive no-padding">--}}
{{--<table class="table table-hover">--}}
{{--<thead>--}}
{{--<tr>--}}
{{--<th style="width:2%;"></th>--}}
{{--<th>Identifier</th>--}}
{{--<th>Server Name</th>--}}
{{--<th>Access</th>--}}
{{--<th>Node</th>--}}
{{--<th style="width:10%;"></th>--}}
{{--</tr>--}}
{{--</thead>--}}
{{--<tbody>--}}
{{--@foreach($user->setAccessLevel('subuser')->access()->get() as $server)--}}
{{--<tr>--}}
{{--<td><a href="{{ route('server.index', $server->uuidShort) }}/"><i class="fa fa-tachometer"></i></a></td>--}}
{{--<td><code>{{ $server->uuidShort }}</code></td>--}}
{{--<td><a href="{{ route('admin.servers.view', $server->id) }}">{{ $server->name }}</a></td>--}}
{{--<td>--}}
{{--@if($server->owner_id === $user->id)--}}
{{--<span class="label bg-purple">Owner</span>--}}
{{--@else--}}
{{--<span class="label bg-blue">Subuser</span>--}}
{{--@endif--}}
{{--</td>--}}
{{--<td><a href="{{ route('admin.nodes.view', $server->node->id) }}">{{ $server->node->name }}</a></td>--}}
{{--<td class="centered">@if($server->suspended === 0)<span class="label muted muted-hover label-success">Active</span>@else<span class="label label-warning">Suspended</span>@endif</td>--}}
{{--</td>--}}
{{--@endforeach--}}
{{--</tbody>--}}
{{--</table>--}}
{{--</div>--}}
{{--</div>--}}
{{--</div>--}}
<div class="col-xs-12">
<div class="box box-danger">
<div class="box-header with-border">