Skip to content

Commit 5636a67

Browse files
committed
Add TotpTokenValidator
It validates two things: 1. The token must only contain numbers 2. The token must have a specific length (this is configurable via the constructor, the default is 6)
1 parent c1bda44 commit 5636a67

3 files changed

Lines changed: 46 additions & 17 deletions

File tree

application/forms/Account/TwoFactorConfigForm.php

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
use Icinga\Authentication\TwoFactorTotp;
88
use Icinga\Common\Database;
99
use Icinga\User;
10+
use Icinga\Web\Form\Validator\TotpTokenValidator;
1011
use Icinga\Web\Notification;
1112
use ipl\Html\Attributes;
1213
use ipl\Html\HtmlElement;
13-
use ipl\Validator\CallbackValidator;
1414
use ipl\Web\Common\FormUid;
1515
use ipl\Web\Compat\CompatForm;
1616
use ipl\Web\Url;
@@ -124,27 +124,15 @@ protected function assemble(): void
124124
);
125125

126126
$this->addElement(
127-
'number',
127+
'text',
128128
'2fa_verification_token',
129129
[
130+
'required' => true,
130131
'label' => $this->translate('Verification Token'),
131132
'description' => $this->translate(
132133
'Please enter the token from your authenticator app to verify your setup.'
133134
),
134-
'min' => 0,
135-
'max' => 999999,
136-
'step' => 1,
137-
'validators' => [
138-
new CallbackValidator(function (string $value, CallbackValidator $validator) {
139-
if (strlen($value) !== 6) {
140-
$validator->addMessage($this->translate('The token must be exactly 6 digits long.'));
141-
142-
return false;
143-
}
144-
145-
return true;
146-
})
147-
]
135+
'validators' => [new TotpTokenValidator()]
148136
]
149137
);
150138

application/forms/Authentication/Challenge2FAForm.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Icinga\Authentication\Auth;
1212
use Icinga\Authentication\TwoFactorTotp;
1313
use Icinga\Common\Database;
14+
use Icinga\Web\Form\Validator\TotpTokenValidator;
1415
use Icinga\Web\Response;
1516
use Icinga\Web\Session;
1617
use Icinga\Web\Url;
@@ -62,7 +63,8 @@ protected function assemble(): void
6263
'decorators' => [
6364
'RenderElement' => new RenderElementDecorator(),
6465
'Errors' => ['name' => 'Errors', 'options' => ['class' => 'errors']]
65-
]
66+
],
67+
'validators' => [new TotpTokenValidator()]
6668
]
6769
);
6870

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
/* Icinga Web 2 | (c) 2025 Icinga GmbH | GPLv2+ */
4+
5+
namespace Icinga\Web\Form\Validator;
6+
7+
use ipl\I18n\Translation;
8+
use ipl\Validator\BaseValidator;
9+
10+
class TotpTokenValidator extends BaseValidator
11+
{
12+
use Translation;
13+
14+
public function __construct(
15+
/** @var int Token length */
16+
protected int $digits = 6
17+
) {
18+
}
19+
20+
public function isValid($value): bool
21+
{
22+
// Multiple isValid() calls must not stack validation messages
23+
$this->clearMessages();
24+
25+
if (! is_numeric($value)) {
26+
$this->addMessage($this->translate('The token must only contain numbers'));
27+
28+
return false;
29+
}
30+
31+
if (strlen($value) !== $this->digits) {
32+
$this->addMessage($this->translate('The token must be exactly 6 digits long.'));
33+
34+
return false;
35+
}
36+
37+
return true;
38+
}
39+
}

0 commit comments

Comments
 (0)