Files
autoreg-skills-max/skills/account-validation/templates/upcloud_verify_card.py

209 lines
7.5 KiB
Python

#!/usr/bin/env python3
"""
UpCloud card verification via API — password login + Braintree tokenize + verify.
This is the working pipeline for verifying a card on an existing UpCloud account.
Usage:
python upcloud_verify_card.py
Prerequisites:
- Anti-captcha API key with balance
- UpCloud account already registered (username + password)
- Email IMAP credentials for OTP fallback
- Card details (number, exp month/year, CVV)
Flow:
1. Solve hCaptcha (login sitekey)
2. Password login via /v2/session
3. Get Braintree client token
4. Tokenize card via Braintree GraphQL
5. Verify card via /v2/account/main/verify (tries EUR/DE first, then USD/US)
6. On success: extract API token, try server creation
If card is UA-BIN, Braintree will reject with 422 VERIFICATION_ERROR before 3DS.
"""
import requests, json, time, base64, re
GATE = 'https://gate.upcloud.com'
HUB = 'https://hub.upcloud.com'
AC_KEY = 'YOUR_ANTICAPTCHA_KEY'
# === CONFIG ===
USERNAME = 'upXXXXXXXX'
PASSWORD = 'your_password'
EMAIL = '[REDACTED-EMAIL]'
EMAIL_PASS = 'your_email_password'
CARD = '0000000000000000'
EXP_M = 'MM'
EXP_Y = 'YYYY'
CVV = 'NNN'
IMAP_HOST = 'secureimap.t-online.de'
IMAP_PORT = 993
UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
SITEKEY = '13b63774-5d8c-4b1a-9cfc-8bae5b1abca0'
def solve_captcha():
r = requests.post('https://api.anti-captcha.com/createTask', json={
'clientKey': AC_KEY,
'task': {'type': 'HCaptchaTaskProxyless', 'websiteURL': HUB,
'websiteKey': SITEKEY,
'isInvisible': True, 'isEnterprise': True}
}, timeout=30)
d = r.json()
tid = d.get('taskId')
if not tid:
return None
for i in range(80):
time.sleep(2)
r = requests.post('https://api.anti-captcha.com/getTaskResult',
json={'clientKey': AC_KEY, 'taskId': tid}, timeout=15)
d = r.json()
if d.get('status') == 'ready':
return d['solution']['gRecaptchaResponse']
if d.get('errorId'):
return None
return None
def get_otp(timeout=120):
import imaplib, email as emaillib
t0 = time.time()
while time.time() - t0 < timeout:
try:
m = imaplib.IMAP4_SSL(IMAP_HOST, IMAP_PORT)
m.login(EMAIL, EMAIL_PASS)
m.select('INBOX')
_, data = m.search(None, '(FROM "upcloud" UNSEEN)')
ids = data[0].split()
if ids:
_, msg_data = m.fetch(ids[-1], '(RFC822)')
msg = emaillib.message_from_bytes(msg_data[0][1])
body = ''
if msg.is_multipart():
for part in msg.walk():
ct = part.get_content_type()
if ct in ('text/plain', 'text/html'):
body = part.get_payload(decode=True).decode(errors='replace')
break
else:
body = msg.get_payload(decode=True).decode(errors='replace')
match = re.search(r'\*([A-Z0-9]{4,10})\*', body)
if match:
m.logout()
return match.group(1)
match = re.search(r'\b(\d{6})\b', body)
if match:
m.logout()
return match.group(1)
m.logout()
except:
pass
time.sleep(5)
return None
def main():
s = requests.Session()
s.headers.update({
'User-Agent': UA,
'Origin': 'https://hub.upcloud.com',
'Referer': 'https://hub.upcloud.com/',
'Content-Type': 'application/json'
})
# 1. Password login
print('[1] Password login...')
t1 = solve_captcha()
if not t1:
return False
r = s.post(f'{GATE}/v2/session', json={
'captcha_token': t1, 'username': USERNAME,
'password': PASSWORD, 'token': True
}, timeout=15)
print(f' Login: {r.status_code}')
if r.status_code == 422:
print(' Captcha rejected, retry...')
t1 = solve_captcha()
if not t1:
return False
r = s.post(f'{GATE}/v2/session', json={
'captcha_token': t1, 'username': USERNAME,
'password': PASSWORD, 'token': True
}, timeout=15)
print(f' Login retry: {r.status_code}')
if r.status_code != 200:
print(f' {r.text[:200]}')
return False
# Token is in cookies, not JSON
auth_token = [REDACTED]'auth-token', '')
if auth_token:
[REDACTED]'Authorization': f'Bearer {auth_token}'})
r = s.get(f'{GATE}/v2/account', timeout=15)
print(f' Account: {r.status_code}')
if r.status_code != 200:
return False
acct = r.json().get('account', {})
print(f' active={acct.get("active")} credits={acct.get("credits")}')
# 2. Braintree
print('[2] Braintree...')
r = s.get(f'{GATE}/v2/braintree/client_token/EUR', timeout=15)
if r.status_code != 200:
r = s.get(f'{GATE}/v2/braintree/client_token/USD', timeout=15)
if r.status_code != 200:
print(f' FAIL: {r.text[:200]}')
return False
dec = json.loads(base64.b64decode(r.json()['client_token']).decode())
afp = dec['authorizationFingerprint']
gql = dec['graphQL']['url']
# 3. Tokenize
print('[3] Tokenize card...')
mut = 'mutation T($input: TokenizeCreditCardInput!){tokenizeCreditCard(input:$input){token}}'
r = requests.post(gql, json={"query": mut, "variables": {
"input": {"creditCard": {"number": CARD, "expirationMonth": EXP_M,
"expirationYear": EXP_Y, "cvv": CVV},
"options": {"validate": False}}
}}, headers={"Authorization": f"Bearer {afp}",
"Content-Type": "application/json",
"Braintree-Version": "2023-08-01"}, timeout=30)
resp = r.json()
if 'errors' in resp:
print(f' ERR: {resp["errors"]}')
return False
nonce = resp["data"]["tokenizeCreditCard"]["token"]
print(f' Nonce: {nonce}')
# 4. Verify (rate limit: wait 10s between attempts, max 2-3)
print('[4] Verify card...')
for curr, country, city, addr, postal, state in [
('EUR', 'DEU', 'Berlin', 'Hauptstrasse 22', '10115', ''),
('USD', 'USA', 'New York', '350 Fifth Avenue', '10118', 'NY'),
]:
time.sleep(10)
print(f' {curr}/{country}...')
v = {"account": {"address": addr, "city": city, "country": country,
"first_name": "signup", "last_name": "user",
"payment_method_nonce": nonce, "postal_code": postal,
"company": "", "currency": curr,
"device_data": json.dumps({"correlation_id": str(int(time.time()))}),
"state": state, "vat_number": ""}}
r = s.post(f'{GATE}/v2/account/main/verify', json=v, timeout=30)
print(f' {r.status_code} {r.text[:400]}')
if r.status_code in [200, 201]:
print('\n=== VERIFIED! ===')
r = s.get(f'{GATE}/v2/account', timeout=15)
a = r.json().get('account', {})
print(f' active={a.get("active")} trial_started={a.get("trial_started")}')
r = s.post(f'{GATE}/v2/account/tokens', json={
"name": "eni-prod", "expires_at": "2027-09-01T00:00:00.00001Z"
}, timeout=15)
tok = r.json().get('token', {}).get('token', '') if r.status_code == 201 else ''
print(f' API token: {tok}')
return True
print('\n[FAIL] Card rejected or rate limited')
return False
if __name__ == '__main__':
main()