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) public function update(UserFormRequest $request, User $user)
{ {
$this->updateService->setUserLevel(User::USER_LEVEL_ADMIN); $this->updateService
$data = $this->updateService->handle($user, $request->normalize()); ->setUserLevel(User::USER_LEVEL_ADMIN)
->handle($user, $request->normalize());
if (! empty($data->get('exceptions'))) { $this->alert->success(trans('admin/user.notices.account_updated'))->flash();
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); 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. * Get a JSON response of users on the system.
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @return \Illuminate\Database\Eloquent\Collection * @return \Illuminate\Support\Collection
*/ */
public function json(Request $request) public function json(Request $request)
{ {

View file

@ -3,6 +3,7 @@
namespace Pterodactyl\Http\Requests\Admin; namespace Pterodactyl\Http\Requests\Admin;
use Pterodactyl\Models\User; use Pterodactyl\Models\User;
use Illuminate\Support\Collection;
class UserFormRequest extends AdminFormRequest class UserFormRequest extends AdminFormRequest
{ {
@ -12,16 +13,16 @@ class UserFormRequest extends AdminFormRequest
*/ */
public function rules() public function rules()
{ {
$rules = collect(User::getRules()); return Collection::make(
if ($this->method() === 'PATCH') { User::getRulesForUpdate($this->route()->parameter('user'))
$rules = collect(User::getRulesForUpdate($this->route()->parameter('user')))->merge([ )->only([
'ignore_connection_error' => ['sometimes', 'nullable', 'boolean'], 'email',
]); 'username',
} 'name_first',
'name_last',
return $rules->only([ 'password',
'email', 'username', 'name_first', 'name_last', 'password', 'language',
'language', 'ignore_connection_error', 'root_admin', 'root_admin',
])->toArray(); ])->toArray();
} }
} }

View file

@ -158,7 +158,7 @@ class User extends Validable implements
'username' => 'required|between:1,255|unique:users,username', 'username' => 'required|between:1,255|unique:users,username',
'name_first' => 'required|string|between:1,255', 'name_first' => 'required|string|between:1,255',
'name_last' => 'required|string|between:1,255', 'name_last' => 'required|string|between:1,255',
'password' => 'required|nullable|string', 'password' => 'sometimes|nullable|string',
'root_admin' => 'boolean', 'root_admin' => 'boolean',
'language' => 'required|string', 'language' => 'required|string',
'use_totp' => 'boolean', 'use_totp' => 'boolean',

View file

@ -5,18 +5,12 @@ namespace Pterodactyl\Services\Users;
use Carbon\Carbon; use Carbon\Carbon;
use Pterodactyl\Models\User; use Pterodactyl\Models\User;
use PragmaRX\Google2FA\Google2FA; use PragmaRX\Google2FA\Google2FA;
use Illuminate\Contracts\Config\Repository;
use Illuminate\Contracts\Encryption\Encrypter; use Illuminate\Contracts\Encryption\Encrypter;
use Pterodactyl\Contracts\Repository\UserRepositoryInterface; use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
use Pterodactyl\Exceptions\Service\User\TwoFactorAuthenticationTokenInvalid; use Pterodactyl\Exceptions\Service\User\TwoFactorAuthenticationTokenInvalid;
class ToggleTwoFactorService class ToggleTwoFactorService
{ {
/**
* @var \Illuminate\Contracts\Config\Repository
*/
private $config;
/** /**
* @var \Illuminate\Contracts\Encryption\Encrypter * @var \Illuminate\Contracts\Encryption\Encrypter
*/ */
@ -37,16 +31,13 @@ class ToggleTwoFactorService
* *
* @param \Illuminate\Contracts\Encryption\Encrypter $encrypter * @param \Illuminate\Contracts\Encryption\Encrypter $encrypter
* @param \PragmaRX\Google2FA\Google2FA $google2FA * @param \PragmaRX\Google2FA\Google2FA $google2FA
* @param \Illuminate\Contracts\Config\Repository $config
* @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $repository * @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $repository
*/ */
public function __construct( public function __construct(
Encrypter $encrypter, Encrypter $encrypter,
Google2FA $google2FA, Google2FA $google2FA,
Repository $config,
UserRepositoryInterface $repository UserRepositoryInterface $repository
) { ) {
$this->config = $config;
$this->encrypter = $encrypter; $this->encrypter = $encrypter;
$this->google2FA = $google2FA; $this->google2FA = $google2FA;
$this->repository = $repository; $this->repository = $repository;
@ -60,16 +51,18 @@ class ToggleTwoFactorService
* @param bool|null $toggleState * @param bool|null $toggleState
* @return bool * @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\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Pterodactyl\Exceptions\Service\User\TwoFactorAuthenticationTokenInvalid * @throws \Pterodactyl\Exceptions\Service\User\TwoFactorAuthenticationTokenInvalid
*/ */
public function handle(User $user, string $token, bool $toggleState = null): bool 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); $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) { if (! $isValidToken) {
throw new TwoFactorAuthenticationTokenInvalid; throw new TwoFactorAuthenticationTokenInvalid;

View file

@ -3,11 +3,9 @@
namespace Pterodactyl\Services\Users; namespace Pterodactyl\Services\Users;
use Pterodactyl\Models\User; use Pterodactyl\Models\User;
use Illuminate\Support\Collection;
use Illuminate\Contracts\Hashing\Hasher; use Illuminate\Contracts\Hashing\Hasher;
use Pterodactyl\Traits\Services\HasUserLevels; use Pterodactyl\Traits\Services\HasUserLevels;
use Pterodactyl\Contracts\Repository\UserRepositoryInterface; use Pterodactyl\Repositories\Eloquent\UserRepository;
use Pterodactyl\Services\DaemonKeys\RevokeMultipleDaemonKeysService;
class UserUpdateService class UserUpdateService
{ {
@ -19,44 +17,33 @@ class UserUpdateService
private $hasher; private $hasher;
/** /**
* @var \Pterodactyl\Contracts\Repository\UserRepositoryInterface * @var \Pterodactyl\Repositories\Eloquent\UserRepository
*/ */
private $repository; private $repository;
/**
* @var \Pterodactyl\Services\DaemonKeys\RevokeMultipleDaemonKeysService
*/
private $revocationService;
/** /**
* UpdateService constructor. * UpdateService constructor.
* *
* @param \Illuminate\Contracts\Hashing\Hasher $hasher * @param \Illuminate\Contracts\Hashing\Hasher $hasher
* @param \Pterodactyl\Services\DaemonKeys\RevokeMultipleDaemonKeysService $revocationService * @param \Pterodactyl\Repositories\Eloquent\UserRepository $repository
* @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $repository
*/ */
public function __construct( public function __construct(Hasher $hasher, UserRepository $repository)
Hasher $hasher, {
RevokeMultipleDaemonKeysService $revocationService,
UserRepositoryInterface $repository
) {
$this->hasher = $hasher; $this->hasher = $hasher;
$this->repository = $repository; $this->repository = $repository;
$this->revocationService = $revocationService;
} }
/** /**
* Update the user model instance. If the user has been removed as an administrator * Update the user model instance.
* revoke all of the authentication tokens that have been assigned to their account.
* *
* @param \Pterodactyl\Models\User $user * @param \Pterodactyl\Models\User $user
* @param array $data * @param array $data
* @return \Illuminate\Support\Collection * @return \Pterodactyl\Models\User
* *
* @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @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'))) { if (! empty(array_get($data, 'password'))) {
$data['password'] = $this->hasher->make($data['password']); $data['password'] = $this->hasher->make($data['password']);
@ -64,17 +51,9 @@ class UserUpdateService
unset($data['password']); unset($data['password']);
} }
if ($this->isUserLevel(User::USER_LEVEL_ADMIN)) { /** @var \Pterodactyl\Models\User $response */
if (array_get($data, 'root_admin', 0) == 0 && $user->root_admin) { $response = $this->repository->update($user->id, $data);
$this->revocationService->handle($user, array_get($data, 'ignore_connection_error', false));
}
} else {
unset($data['root_admin']);
}
return collect([ return $response;
'model' => $this->repository->update($user->id, $data),
'exceptions' => $this->revocationService->getExceptions(),
]);
} }
} }

View file

@ -102,55 +102,11 @@
</select> </select>
<p class="text-muted"><small>Setting this to 'Yes' gives a user full administrative access.</small></p> <p class="text-muted"><small>Setting this to 'Yes' gives a user full administrative access.</small></p>
</div> </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>
</div> </div>
</div> </div>
</form> </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="col-xs-12">
<div class="box box-danger"> <div class="box box-danger">
<div class="box-header with-border"> <div class="box-header with-border">