Optional time-based 2FA on top of password login. TOTP core is hand-rolled
on node:crypto (RFC 6238) — no runtime dep — and verified against the RFC
test vectors.
- migration 027: users.totp_secret/totp_enabled + user_recovery_codes
- src/auth/totp.js: base32, secret gen, RFC 6238 verify, otpauth URI,
recovery codes
- src/auth/mfa-tickets.js: short-lived single-use tickets bridging the two
login steps (in-memory, single-instance like the rate-limiter)
- auth routes: /totp/setup, /totp/enable (returns recovery codes once),
/totp/disable (password-confirmed); login returns {mfa_required, ticket}
when enabled, /login/totp completes with a code or recovery code
- /auth/me and loadUser surface totp_enabled
- web-ui: login second-factor step; Settings -> Account TOTP enroll (QR +
manual secret + recovery codes + disable)
- qrcode added as an optional dep; setup degrades to manual entry if absent
- tests: totp unit (RFC vectors) + integration (enable/login/recovery/disable)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
31 lines
806 B
JSON
31 lines
806 B
JSON
{
|
|
"name": "wild-dragon-mam-api",
|
|
"version": "0.1.0",
|
|
"description": "Media Asset Management API for Wild Dragon",
|
|
"type": "module",
|
|
"main": "src/index.js",
|
|
"scripts": {
|
|
"start": "node src/index.js",
|
|
"dev": "node --watch src/index.js",
|
|
"test": "node --test $(find test -name '*.test.js' | sort)"
|
|
},
|
|
"dependencies": {
|
|
"express": "^4.18.2",
|
|
"pg": "^8.11.3",
|
|
"connect-pg-simple": "^9.0.1",
|
|
"express-session": "^1.17.3",
|
|
"cors": "^2.8.5",
|
|
"bcrypt": "^5.1.1",
|
|
"@aws-sdk/client-s3": "^3.500.0",
|
|
"@aws-sdk/s3-request-presigner": "^3.500.0",
|
|
"@aws-sdk/lib-storage": "^3.500.0",
|
|
"bullmq": "^5.5.0",
|
|
"multer": "^1.4.5-lts.1",
|
|
"uuid": "^9.0.1",
|
|
"dotenv": "^16.4.5",
|
|
"qrcode": "^1.5.4"
|
|
},
|
|
"engines": {
|
|
"node": ">=22.0.0"
|
|
}
|
|
}
|