Skip to content

Commit 7711b69

Browse files
committed
Finalize two-factor handling on account.
1 parent 0cc895f commit 7711b69

File tree

13 files changed

+299
-137
lines changed

13 files changed

+299
-137
lines changed

app/Http/Controllers/Base/SecurityController.php

Lines changed: 29 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Pterodactyl\Http\Controllers\Base;
44

55
use Illuminate\Http\Request;
6+
use Illuminate\Http\JsonResponse;
67
use Prologue\Alerts\AlertsMessageBag;
78
use Pterodactyl\Http\Controllers\Controller;
89
use Pterodactyl\Services\Users\TwoFactorSetupService;
@@ -62,90 +63,72 @@ public function __construct(
6263
}
6364

6465
/**
65-
* Returns Security Management Page.
66-
*
67-
* @param \Illuminate\Http\Request $request
68-
* @return \Illuminate\View\View
69-
*/
70-
public function index(Request $request)
71-
{
72-
if ($this->config->get('session.driver') === 'database') {
73-
$activeSessions = $this->repository->getUserSessions($request->user()->id);
74-
}
75-
76-
return view('base.security', [
77-
'sessions' => $activeSessions ?? null,
78-
]);
79-
}
80-
81-
/**
82-
* Generates TOTP Secret and returns popup data for user to verify
83-
* that they can generate a valid response.
66+
* Return information about the user's two-factor authentication status. If not enabled setup their
67+
* secret and return information to allow the user to proceede with setup.
8468
*
8569
* @param \Illuminate\Http\Request $request
8670
* @return \Illuminate\Http\JsonResponse
87-
*
8871
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
8972
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
9073
*/
91-
public function generateTotp(Request $request)
74+
public function index(Request $request): JsonResponse
9275
{
93-
return response()->json([
94-
'qrImage' => $this->twoFactorSetupService->handle($request->user()),
76+
if ($request->user()->use_totp) {
77+
return JsonResponse::create([
78+
'enabled' => true,
79+
]);
80+
}
81+
82+
$response = $this->twoFactorSetupService->handle($request->user());
83+
84+
return JsonResponse::create([
85+
'enabled' => false,
86+
'qr_image' => $response->get('image'),
87+
'secret' => $response->get('secret'),
9588
]);
9689
}
9790

9891
/**
9992
* Verifies that 2FA token received is valid and will work on the account.
10093
*
10194
* @param \Illuminate\Http\Request $request
102-
* @return \Illuminate\Http\Response
95+
* @return \Illuminate\Http\JsonResponse
10396
*
10497
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
10598
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
10699
*/
107-
public function setTotp(Request $request)
100+
public function store(Request $request): JsonResponse
108101
{
109102
try {
110103
$this->toggleTwoFactorService->handle($request->user(), $request->input('token') ?? '');
111-
112-
return response('true');
113104
} catch (TwoFactorAuthenticationTokenInvalid $exception) {
114-
return response('false');
105+
$error = true;
115106
}
107+
108+
return JsonResponse::create([
109+
'success' => ! isset($error),
110+
]);
116111
}
117112

118113
/**
119114
* Disables TOTP on an account.
120115
*
121116
* @param \Illuminate\Http\Request $request
122-
* @return \Illuminate\Http\RedirectResponse
117+
* @return \Illuminate\Http\JsonResponse
123118
*
124119
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
125120
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
126121
*/
127-
public function disableTotp(Request $request)
122+
public function delete(Request $request): JsonResponse
128123
{
129124
try {
130125
$this->toggleTwoFactorService->handle($request->user(), $request->input('token') ?? '', false);
131126
} catch (TwoFactorAuthenticationTokenInvalid $exception) {
132-
$this->alert->danger(trans('base.security.2fa_disable_error'))->flash();
127+
$error = true;
133128
}
134129

135-
return redirect()->route('account.security');
136-
}
137-
138-
/**
139-
* Revokes a user session.
140-
*
141-
* @param \Illuminate\Http\Request $request
142-
* @param string $id
143-
* @return \Illuminate\Http\RedirectResponse
144-
*/
145-
public function revoke(Request $request, string $id)
146-
{
147-
$this->repository->deleteUserSession($request->user()->id, $id);
148-
149-
return redirect()->route('account.security');
130+
return JsonResponse::create([
131+
'success' => ! isset($error),
132+
]);
150133
}
151134
}

app/Services/Users/TwoFactorSetupService.php

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,12 @@
1111

1212
use Pterodactyl\Models\User;
1313
use PragmaRX\Google2FA\Google2FA;
14+
use Illuminate\Support\Collection;
1415
use Illuminate\Contracts\Encryption\Encrypter;
1516
use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
16-
use Illuminate\Contracts\Config\Repository as ConfigRepository;
1717

1818
class TwoFactorSetupService
1919
{
20-
/**
21-
* @var \Illuminate\Contracts\Config\Repository
22-
*/
23-
private $config;
24-
2520
/**
2621
* @var \Illuminate\Contracts\Encryption\Encrypter
2722
*/
@@ -40,18 +35,15 @@ class TwoFactorSetupService
4035
/**
4136
* TwoFactorSetupService constructor.
4237
*
43-
* @param \Illuminate\Contracts\Config\Repository $config
4438
* @param \Illuminate\Contracts\Encryption\Encrypter $encrypter
4539
* @param \PragmaRX\Google2FA\Google2FA $google2FA
4640
* @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $repository
4741
*/
4842
public function __construct(
49-
ConfigRepository $config,
5043
Encrypter $encrypter,
5144
Google2FA $google2FA,
5245
UserRepositoryInterface $repository
5346
) {
54-
$this->config = $config;
5547
$this->encrypter = $encrypter;
5648
$this->google2FA = $google2FA;
5749
$this->repository = $repository;
@@ -62,20 +54,23 @@ public function __construct(
6254
* QR code image.
6355
*
6456
* @param \Pterodactyl\Models\User $user
65-
* @return string
57+
* @return \Illuminate\Support\Collection
6658
*
6759
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
6860
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
6961
*/
70-
public function handle(User $user): string
62+
public function handle(User $user): Collection
7163
{
72-
$secret = $this->google2FA->generateSecretKey($this->config->get('pterodactyl.auth.2fa.bytes'));
73-
$image = $this->google2FA->getQRCodeGoogleUrl($this->config->get('app.name'), $user->email, $secret);
64+
$secret = $this->google2FA->generateSecretKey(config('pterodactyl.auth.2fa.bytes'));
65+
$image = $this->google2FA->getQRCodeGoogleUrl(config('app.name'), $user->email, $secret);
7466

7567
$this->repository->withoutFreshModel()->update($user->id, [
7668
'totp_secret' => $this->encrypter->encrypt($secret),
7769
]);
7870

79-
return $image;
71+
return new Collection([
72+
'image' => $image,
73+
'secret' => $secret,
74+
]);
8075
}
8176
}

resources/assets/scripts/components/dashboard/Account.vue

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
<navigation/>
44
<div class="container animate fadein mt-2 sm:mt-6">
55
<modal :show="modalVisible" v-on:close="modalVisible = false">
6-
<TwoFactorAuthentication/>
6+
<TwoFactorAuthentication v-on:close="modalVisible = false"/>
77
</modal>
88
<flash container="mt-2 sm:mt-6 mb-2"/>
99
<div class="flex flex-wrap">
1010
<div class="w-full md:w-1/2">
1111
<div class="sm:m-4 md:ml-0">
1212
<update-email class="mb-4 sm:mb-8"/>
1313
<div class="content-box text-center mb-4 sm:mb-0">
14-
<button class="btn btn-green btn-sm" type="submit" v-on:click="modalVisible = true">Configure 2-Factor Authentication</button>
14+
<button class="btn btn-green btn-sm" type="submit" v-on:click="openModal">Configure 2-Factor Authentication</button>
1515
</div>
1616
</div>
1717
</div>
@@ -39,5 +39,11 @@
3939
modalVisible: false,
4040
};
4141
},
42+
methods: {
43+
openModal: function () {
44+
this.$data.modalVisible = true;
45+
window.events.$emit('two_factor:open');
46+
},
47+
}
4248
};
4349
</script>

resources/assets/scripts/components/dashboard/account/ChangePassword.vue

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,26 @@
22
<div>
33
<form method="post" v-on:submit.prevent="submitForm">
44
<div class="content-box">
5-
<h2 class="mb-6 text-grey-darkest font-medium">Change your password</h2>
5+
<h2 class="mb-6 text-grey-darkest font-medium">{{ $t('dashboard.account.password.title') }}</h2>
66
<div class="mt-6">
7-
<label for="grid-password-current" class="input-label">Current password</label>
7+
<label for="grid-password-current" class="input-label">{{ $t('strings.password') }}</label>
88
<input id="grid-password-current" name="current_password" type="password" class="input" required
99
ref="current"
1010
v-model="current"
1111
>
1212
</div>
1313
<div class="mt-6">
14-
<label for="grid-password-new" class="input-label">New password</label>
14+
<label for="grid-password-new" class="input-label">{{ $t('strings.new_password') }}</label>
1515
<input id="grid-password-new" name="password" type="password" class="input" required
1616
:class="{ error: errors.has('password') }"
1717
v-model="newPassword"
1818
v-validate="'min:8'"
1919
>
2020
<p class="input-help error" v-show="errors.has('password')">{{ errors.first('password') }}</p>
21-
<p class="input-help">Your new password should be at least 8 characters in length.</p>
21+
<p class="input-help">{{ $t('dashboard.account.password.requirements') }}</p>
2222
</div>
2323
<div class="mt-6">
24-
<label for="grid-password-new-confirm" class="input-label">Confirm new password</label>
24+
<label for="grid-password-new-confirm" class="input-label">{{ $t('strings.confirm_password') }}</label>
2525
<input id="grid-password-new-confirm" name="password_confirmation" type="password" class="input" required
2626
:class="{ error: errors.has('password_confirmation') }"
2727
v-model="confirmNew"
@@ -31,7 +31,7 @@
3131
<p class="input-help error" v-show="errors.has('password_confirmation')">{{ errors.first('password_confirmation') }}</p>
3232
</div>
3333
<div class="mt-6 text-right">
34-
<button class="btn btn-blue btn-sm text-right" type="submit">Save</button>
34+
<button class="btn btn-blue btn-sm text-right" type="submit">{{ $t('strings.save') }}</button>
3535
</div>
3636
</div>
3737
</form>
@@ -68,7 +68,7 @@
6868
this.$data.newPassword = '';
6969
this.$data.confirmNew = '';
7070
71-
this.success('Your password has been updated.');
71+
this.success(this.$t('dashboard.account.password.updated'));
7272
})
7373
.catch(err => {
7474
if (!err.response) {

0 commit comments

Comments
 (0)