This commit is contained in:
dengqichen 2025-11-19 23:22:56 +08:00
parent 2cc8139924
commit 8855683f2f
5 changed files with 95 additions and 23 deletions

3
.env
View File

@ -1,7 +1,8 @@
# AdsPower 指纹浏览器配置
ADSPOWER_USER_ID=k1728p8l
ADSPOWER_API_KEY=35de43696f6241f3df895f2f48777a99
# ADSPOWER_API=http://local.adspower.net:50325
# 使用 127.0.0.1 而不是 local.adspower.net避免 TUN VPN 路由冲突
ADSPOWER_API=http://127.0.0.1:50325
# MySQL 数据库配置
MYSQL_HOST=172.22.222.111

View File

@ -6,8 +6,21 @@
const CARD_TYPES = {
unionpay: {
name: '中国银联 (UnionPay)',
// 固定前缀(用户提供的成功案例都是这个前缀)
prefix: '622836754', // 固定BIN前缀
// 多个 9 位银联卡 BIN 前缀(基于真实成功案例和同系列扩展)
// 策略:优先使用已验证成功的 622836754 和其同系列变体
prefixes: [
'622836754', // ✅ 原始成功案例(最高优先级)
'622836755', '622836756', '622836757', // 同系列变体
'622836758', '622836759', '622836750', // 继续同系列
'622836751', '622836752', '622836753', // 更多同系列
],
// 备用:如果同系列都失败,尝试其他真实 BIN
// 暂时注释掉未验证的 BIN减少失败率
// prefixes_backup: [
// '622206000', '622210000', // 工商银行
// '622620000', // 民生银行
// '622588000', // 招商银行
// ],
length: 16,
cvvLength: 3,
useLuhn: true,
@ -29,10 +42,10 @@ const CARD_TYPES = {
'5956423', '7237848', '0385107', '4252006', '7562054'
],
// 生成策略配置
// 生成策略配置(优化后)
generation: {
mutationRate: 0.5, // 50% 使用变异策略
randomRate: 0.5, // 50% 使用纯随机
mutationRate: 0.7, // 70% 使用变异策略(基于真实成功案例)
randomRate: 0.3, // 30% 使用纯随机
mutationDigits: [1, 2] // 变异时改变1-2个数字
}
},

View File

@ -83,29 +83,36 @@ class CardGenerator {
* @returns {string}
*/
_generateCardNumberInternal(type, config) {
const { prefix, length, useLuhn, successfulPatterns, generation } = config;
const { prefix, prefixes, length, useLuhn, successfulPatterns, generation } = config;
// 如果有成功案例和生成策略配置,使用三策略混合
// 支持单个 prefix 或多个 prefixes
let selectedPrefix = prefix;
if (prefixes && Array.isArray(prefixes) && prefixes.length > 0) {
// 从 prefixes 数组中随机选择一个
selectedPrefix = prefixes[randomInt(0, prefixes.length - 1)];
}
// 如果有成功案例和生成策略配置,使用三策略混合(优化版)
if (successfulPatterns && generation) {
const rand = Math.random();
// 策略130%):加权生成(基于统计分布)
if (rand < 0.3) {
return this.generateByWeights(prefix, length);
// 策略120%):加权生成(基于统计分布)
if (rand < 0.2) {
return this.generateByWeights(selectedPrefix, length);
}
// 策略240%):变异真实案例
else if (rand < 0.7) {
return this.generateByMutation(prefix, successfulPatterns, generation.mutationDigits);
// 策略260%变异真实案例提高到60%,因为这是最可靠的)
else if (rand < 0.8) {
return this.generateByMutation(selectedPrefix, successfulPatterns, generation.mutationDigits);
}
// 策略330%):完全随机
// 策略320%完全随机降低到20%
}
// 策略3纯随机生成默认或回退
if (useLuhn) {
return generateLuhnNumber(prefix, length);
return generateLuhnNumber(selectedPrefix, length);
} else {
const remainingLength = length - prefix.length;
return prefix + randomDigits(remainingLength);
const remainingLength = length - selectedPrefix.length;
return selectedPrefix + randomDigits(remainingLength);
}
}

View File

@ -151,8 +151,11 @@ workflow:
type: "select"
addressLine1:
find:
- css: '#billingAddressLine1' # 使用 id 选择器,兼容所有语言
- css: 'input[name="billingAddressLine1"]'
- css: 'input[placeholder*="地址"]'
- css: 'input[placeholder*="Address"]'
- css: 'input[placeholder*="Alamat"]' # 印尼语
value: "kowloon"
# 滚动到页面底部(确保订阅按钮可见)
@ -164,8 +167,10 @@ workflow:
- action: click
name: "点击提交支付"
selector:
- css: 'button[data-testid="hosted-payment-submit-button"]'
- css: 'button[type="submit"]'
- css: 'button[data-testid="hosted-payment-submit-button"]' # Stripe 官方 testid
- css: 'button.SubmitButton' # Stripe 按钮类名
- css: 'button[type="submit"]' # 通用 submit 按钮
- css: 'button:has(.SubmitButton-IconContainer)' # 包含 icon 容器的按钮
timeout: 30000 # 给足够时间等待按钮从 disabled 变为可点击
waitForEnabled: true # 循环等待按钮激活(不是等待出现,而是等待可点击)
@ -187,13 +192,30 @@ workflow:
- urlNotContains: "stripe.com"
- urlNotContains: "checkout.stripe.com"
failure:
# 英文
- textContains: "card was declined"
- textContains: "Your card was declined"
- textContains: "declined"
- textContains: "We are unable to authenticate your payment method"
# 中文
- textContains: "卡片被拒绝"
- textContains: "我们无法验证您的支付方式"
- textContains: "我们未能验证您的支付方式"
- textContains: "请选择另一支付方式并重试"
# 马来语
- textContains: "Kad anda telah ditolak" # 您的卡已被拒绝
- textContains: "Kami tidak dapat mensahihkan kaedah pembayaran"
- textContains: "Sila pilih kaedah pembayaran yang berbeza"
# 印尼语
- textContains: "Kami tidak dapat memverifikasi metode pembayaran"
- textContains: "Silakan pilih metode pembayaran"
- textContains: "kartu ditolak"
# 泰语
- textContains: "บัตรของคุณถูกปฏิเสธ" # 您的卡被拒绝
- textContains: "ไม่สามารถยืนยัน" # 无法验证
- textContains: "เราตรวจสอบสิทธิ์วิธีการชำระเงินของคุณไม่ได้" # 我们无法验证您的支付方式
- textContains: "โปรดเลือกวิธีการชำระเงินอื่น" # 请选择另一个支付方式
# 通用错误元素
- elementExists: ".error-message"
timeout: 15000
pollInterval: 500
@ -240,13 +262,42 @@ workflow:
optional: true
# ==================== 步骤 9: 退出登录 ====================
# 9.1 滚动到页面底部
- action: scroll
name: "滚动到页面底部"
direction: "bottom"
# 9.2 等待滚动完成
- action: wait
name: "等待滚动完成"
duration: 1000
# 9.3 点击退出登录
- action: click
name: "点击退出登录"
selector:
- css: "div.body3.cursor-pointer"
text: "Log out"
- text: "Log out"
options:
exact: true
caseInsensitive: false
exact: false
caseInsensitive: true
timeout: 15000
waitForNavigation: false
# 9.4 等待退出完成
- action: wait
name: "等待退出完成"
duration: 3000
# 9.5 验证是否跳转到登录页
- action: verify
name: "验证跳转到登录页"
conditions:
success:
- urlContains: "/account/login"
timeout: 10000
onFailure: "throw"
# 错误处理配置
errorHandling:

View File

@ -42,7 +42,7 @@ class ConfigValidator {
},
scroll: {
required: [],
optional: ['name', 'type', 'selector', 'x', 'y', 'behavior']
optional: ['name', 'type', 'selector', 'x', 'y', 'behavior', 'direction']
},
custom: {
required: ['handler'],