Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 18s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 2m15s
Deploy / Build API Image (push) Failing after 28s
Deploy / Build Web Image (push) Failing after 16s
Deploy / Build AI Services Image (push) Failing after 17s
E2E Tests / Playwright E2E (push) Failing after 31s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Security Scanning / Trivy Scan — API Image (push) Failing after 1m46s
Security Scanning / Trivy Scan — Web Image (push) Failing after 1m7s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 53s
Security Scanning / Trivy Filesystem Scan (push) Failing after 35s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 0s
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
Hoàn tất đợt cuối của nhiệm vụ chuyển toàn bộ tài liệu sang tiếng Việt. Đã dịch 22 file `.md` còn sót (~9.7k dòng) — gồm RUNBOOK, audits, docs/architecture, docs/load-testing, libs READMEs và các quick references. Giữ nguyên code blocks, đường dẫn, identifier kỹ thuật, URL và biến môi trường. Co-Authored-By: Paperclip <noreply@paperclip.ing>
4.5 KiB
4.5 KiB
GoodGo Platform - Tham chiếu nhanh Authentication
🔑 Các điểm chính trong nháy mắt
Hash mật khẩu
Algorithm: bcrypt
Salt Rounds: 12 (env: BCRYPT_ROUNDS)
Min Length: 8 characters
Example: bcrypt.hash('password', 12)
Số điện thoại (Việt Nam)
Valid Formats: 0900000001, 84900000001, +84900000001
Normalized: +84900000001
Regex: /^(?:\+84|84|0)(3[2-9]|5[2689]|7[06-9]|8[1-9]|9[0-9])\d{7}$/
File: apps/api/src/modules/shared/utils/vietnam-phone.validator.ts
Regex: /^[^\s@]+@[^\s@]+\.[^\s@]+$/
Normalization: lowercase + trim
Storage: admin@goodgo.vn
Mã hoá PII
Algorithm: AES-256-GCM
Key: 32 bytes (64 hex chars)
Encrypted: email, phone, kycData
Searchable: email → emailHash (HMAC-SHA256)
phone → phoneHash (HMAC-SHA256)
Env Var: FIELD_ENCRYPTION_KEY
Đăng nhập User
Username: phone (normalized)
Password: plain text
Lookup: by phoneHash (unique index)
Required: isActive = true, passwordHash ≠ null
Response: tokens (or MFA challenge)
Vai trò người dùng
BUYER - Search, inquire, offer (default)
SELLER - Create listings
AGENT - Professional agent
ADMIN - Full access
MFA
TOTP: otplib (RFC 6238)
Period: 30 seconds
Digits: 6
Backup Codes: 10 × 8 chars (A-Z no OI, 2-9 no 01)
Hashing: HMAC-SHA256 (not bcrypt)
📋 Tạo người dùng Admin có thể đăng nhập
Quy trình 5 bước
1. Chuẩn hoá số điện thoại
phone = '0900000001' → '+84900000001'
2. Tạo HMAC key
hmacKey = crypto.hkdfSync('sha256', Buffer.from(encryptionKey, 'hex'),
Buffer.alloc(0), Buffer.from('goodgo-field-hash', 'utf8'), 32)
3. Tính các hash
phoneHash = crypto.createHmac('sha256', hmacKey).update('+84900000001').digest('hex')
emailHash = crypto.createHmac('sha256', hmacKey).update('admin@goodgo.vn').digest('hex')
4. Hash mật khẩu
passwordHash = await bcrypt.hash('AdminPassword123', 12)
5. Tạo user
await prisma.user.create({
data: {
id: 'admin-seed-001',
phone: '+84900000001',
phoneHash,
email: 'admin@goodgo.vn',
emailHash,
passwordHash,
fullName: 'Admin',
role: 'ADMIN',
kycStatus: 'VERIFIED',
isActive: true,
totpEnabled: false,
totpBackupCodes: [],
},
});
🧪 Test đăng nhập
curl -X POST http://localhost:3000/auth/login \
-H "Content-Type: application/json" \
-d '{
"phone": "0900000001",
"password": "AdminPassword123"
}'
Response thành công:
{
"requiresMfa": false,
"tokens": {
"accessToken": "eyJ...",
"refreshToken": "eyJ...",
"expiresIn": 3600
}
}
⚠️ Vấn đề thường gặp
| Vấn đề | Cách sửa |
|---|---|
| User không đăng nhập được | Kiểm tra: passwordHash ≠ null, isActive = true |
| "Invalid phone" | Phone phải khớp regex (chỉ mobile) |
| Hash không khớp | Xác minh FIELD_ENCRYPTION_KEY nhất quán |
| Vấn đề MFA | Xác minh biến môi trường MFA_BACKUP_CODE_SECRET |
| PII không được mã hoá | Xác minh key đúng 32 bytes (64 ký tự hex) |
📁 Các file chính
| File | Mục đích |
|---|---|
hashed-password.vo.ts |
Hash bcrypt |
vietnam-phone.validator.ts |
Validation số điện thoại |
field-encryption.ts |
Mã hoá AES-256-GCM |
local.strategy.ts |
Endpoint đăng nhập |
mfa.service.ts |
TOTP / backup code |
user.entity.ts |
Domain model User |
prisma-user.repository.ts |
Persistence User |
seed.ts |
Script seed |
🔐 Checklist cho Seed User
- Mật khẩu ≥ 8 ký tự
- Phone khớp regex
- Phone đã chuẩn hoá: +84...
- Phone đã hash: HMAC-SHA256
- Email đã chuyển lowercase
- Email đã hash: HMAC-SHA256
- Password đã hash: bcrypt (12 rounds)
isActive: truepasswordHash≠ nulltotpEnabled: falsetotpBackupCodes: []
📚 Các file tài liệu đầy đủ
- AUTHENTICATION_GUIDE.md - Tham chiếu kỹ thuật đầy đủ
- AUTH_IMPLEMENTATION_CHECKLIST.md - Checklist triển khai & troubleshoot
- SEED_GENERATION_SCRIPT.ts - Script seed sẵn sàng dùng
- QUICK_REFERENCE.md - File này
Cập nhật cuối: 12 tháng 4, 2026 Trạng thái: ✅ Sẵn sàng Production