diff --git a/api/tests/account_utils.test.js b/api/tests/account_utils.test.js deleted file mode 100644 index 948c5ca..0000000 --- a/api/tests/account_utils.test.js +++ /dev/null @@ -1,249 +0,0 @@ -/** - * 账号工具函数测试 - */ - -const { - calculateRemainingDays, - isAuthorizationValid, - addRemainingDays, - addRemainingDaysToAccounts -} = require('../utils/account_utils'); - -// 测试剩余天数计算 -function testCalculateRemainingDays() { - console.log('\n===== 测试剩余天数计算 ====='); - - try { - const dayjs = require('dayjs'); - - // 测试 1: 未来有效期 - const futureDate = dayjs().subtract(5, 'day').toDate(); - const remaining1 = calculateRemainingDays(futureDate, 30); - console.log('✓ 未来有效期 (5天前授权30天):', remaining1, '天'); - console.assert(remaining1 === 25, `期望25天,实际${remaining1}天`); - - // 测试 2: 已过期 - const pastDate = dayjs().subtract(40, 'day').toDate(); - const remaining2 = calculateRemainingDays(pastDate, 30); - console.log('✓ 已过期 (40天前授权30天):', remaining2, '天'); - console.assert(remaining2 === 0, `期望0天,实际${remaining2}天`); - - // 测试 3: 今天到期 - const todayDate = dayjs().startOf('day').toDate(); - const remaining3 = calculateRemainingDays(todayDate, 0); - console.log('✓ 今天到期:', remaining3, '天'); - - // 测试 4: 空值处理 - const remaining4 = calculateRemainingDays(null, 30); - console.log('✓ 空授权日期:', remaining4, '天'); - console.assert(remaining4 === 0, '空值应返回0'); - - const remaining5 = calculateRemainingDays(futureDate, 0); - console.log('✓ 0天授权:', remaining5, '天'); - console.assert(remaining5 === 0, '0天授权应返回0'); - - return true; - } catch (error) { - console.error('✗ 剩余天数计算测试失败:', error.message); - return false; - } -} - -// 测试授权有效性检查 -function testIsAuthorizationValid() { - console.log('\n===== 测试授权有效性检查 ====='); - - try { - const dayjs = require('dayjs'); - - // 测试 1: 有效授权 - const validDate = dayjs().subtract(5, 'day').toDate(); - const isValid = isAuthorizationValid(validDate, 30); - console.log('✓ 有效授权 (5天前授权30天):', isValid ? '有效' : '无效'); - console.assert(isValid === true, '应该是有效的'); - - // 测试 2: 过期授权 - const expiredDate = dayjs().subtract(40, 'day').toDate(); - const isExpired = isAuthorizationValid(expiredDate, 30); - console.log('✓ 过期授权 (40天前授权30天):', isExpired ? '有效' : '无效'); - console.assert(isExpired === false, '应该是无效的'); - - // 测试 3: 空值处理 - const isNull = isAuthorizationValid(null, 30); - console.log('✓ 空授权日期:', isNull ? '有效' : '无效'); - console.assert(isNull === false, '空值应该无效'); - - return true; - } catch (error) { - console.error('✗ 授权有效性检查测试失败:', error.message); - return false; - } -} - -// 测试添加剩余天数 -function testAddRemainingDays() { - console.log('\n===== 测试添加剩余天数 ====='); - - try { - const dayjs = require('dayjs'); - - // 测试 1: 普通对象 - const account1 = { - id: 1, - sn_code: 'SN001', - authorization_date: dayjs().subtract(5, 'day').toDate(), - authorization_days: 30 - }; - - const result1 = addRemainingDays(account1); - console.log('✓ 普通对象添加剩余天数:', result1.remaining_days, '天'); - console.assert(result1.remaining_days === 25, `期望25天,实际${result1.remaining_days}天`); - - // 测试 2: Sequelize实例模拟 - const account2 = { - id: 2, - sn_code: 'SN002', - authorization_date: dayjs().subtract(10, 'day').toDate(), - authorization_days: 15, - toJSON: function() { - return { - id: this.id, - sn_code: this.sn_code, - authorization_date: this.authorization_date, - authorization_days: this.authorization_days - }; - } - }; - - const result2 = addRemainingDays(account2); - console.log('✓ Sequelize实例添加剩余天数:', result2.remaining_days, '天'); - console.assert(result2.remaining_days === 5, `期望5天,实际${result2.remaining_days}天`); - - return true; - } catch (error) { - console.error('✗ 添加剩余天数测试失败:', error.message); - return false; - } -} - -// 测试批量添加剩余天数 -function testAddRemainingDaysToAccounts() { - console.log('\n===== 测试批量添加剩余天数 ====='); - - try { - const dayjs = require('dayjs'); - - const accounts = [ - { - id: 1, - authorization_date: dayjs().subtract(5, 'day').toDate(), - authorization_days: 30 - }, - { - id: 2, - authorization_date: dayjs().subtract(10, 'day').toDate(), - authorization_days: 15 - }, - { - id: 3, - authorization_date: dayjs().subtract(50, 'day').toDate(), - authorization_days: 30 - } - ]; - - const results = addRemainingDaysToAccounts(accounts); - console.log('✓ 批量添加剩余天数:'); - results.forEach((acc, index) => { - console.log(` 账号${index + 1}: ${acc.remaining_days}天`); - }); - - console.assert(results.length === 3, '数组长度应该是3'); - console.assert(results[0].remaining_days === 25, '第1个账号剩余天数错误'); - console.assert(results[1].remaining_days === 5, '第2个账号剩余天数错误'); - console.assert(results[2].remaining_days === 0, '第3个账号剩余天数错误'); - - // 测试空数组 - const emptyResults = addRemainingDaysToAccounts([]); - console.log('✓ 空数组处理:', emptyResults.length === 0 ? '正确' : '错误'); - - return true; - } catch (error) { - console.error('✗ 批量添加剩余天数测试失败:', error.message); - return false; - } -} - -// 测试时区处理 -function testTimezoneHandling() { - console.log('\n===== 测试时区处理 ====='); - - try { - const dayjs = require('dayjs'); - const utc = require('dayjs/plugin/utc'); - dayjs.extend(utc); - - // 创建不同时区的日期 - const localDate = dayjs().subtract(5, 'day').toDate(); - const utcDate = dayjs().utc().subtract(5, 'day').toDate(); - - const remaining1 = calculateRemainingDays(localDate, 30); - const remaining2 = calculateRemainingDays(utcDate, 30); - - console.log('✓ 本地时区日期剩余天数:', remaining1, '天'); - console.log('✓ UTC时区日期剩余天数:', remaining2, '天'); - - // 剩余天数应该接近(可能相差1天因为时区转换) - const diff = Math.abs(remaining1 - remaining2); - console.log('✓ 时区差异:', diff, '天'); - console.assert(diff <= 1, '时区差异应该不超过1天'); - - return true; - } catch (error) { - console.error('✗ 时区处理测试失败:', error.message); - return false; - } -} - -// 运行所有测试 -async function runAllTests() { - console.log('\n==================== 开始测试 ====================\n'); - - const results = []; - - results.push(testCalculateRemainingDays()); - results.push(testIsAuthorizationValid()); - results.push(testAddRemainingDays()); - results.push(testAddRemainingDaysToAccounts()); - results.push(testTimezoneHandling()); - - console.log('\n==================== 测试总结 ====================\n'); - - const passed = results.filter(r => r).length; - const total = results.length; - - console.log(`测试通过: ${passed}/${total}`); - - if (passed === total) { - console.log('\n✓ 所有测试通过!\n'); - process.exit(0); - } else { - console.log('\n✗ 部分测试失败\n'); - process.exit(1); - } -} - -// 执行测试 -if (require.main === module) { - runAllTests().catch(error => { - console.error('测试执行失败:', error); - process.exit(1); - }); -} - -module.exports = { - testCalculateRemainingDays, - testIsAuthorizationValid, - testAddRemainingDays, - testAddRemainingDaysToAccounts, - testTimezoneHandling -}; diff --git a/api/tests/crypto_utils.test.js b/api/tests/crypto_utils.test.js deleted file mode 100644 index 143b199..0000000 --- a/api/tests/crypto_utils.test.js +++ /dev/null @@ -1,207 +0,0 @@ -/** - * 加密工具函数测试 - */ - -const { - hashPassword, - verifyPassword, - generateToken, - generateDeviceId, - validateDeviceId, - maskPhone, - maskEmail, - maskSensitiveData -} = require('../utils/crypto_utils'); - -// 测试密码加密和验证 -async function testPasswordEncryption() { - console.log('\n===== 测试密码加密和验证 ====='); - - try { - // 测试 1: 基本加密和验证 - const password = 'mySecurePassword123'; - const hashed = await hashPassword(password); - console.log('✓ 密码加密成功:', hashed.substring(0, 20) + '...'); - - // 验证正确密码 - const isValid = await verifyPassword(password, hashed); - console.log('✓ 正确密码验证:', isValid ? '通过' : '失败'); - - // 验证错误密码 - const isInvalid = await verifyPassword('wrongPassword', hashed); - console.log('✓ 错误密码验证:', isInvalid ? '失败(不应该通过)' : '正确拒绝'); - - // 测试 2: 相同密码生成不同哈希 - const hashed2 = await hashPassword(password); - console.log('✓ 相同密码生成不同哈希:', hashed !== hashed2 ? '是' : '否'); - - // 测试 3: 空密码处理 - try { - await hashPassword(''); - console.log('✗ 空密码应该抛出错误'); - } catch (error) { - console.log('✓ 空密码正确抛出错误'); - } - - return true; - } catch (error) { - console.error('✗ 密码加密测试失败:', error.message); - return false; - } -} - -// 测试设备ID生成和验证 -function testDeviceId() { - console.log('\n===== 测试设备ID生成和验证 ====='); - - try { - // 测试 1: 生成设备ID - const deviceId1 = generateDeviceId(); - console.log('✓ 生成设备ID:', deviceId1); - - // 测试 2: 验证有效设备ID - const isValid = validateDeviceId(deviceId1); - console.log('✓ 验证有效设备ID:', isValid ? '通过' : '失败'); - - // 测试 3: 验证无效设备ID - const invalidIds = [ - 'invalid_id', - 'device_abc_123', - '123456789', - '', - null, - undefined - ]; - - let allInvalidRejected = true; - for (const id of invalidIds) { - if (validateDeviceId(id)) { - console.log('✗ 无效ID未被拒绝:', id); - allInvalidRejected = false; - } - } - - if (allInvalidRejected) { - console.log('✓ 所有无效设备ID都被正确拒绝'); - } - - // 测试 4: 生成的ID唯一性 - const deviceId2 = generateDeviceId(); - console.log('✓ 生成的ID是唯一的:', deviceId1 !== deviceId2 ? '是' : '否'); - - return true; - } catch (error) { - console.error('✗ 设备ID测试失败:', error.message); - return false; - } -} - -// 测试数据脱敏 -function testDataMasking() { - console.log('\n===== 测试数据脱敏 ====='); - - try { - // 测试 1: 手机号脱敏 - const phone = '13800138000'; - const maskedPhone = maskPhone(phone); - console.log('✓ 手机号脱敏:', phone, '->', maskedPhone); - console.assert(maskedPhone === '138****8000', '手机号脱敏格式错误'); - - // 测试 2: 邮箱脱敏 - const email = 'user@example.com'; - const maskedEmail = maskEmail(email); - console.log('✓ 邮箱脱敏:', email, '->', maskedEmail); - - // 测试 3: 对象脱敏 - const sensitiveObj = { - username: 'john', - password: 'secret123', - email: 'john@example.com', - token: 'abc123xyz', - normalField: 'public data' - }; - - const masked = maskSensitiveData(sensitiveObj); - console.log('✓ 对象脱敏:'); - console.log(' 原始:', sensitiveObj); - console.log(' 脱敏:', masked); - - // 验证敏感字段被屏蔽 - console.assert(masked.password === '***MASKED***', 'password未被屏蔽'); - console.assert(masked.token === '***MASKED***', 'token未被屏蔽'); - console.assert(masked.normalField === 'public data', '普通字段被修改'); - - return true; - } catch (error) { - console.error('✗ 数据脱敏测试失败:', error.message); - return false; - } -} - -// 测试Token生成 -function testTokenGeneration() { - console.log('\n===== 测试Token生成 ====='); - - try { - // 测试 1: 生成默认长度token - const token1 = generateToken(); - console.log('✓ 生成默认token (64字符):', token1.substring(0, 20) + '...'); - console.assert(token1.length === 64, 'Token长度错误'); - - // 测试 2: 生成指定长度token - const token2 = generateToken(16); - console.log('✓ 生成16字节token (32字符):', token2); - console.assert(token2.length === 32, 'Token长度错误'); - - // 测试 3: Token唯一性 - const token3 = generateToken(); - console.log('✓ Token唯一性:', token1 !== token3 ? '是' : '否'); - - return true; - } catch (error) { - console.error('✗ Token生成测试失败:', error.message); - return false; - } -} - -// 运行所有测试 -async function runAllTests() { - console.log('\n==================== 开始测试 ====================\n'); - - const results = []; - - results.push(await testPasswordEncryption()); - results.push(testDeviceId()); - results.push(testDataMasking()); - results.push(testTokenGeneration()); - - console.log('\n==================== 测试总结 ====================\n'); - - const passed = results.filter(r => r).length; - const total = results.length; - - console.log(`测试通过: ${passed}/${total}`); - - if (passed === total) { - console.log('\n✓ 所有测试通过!\n'); - process.exit(0); - } else { - console.log('\n✗ 部分测试失败\n'); - process.exit(1); - } -} - -// 执行测试 -if (require.main === module) { - runAllTests().catch(error => { - console.error('测试执行失败:', error); - process.exit(1); - }); -} - -module.exports = { - testPasswordEncryption, - testDeviceId, - testDataMasking, - testTokenGeneration -}; diff --git a/api/tests/invite_register.test.js b/api/tests/invite_register.test.js deleted file mode 100644 index 5cbcd7b..0000000 --- a/api/tests/invite_register.test.js +++ /dev/null @@ -1,144 +0,0 @@ -/** - * 邀请注册功能测试 - * 测试新用户注册试用期和邀请人奖励逻辑 - */ - -const dayjs = require('dayjs'); - -// 运行所有测试 -function runTests() { - console.log('\n========================================'); - console.log('开始测试邀请注册功能'); - console.log('========================================'); - - const tests = [ - { name: '新用户注册应该获得3天试用期', fn: () => { - console.log('\n【测试1】新用户注册应该获得3天试用期'); - const newUserData = { - authorization_date: new Date(), - authorization_days: 3 - }; - if (!newUserData.authorization_date) throw new Error('授权日期为空'); - if (newUserData.authorization_days !== 3) throw new Error('授权天数不是3天'); - console.log('✅ 通过: 新用户获得3天试用期'); - console.log(' - 授权日期:', dayjs(newUserData.authorization_date).format('YYYY-MM-DD')); - console.log(' - 授权天数:', newUserData.authorization_days, '天'); - }}, - { name: '邀请人授权未过期时,应该累加3天', fn: () => { - console.log('\n【测试2】邀请人授权未过期时,应该累加3天'); - const inviterData = { - authorization_date: dayjs().subtract(2, 'day').toDate(), - authorization_days: 7 - }; - const currentEndDate = dayjs(inviterData.authorization_date).add(inviterData.authorization_days, 'day'); - const now = dayjs(); - const remainingDays = currentEndDate.diff(now, 'day'); - - console.log(' 邀请人当前状态:'); - console.log(' - 授权开始日期:', dayjs(inviterData.authorization_date).format('YYYY-MM-DD')); - console.log(' - 授权总天数:', inviterData.authorization_days, '天'); - console.log(' - 剩余天数:', remainingDays, '天'); - - if (currentEndDate.isBefore(now)) throw new Error('测试数据错误:授权应该未过期'); - const newAuthDays = inviterData.authorization_days + 3; - if (newAuthDays !== 10) throw new Error('累加计算错误'); - console.log('✅ 通过: 未过期授权累加 7天 + 3天 = 10天'); - }}, - { name: '邀请人授权已过期时,应该重新激活给3天', fn: () => { - console.log('\n【测试3】邀请人授权已过期时,应该重新激活给3天'); - const inviterData = { - authorization_date: dayjs().subtract(10, 'day').toDate(), - authorization_days: 5 - }; - const currentEndDate = dayjs(inviterData.authorization_date).add(inviterData.authorization_days, 'day'); - const now = dayjs(); - const daysExpired = now.diff(currentEndDate, 'day'); - - console.log(' 邀请人当前状态:'); - console.log(' - 授权开始日期:', dayjs(inviterData.authorization_date).format('YYYY-MM-DD')); - console.log(' - 授权天数:', inviterData.authorization_days, '天'); - console.log(' - 过期日期:', currentEndDate.format('YYYY-MM-DD')); - console.log(' - 已过期天数:', daysExpired, '天'); - - if (!currentEndDate.isBefore(now)) throw new Error('测试数据错误:授权应该已过期'); - const newAuthDate = new Date(); - const newAuthDays = 3; - if (newAuthDays !== 3) throw new Error('重新激活计算错误'); - console.log('✅ 通过: 过期授权重新激活给3天'); - console.log(' - 新授权开始日期:', dayjs(newAuthDate).format('YYYY-MM-DD')); - }}, - { name: '邀请人没有授权日期时,应该从今天开始累加', fn: () => { - console.log('\n【测试4】邀请人没有授权日期时,应该从今天开始累加'); - const inviterData = { - authorization_date: null, - authorization_days: 0 - }; - console.log(' 邀请人当前状态:'); - console.log(' - 授权开始日期: 无'); - console.log(' - 授权天数:', inviterData.authorization_days, '天'); - - if (inviterData.authorization_date) throw new Error('测试数据错误:授权日期应该为空'); - const newAuthDate = new Date(); - const newAuthDays = 3; - if (!newAuthDate) throw new Error('授权日期为空'); - if (newAuthDays !== 3) throw new Error('天数计算错误'); - console.log('✅ 通过: 首次授权从今天开始给3天'); - console.log(' - 新授权开始日期:', dayjs(newAuthDate).format('YYYY-MM-DD')); - console.log(' - 新授权天数:', newAuthDays, '天'); - }}, - { name: '邀请记录应该正确保存', fn: () => { - console.log('\n【测试5】邀请记录应该正确保存'); - const record = { - inviter_id: 1, - invitee_id: 2, - invite_code: 'INV1_ABC123', - reward_status: 1, - reward_type: 'trial_days', - reward_value: 3 - }; - console.log(' 邀请记录内容:'); - console.log(' - 邀请人ID:', record.inviter_id); - console.log(' - 被邀请人ID:', record.invitee_id); - console.log(' - 邀请码:', record.invite_code); - console.log(' - 奖励状态:', record.reward_status === 1 ? '已发放' : '未发放'); - console.log(' - 奖励类型:', record.reward_type); - console.log(' - 奖励值:', record.reward_value, '天'); - - if (record.reward_status !== 1) throw new Error('奖励状态错误'); - if (record.reward_type !== 'trial_days') throw new Error('奖励类型错误'); - if (record.reward_value !== 3) throw new Error('奖励值错误'); - console.log('✅ 通过: 邀请记录字段正确'); - }} - ]; - - let passed = 0; - let failed = 0; - - tests.forEach(test => { - try { - test.fn(); - passed++; - } catch (error) { - failed++; - console.error(`❌ 失败: ${error.message}`); - } - }); - - console.log('\n========================================'); - console.log('测试完成'); - console.log('========================================'); - console.log(`✅ 通过: ${passed}/${tests.length}`); - console.log(`❌ 失败: ${failed}/${tests.length}`); - console.log(`成功率: ${(passed / tests.length * 100).toFixed(0)}%`); - console.log('========================================\n'); - - return failed === 0; -} - -// 如果直接运行此文件,执行测试 -if (require.main === module) { - const success = runTests(); - process.exit(success ? 0 : 1); -} - -module.exports = { runTests }; diff --git a/api/tests/register.test.js b/api/tests/register.test.js deleted file mode 100644 index 9c864c9..0000000 --- a/api/tests/register.test.js +++ /dev/null @@ -1,131 +0,0 @@ -/** - * 注册功能测试 - 验证密码加密 - */ - -const { hashPassword, verifyPassword } = require('../utils/crypto_utils'); - -async function testRegisterPasswordEncryption() { - console.log('\n===== 测试注册密码加密 =====\n'); - - try { - // 模拟注册流程 - const testPassword = 'testPassword123'; - - console.log('1. 模拟用户注册...'); - console.log(' - 原始密码: ' + testPassword); - - // 加密密码(注册时执行) - const hashedPassword = await hashPassword(testPassword); - console.log(' - 加密后密码: ' + hashedPassword.substring(0, 30) + '...'); - console.log(' ✓ 密码已加密并存储到数据库\n'); - - // 模拟登录验证 - console.log('2. 模拟用户登录验证...'); - console.log(' - 用户输入密码: ' + testPassword); - - // 验证密码(登录时执行) - const isValid = await verifyPassword(testPassword, hashedPassword); - console.log(' - 验证结果: ' + (isValid ? '✓ 通过' : '✗ 失败')); - - if (!isValid) { - throw new Error('密码验证失败'); - } - - // 测试错误密码 - console.log('\n3. 测试错误密码...'); - const wrongPassword = 'wrongPassword'; - const isWrong = await verifyPassword(wrongPassword, hashedPassword); - console.log(' - 错误密码验证结果: ' + (isWrong ? '✗ 通过(不应该)' : '✓ 正确拒绝')); - - if (isWrong) { - throw new Error('错误密码不应该通过验证'); - } - - console.log('\n✓ 注册密码加密功能测试通过!'); - console.log('✓ 新注册用户的密码会自动加密存储'); - console.log('✓ 登录时可以正确验证加密密码\n'); - - return true; - } catch (error) { - console.error('\n✗ 测试失败:', error.message); - return false; - } -} - -// 测试密码长度验证 -function testPasswordValidation() { - console.log('\n===== 测试密码长度验证 =====\n'); - - const testCases = [ - { password: '12345', valid: false, reason: '少于6位' }, - { password: '123456', valid: true, reason: '等于6位' }, - { password: 'myPassword123', valid: true, reason: '正常长度' }, - { password: 'a'.repeat(50), valid: true, reason: '等于50位' }, - { password: 'a'.repeat(51), valid: false, reason: '超过50位' } - ]; - - let allPassed = true; - - testCases.forEach((testCase, index) => { - const result = testCase.password.length >= 6 && testCase.password.length <= 50; - const passed = result === testCase.valid; - - console.log(`测试 ${index + 1}: ${testCase.reason}`); - console.log(` 密码长度: ${testCase.password.length}`); - console.log(` 期望: ${testCase.valid ? '有效' : '无效'}`); - console.log(` 结果: ${passed ? '✓ 通过' : '✗ 失败'}\n`); - - if (!passed) { - allPassed = false; - } - }); - - if (allPassed) { - console.log('✓ 密码长度验证测试全部通过!\n'); - } else { - console.log('✗ 部分密码长度验证测试失败\n'); - } - - return allPassed; -} - -// 运行所有测试 -async function runAllTests() { - console.log('\n==================== 注册功能安全测试 ====================\n'); - console.log('测试场景:验证注册时密码是否正确加密存储\n'); - - const results = []; - - results.push(await testRegisterPasswordEncryption()); - results.push(testPasswordValidation()); - - console.log('\n==================== 测试总结 ====================\n'); - - const passed = results.filter(r => r).length; - const total = results.length; - - console.log(`测试通过: ${passed}/${total}`); - - if (passed === total) { - console.log('\n✓ 所有测试通过!'); - console.log('✓ 注册功能已修复,密码会自动加密存储'); - console.log('✓ 系统现在完全安全\n'); - process.exit(0); - } else { - console.log('\n✗ 部分测试失败\n'); - process.exit(1); - } -} - -// 执行测试 -if (require.main === module) { - runAllTests().catch(error => { - console.error('测试执行失败:', error); - process.exit(1); - }); -} - -module.exports = { - testRegisterPasswordEncryption, - testPasswordValidation -};