feat: 2fa backup codes#9
Conversation
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Codoki PR ReviewSummary: Add 2FA backup codes, improve UX; fix a11y
Issues (Critical & High only)
Showing top 1 issues. Critical: 0, High: 1. See inline suggestions for more. Key Feedback (click to expand)
Confidence: 3/5 — Needs work before merge (1 high · status: Requires changes) React with 👍 or 👎 if you found this review useful. |
| if (user.twoFactorEnabled && req.body.backupCode) { | ||
| if (!process.env.CALENDSO_ENCRYPTION_KEY) { | ||
| console.error("Missing encryption key; cannot proceed with backup code login."); | ||
| throw new Error(ErrorCode.InternalServerError); |
There was a problem hiding this comment.
🔷 Medium: This API mixes returned JSON errors with thrown errors; throwing here can produce an unstructured 500 response and bypass the established error body shape. Use a consistent JSON response (e.g., res.status(500).json({ error })) and avoid throwing to keep clients predictable. Apply the same approach to other throws in this handler (missing secret/encryption key/decrypt length).
| throw new Error(ErrorCode.InternalServerError); | |
| return res.status(500).json({ error: ErrorCode.InternalServerError }); |
| const [dataUri, setDataUri] = useState(""); | ||
| const [secret, setSecret] = useState(""); | ||
| const [isSubmitting, setIsSubmitting] = useState(false); | ||
| const [errorMessage, setErrorMessage] = useState<string | null>(null); |
There was a problem hiding this comment.
💡 Low: Blob URLs created for backup code download are revoked only when replaced, not when closing the modal. Revoke on reset to prevent object URL leaks across open/close cycles.
| <button className="text-emphasis h-9" type="button" onClick={() => toggleIsPasswordVisible()}> | ||
| <button | ||
| className="text-emphasis h-9" | ||
| tabIndex={-1} |
There was a problem hiding this comment.
🔷 Medium: Setting tabIndex to -1 removes the password visibility toggle from the tab order, hurting keyboard accessibility and discoverability. Users relying on keyboard navigation won't be able to reach this control, despite it being essential to the input UX.
suggestion
tabIndex={0}
No description provided.