feat: production hardening - CORS whitelist, strong password, tokenVersion revoke, VIP card hashing, admin secret

This commit is contained in:
2026-05-10 22:53:32 +08:00
parent 5b23c88df9
commit 21709e5d97
9 changed files with 299 additions and 69 deletions

View File

@@ -4,15 +4,17 @@ import crypto from 'crypto';
const prisma = new PrismaClient();
/**
* 生成 VIP 卡密
* 生成 VIP 卡密 (原始 + 哈希)
*/
function generateCardKey(days: number): string {
function generateCardKey(days: number): { raw: string; hash: string } {
const prefix = `VIP${days}`;
const segments = [];
for (let i = 0; i < 4; i++) {
segments.push(crypto.randomBytes(2).toString('hex').toUpperCase());
}
return `${prefix}-${segments.join('-')}`;
const raw = `${prefix}-${segments.join('-')}`;
const hash = crypto.createHash('sha256').update(raw).digest('hex');
return { raw, hash };
}
async function main() {
@@ -22,79 +24,59 @@ async function main() {
// 创建分类
// ============================================
const categories = [
// 烽火地带
{ name: '突击步枪', type: 'SCHEME' },
{ name: '冲锋枪', type: 'SCHEME' },
{ name: '狙击步枪', type: 'SCHEME' },
{ name: '轻机枪', type: 'SCHEME' },
{ name: '霰弹枪', type: 'SCHEME' },
{ name: '手枪', type: 'SCHEME' },
// 全面战场
{ name: '发射器', type: 'SCHEME' },
{ name: '突击步枪', type: 'SCHEME_AOB' },
{ name: '冲锋枪', type: 'SCHEME_AOB' },
{ name: '狙击步枪', type: 'SCHEME_AOB' },
{ name: '轻机枪', type: 'SCHEME_AOB' },
{ name: '霰弹枪', type: 'SCHEME_AOB' },
// 滤镜
{ name: '烽火地带', type: 'FILTER' },
{ name: '全面战场', type: 'FILTER' },
{ name: '通用', type: 'FILTER' },
];
for (const cat of categories) {
await prisma.category.create({
data: cat,
}).catch(() => {}); // 忽略重复错误
await prisma.category.create({ data: cat }).catch(() => {});
}
console.log(`✅ 创建 ${categories.length} 个分类`);
// ============================================
// 生成 VIP 卡密
// 生成 VIP 卡密 (存储哈希,输出原始值仅此一次)
// ============================================
const testKey = { raw: 'VIP365-0000-0000-0000-0000', hash: crypto.createHash('sha256').update('VIP365-0000-0000-0000-0000').digest('hex') };
await prisma.vipCard.create({
data: { cardKey: testKey.hash, cardType: 'YEAR', days: 365 },
}).catch(() => {});
console.log(`\n🔑 测试卡密 (仅显示一次): ${testKey.raw}`);
const cardConfigs = [
{ type: 'MONTH', days: 30, count: 100 },
{ type: 'QUARTER', days: 90, count: 50 },
{ type: 'YEAR', days: 365, count: 20 },
];
// 测试卡密 (固定值,方便开发验证)
await prisma.vipCard.create({
data: {
cardKey: 'VIP365-0000-0000-0000-0000',
cardType: 'YEAR',
days: 365,
},
}).catch(() => {});
console.log(`✅ 创建测试卡密: VIP365-0000-0000-0000-0000`);
let totalCards = 0;
for (const config of cardConfigs) {
const cards = [];
console.log(`\n📦 ${config.type} 卡密 (${config.count} 张):`);
for (let i = 0; i < config.count; i++) {
cards.push({
cardKey: generateCardKey(config.days),
cardType: config.type,
days: config.days,
});
const { raw, hash } = generateCardKey(config.days);
cards.push({ cardKey: hash, cardType: config.type, days: config.days });
console.log(` ${raw}`);
}
await prisma.vipCard.createMany({ data: cards, skipDuplicates: true });
totalCards += config.count;
console.log(`✅ 生成 ${config.type} 卡密 ${config.count}`);
}
console.log(`\n🎉 种子数据初始化完成!`);
console.log(` ⚠️ 以上卡密仅显示一次,请妥善保存`);
console.log(` - 分类:${categories.length}`);
console.log(` - VIP 卡密:${totalCards}`);
console.log(` - VIP 卡密:${totalCards + 1}`);
}
main()
.catch((e) => {
console.error('❌ 种子数据初始化失败:', e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});