From fe15b877abaa7acba9387f3022c728dddd709151 Mon Sep 17 00:00:00 2001 From: dengqichen Date: Wed, 19 Nov 2025 15:58:01 +0800 Subject: [PATCH] dasdasd --- src/shared/libs/card-generator/config.js | 19 ++++- src/shared/libs/card-generator/generator.js | 93 +++++++++++++++++---- 2 files changed, 96 insertions(+), 16 deletions(-) diff --git a/src/shared/libs/card-generator/config.js b/src/shared/libs/card-generator/config.js index 28a3c67..a84f0a9 100644 --- a/src/shared/libs/card-generator/config.js +++ b/src/shared/libs/card-generator/config.js @@ -7,10 +7,25 @@ const CARD_TYPES = { unionpay: { name: '中国银联 (UnionPay)', // 固定前缀(用户提供的成功案例都是这个前缀) - prefix: '622836754', + prefix: '622836754', // 固定BIN前缀 length: 16, cvvLength: 3, - useLuhn: true // 使用Luhn算法校验 + useLuhn: true, + + // 成功案例的后7位模式(用于智能生成) + successfulPatterns: [ + '5055812', '8774419', '6781457', '2738949', + '2602400', '8575105', '6496080', '0057649', + '9574719', '8435128', '2797374', '5956423', + '7237848', '0385107', '4252006', '7562054' + ], + + // 生成策略配置 + generation: { + mutationRate: 0.5, // 50% 使用变异策略 + randomRate: 0.5, // 50% 使用纯随机 + mutationDigits: [1, 2] // 变异时改变1-2个数字 + } }, visa: { name: 'Visa', diff --git a/src/shared/libs/card-generator/generator.js b/src/shared/libs/card-generator/generator.js index e96021f..8391820 100644 --- a/src/shared/libs/card-generator/generator.js +++ b/src/shared/libs/card-generator/generator.js @@ -13,7 +13,7 @@ class CardGenerator { } /** - * 生成卡号 + * 生成卡号(混合策略:变异真实案例 + 纯随机) * @param {string} type - 卡类型 * @returns {string} */ @@ -23,28 +23,93 @@ class CardGenerator { throw new ValidationError('card-generator', `Unknown card type: ${type}`); } - const { length, useLuhn } = config; + const { prefix, length, useLuhn, successfulPatterns, generation } = config; - // 支持多个前缀(随机选择)或单个前缀 - let prefix; - if (Array.isArray(config.prefixes)) { - // 从数组中随机选择一个前缀 - const randomIndex = randomInt(0, config.prefixes.length - 1); - prefix = config.prefixes[randomIndex]; - } else { - // 兼容旧配置(单个prefix) - prefix = config.prefix; + // 如果有成功案例和生成策略配置,使用混合策略 + if (successfulPatterns && generation) { + const useMutation = Math.random() < generation.mutationRate; + + if (useMutation) { + // 策略1:基于真实案例变异 + return this.generateByMutation(prefix, successfulPatterns, generation.mutationDigits); + } } - + + // 策略2:纯随机生成(默认或回退) if (useLuhn) { - // 使用Luhn算法生成 return generateLuhnNumber(prefix, length); } else { - // 纯随机生成 const remainingLength = length - prefix.length; return prefix + randomDigits(remainingLength); } } + + /** + * 基于真实案例变异生成卡号 + * @param {string} prefix - BIN前缀 + * @param {Array} patterns - 成功案例的后7位 + * @param {Array} mutationDigits - 变异数字个数[min, max] + * @returns {string} + */ + generateByMutation(prefix, patterns, mutationDigits) { + // 随机选择一个成功案例 + const basePattern = patterns[randomInt(0, patterns.length - 1)]; + + // 随机决定改变几个数字 + const changeCount = randomInt(mutationDigits[0], mutationDigits[1]); + const mutated = basePattern.split(''); + + // 改变指定数量的数字 + const changedPositions = new Set(); + for (let i = 0; i < changeCount; i++) { + let pos; + do { + pos = randomInt(0, mutated.length - 1); + } while (changedPositions.has(pos)); // 避免重复位置 + + changedPositions.add(pos); + + // 生成不同的数字 + let newDigit; + do { + newDigit = randomInt(0, 9).toString(); + } while (newDigit === mutated[pos]); + + mutated[pos] = newDigit; + } + + // 组合前缀和变异后的后7位(去掉最后一位校验位) + const prefix15 = prefix + mutated.join('').slice(0, -1); + + // 重新计算Luhn校验位 + const checkDigit = this.calculateLuhnCheckDigit(prefix15); + + return prefix15 + checkDigit; + } + + /** + * 计算Luhn校验位 + * @param {string} partial - 不含校验位的卡号 + * @returns {string} + */ + calculateLuhnCheckDigit(partial) { + let sum = 0; + let isEven = true; + + for (let i = partial.length - 1; i >= 0; i--) { + let digit = parseInt(partial[i]); + + if (isEven) { + digit *= 2; + if (digit > 9) digit -= 9; + } + + sum += digit; + isEven = !isEven; + } + + return ((10 - (sum % 10)) % 10).toString(); + } /** * 生成有效期