De ce hand-rolled vs library
Implementăm TOTP RFC 6238 direct cu Node.js crypto built-in (HMAC-SHA1, base32 encoding) în loc de speakeasy/otplib. Motivul: zero supply-chain risk pentru auth-critical code, code review trivial (~80 linii), audit independent simplu. Library-urile TOTP sunt simple superficial dar adaugă dependency pe maintenance third-party. Pentru cod cu impact security ridicat, less is more.
Setup flow user
1. User → settings → Enable 2FA. 2. Sistem generează secret base32 random 32 chars (160 bit). 3. UI afișează QR code (otpauth://totp/{...}) + secret manual fallback. 4. User scanează cu Google Authenticator / Authy / 1Password / Bitwarden / iOS Keychain. 5. User introduce primul cod TOTP din app pentru verify. 6. Sistem verifică, activează 2FA, generează 10 backup codes single-use. User trebuie să descarce/print backup codes (afișate o singură dată).
Verify implementation — time drift tolerance
TOTP standard: cod valid 30 secunde, dar acceptăm și ±1 window (totalul 90 secunde) pentru tolerance la clock drift între device și server. Anti-replay: ultimul cod folosit cache-uit 60 secunde — nu acceptăm același cod twice consecutive.
// Hand-rolled TOTP verify (simplified)
import crypto from 'crypto';
function verifyTotp(token: string, secret: string): boolean {
const now = Math.floor(Date.now() / 1000 / 30);
for (const offset of [-1, 0, 1]) {
if (generateTotp(secret, now + offset) === token) {
// Replay protection: cache used token
if (recentTokens.has(token)) return false;
recentTokens.add(token, 60);
return true;
}
}
return false;
}
function generateTotp(secret: string, timeStep: number): string {
const key = base32Decode(secret);
const buf = Buffer.alloc(8);
buf.writeBigUInt64BE(BigInt(timeStep));
const hmac = crypto.createHmac('sha1', key).update(buf).digest();
const offset = hmac[hmac.length - 1] & 0xf;
const code = ((hmac.readUInt32BE(offset) & 0x7fffffff) % 1_000_000).toString().padStart(6, '0');
return code;
}Backup codes — recovery sigur
La activare 2FA, sistem generează 10 backup codes (16 chars alphanum cada). Display o singură dată — user trebuie să salveze (download txt sau print). Codes single-use: după consum, devin invalid. Tracking în DB cu hash bcrypt (nu plaintext). User poate regenera setul de codes oricând (invalidează cele vechi).
Enforcement la nivel workspace
Workspace owner poate enforce 2FA pentru toți membri cu role admin (settings workspace). Membri fără 2FA, la next login forced enroll flow. Pentru roluri editor/viewer, 2FA optional. Pentru întreg workspace mandate, contactează support.