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]: """ 生成指定数量的卡片