diff --git a/checker/scripts/setup_with_uv.sh b/checker/scripts/setup_with_uv.sh
index 1c0c66c..946b67b 100755
--- a/checker/scripts/setup_with_uv.sh
+++ b/checker/scripts/setup_with_uv.sh
@@ -21,4 +21,4 @@ echo ""
echo "现在你可以运行:"
echo " checker # 运行命令行工具"
echo " python -m checker # 或使用模块方式"
-echo " uv run python -m checker # 使用uv运行"
+echo " uv run python -m checker.bot.main # 使用uv运行"
diff --git a/checker/src/checker/bot/handlers.py b/checker/src/checker/bot/handlers.py
index f95d2da..cf2767b 100644
--- a/checker/src/checker/bot/handlers.py
+++ b/checker/src/checker/bot/handlers.py
@@ -27,34 +27,52 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"1. /chk - 检测卡片\n"
" /chk cc|mm|yy|cvv\n\n"
"2. /gen - 生成卡片\n"
- " /gen 10 536737xxxx (生成10张)\n"
- " /gen 10 536737xxxx /chk (生成并检测)"
+ " /gen 536737xxxx (默认10张)\n"
+ " /gen 20 536737xxxx (生成20张)\n"
+ " /gen 536737xxxx /chk (生成并检测)"
)
async def gen_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""响应 /gen 命令"""
- # 格式: /gen [/chk]
- if not context.args or len(context.args) < 2:
+ # 格式: /gen [count] [/chk]
+ # 默认数量为 10
+ if not context.args or len(context.args) < 1:
await update.message.reply_html(
"❌ 格式错误\n\n"
"用法:\n"
- "/gen 10 536737xxxxxxxxxx\n"
- "/gen 10 536737xxxxxxxxxx /chk"
+ "/gen 536737xxxxxxxxxx (默认10张)\n"
+ "/gen 20 536737xxxxxxxxxx (指定数量)\n"
+ "/gen 536737xxxxxxxxxx /chk (生成并检测)"
)
return
- try:
- count = int(context.args[0])
- pattern = context.args[1]
- except ValueError:
- await update.message.reply_text("❌ 数量必须是数字。")
- return
-
- # 检查是否有 /chk
+ # 智能解析参数
+ count = 10 # 默认数量
+ pattern = None
do_check = False
- if len(context.args) > 2 and '/chk' in context.args[2:]:
+
+ # 检查是否有 /chk 参数
+ args_without_chk = [arg for arg in context.args if arg != '/chk']
+ if '/chk' in context.args:
do_check = True
+ # 解析数量和模式
+ if len(args_without_chk) == 1:
+ # /gen
+ pattern = args_without_chk[0]
+ elif len(args_without_chk) >= 2:
+ # 尝试第一个参数是否为数字
+ try:
+ count = int(args_without_chk[0])
+ pattern = args_without_chk[1]
+ except ValueError:
+ # 如果第一个参数不是数字,则当作模式,使用默认数量
+ pattern = args_without_chk[0]
+
+ if not pattern:
+ await update.message.reply_text("❌ 请提供卡片模式。")
+ return
+
# 限制生成数量
if count > 1000:
await update.message.reply_text("❌ 一次最多生成 1000 张卡片。")
@@ -143,7 +161,8 @@ async def process_input_text(update: Update, context: ContextTypes.DEFAULT_TYPE,
"dead": 0,
"unknown": 0,
"total": len(cards),
- "checked": 0
+ "checked": 0,
+ "results": [] # 存储所有检测结果
}
# 4. 创建并发任务
@@ -156,27 +175,35 @@ async def process_input_text(update: Update, context: ContextTypes.DEFAULT_TYPE,
await asyncio.gather(*tasks)
# 5. 最终报告
- report = (
- f"🏁 检测完成\n\n"
- f"Total: {stats['total']}\n"
- f"Live: {stats['live']} ✅\n"
- f"Dead: {stats['dead']} ❌\n"
- f"Unknown: {stats['unknown']} ⚠️"
- )
+ report_lines = [
+ f"🏁 检测完成\n",
+ f"Total: {stats['total']}",
+ f"Live: {stats['live']} ✅",
+ f"Dead: {stats['dead']} ❌",
+ f"Unknown: {stats['unknown']} ⚠️\n"
+ ]
+
+ # 添加所有卡片的详细结果
+ if stats['results']:
+ report_lines.append("详细结果:")
+ for result_info in stats['results']:
+ report_lines.append(result_info)
+
+ report = "\n".join(report_lines)
await status_msg.edit_text(report, parse_mode=ParseMode.HTML)
async def process_card(
- card: Card,
- checker: StripeChecker,
- update: Update,
+ card: Card,
+ checker: StripeChecker,
+ update: Update,
stats: dict
):
"""异步处理单张卡片"""
loop = asyncio.get_running_loop()
-
+
# 每个任务独立的 Session
session = requests.Session()
-
+
try:
# 在线程池中运行阻塞的检测逻辑
result = await loop.run_in_executor(
@@ -186,20 +213,32 @@ async def process_card(
session,
None # 暂时不使用代理,后续可扩展
)
-
+
stats["checked"] += 1
-
+
+ # 格式化结果信息
+ card_info = f"{card.formatted}"
+
if result.status == CheckStatus.LIVE:
stats["live"] += 1
+ result_line = f"{card_info} - {result.message} ✅"
+ stats["results"].append(result_line)
await send_live_alert(update, result)
elif result.status == CheckStatus.DEAD:
stats["dead"] += 1
+ result_line = f"{card_info} - {result.message} ❌"
+ stats["results"].append(result_line)
else:
stats["unknown"] += 1
-
+ result_line = f"{card_info} - {result.message} ⚠️"
+ stats["results"].append(result_line)
+
except Exception as e:
logger.error(f"Error checking card {card.formatted}: {e}")
stats["unknown"] += 1
+ card_info = f"{card.formatted}"
+ result_line = f"{card_info} - Error: {str(e)} ⚠️"
+ stats["results"].append(result_line)
finally:
session.close()
diff --git a/checker/src/checker/cards/generator.py b/checker/src/checker/cards/generator.py
index 0ed838c..4ac0e99 100644
--- a/checker/src/checker/cards/generator.py
+++ b/checker/src/checker/cards/generator.py
@@ -67,30 +67,52 @@ class CardGenerator:
def parse_date_cvv(self, card_num: str, m_req: Optional[str], y_req: Optional[str], c_req: Optional[str]) -> Tuple[str, str, str]:
"""
处理日期和CVV的占位符逻辑
+ 支持 (m), (y), (cvv), rnd 或任何非纯数字的值作为随机标记
"""
# --- Month ---
- if m_req in ['(m)', 'rnd', '', None]:
+ if self._is_random_placeholder(m_req):
month = str(random.randint(1, 12)).zfill(2)
else:
month = m_req.strip()
-
+
# --- Year ---
- if y_req in ['(y)', 'rnd', '', None]:
+ if self._is_random_placeholder(y_req):
year = str(self.current_year + random.randint(2, 5))
else:
year = y_req.strip()
# --- CVV ---
- if c_req in ['(cvv)', 'rnd', '', None]:
+ if self._is_random_placeholder(c_req):
if card_num.startswith(('34', '37')):
cvv = str(random.randint(1102, 9999))
else:
cvv = str(random.randint(112, 999))
else:
cvv = c_req.strip()
-
+
return month, year, cvv
+ def _is_random_placeholder(self, value: Optional[str]) -> bool:
+ """
+ 判断值是否为随机占位符
+ 支持: None, '', '(m)', '(y)', '(cvv)', 'rnd', 或任何非纯数字的值(如 'xxx', 'abc' 等)
+ """
+ if value is None or value.strip() == '':
+ return True
+
+ value = value.strip()
+
+ # 已知的占位符
+ known_placeholders = ['(m)', '(y)', '(cvv)', 'rnd']
+ if value in known_placeholders:
+ return True
+
+ # 如果是非纯数字的字符串,视为占位符
+ if not value.isdigit():
+ return True
+
+ return False
+
def process_line(self, raw_input: str, count: int = 1) -> List[str]:
"""
生成指定数量的卡片