Commit 00333b6
committed
[#5864] Add MFA enrollment UI with self-contained QR rendering
This patch adds a "Two-Factor Authentication" card to the user profile
page, providing the complete MFA lifecycle management UI, and adds
client-side QR code generation.
QR code rendering - qrcode library (v1.5.4, MIT license):
The QR code for the TOTP provisioning URI is generated entirely
client-side using a <canvas> element. No external services (Google
Charts API, QR Server, etc.) are involved. This is a deliberate
decision: academic tools aimed at digital preservation must not depend
on third-party services subject to arbitrary policy changes,
deprecation, or rate limits. The qrcode library is pure JavaScript
with zero runtime dependencies.
Profile page MFA card features:
- Setup mode: generates secret via POST /mfa/setup, renders QR code
from the otpauth:// provisioning URI on a canvas element
- Enrollment confirmation: validates first TOTP code, displays
recovery codes (shown once, never stored in plaintext client-side)
- Status display: shows enabled badge + remaining recovery code count
- Disable: requires current TOTP code (prevents unauthorized disable)
- Regenerate recovery codes: requires current TOTP code
Design decisions:
1. QR rendered in ngAfterViewChecked (not ngOnInit):
The canvas element is inside an @if block. It only exists in the
DOM after provisioningUri$ emits. AfterViewChecked ensures the
canvas is available when we call QRCode.toCanvas().
2. BehaviorSubjects (not NgRx) for profile component state:
The profile MFA card is self-contained and does not need cross-
component coordination. Local reactive state with BehaviorSubjects
keeps it simple and testable without NgRx boilerplate.
3. All destructive operations require TOTP code:
Disable and regenerate-codes both require a valid current code.
This prevents a session-hijacker from removing MFA protection.
4. Custom theme compatibility:
ProfilePageMfaFormComponent added to custom theme's imports array.
New dependencies:
- qrcode@1.5.4 (MIT) - client-side QR generation
- @types/qrcode (devDep) - TypeScript type definitions
i18n keys added: login.mfa.*, profile.mfa.* (25 keys total)
Test plan:
1. Apply patch
2. Login, navigate to /profile
=> SUCCESS: "Two-Factor Authentication" card visible
3. Click setup, verify QR code renders (no network requests to external)
4. Scan with authenticator app, enter code
=> SUCCESS: Recovery codes displayed
5. Run: npm run lint
=> SUCCESS: 0 errors
6. Sign off :-D1 parent 20d56d0 commit 00333b6
13 files changed
Lines changed: 587 additions & 24 deletions
File tree
- src
- app
- core/auth
- profile-page
- profile-page-mfa-form
- assets/i18n
- themes/custom/app/profile-page
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
100 | 100 | | |
101 | 101 | | |
102 | 102 | | |
| 103 | + | |
103 | 104 | | |
104 | 105 | | |
105 | 106 | | |
| |||
147 | 148 | | |
148 | 149 | | |
149 | 150 | | |
| 151 | + | |
150 | 152 | | |
151 | 153 | | |
152 | 154 | | |
| |||
179 | 181 | | |
180 | 182 | | |
181 | 183 | | |
| 184 | + | |
182 | 185 | | |
183 | 186 | | |
184 | 187 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
72 | 72 | | |
73 | 73 | | |
74 | 74 | | |
75 | | - | |
| 75 | + | |
76 | 76 | | |
77 | 77 | | |
78 | | - | |
| 78 | + | |
79 | 79 | | |
80 | 80 | | |
81 | 81 | | |
| |||
164 | 164 | | |
165 | 165 | | |
166 | 166 | | |
167 | | - | |
168 | | - | |
169 | | - | |
170 | | - | |
171 | | - | |
172 | | - | |
173 | | - | |
174 | 167 | | |
175 | 168 | | |
176 | 169 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
2 | 5 | | |
3 | 6 | | |
4 | 7 | | |
| |||
79 | 82 | | |
80 | 83 | | |
81 | 84 | | |
82 | | - | |
| 85 | + | |
| 86 | + | |
83 | 87 | | |
84 | 88 | | |
85 | 89 | | |
| |||
0 commit comments