auto-account-machine/generate-1000-accounts.js
2025-11-21 13:27:41 +08:00

175 lines
6.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 生成1000个完整的账号数据用于手动测试Stripe通过率
*/
const AccountDataGenerator = require('./src/shared/libs/account-generator');
const CardGenerator = require('./src/shared/libs/card-generator');
const fs = require('fs');
const path = require('path');
console.log('\n========== 生成1000个账号数据 ==========\n');
async function generate() {
const accountGen = new AccountDataGenerator();
const cardGen = new CardGenerator(); // 不连接数据库,只生成
const accounts = [];
const stats = {
total: 0,
success: 0,
failed: 0,
binDistribution: {}
};
console.log('开始生成...\n');
const startTime = Date.now();
for (let i = 0; i < 1000; i++) {
try {
// 生成账号
const account = accountGen.generateAccount();
// 生成卡号
const card = await cardGen.generate('unionpay');
// 组合数据
const fullAccount = {
id: i + 1,
email: account.email,
password: account.password,
firstName: account.firstName,
lastName: account.lastName,
cardNumber: card.number,
expMonth: card.month,
expYear: card.year,
cvv: card.cvv,
issuer: card.issuer,
country: card.country,
countryName: card.countryName
};
accounts.push(fullAccount);
stats.success++;
stats.total++;
// 统计BIN分布前6位
const bin6 = card.number.substring(0, 6);
stats.binDistribution[bin6] = (stats.binDistribution[bin6] || 0) + 1;
// 进度显示
if ((i + 1) % 100 === 0) {
console.log(` 进度: ${i + 1}/1000 (${((i + 1) / 10).toFixed(1)}%)`);
}
} catch (error) {
stats.failed++;
stats.total++;
console.log(` ❌ 第 ${i + 1} 个生成失败: ${error.message}`);
}
}
const endTime = Date.now();
const duration = ((endTime - startTime) / 1000).toFixed(2);
console.log(`\n✅ 生成完成!耗时: ${duration}`);
console.log(` 成功: ${stats.success}`);
console.log(` 失败: ${stats.failed}\n`);
// 保存为多种格式
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('T')[0];
const outputDir = path.join(__dirname, 'generated-accounts');
// 创建输出目录
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
// 1. JSON格式完整数据
const jsonFile = path.join(outputDir, `accounts-1000-${timestamp}.json`);
fs.writeFileSync(jsonFile, JSON.stringify(accounts, null, 2), 'utf-8');
console.log(`✅ JSON文件: ${jsonFile}`);
// 2. CSV格式便于Excel打开
const csvFile = path.join(outputDir, `accounts-1000-${timestamp}.csv`);
const csvHeader = 'ID,Email,Password,FirstName,LastName,CardNumber,ExpMonth,ExpYear,CVV,Issuer,Country,CountryName\n';
const csvRows = accounts.map(a =>
`${a.id},${a.email},${a.password},${a.firstName},${a.lastName},${a.cardNumber},${a.expMonth},${a.expYear},${a.cvv},${a.issuer},${a.country},${a.countryName}`
).join('\n');
fs.writeFileSync(csvFile, csvHeader + csvRows, 'utf-8');
console.log(`✅ CSV文件: ${csvFile}`);
// 3. 可读格式(用于快速查看)
const txtFile = path.join(outputDir, `accounts-1000-${timestamp}.txt`);
let txtContent = '========== 1000个Windsurf测试账号 ==========\n\n';
txtContent += `生成时间: ${new Date().toLocaleString('zh-CN')}\n`;
txtContent += `总数: ${stats.success}\n\n`;
txtContent += '=' .repeat(80) + '\n\n';
accounts.forEach((a, index) => {
txtContent += `【账号 ${a.id}\n`;
txtContent += ` 邮箱: ${a.email}\n`;
txtContent += ` 密码: ${a.password}\n`;
txtContent += ` 姓名: ${a.firstName} ${a.lastName}\n`;
txtContent += ` 卡号: ${a.cardNumber}\n`;
txtContent += ` 有效期: ${a.expMonth}/${a.expYear}\n`;
txtContent += ` CVV: ${a.cvv}\n`;
txtContent += ` 银行: ${a.issuer}\n`;
txtContent += ` 国家: ${a.countryName} (${a.country})\n`;
txtContent += '\n';
if ((index + 1) % 50 === 0) {
txtContent += '-'.repeat(80) + '\n\n';
}
});
fs.writeFileSync(txtFile, txtContent, 'utf-8');
console.log(`✅ TXT文件: ${txtFile}`);
// 4. Stripe测试专用格式卡号|有效期|CVV
const stripeFile = path.join(outputDir, `stripe-test-cards-${timestamp}.txt`);
let stripeContent = '========== Stripe测试卡号列表 ==========\n\n';
stripeContent += '格式: 卡号|有效期|CVV|邮箱\n\n';
accounts.forEach(a => {
stripeContent += `${a.cardNumber}|${a.expMonth}/${a.expYear}|${a.cvv}|${a.email}\n`;
});
fs.writeFileSync(stripeFile, stripeContent, 'utf-8');
console.log(`✅ Stripe测试文件: ${stripeFile}`);
// 统计报告
console.log('\n========== 统计报告 ==========\n');
console.log('BIN分布前6位');
const sortedBins = Object.entries(stats.binDistribution)
.sort((a, b) => b[1] - a[1]);
sortedBins.forEach(([bin, count], index) => {
if (index < 5) {
console.log(` ${bin}: ${count}张 (${(count / stats.success * 100).toFixed(1)}%)`);
}
});
console.log(`\n唯一BIN数: ${sortedBins.length}`);
console.log(`平均每个BIN: ${(stats.success / sortedBins.length).toFixed(1)}`);
// 示例账号
console.log('\n========== 示例账号前3个==========\n');
accounts.slice(0, 3).forEach(a => {
console.log(`${a.id}. ${a.email} | ${a.password}`);
console.log(` 卡号: ${a.cardNumber} | ${a.expMonth}/${a.expYear} | CVV: ${a.cvv}`);
console.log(` 国家: ${a.countryName}\n`);
});
console.log('\n========== 使用说明 ==========\n');
console.log('1. 打开 CSV 文件用 Excel 查看');
console.log('2. 打开 TXT 文件查看完整信息');
console.log('3. 使用 stripe-test-cards 文件手动测试Stripe');
console.log('4. 建议测试方法:');
console.log(' - 先测试前50个记录通过率');
console.log(' - 如果通过率高,再测试更多');
console.log(' - 记录失败原因(卡被拒/金额不足/其他)');
console.log('\n================================\n');
}
generate().catch(console.error);