Skip to content

Commit 22eb15c

Browse files
committed
Add hint to store the secret for recovery
If the device running the authenticator app is lost, the secret can be used to set up an authenticator app on another device. But for that the secret has to be stored on another device when setting up 2FA.
1 parent ee96b88 commit 22eb15c

3 files changed

Lines changed: 88 additions & 1 deletion

File tree

application/forms/Account/TwoFactorConfigForm.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use ipl\Web\Url;
2121
use ipl\Web\Widget\ActionLink;
2222
use ipl\Web\Widget\CopyToClipboard;
23+
use ipl\Web\Widget\Icon;
2324

2425
/**
2526
* Form for enabling and disabling 2FA or creating and updating the 2FA TOTP secret
@@ -92,6 +93,24 @@ protected function assemble(): void
9293
]
9394
);
9495
} else {
96+
$twoFactorEnabled = $this->getPopulatedValue('enabled_2fa') === 'y';
97+
if ($twoFactorEnabled) {
98+
$this->addHtml(HtmlElement::create(
99+
'div',
100+
Attributes::create(['class' => 'two-factor-warning']),
101+
[
102+
new Icon('warning'),
103+
HtmlElement::create(
104+
'p',
105+
null,
106+
new Text(
107+
$this->translate('Make sure to save the QR code or the secret for recovery purposes!')
108+
)
109+
)
110+
]
111+
));
112+
}
113+
95114
$this->addElement(
96115
'checkbox',
97116
'enabled_2fa',
@@ -104,7 +123,7 @@ protected function assemble(): void
104123
]
105124
);
106125

107-
if ($this->getPopulatedValue('enabled_2fa') === 'y') {
126+
if ($twoFactorEnabled) {
108127
// Keep the secret after form submission, otherwise every form submission would generate a new secret.
109128
// This would result in the following:
110129
// - Users would have to scan a new QR code every time the verification fails.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
/* Icinga Notifications Web | (c) 2025 Icinga GmbH | GPLv2 */
4+
5+
namespace Icinga\Web\Widget;
6+
7+
use ipl\Html\BaseHtmlElement;
8+
use ipl\Html\HtmlElement;
9+
use ipl\Html\Text;
10+
use ipl\I18n\Translation;
11+
use ipl\Web\Widget\Icon;
12+
13+
/**
14+
* A warning box that indicates the schedule timezone. It should be used to warn
15+
* the user that the display timezone differs from the schedule timezone.
16+
*/
17+
class TwoFactorWarning extends BaseHtmlElement
18+
{
19+
use Translation;
20+
21+
protected $tag = 'div';
22+
23+
protected $defaultAttributes = ['class' => 'two-factor-warning'];
24+
25+
/**
26+
* @param string $timezone The schedule timezone
27+
*/
28+
public function __construct()
29+
{
30+
}
31+
32+
public function assemble(): void
33+
{
34+
$this->addHtml(new Icon('warning'));
35+
$this->addHtml(new HtmlElement(
36+
'p',
37+
null,
38+
new Text('Make sure to save the QR code or the secret for recovery purposes!')
39+
));
40+
}
41+
}

public/css/icinga/forms.less

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,3 +618,30 @@ form.icinga-form .form-info {
618618
line-break: anywhere;
619619
user-select: all;
620620
}
621+
622+
623+
.two-factor-warning {
624+
display: flex;
625+
align-items: center;
626+
justify-content: center;
627+
column-gap: 1em;
628+
629+
width: fit-content;
630+
margin: 0 auto 1em auto;
631+
padding: .5em 1em;
632+
border: 1px solid @state-warning;
633+
border-radius: .25em;
634+
635+
i.icon{
636+
color: @state-warning;
637+
font-size: 1.5em;
638+
639+
&::before {
640+
margin-right: 0;
641+
}
642+
}
643+
644+
p {
645+
margin: 0;
646+
}
647+
}

0 commit comments

Comments
 (0)