import { CardPrivacyPasswordService, hashPrivacyPassword, verifyPrivacyPassword, generatePrivacyAccessToken, verifyPrivacyAccessToken, } from '../../../src/modules/card/service/privacy'; describe('Point 59 (P2): 移动微官网名片私密保护模式与访问口令鉴权', () => { let service: CardPrivacyPasswordService; const mockCardId = 601; const rawPassword = 'Vip-Secret-Pass-2026'; beforeEach(() => { service = new CardPrivacyPasswordService(); }); describe('1. 密码加盐哈希与校验 (hashPrivacyPassword & verifyPrivacyPassword)', () => { it('应使用 SHA-256 加盐算法生成密码哈希,不存明文', () => { const hashed = hashPrivacyPassword(rawPassword); expect(hashed).toContain(':'); expect(hashed).not.toBe(rawPassword); // 正确口令校验成功 expect(verifyPrivacyPassword(rawPassword, hashed)).toBe(true); // 错误口令校验失败 expect(verifyPrivacyPassword('wrong-password', hashed)).toBe(false); }); it('空密码或无效哈希时应安全返回 false', () => { expect(verifyPrivacyPassword('', 'salt:hash')).toBe(false); expect(verifyPrivacyPassword('pass', '')).toBe(false); }); }); describe('2. 私密解锁授权凭据 (Privacy Access Token)', () => { it('口令验证成功后生成包含时钟与签名的临时访问 Token', () => { const token = generatePrivacyAccessToken(mockCardId, 'sys-secret-key', 3600); expect(token).toBeDefined(); const verifyRes = verifyPrivacyAccessToken(mockCardId, token, 'sys-secret-key'); expect(verifyRes.valid).toBe(true); expect(verifyRes.cardId).toBe(mockCardId); }); it('Token 跨名片使用时应被严密拦截', () => { const token = generatePrivacyAccessToken(mockCardId, 'sys-secret-key'); // 尝试用来解锁 602 名片 const verifyRes = verifyPrivacyAccessToken(602, token, 'sys-secret-key'); expect(verifyRes.valid).toBe(false); expect(verifyRes.reason).toMatch(/不匹配|mismatch/i); }); it('伪造或过期的 Token 应被坚决拒绝', () => { const expiredToken = generatePrivacyAccessToken(mockCardId, 'sys-secret-key', -10); // 已过期 const res = verifyPrivacyAccessToken(mockCardId, expiredToken, 'sys-secret-key'); expect(res.valid).toBe(false); expect(res.reason).toMatch(/过期|expired/i); }); }); describe('3. CardPrivacyPasswordService 解锁与脱敏输出', () => { it('未解锁前返回脱敏联系方式,验证口令后颁发解锁凭据', async () => { const hashed = hashPrivacyPassword(rawPassword); // 1. 验证错误口令 const failUnlock = await service.unlockCard(mockCardId, 'wrong', hashed); expect(failUnlock.success).toBe(false); // 2. 验证正确口令 const successUnlock = await service.unlockCard(mockCardId, rawPassword, hashed); expect(successUnlock.success).toBe(true); expect(successUnlock.accessToken).toBeDefined(); }); }); });