1169 lines
74 KiB
Python
1169 lines
74 KiB
Python
#!/usr/bin/env python3
|
||
"""AURIGA v2 — toolbox: IP intel, card validator, SMS rentals, proxy lab, stego lab,
|
||
trackable files (BTCPay), no-KYC site-only messaging inbox. Single-file Flask + SQLite."""
|
||
import base64, binascii, hashlib, hmac, html, io, json, os, re, secrets, socket, sqlite3, struct, time, uuid
|
||
import urllib.request, urllib.parse
|
||
from flask import Flask, request, jsonify, render_template_string, Response, send_file
|
||
|
||
app = Flask(__name__)
|
||
DB_PATH = os.environ.get("AURIGA_DB", "/opt/auriga/auriga.db")
|
||
UPLOAD_DIR = os.environ.get("AURIGA_UPLOADS", "/opt/auriga/uploads")
|
||
os.makedirs(UPLOAD_DIR, exist_ok=True)
|
||
SMSP_KEY = os.environ.get("SMSP_KEY", "")
|
||
PLEIADES_GW = os.environ.get("PLEIADES_GW", "10.30.20.178:8080")
|
||
PLEIADES_APP = os.environ.get("PLEIADES_APP", "https://pleiades.thetempleofdoom.com")
|
||
BTCPAY = "https://10.30.20.140/api/v1"
|
||
BTCPAY_KEY = os.environ.get("BTCPAY_KEY", "6026288e2e315984661c748baafd509e81a75f22")
|
||
BTCPAY_STORE = os.environ.get("BTCPAY_STORE", "7h79ndYyZX2yF6CPa12xt2uVGQ5Fd6nrSDG4Koy86x6u")
|
||
WEBCHECK = os.environ.get("WEBCHECK", "http://10.30.20.13:3000")
|
||
ADMIN_PW = os.environ.get("AURIGA_ADMIN", "Czapiewski1!")
|
||
BTCPAY_WHSEC = os.environ.get("BTCPAY_WHSEC", "TgJhmoBcNf9ATK2SFCg1VS")
|
||
BMAC = "https://buymeacoffee.com/r26xrthzttg"
|
||
SITE = "https://auriga.thetempleofdoom.com"
|
||
|
||
def db():
|
||
con = sqlite3.connect(DB_PATH); con.row_factory = sqlite3.Row
|
||
con.executescript("""CREATE TABLE IF NOT EXISTS sms_rentals(id INTEGER PRIMARY KEY, phone TEXT, service TEXT, country TEXT, purchase_id TEXT, cost REAL, status TEXT, created INTEGER, expires INTEGER);
|
||
CREATE TABLE IF NOT EXISTS proxy_checks(id INTEGER PRIMARY KEY, user_key TEXT, egress_ip TEXT, geo TEXT, ok INTEGER, ts INTEGER);
|
||
CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, username TEXT UNIQUE, passhash TEXT, created INTEGER);
|
||
CREATE TABLE IF NOT EXISTS sessions(id INTEGER PRIMARY KEY, token TEXT UNIQUE, user_id INTEGER, created INTEGER);
|
||
CREATE TABLE IF NOT EXISTS trackables(id INTEGER PRIMARY KEY, user_id INTEGER, token TEXT UNIQUE, filename TEXT, kind TEXT, invoice_id TEXT, paid INTEGER DEFAULT 0, created INTEGER);
|
||
CREATE TABLE IF NOT EXISTS track_events(id INTEGER PRIMARY KEY, trackable_id INTEGER, ts INTEGER, ip TEXT, ua TEXT);
|
||
CREATE TABLE IF NOT EXISTS messages(id INTEGER PRIMARY KEY, user_id INTEGER, sender TEXT, body TEXT, created INTEGER);
|
||
CREATE TABLE IF NOT EXISTS mailboxes(id INTEGER PRIMARY KEY, user_id INTEGER, address TEXT UNIQUE, invoice_id TEXT, paid INTEGER DEFAULT 0, expires INTEGER DEFAULT 0, created INTEGER, plan_days INTEGER DEFAULT 7, cnt INTEGER DEFAULT 0);
|
||
CREATE TABLE IF NOT EXISTS mails(id INTEGER PRIMARY KEY, mailbox_id INTEGER, sender TEXT, subject TEXT, body TEXT, ts INTEGER);
|
||
CREATE TABLE IF NOT EXISTS passes(id INTEGER PRIMARY KEY, user_id INTEGER, invoice_id TEXT, paid INTEGER DEFAULT 0, expires INTEGER DEFAULT 0, plan_days INTEGER DEFAULT 30);""")
|
||
return con
|
||
|
||
import ssl as _ssl
|
||
_CTX = _ssl.create_default_context()
|
||
_CTX.check_hostname = False
|
||
_CTX.verify_mode = _ssl.CERT_NONE
|
||
|
||
def http(url, headers=None, data=None, method="GET", timeout=12):
|
||
h = {"User-Agent": "Mozilla/5.0 (Auriga toolbox)"}
|
||
h.update(headers or {})
|
||
req = urllib.request.Request(url, headers=h, data=data, method=method)
|
||
try:
|
||
with urllib.request.urlopen(req, timeout=timeout, context=_CTX) as r:
|
||
return r.status, r.read().decode("utf-8", "replace")
|
||
except urllib.error.HTTPError as e:
|
||
return e.code, e.read().decode("utf-8", "replace")
|
||
except Exception as e:
|
||
return 0, str(e)
|
||
|
||
def jf(b):
|
||
try: return json.loads(b)
|
||
except Exception: return None
|
||
|
||
def param(name):
|
||
return request.form.get(name) or request.args.get(name)
|
||
|
||
def esc(s): return html.escape(str(s))
|
||
|
||
BASE = """<!doctype html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1">
|
||
<title>AURIGA — Toolbox</title>
|
||
<style>
|
||
:root{--bg:#0b0e17;--card:#141a2b;--fg:#e8ecf7;--dim:#8b95b3;--acc:#f0b429;--acc2:#7dd3fc;--ok:#3ecf8e;--bad:#ff5d5d}
|
||
*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--fg);font:16px/1.5 ui-monospace,Menlo,Consolas,monospace}
|
||
body::before{content:"";position:fixed;inset:0;background:radial-gradient(1px 1px at 20% 30%,#fff8,transparent),radial-gradient(1px 1px at 80% 20%,#fff6,transparent),radial-gradient(1px 1px at 60% 70%,#fff5,transparent),radial-gradient(1px 1px at 40% 80%,#fff7,transparent),radial-gradient(2px 2px at 90% 60%,#fff4,transparent);pointer-events:none;animation:tw 6s ease-in-out infinite alternate}
|
||
@keyframes tw{from{opacity:.5}to{opacity:1}}
|
||
nav{display:flex;flex-wrap:wrap;gap:.4rem;padding:1rem 1.4rem;border-bottom:1px solid #232b45;position:sticky;top:0;background:rgba(11,14,23,.92);backdrop-filter:blur(8px);z-index:5}
|
||
nav a{color:var(--dim);text-decoration:none;padding:.45rem .9rem;border:1px solid #232b45;border-radius:999px;transition:.2s}
|
||
nav a.on,nav a:hover{color:var(--acc);border-color:var(--acc)}
|
||
main{max-width:960px;margin:0 auto;padding:2rem 1.4rem;position:relative}
|
||
h1{font-size:1.7rem;letter-spacing:.2em}h1 span{color:var(--acc)}
|
||
.sub{color:var(--dim);margin:.3rem 0 1.6rem}
|
||
.card{background:var(--card);border:1px solid #232b45;border-radius:14px;padding:1.2rem 1.4rem;margin:1rem 0;position:relative}
|
||
.card.glow{box-shadow:0 0 24px -12px var(--acc)}
|
||
.kv{display:grid;grid-template-columns:minmax(140px,220px) 1fr;gap:.3rem 1rem}
|
||
.kv div:nth-child(odd){color:var(--dim)}
|
||
input,select,button,textarea{font:inherit;background:#0e1424;color:var(--fg);border:1px solid #2a3555;border-radius:8px;padding:.6rem .8rem}
|
||
button{background:var(--acc);color:#111;border:0;font-weight:700;cursor:pointer;transition:.2s}
|
||
button:hover{filter:brightness(1.15);transform:translateY(-1px)}
|
||
button.ghost{background:transparent;color:var(--acc);border:1px solid var(--acc)}
|
||
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:1rem}
|
||
@media(max-width:700px){.grid2{grid-template-columns:1fr}.kv{grid-template-columns:1fr}}
|
||
.tag{display:inline-block;padding:.15rem .6rem;border-radius:999px;font-size:.8rem;border:1px solid}
|
||
.tag.ok{color:var(--ok);border-color:var(--ok)}.tag.bad{color:var(--bad);border-color:var(--bad)}.tag.warn{color:var(--acc);border-color:var(--acc)}
|
||
table{width:100%;border-collapse:collapse}td,th{padding:.4rem;border-bottom:1px solid #232b45;text-align:left;font-size:.9rem}
|
||
footer{color:var(--dim);text-align:center;padding:2rem;font-size:.85rem}footer a{color:var(--acc)}
|
||
code{background:#0e1424;padding:.1rem .4rem;border-radius:4px}
|
||
a{color:var(--acc2)}
|
||
.drop{border:2px dashed #2a3555;border-radius:12px;padding:2rem;text-align:center;cursor:pointer;transition:.2s}
|
||
.drop:hover,.drop.over{border-color:var(--acc);background:#f0b42908}
|
||
.msg{background:#0e1424;border-left:3px solid var(--acc);border-radius:0 8px 8px 0;padding:.7rem 1rem;margin:.6rem 0}
|
||
.msg.me{border-left-color:var(--acc2)}
|
||
.msg .who{color:var(--dim);font-size:.8rem}
|
||
.bar{height:6px;background:#0e1424;border-radius:3px;overflow:hidden}.bar>i{display:block;height:100%;background:var(--acc);width:0;transition:width .6s}
|
||
</style></head><body>
|
||
<nav>
|
||
<a href=/ class={{o(home)}}>◈ AURIGA</a><a href=/ip class={{o(ip)}}>◈ IP INTEL</a><a href=/card class={{o(card)}}>◈ CARD CHECK</a>
|
||
<a href=/sms class={{o(sms)}}>◈ SMS RENTAL</a><a href=/proxy class={{o(proxy)}}>◈ PROXY LAB</a>
|
||
<a href=/steg class={{o(steg)}}>◈ STEGO</a><a href=/track class={{o(track)}}>◈ TRACK FILE</a>
|
||
<a href=/mail class={{o(steg2)}}>◈ MAIL</a><a href=/inbox class={{o(inbox)}}>◈ INBOX</a>
|
||
<a href=/pass class={{o(sms2)}}>◈ PASS</a><a href=/tools class={{o(tools)}}>◈ TOOLS</a>
|
||
</nav><main>{{body}}</main>
|
||
<footer>Built for agents & humans · <a href="{{bmac}}" target=_blank rel=noopener>☕ fuel the lab</a></footer>
|
||
<script defer src="https://analytics.thetempleofdoom.com/script.js" data-website-id="953c15df-ba4c-453a-a7c6-465fa9e3f202"></script>
|
||
<script>
|
||
function cp(t){navigator.clipboard.writeText(t).then(function(){toast('Copied ✓')})}
|
||
function toast(m){var d=document.createElement('div');d.textContent=m;d.style.cssText='position:fixed;bottom:20px;left:50%;transform:translateX(-50%);background:var(--acc);color:#111;padding:.5rem 1rem;border-radius:8px;font-weight:700;z-index:99';document.body.appendChild(d);setTimeout(function(){d.remove()},1800)}
|
||
</script>
|
||
</body></html>"""
|
||
|
||
def page(sec, body):
|
||
return render_template_string(BASE, body=body, bmac=BMAC, o=lambda s: "on" if s == sec else "")
|
||
|
||
def kv(pairs):
|
||
rows = "".join(f"<div>{k}</div><div>{v}</div>" for k, v in pairs)
|
||
return f'<div class="card glow"><div class="kv">{rows}</div></div>'
|
||
|
||
# ---------- AGENT DISCOVERY ----------
|
||
API_INDEX = {
|
||
"service": "AURIGA toolbox",
|
||
"description": "IP intel, card BIN validation, 30-min SMS rentals, residential proxy lab, steganography, trackable files, no-KYC messaging, utilities.",
|
||
"endpoints": [
|
||
{"method": "GET", "path": "/api/ip?target=", "desc": "Caller IP intel (auto) or any IP you pass: geo, ASN, ISP, VPN/hosting flags, rDNS."},
|
||
{"method": "POST", "path": "/api/card", "params": {"num": "card number"}, "desc": "Luhn + BIN intel. Nothing stored/charged."},
|
||
{"method": "POST", "path": "/api/sms/rent", "params": {"service": "id/keyword", "country": "id"}, "desc": "Rent disposable number, 30 min, refundable."},
|
||
{"method": "GET", "path": "/api/sms/check?pid=", "desc": "Poll SMS code."},
|
||
{"method": "GET", "path": "/api/sms/cancel?pid=", "desc": "Cancel + refund."},
|
||
{"method": "GET", "path": "/api/sms/history", "desc": "Rental history."},
|
||
{"method": "POST", "path": "/api/proxy/test", "params": {"user": "Pleiades user", "pass": "password"}, "desc": "Tunnel CONNECT via Pleiades gateway, return egress IP/geo."},
|
||
{"method": "POST", "path": "/api/steg/hide", "params": {"image": "png file", "text": "secret", "password": "optional", "bits": "1-3", "spread": "sequential|random"}, "desc": "LSB steganography → PNG download."},
|
||
{"method": "POST", "path": "/api/steg/extract", "params": {"image": "png file", "password": "optional"}, "desc": "Extract hidden text."},
|
||
{"method": "POST", "path": "/api/track/create", "params": {"filename": "name"}, "desc": "Create $1 BTCPay invoice for a trackable file. Returns checkoutLink."},
|
||
{"method": "GET", "path": "/api/track/events?token=", "desc": "Open events for a trackable (auth via account)."},
|
||
{"method": "GET", "path": "/api/hash?s=", "desc": "md5/sha1/sha256/sha512."},
|
||
{"method": "GET", "path": "/api/hdr?url=", "desc": "Fetch URL, return status + headers."},
|
||
],
|
||
"payment": "BTCPay BTC only (no Stripe). SMS meters to house account; trackables $1 each.",
|
||
}
|
||
|
||
@app.route("/api")
|
||
def api_index(): return jsonify(API_INDEX)
|
||
|
||
@app.route("/robots.txt")
|
||
def robots(): return "User-agent: *\nAllow: /\n", 200, {"Content-Type": "text/plain"}
|
||
|
||
@app.route("/llms.txt")
|
||
def llms():
|
||
eps = "\n".join(f"- `{e['method']} {e['path']}` — {e['desc']}" for e in API_INDEX["endpoints"])
|
||
return f"# AURIGA toolbox\n\nBase: {SITE}\n\n## API\n{eps}\n", 200, {"Content-Type": "text/plain"}
|
||
|
||
@app.route("/ai-plugin.json")
|
||
def aiplugin():
|
||
return jsonify({"name_for_model": "auriga", "schema_version": "v1",
|
||
"description_for_model": "IP intelligence, card BIN validation, SMS number rentals, proxy egress testing, LSB steganography, trackable file links with open-notifications, no-KYC site messaging.",
|
||
"api": {"type": "openapi", "url": SITE + "/openapi.json"}, "auth": {"type": "none"}, "contact_email": "indianaholmes1@icloud.com"})
|
||
|
||
@app.route("/openapi.json")
|
||
def openapi():
|
||
ps = {"openapi": "3.0.0", "info": {"title": "AURIGA", "version": "2.0.0"}, "paths": {}}
|
||
def add(path, method, desc, params=None, req=False, files=None):
|
||
item = {"summary": desc}
|
||
if files:
|
||
item["requestBody"] = {"content": {"multipart/form-data": {"schema": {"type": "object", "properties": {**{k: {"type": "string"} for k, v in (params or {}).items()}, **{f: {"type": "string", "format": "binary"} for f in files}}}}}}
|
||
elif params:
|
||
if method == "get":
|
||
item["parameters"] = [{"name": k, "in": "query", "required": req, "schema": {"type": "string"}} for k in params]
|
||
else:
|
||
item["requestBody"] = {"content": {"application/x-www-form-urlencoded": {"schema": {"type": "object", "properties": {k: {"type": "string"} for k in params}}}}}
|
||
ps["paths"][path] = ps["paths"].get(path, {}) | {method: {"responses": {"200": {"description": "ok"}}, **item}}
|
||
add("/api/ip", "get", "IP intel (caller or ?target=)", {"target": "optional IP"})
|
||
add("/api/card", "post", "Luhn + BIN validation", {"num": "card number"}, req=True)
|
||
add("/api/sms/rent", "post", "Rent number 30 min", {"service": "id", "country": "id"}, req=True)
|
||
add("/api/sms/check", "get", "Poll SMS code", {"pid": "orderid"}, req=True)
|
||
add("/api/sms/cancel", "get", "Cancel + refund", {"pid": "orderid"}, req=True)
|
||
add("/api/sms/history", "get", "Rental history")
|
||
add("/api/proxy/test", "post", "Test Pleiades gateway creds", {"user": "user", "pass": "pass"}, req=True)
|
||
add("/api/steg/hide", "post", "LSB-hide text in PNG", {"text": "secret", "password": "opt"}, req=True, files=["image"])
|
||
add("/api/steg/extract", "post", "Extract text from PNG", {"password": "opt"}, files=["image"])
|
||
add("/api/track/create", "post", "Create $1 invoice for trackable", {"filename": "name"}, req=True)
|
||
add("/api/track/events", "get", "Trackable open events", {"token": "token"}, req=True)
|
||
add("/api/hash", "get", "Hashes", {"s": "string"}, req=True)
|
||
add("/api/hdr", "get", "HTTP headers", {"url": "url"}, req=True)
|
||
return jsonify(ps)
|
||
|
||
# ---------- 1. IP INTEL (auto + manual target) ----------
|
||
def ip_report(ip):
|
||
st, b = http(f"http://ip-api.com/json/{ip}?fields=66846719")
|
||
d = jf(b) or {}
|
||
try: d["reverse"] = d.get("reverse") or socket.gethostbyaddr(ip)[0]
|
||
except Exception: pass
|
||
return d
|
||
|
||
@app.route("/ip", methods=["GET", "POST"])
|
||
def ip_page():
|
||
target = param("target") if request.method == "POST" else param("target")
|
||
if target and target.strip():
|
||
target = target.strip()
|
||
d = ip_report(target)
|
||
heading = f"INTEL FOR <span>{esc(target)}</span>"
|
||
mine = False
|
||
else:
|
||
ip = request.headers.get("X-Real-IP") or request.remote_addr or ""
|
||
d = ip_report(ip)
|
||
heading = "WHATS <span>MY IP</span>"
|
||
mine = True
|
||
if d.get("status") == "fail" or not d:
|
||
body = f"<h1>{heading}</h1><div class=card><span class=tag bad>lookup failed</span></div>{ip_form()}"
|
||
return page("ip", body)
|
||
rows = [
|
||
("IP", f"<b style='font-size:1.3rem;color:var(--acc)'>{esc(d.get('query'))}</b>"),
|
||
("Country", f"{esc(d.get('country'))} ({esc(d.get('countryCode'))})"),
|
||
("Region / City", f"{esc(d.get('regionName'))} / {esc(d.get('city'))} {esc(d.get('zip'))}"),
|
||
("Lat, Lon", f"{d.get('lat')}, {d.get('lon')} · TZ {esc(d.get('timezone'))}"),
|
||
("ISP", esc(d.get("isp"))), ("Organization", esc(d.get("org"))), ("AS", esc(d.get("as") or d.get("asname"))),
|
||
("Reverse DNS", esc(d.get("reverse") or "—")),
|
||
("Flags", f"mobile: {d.get('mobile')} · proxy/VPN: {d.get('proxy')} · hosting: {d.get('hosting')}"),
|
||
("Currency", esc(d.get("currency"))),
|
||
]
|
||
extra = ""
|
||
if mine:
|
||
hdrs = {k: v for k, v in request.headers.items() if k.lower() in ("user-agent","accept-language","x-forwarded-for","cf-connecting-ip","cf-ipcountry")}
|
||
extra = '<div class=card><b>Headers you sent</b><table>' + "".join(f"<tr><td>{esc(k)}</td><td>{esc(v)}</td></tr>" for k, v in hdrs.items()) + "</table></div>"
|
||
body = f"""
|
||
<h1>{heading}</h1><p class=sub>Auto-detects your IP and shows everything. Want intel on another IP? Type it below — full report, any target.</p>
|
||
{kv(rows)}
|
||
<div class=card><form method=post><input name=target placeholder="any IP or hostname" style="width:70%" value="{esc(param('target') or '')}"> <button>Look up</button></form></div>
|
||
{extra}
|
||
<div class=card style=color:var(--dim)>API: GET /api/ip (caller) · GET /api/ip?target=1.2.3.4 (any target)</div>"""
|
||
return page("ip", body)
|
||
|
||
def ip_form():
|
||
return '<div class=card><form method=post><input name=target placeholder="IP or hostname"><button>Look up</button></form></div>'
|
||
|
||
@app.route("/api/ip")
|
||
def api_ip():
|
||
target = param("target")
|
||
if target and target.strip():
|
||
return jsonify(ip_report(target.strip()))
|
||
ip = request.headers.get("X-Real-IP") or request.remote_addr or ""
|
||
d = ip_report(ip)
|
||
d["headers_seen"] = dict(request.headers)
|
||
return jsonify(d)
|
||
|
||
# ---------- 2. CARD CHECK ----------
|
||
def luhn_ok(num):
|
||
digits = [int(c) for c in num]
|
||
s = sum(digits[-1::-2])
|
||
for d in digits[-2::-2]:
|
||
d *= 2
|
||
if d > 9: d -= 9
|
||
s += d
|
||
return s % 10 == 0
|
||
|
||
BRANDS = [("4","Visa"),("51","Mastercard"),("52","Mastercard"),("53","Mastercard"),("54","Mastercard"),("55","Mastercard"),
|
||
("22","Mastercard"),("23","Mastercard"),("24","Mastercard"),("25","Mastercard"),("26","Mastercard"),("27","Mastercard"),
|
||
("34","Amex"),("37","Amex"),("6011","Discover"),("65","Discover"),("644","Discover"),("645","Discover"),("646","Discover"),("647","Discover"),("648","Discover"),("649","Discover"),
|
||
("50","Maestro"),("56","Maestro"),("57","Maestro"),("58","Maestro"),("63","Maestro"),("67","Maestro"),
|
||
("30","Diners"),("36","Diners"),("38","Diners"),("39","Diners"),
|
||
("35","JCB"),("62","UnionPay"),("7","Mir")]
|
||
|
||
def brand_of(num):
|
||
for pfx, b in BRANDS:
|
||
if num.startswith(pfx): return b
|
||
return "Unknown"
|
||
|
||
def bin_lookup(bin8):
|
||
st, b = http(f"https://lookup.binlist.net/{bin8}", headers={"Accept-Version": "3"})
|
||
bl = jf(b) or {}
|
||
if not bl.get("bank") and not bl.get("type") and not bl.get("scheme"):
|
||
st, b = http(f"https://data.handyapi.com/bin/{bin8}")
|
||
h = jf(b) or {}
|
||
if h.get("Status") == "SUCCESS":
|
||
return {"bank": {"name": h.get("Issuer")}, "country": {"name": (h.get("Country") or {}).get("Name") if isinstance(h.get("Country"), dict) else h.get("Country")},
|
||
"type": str(h.get("Type", "")).lower() or None, "prepaid": "prepaid" in str(h.get("Type","")).lower() or None, "scheme": h.get("Scheme")}
|
||
return bl
|
||
|
||
@app.route("/card", methods=["GET", "POST"])
|
||
def card():
|
||
result = ""
|
||
num = re.sub(r"\D", "", param("num") or "")[:19]
|
||
if num:
|
||
ok = luhn_ok(num)
|
||
tags = ['<span class="tag ok">LUHN VALID</span>' if ok else '<span class="tag bad">LUHN INVALID — fake/dead number</span>']
|
||
brand = brand_of(num)
|
||
bl = bin_lookup(num[:8])
|
||
bank = (bl.get("bank") or {}).get("name", "—")
|
||
country = (bl.get("country") or {}).get("name", "—")
|
||
ctype = bl.get("type", "—")
|
||
prepaid = bl.get("prepaid", "—")
|
||
flags = []
|
||
if ctype == "prepaid" or prepaid is True: flags.append("PREPAID — commonly flagged by merchants")
|
||
rng = {"Visa":(13,16,19),"Mastercard":(16,),"Amex":(15,)}.get(brand,(13,15,16,19))
|
||
tags.append(f'<span class="tag ok">length {len(num)} valid for {brand}</span>' if len(num) in rng else f'<span class="tag bad">LENGTH {len(num)} WRONG for {brand}</span>')
|
||
result = f"""
|
||
{kv([("Brand",brand),("BIN",num[:8]),("Bank / Issuer",esc(bank)),("Country",esc(country)),("Type",str(ctype)),("Prepaid",str(prepaid))])}
|
||
<div class=card><b>Fraud & structure flags</b><br>{' '.join(tags)}{'<br>⚠ ' + ' · '.join(flags) if flags else ''}</div>
|
||
<div class=card style=color:var(--dim)>Nothing stored. No charge, no auth — BIN + math validation only. Fraud "flagged" status lives at the issuer.</div>"""
|
||
body = f"""
|
||
<h1>CARD <span>CHECK</span></h1><p class=sub>Luhn + BIN intelligence: issuer, brand, type, country, prepaid risk flags.</p>
|
||
<div class=card><form method=post><input id=cardnum name=num placeholder="4539 1488 0343 6467" style="width:70%" value="{esc(' '.join(num[i:i+4] for i in range(0,len(num),4))) if num else ''}" autocomplete=off inputmode=numeric> <button>Check</button></form>
|
||
<div style=color:var(--dim);font-size:.85rem;margin-top:.4rem>Paste anything — auto-formats. Nothing stored.</div></div>
|
||
<script>
|
||
var cn=document.getElementById('cardnum');
|
||
cn.addEventListener('input',function(){{var v=this.value.replace(/\\D/g,'').slice(0,19);this.value=v.replace(/(.{{4}})/g,'$1 ').trim()}});
|
||
</script>
|
||
{result}"""
|
||
return page("card", body)
|
||
|
||
@app.route("/api/card", methods=["POST"])
|
||
def api_card():
|
||
num = re.sub(r"\D", "", param("num") or "")[:19]
|
||
if not num: return jsonify({"ok": False, "error": "num required"})
|
||
ok = luhn_ok(num)
|
||
bl = bin_lookup(num[:8])
|
||
return jsonify({"ok": True, "luhn": ok, "brand": brand_of(num), "length_ok": len(num) in
|
||
{"Visa":(13,16,19),"Mastercard":(16,),"Amex":(15,)}.get(brand_of(num),(13,15,16,19)),
|
||
"bin": {"issuer": (bl.get("bank") or {}).get("name"), "country": (bl.get("country") or {}).get("name"),
|
||
"type": bl.get("type"), "prepaid": bl.get("prepaid")},
|
||
"flags": (["prepaid-risk"] if (bl.get("type")=="prepaid" or bl.get("prepaid") is True) else []) + (["luhn-invalid"] if not ok else [])})
|
||
|
||
# ---------- 3. SMS RENTALS ----------
|
||
SMSP = "https://api.smspool.net"
|
||
SERVICES = [("google","Google"),("discord","Discord"),("telegram","Telegram"),("whatsapp","WhatsApp"),("other","Other/Any")]
|
||
COUNTRIES = [("1","United States"),("2","United Kingdom"),("4","Netherlands"),("22","Russia"),("150","Germany")]
|
||
|
||
def sms_api(path, **kw):
|
||
if kw:
|
||
kw["key"] = SMSP_KEY
|
||
return http(f"{SMSP}/{path}", data=urllib.parse.urlencode(kw).encode(), method="POST")
|
||
return http(f"{SMSP}/{path}?key={SMSP_KEY}")
|
||
|
||
def sms_guard():
|
||
con = db(); now = int(time.time())
|
||
uid = current_user_id()
|
||
st, b = sms_api("request/balance")
|
||
bal = jf(b) or {}
|
||
try: bal = float(bal.get("balance", 0))
|
||
except Exception: bal = 0
|
||
if bal < 5: return f"house balance too low (${bal:.2f}) — rentals paused"
|
||
act = con.execute("SELECT COUNT(*) c FROM sms_rentals WHERE status='active' AND expires > ?", (now,)).fetchone()["c"]
|
||
if act >= (5 if has_pass(uid) else 3): return "too many active rentals right now — try again later"
|
||
h = con.execute("SELECT COUNT(*) c FROM sms_rentals WHERE created > ?", (now-3600,)).fetchone()["c"]
|
||
if h >= (20 if has_pass(uid) else 6): return "hourly rental cap reached"
|
||
d = con.execute("SELECT COUNT(*) c FROM sms_rentals WHERE created > ?", (now-86400,)).fetchone()["c"]
|
||
if d >= (50 if has_pass(uid) else 15): return "daily rental cap reached"
|
||
return None
|
||
|
||
@app.route("/sms", methods=["GET", "POST"])
|
||
def sms():
|
||
msg = ""
|
||
if request.method == "POST":
|
||
act = request.form.get("act")
|
||
if act == "rent":
|
||
guard = sms_guard()
|
||
if guard:
|
||
msg = f'<div class="card"><span class="tag warn">PAUSED</span> {guard}</div>'
|
||
else:
|
||
st, b = sms_api("purchase/sms", service=request.form["service"], country=request.form["country"])
|
||
d = jf(b) or {}
|
||
if d.get("success") == 1:
|
||
con = db(); now = int(time.time())
|
||
con.execute("INSERT INTO sms_rentals(phone,service,country,purchase_id,cost,status,created,expires) VALUES(?,?,?,?,?,?,?,?)",
|
||
(d.get("number"), request.form["service"], request.form["country"], str(d.get("purchase_id")), d.get("cost",0), "active", now, now+1800))
|
||
con.commit()
|
||
msg = f'<div class="card"><span class="tag ok">RENTED</span> Your number: <b style="font-size:1.2rem;color:var(--acc)">+{d.get("number")}</b> <button style="padding:.2rem .6rem;font-size:.8rem" onclick="cp(\'+{d.get("number")}\')">copy</button> · 30 min · order #{d.get("purchase_id")}</div>'
|
||
else:
|
||
msg = f'<div class="card"><span class="tag bad">RENT FAILED</span><br><pre>{esc(b[:400])}</pre></div>'
|
||
elif act == "check":
|
||
st, b = sms_api("sms/check", orderid=request.form["pid"])
|
||
d = jf(b) or {}
|
||
sms_txt = d.get("sms") or d.get("code") or ""
|
||
status = d.get("status", "?")
|
||
msg = f'<div class="card"><span class="tag {"ok" if sms_txt else "warn"}">STATUS: {status}</span> {"<b style=color:var(--ok)>" + esc(sms_txt) + "</b>" if sms_txt else "no code yet — poll again in 10s"}</div>'
|
||
elif act == "cancel":
|
||
st, b = sms_api("sms/cancel", orderid=request.form["pid"])
|
||
d = jf(b) or {}
|
||
ok = d.get("success") == 1
|
||
con = db(); con.execute("UPDATE sms_rentals SET status=? WHERE purchase_id=?", ("refunded" if ok else "cancel-failed", request.form["pid"])); con.commit()
|
||
msg = f'<div class="card"><span class="tag {"ok" if ok else "bad"}">{"CANCELLED + REFUNDED" if ok else "CANCEL FAILED"}</span></div>'
|
||
con = db()
|
||
hist = con.execute("SELECT * FROM sms_rentals ORDER BY id DESC LIMIT 8").fetchall()
|
||
hist_rows = "".join(f"<tr><td>+{h['phone']} <a href=# onclick=\"cp('+{h['phone']});return false\" style=color:var(--acc)>copy</a></td><td>{h['service']}</td><td>{h['status']}</td><td>#{h['purchase_id']}</td><td class=cdown data-exp={h['expires']}>…</td></tr>" for h in hist)
|
||
body = f"""
|
||
<h1>SMS <span>RENTAL</span></h1><p class=sub>Disposable numbers, 30-minute windows. Cancel before a code = full refund.</p>
|
||
<div class="grid2">
|
||
<div class=card><b>Rent a number</b>
|
||
<form method=post><input type=hidden name=act value=rent>
|
||
<select name=service style="width:100%">{''.join(f'<option value={v}>{n}</option>' for v,n in SERVICES)}</select>
|
||
<select name=country style="width:100%;margin:.5rem 0">{''.join(f'<option value={v}>{n}</option>' for v,n in COUNTRIES)}</select>
|
||
<button>Rent — 30 min</button></form></div>
|
||
<div class=card><b>Check / manage</b>
|
||
<form method=post><input type=hidden name=act value=check><input name=pid placeholder="order #" style="width:100%"><button style="margin:.5rem 0">Poll for code</button></form>
|
||
<form method=post><input type=hidden name=act value=cancel><input name=pid placeholder="order #" style="width:100%"><button style="background:var(--bad);color:#fff">Cancel & refund</button></form></div>
|
||
</div>{msg}
|
||
<div class=card><b>Recent rentals</b><table><tr><th>Number</th><th>Service</th><th>Status</th><th>Order</th><th>Window</th></tr>{hist_rows or '<tr><td colspan=5 style=color:var(--dim)>none yet</td></tr>'}</table></div>
|
||
<script>
|
||
setInterval(function(){{var els=document.querySelectorAll('.cdown');var now=Math.floor(Date.now()/1000);
|
||
els.forEach(function(e){{var s=e.dataset.exp-now;if(s>0)e.textContent=Math.floor(s/60)+'m '+(s%60)+'s left';else e.textContent='expired'}});}},1000);
|
||
</script>
|
||
<div class=card style=color:var(--dim)>API: POST /api/sms/rent (service,country) · GET /api/sms/check?pid= · GET /api/sms/cancel?pid= · GET /api/sms/history</div>"""
|
||
return page("sms", body)
|
||
|
||
@app.route("/api/sms/rent", methods=["POST"])
|
||
def api_sms_rent():
|
||
guard = sms_guard()
|
||
if guard: return jsonify({"success": 0, "message": guard, "paused": True})
|
||
st, b = sms_api("purchase/sms", service=param("service"), country=param("country"))
|
||
d = jf(b) or {}
|
||
if d.get("success") == 1:
|
||
con = db(); now = int(time.time())
|
||
con.execute("INSERT INTO sms_rentals(phone,service,country,purchase_id,cost,status,created,expires) VALUES(?,?,?,?,?,?,?,?)",
|
||
(d.get("number"), param("service"), param("country"), str(d.get("purchase_id")), d.get("cost",0), "active", now, now+1800))
|
||
con.commit()
|
||
return jsonify(d)
|
||
|
||
@app.route("/api/sms/check", methods=["GET","POST"])
|
||
def api_sms_check():
|
||
st, b = sms_api("sms/check", orderid=param("pid"))
|
||
return jf(b) or jsonify({"error": b[:200]})
|
||
|
||
@app.route("/api/sms/cancel", methods=["GET","POST"])
|
||
def api_sms_cancel():
|
||
st, b = sms_api("sms/cancel", orderid=param("pid"))
|
||
d = jf(b) or {}
|
||
if d.get("success") == 1:
|
||
con = db(); con.execute("UPDATE sms_rentals SET status='refunded' WHERE purchase_id=?", (param("pid"),)); con.commit()
|
||
return d
|
||
|
||
@app.route("/api/sms/history")
|
||
def api_sms_history():
|
||
con = db(); now = int(time.time())
|
||
con.execute("UPDATE sms_rentals SET status='expired' WHERE status='active' AND expires < ?", (now,))
|
||
con.commit()
|
||
return jsonify([dict(r) for r in con.execute("SELECT * FROM sms_rentals ORDER BY id DESC LIMIT 50")])
|
||
|
||
# ---------- 4. PROXY LAB ----------
|
||
@app.route("/proxy", methods=["GET", "POST"])
|
||
def proxy():
|
||
result = ""
|
||
if request.method == "POST" and request.form.get("act") == "test":
|
||
user, pw = request.form.get("user",""), request.form.get("pass","")
|
||
pauth = base64.b64encode(f"{user}:{pw}".encode()).decode()
|
||
try:
|
||
s = socket.create_connection((PLEIADES_GW.split(":")[0], int(PLEIADES_GW.split(":")[1])), timeout=15)
|
||
s.sendall(f"CONNECT ip-api.com:80 HTTP/1.1\r\nHost: ip-api.com:80\r\nProxy-Authorization: Basic {pauth}\r\n\r\n".encode())
|
||
resp = s.recv(4096)
|
||
if b"200" in resp.split(b"\r\n")[0]:
|
||
s.sendall(b"GET /json/?fields=66846719 HTTP/1.1\r\nHost: ip-api.com\r\nConnection: close\r\n\r\n")
|
||
data = b""
|
||
while True:
|
||
c = s.recv(8192)
|
||
if not c: break
|
||
data += c
|
||
s.close()
|
||
j = jf(data.split(b"\r\n\r\n",1)[-1].decode("utf-8","replace")) or {}
|
||
con = db()
|
||
con.execute("INSERT INTO proxy_checks(user_key,egress_ip,geo,ok,ts) VALUES(?,?,?,?,?)", (user[:12], j.get("query","?"), f"{j.get('country')}/{j.get('city')}", 1, int(time.time())))
|
||
con.commit()
|
||
result = f'<div class="card"><span class="tag ok">PROXY LIVE</span> Egress: <b style=color:var(--acc)>{esc(j.get("query"))}</b> — {esc(j.get("country"))} / {esc(j.get("city"))} · ISP {esc(j.get("isp"))} · tz {esc(j.get("timezone"))} <button style="padding:.2rem .6rem;font-size:.8rem" onclick="cp(\'{esc(j.get("query"))}\')">copy</button></div>'
|
||
else:
|
||
con = db()
|
||
con.execute("INSERT INTO proxy_checks(user_key,egress_ip,geo,ok,ts) VALUES(?,?,?,?,?)", (user[:12], "", "", 0, int(time.time())))
|
||
con.commit()
|
||
result = f'<div class="card"><span class="tag bad">AUTH/TUNNEL FAILED</span><pre>{esc(resp[:200])}</pre></div>'
|
||
except Exception as e:
|
||
result = f'<div class="card"><span class="tag bad">ERROR</span> {esc(e)}</div>'
|
||
body = f"""
|
||
<h1>PROXY <span>LAB</span></h1><p class=sub>Test + rent residential proxies on the Pleiades rail — same gateway keys as everywhere.</p>
|
||
<div class=card><form method=post><input type=hidden name=act value=test>
|
||
<label>Gateway user</label><br><input name=user style="width:100%" placeholder="your Pleiades username"><br>
|
||
<label style=color:var(--dim)>Password</label><br><input name=pass type=password style="width:100%"><br>
|
||
<button style=margin-top:.6rem>Test egress now</button></form></div>
|
||
{result}
|
||
<div class=card><b>Geo session builder</b>:
|
||
<select id=geoK onchange="gb()"><option value="">none</option><option value="_region-us">region US</option><option value="_region-eu">region EU</option><option value="_country-gb">country GB</option><option value="_country-de">country DE</option><option value="_city-london">city London</option></select>
|
||
<select id=geoS onchange="gb()"><option value="">rotating</option><option value="_session-a7x9_lifetime-30m">sticky 30-min</option></select>
|
||
<div style=margin-top:.5rem><code id=geoOut style=color:var(--acc)>yourpassword</code> <button style="padding:.2rem .6rem;font-size:.8rem" onclick="cp(document.getElementById('geoOut').textContent)">copy</button></div>
|
||
<script>function gb(){{document.getElementById('geoOut').textContent='yourpassword'+document.getElementById('geoK').value+document.getElementById('geoS').value}}</script></div>
|
||
<div class=card><b>Rent more</b> — storefront: <a href="{PLEIADES_APP}">{PLEIADES_APP}</a></div>
|
||
<div class=card style=color:var(--dim)>API: POST /api/proxy/test (user, pass) → egress IP + geo JSON.</div>"""
|
||
return page("proxy", body)
|
||
|
||
@app.route("/api/proxy/test", methods=["POST"])
|
||
def api_proxy_test():
|
||
user, pw = param("user") or "", param("pass") or ""
|
||
pauth = base64.b64encode(f"{user}:{pw}".encode()).decode()
|
||
try:
|
||
s = socket.create_connection((PLEIADES_GW.split(":")[0], int(PLEIADES_GW.split(":")[1])), timeout=15)
|
||
s.sendall(f"CONNECT ip-api.com:80 HTTP/1.1\r\nHost: ip-api.com:80\r\nProxy-Authorization: Basic {pauth}\r\n\r\n".encode())
|
||
resp = s.recv(4096)
|
||
if b"200" not in resp.split(b"\r\n")[0]: return jsonify({"ok": False, "raw": resp[:120].decode("utf-8","replace")})
|
||
s.sendall(b"GET /json/?fields=66846719 HTTP/1.1\r\nHost: ip-api.com\r\nConnection: close\r\n\r\n")
|
||
data = b""
|
||
while True:
|
||
c = s.recv(8192)
|
||
if not c: break
|
||
data += c
|
||
s.close()
|
||
j = jf(data.split(b"\r\n\r\n",1)[-1].decode("utf-8","replace")) or {}
|
||
return jsonify({"ok": True, "egress": j})
|
||
except Exception as e:
|
||
return jsonify({"ok": False, "error": str(e)})
|
||
|
||
# ---------- 5. STEGO LAB ----------
|
||
def _keystream(password, n):
|
||
ks = b""; seed = password.encode()
|
||
while len(ks) < n:
|
||
seed = hashlib.sha256(seed).digest()
|
||
ks += seed
|
||
return ks[:n]
|
||
|
||
def steg_hide(img_bytes, text, password="", bits=1, spread="sequential"):
|
||
from PIL import Image
|
||
im = Image.open(io.BytesIO(img_bytes)).convert("RGBA")
|
||
px = im.load()
|
||
w, h = im.size
|
||
capacity = w * h * 3 * bits
|
||
payload = text.encode("utf-8")
|
||
phash = hashlib.sha256(password.encode()).digest()[:4] if password else b"\x00\x00\x00\x00"
|
||
header = b"AUR1" + struct.pack(">I", len(payload)) + phash
|
||
body = payload
|
||
if password:
|
||
body = bytes(a ^ b for a, b in zip(body, _keystream(password, len(body))))
|
||
data = header + body
|
||
if len(data) * 8 > capacity:
|
||
return None, f"too big: need {len(data)*8} bits, image holds {capacity}"
|
||
if spread == "random":
|
||
import random as _r
|
||
_r.seed(int.from_bytes(hashlib.sha256((password + "auriga").encode()).digest()[:4], "big") if password else int.from_bytes(hashlib.sha256(b"auriga-random-no-pass").digest()[:4], "big"))
|
||
order = list(range(w*h)); _r.shuffle(order)
|
||
else:
|
||
order = list(range(w*h))
|
||
bits_needed = len(data) * 8
|
||
idx = 0
|
||
mask = (1 << bits) - 1
|
||
for pos in order:
|
||
if idx >= bits_needed: break
|
||
x, y = pos % w, pos // w
|
||
r, g, b, a = px[x, y]
|
||
chs = [r, g, b]
|
||
for ch_i in range(3):
|
||
if idx >= bits_needed: break
|
||
chunk = 0
|
||
taken = 0
|
||
for k in range(bits):
|
||
if idx >= bits_needed: break
|
||
chunk = (chunk << 1) | ((data[idx >> 3] >> (7 - (idx & 7))) & 1)
|
||
idx += 1; taken += 1
|
||
if taken < bits: chunk <<= (bits - taken)
|
||
chs[ch_i] = (chs[ch_i] & ~mask) | chunk
|
||
px[x, y] = tuple(chs) + (a,)
|
||
# also stash settings in a tEXt chunk for reliable extraction hints
|
||
out = io.BytesIO()
|
||
im.save(out, "PNG", pnginfo=_pnginfo(bits, spread))
|
||
return out.getvalue(), {"bits": bits, "spread": spread}
|
||
|
||
def _pnginfo(bits, spread):
|
||
try:
|
||
from PIL.PngImagePlugin import PngInfo
|
||
info = PngInfo()
|
||
info.add_text("auriga_meta", json.dumps({"bits": bits, "spread": spread, "v": 2}))
|
||
return info
|
||
except Exception:
|
||
return None
|
||
|
||
def steg_extract(img_bytes, password="", bits=None, spread=None):
|
||
from PIL import Image
|
||
im = Image.open(io.BytesIO(img_bytes))
|
||
meta = im.info.get("auriga_meta")
|
||
if meta:
|
||
try:
|
||
m = json.loads(meta)
|
||
bits = int(m.get("bits", bits or 1)); spread = m.get("spread", spread or "sequential")
|
||
except Exception: pass
|
||
bits = bits or 1
|
||
im = im.convert("RGBA")
|
||
px = im.load()
|
||
w, h = im.size
|
||
mask = (1 << bits) - 1
|
||
# replicate the shuffle used at hide time
|
||
if spread == "random":
|
||
import random as _r
|
||
_r.seed(int.from_bytes(hashlib.sha256((password + "auriga").encode()).digest()[:4], "big") if password else int.from_bytes(hashlib.sha256(b"auriga-random-no-pass").digest()[:4], "big"))
|
||
order = list(range(w*h)); _r.shuffle(order)
|
||
else:
|
||
order = list(range(w*h))
|
||
raw = bytearray()
|
||
need = None
|
||
idx = 0
|
||
for pos in order:
|
||
if need is not None and idx >= need: break
|
||
x, y = pos % w, pos // w
|
||
r, g, b, a = px[x, y]
|
||
for ch in (r, g, b):
|
||
chunk = ch & mask
|
||
for k in range(bits-1, -1, -1):
|
||
if need is not None and idx >= need: break
|
||
bit = (chunk >> k) & 1
|
||
while len(raw) < (idx >> 3) + 1: raw.append(0)
|
||
if bit: raw[idx >> 3] |= (0x80 >> (idx & 7))
|
||
idx += 1
|
||
if need is not None and idx >= need: break
|
||
if need is None and idx >= 64:
|
||
if bytes(raw[:4]) != b"AUR1":
|
||
return None, f"no AURIGA payload found with LSB depth {bits} (try other depth / randomized)"
|
||
ln = struct.unpack(">I", bytes(raw[4:8]))[0]
|
||
need = 64 + ln * 8
|
||
data = bytes(raw)
|
||
if len(data) < 12: return None, "payload too small"
|
||
if bytes(data[:4]) != b"AUR1":
|
||
return None, "no AURIGA payload found (wrong password or settings?)"
|
||
if password and hashlib.sha256(password.encode()).digest()[:4] != data[8:12]:
|
||
return None, "wrong password"
|
||
ln = struct.unpack(">I", data[4:8])[0]
|
||
body = data[12:12+ln]
|
||
if password:
|
||
body = bytes(a ^ b for a, b in zip(body, _keystream(password, len(body))))
|
||
text = body.decode("utf-8", "replace")
|
||
return text, None
|
||
|
||
@app.route("/steg", methods=["GET"])
|
||
def steg():
|
||
body = f"""
|
||
<h1>STEGO <span>LAB</span></h1><p class=sub>Hide words inside pictures — LSB steganography with real settings. PNG in, PNG out, looks untouched.</p>
|
||
<div class="grid2">
|
||
<div class=card><b>Hide text</b>
|
||
<form action=/api/steg/hide method=post enctype=multipart/form-data target=stegout>
|
||
<div class=drop onclick="document.getElementById('ih').click()">📤 drop a PNG here or click<input id=ih type=file name=image accept="image/png" style=display:none required></div>
|
||
<div class=fnh style=color:var(--dim);font-size:.85rem></div>
|
||
<textarea name=text rows=3 style="width:100%;margin:.6rem 0" placeholder="the words to hide"></textarea>
|
||
<input name=password placeholder="password (optional)" style="width:100%">
|
||
<div style=margin:.6rem 0>
|
||
<label>LSB depth</label> <select name=bits><option>1</option><option>2</option><option>3</option></select>
|
||
<label style=margin-left:.8rem>Spread</label> <select name=spread><option value=sequential>sequential</option><option value=random>randomized</option></select>
|
||
</div>
|
||
<button>Hide & download</button></form></div>
|
||
<div class=card><b>Extract text</b>
|
||
<form action=/api/steg/extract method=post enctype=multipart/form-data target=stegout>
|
||
<div class=drop onclick="document.getElementById('ie').click()">📥 drop the carrier PNG<input id=ie type=file name=image accept="image/png" style=display:none required></div>
|
||
<div class=fne style=color:var(--dim);font-size:.85rem></div>
|
||
<input name=password placeholder="password if used" style="width:100%;margin:.6rem 0">
|
||
<div style=margin:.6rem 0><label>LSB depth</label> <select name=bits><option value="">auto (reads metadata)</option><option>1</option><option>2</option><option>3</option></select>
|
||
<label style=margin-left:.8rem>Spread</label> <select name=spread><option value="">auto</option><option value=sequential>sequential</option><option value=random>randomized</option></select></div>
|
||
<button>Extract</button></form></div>
|
||
</div>
|
||
<script>
|
||
document.querySelectorAll('.drop').forEach(function(d){{
|
||
d.addEventListener('dragover',function(e){{e.preventDefault();d.classList.add('over')}});
|
||
d.addEventListener('dragleave',function(){{d.classList.remove('over')}});
|
||
d.addEventListener('drop',function(e){{e.preventDefault();d.classList.remove('over');
|
||
var inp=d.querySelector('input[type=file]');if(e.dataTransfer.files.length){{inp.files=e.dataTransfer.files;
|
||
var fn=d.parentElement.querySelector('.fnh, .fne');if(fn)fn.textContent=e.dataTransfer.files[0].name}}}});
|
||
d.addEventListener('change',function(){{}});
|
||
}});
|
||
document.getElementById('ih').addEventListener('change',function(){{document.querySelector('.fnh').textContent=this.files[0].name}});
|
||
document.getElementById('ie').addEventListener('change',function(){{document.querySelector('.fne').textContent=this.files[0].name}});
|
||
</script>
|
||
<div class=card style=color:var(--dim)>API: POST /api/steg/hide (image, text, password?, bits 1-3, spread) → PNG · POST /api/steg/extract (image, password?, bits?, spread?) → JSON</div>"""
|
||
return page("steg", body)
|
||
|
||
@app.route("/api/steg/hide", methods=["POST"])
|
||
def api_steg_hide():
|
||
f = request.files.get("image")
|
||
text = param("text") or ""
|
||
if not f or not text: return jsonify({"ok": False, "error": "image + text required"}), 400
|
||
bits = min(3, max(1, int(param("bits") or 1)))
|
||
spread = param("spread") or "sequential"
|
||
try:
|
||
out, meta = steg_hide(f.read(), text, param("password") or "", bits, spread)
|
||
except Exception as e:
|
||
return jsonify({"ok": False, "error": str(e)}), 400
|
||
if out is None: return jsonify({"ok": False, "error": meta}), 400
|
||
return send_file(io.BytesIO(out), mimetype="image/png", as_attachment=True, download_name="auriga-hidden.png")
|
||
|
||
@app.route("/api/steg/extract", methods=["POST"])
|
||
def api_steg_extract():
|
||
f = request.files.get("image")
|
||
if not f: return jsonify({"ok": False, "error": "image required"}), 400
|
||
bits = param("bits")
|
||
bits = min(3, max(1, int(bits))) if bits else None
|
||
try:
|
||
text, err = steg_extract(f.read(), param("password") or "", bits, param("spread") or None)
|
||
except Exception as e:
|
||
return jsonify({"ok": False, "error": str(e)}), 400
|
||
if err: return jsonify({"ok": False, "error": err}), 200
|
||
return jsonify({"ok": True, "text": text})
|
||
|
||
# ---------- 6. TRACKABLE FILES ----------
|
||
@app.route("/track", methods=["GET"])
|
||
def track():
|
||
uid = current_user_id()
|
||
mine = ""
|
||
if uid:
|
||
con = db()
|
||
rows = con.execute("SELECT * FROM trackables WHERE user_id=? ORDER BY id DESC LIMIT 10", (uid,)).fetchall()
|
||
if rows:
|
||
trs = "".join(f"<tr><td>{esc(t['filename'])}</td><td>{'<a href=/api/track/events?token='+t['token']+'>events</a>' if t['paid'] else '—'}</td><td>{'paid ✓' if t['paid'] else 'unpaid'}</td></tr>" for t in rows)
|
||
mine = f'<div class=card><b>Your trackables</b><table><tr><th>File</th><th>Events</th><th>Status</th></tr>{trs}</table></div>'
|
||
body = f"""
|
||
<h1>TRACK <span>FILE</span></h1><p class=sub>Pay $1 BTC → upload a file or picture → get a tracked link + an email-ready version. Every open pings back into your INBOX.</p>
|
||
<div class=card>
|
||
<b>1 · Pay $1</b><form action=/api/track/create method=post>
|
||
<input name=filename placeholder="file name e.g. flyer.jpg" style="width:70%" required> <button>Create invoice</button></form>
|
||
<div style=color:var(--dim);font-size:.85rem;margin-top:.4rem>BTCPay BTC only. After payment the upload opens automatically.</div></div>
|
||
{mine}
|
||
<div class=card style=color:var(--dim)>How it works: your file gets a secret link — every open is logged (time, IP, device) and lands in your inbox. You also get an HTML copy with an embedded tracking pixel: email THAT and every view fires too. <a href=/inbox>Login (no KYC)</a> to see events.</div>
|
||
<div class=card style=color:var(--dim)>API: POST /api/track/create (filename) → invoice · POST /api/track/upload?token= (file) → link · GET /api/track/events?token=</div>"""
|
||
return page("track", body)
|
||
|
||
def btc_invoice(amount="1.00"):
|
||
st, b = http(f"{BTCPAY}/stores/{BTCPAY_STORE}/invoices",
|
||
headers={"Authorization": "token " + BTCPAY_KEY, "Content-Type": "application/json"},
|
||
data=json.dumps({"amount": amount, "currency": "USD", "metadata": {"orderId": "auriga-track"}}).encode(), method="POST")
|
||
return jf(b) or {}
|
||
|
||
@app.route("/api/track/create", methods=["POST"])
|
||
def api_track_create():
|
||
fn = param("filename") or "file"
|
||
uid = current_user_id()
|
||
token = secrets.token_urlsafe(16)
|
||
con = db()
|
||
if has_pass(uid):
|
||
con.execute("INSERT INTO trackables(user_id,token,filename,kind,invoice_id,paid,created) VALUES(?,?,?,?,?,1,?)",
|
||
(uid or 0, token, esc(fn[:100]), "file", "PASS", int(time.time())))
|
||
con.commit()
|
||
return jsonify({"ok": True, "free": True, "token": token, "upload_url": f"{SITE}/track/pay?token={token}"})
|
||
inv = btc_invoice()
|
||
if not inv.get("id"): return jsonify({"ok": False, "error": str(inv)[:200]}), 400
|
||
con.execute("INSERT INTO trackables(user_id,token,filename,kind,invoice_id,paid,created) VALUES(?,?,?,?,?,0,?)",
|
||
(uid or 0, token, esc(fn[:100]), "file", inv["id"], int(time.time())))
|
||
con.commit()
|
||
return jsonify({"ok": True, "invoice_id": inv["id"], "checkoutLink": inv.get("checkoutLink"), "token": token,
|
||
"after_payment_upload_url": f"{SITE}/track/pay?token={token}"})
|
||
|
||
@app.route("/track/pay", methods=["GET"])
|
||
def track_pay():
|
||
token = param("token") or ""
|
||
con = db()
|
||
t = con.execute("SELECT * FROM trackables WHERE token=?", (token,)).fetchone()
|
||
if not t: return page("track", "<h1>TRACK <span>FILE</span></h1><div class=card><span class=tag bad>unknown token</span></div>")
|
||
return page("track", f"""
|
||
<h1>TRACK <span>FILE</span></h1><p class=sub>Upload your file — then it's trackable.</p>
|
||
<div class=card><form action=/api/track/upload?token={esc(token)} method=post enctype=multipart/form-data>
|
||
<div class=drop onclick="document.getElementById('tf').click()">📤 drop file / picture here<input id=tf type=file name=file style=display:none required></div>
|
||
<div id=tfname style=color:var(--dim);font-size:.85rem;margin:.4rem 0></div>
|
||
<button>Upload & make trackable</button></form></div>
|
||
<script>document.getElementById('tf').addEventListener('change',function(){{document.getElementById('tfname').textContent=this.files[0].name}})</script>""")
|
||
|
||
@app.route("/api/track/upload", methods=["POST"])
|
||
def api_track_upload():
|
||
token = param("token")
|
||
f = request.files.get("file")
|
||
if not f: return jsonify({"ok": False, "error": "file required"}), 400
|
||
con = db()
|
||
t = con.execute("SELECT * FROM trackables WHERE token=?", (token,)).fetchone()
|
||
if not t: return jsonify({"ok": False, "error": "unknown token"}), 400
|
||
st, b = http(f"{BTCPAY}/stores/{BTCPAY_STORE}/invoices/{t['invoice_id']}", headers={"Authorization": "token " + BTCPAY_KEY}) if t["invoice_id"] != "PASS" else (200, '{"status":"settled"}')
|
||
inv = jf(b) or {}
|
||
paid = inv.get("status") in ("settled", "processing", "paid")
|
||
if not paid: return jsonify({"ok": False, "error": f"invoice not paid yet ({inv.get('status')})"}), 402
|
||
data = f.read()
|
||
open(os.path.join(UPLOAD_DIR, token + ".bin"), "wb").write(data)
|
||
kind = "image" if (f.content_type or "").startswith("image") else "file"
|
||
fn = (f.filename or t["filename"])[:100]
|
||
con.execute("UPDATE trackables SET paid=1, kind=?, filename=? WHERE token=?", (kind, fn, token))
|
||
con.commit()
|
||
b64 = base64.b64encode(data).decode()
|
||
pixel = f"{SITE}/t/{token}.png"
|
||
if kind == "image":
|
||
viewer = f'<!doctype html><meta charset=utf-8><body style="margin:0;background:#111;text-align:center"><img src="data:image;base64,{b64}" style="max-width:100%"><img src="{pixel}" width=1 height=1></body>'
|
||
else:
|
||
viewer = f'<!doctype html><meta charset=utf-8><body style="background:#111;color:#eee;font-family:monospace;padding:2rem"><p>📎 {esc(fn)} ({len(data)} bytes)</p><p><a href="{SITE}/t/{token}" style="color:#f0b429">Open / download the file</a></p><img src="{pixel}" width=1 height=1></body>'
|
||
open(os.path.join(UPLOAD_DIR, token + ".html"), "w").write(viewer)
|
||
con.execute("INSERT INTO track_events(trackable_id,ts,ip,ua) VALUES(?,?,?,?)", (t["id"], int(time.time()), "created", "upload"))
|
||
con.commit()
|
||
return jsonify({"ok": True, "tracked_link": f"{SITE}/t/{token}", "pixel": pixel,
|
||
"email_html": f"{SITE}/t/{token}/html",
|
||
"note": "attach/email the HTML version — every view fires the pixel and lands in the inbox"})
|
||
|
||
@app.route("/t/<token>")
|
||
def tracked_download(token):
|
||
con = db()
|
||
t = con.execute("SELECT * FROM trackables WHERE token=?", (token,)).fetchone()
|
||
if not t or not t["paid"]: return "not found", 404
|
||
con.execute("INSERT INTO track_events(trackable_id,ts,ip,ua) VALUES(?,?,?,?)",
|
||
(t["id"], int(time.time()), request.headers.get("X-Real-IP") or request.remote_addr, request.headers.get("User-Agent","")))
|
||
uid = t["user_id"]
|
||
if uid:
|
||
con.execute("INSERT INTO messages(user_id,sender,body,created) VALUES(?,?,?,?)",
|
||
(uid, "operator-bot", f"👁 your tracked file '{esc(t['filename'])}' was just opened — IP {esc(request.headers.get('X-Real-IP') or request.remote_addr)}, device: {esc(request.headers.get('User-Agent','')[:80])}", int(time.time())))
|
||
con.commit()
|
||
path = os.path.join(UPLOAD_DIR, token + ".bin")
|
||
if not os.path.exists(path): return "file gone", 404
|
||
return send_file(path, as_attachment=True, download_name=t["filename"])
|
||
|
||
@app.route("/t/<token>.png")
|
||
def tracked_pixel(token):
|
||
con = db()
|
||
t = con.execute("SELECT * FROM trackables WHERE token=?", (token,)).fetchone()
|
||
if t and t["paid"]:
|
||
con.execute("INSERT INTO track_events(trackable_id,ts,ip,ua) VALUES(?,?,?,?)",
|
||
(t["id"], int(time.time()), request.headers.get("X-Real-IP") or request.remote_addr, request.headers.get("User-Agent","")))
|
||
uid = t["user_id"]
|
||
if uid:
|
||
con.execute("INSERT INTO messages(user_id,sender,body,created) VALUES(?,?,?,?)",
|
||
(uid, "operator-bot", f"👁 '{esc(t['filename'])}' was just viewed (email/pixel) — IP {esc(request.headers.get('X-Real-IP') or request.remote_addr)}", int(time.time())))
|
||
con.commit()
|
||
px = base64.b64decode("R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")
|
||
return Response(px, mimetype="image/gif", headers={"Cache-Control": "no-store"})
|
||
|
||
@app.route("/t/<token>/html")
|
||
def tracked_html(token):
|
||
con = db()
|
||
t = con.execute("SELECT * FROM trackables WHERE token=?", (token,)).fetchone()
|
||
if not t or not t["paid"]: return "not found", 404
|
||
p = os.path.join(UPLOAD_DIR, token + ".html")
|
||
return send_file(p, mimetype="text/html") if os.path.exists(p) else ("no html wrapper", 404)
|
||
|
||
@app.route("/api/track/events", methods=["GET"])
|
||
def api_track_events():
|
||
con = db(); token = param("token")
|
||
t = con.execute("SELECT * FROM trackables WHERE token=?", (token,)).fetchone()
|
||
if not t: return jsonify({"ok": False, "error": "unknown token"})
|
||
uid = current_user_id()
|
||
if not uid or uid != t["user_id"]: return jsonify({"ok": False, "error": "auth required (login on /inbox)"})
|
||
return jsonify([dict(r) for r in con.execute("SELECT * FROM track_events WHERE trackable_id=? ORDER BY id DESC LIMIT 100", (t["id"],))])
|
||
|
||
# ---------- 6b. BURNER MAIL (receive-only, BTC packages) ----------
|
||
MAIL_PACKS = [("7","7 days — $3",3,7),("30","30 days — $8",8,30),("90","90 days — $20",20,90)]
|
||
MAIL_DOMAIN = "thetempleofdoom.com"
|
||
MAIL_RESERVED = {"indianaholmes","admin","operator","drjones","root","noreply","support","pass","mail"}
|
||
MAIL_SECRET = "auriga-mail-relay-2026"
|
||
|
||
@app.route("/mail", methods=["GET"])
|
||
def mail():
|
||
uid = current_user_id()
|
||
mine = ""
|
||
if uid:
|
||
con = db(); now = int(time.time())
|
||
con.execute("UPDATE mailboxes SET paid=2 WHERE paid=1 AND expires < ?", (now,)) # expired
|
||
rows = con.execute("SELECT * FROM mailboxes WHERE user_id=? ORDER BY id DESC LIMIT 10", (uid,)).fetchall()
|
||
if rows:
|
||
trs = "".join(f"<tr><td>{esc(m['address'])} <a href=# onclick=\"cp('{esc(m['address'])}');return false\" style=color:var(--acc)>copy</a></td><td><a href=/mail/view?addr={esc(m['address'])}>view mail</a></td><td class=mcd data-exp={m['expires']}>…</td><td>{'live' if m['paid']==1 else 'expired'}</td><td>{m['cnt']}</td></tr>" for m in rows)
|
||
mine = f'<div class=card><b>Your mailboxes</b><table><tr><th>Address</th><th></th><th>Expires</th><th>Status</th><th>Mail</th></tr>{trs}</table></div>'
|
||
body = f"""
|
||
<h1>BURNER <span>MAIL</span></h1><p class=sub>Receive-only disposable mailboxes @thetempleofdoom.com. Counting down in real time. Anything you sign up for — codes, confirmations, one-off handouts — lands right here, no other identity attached.</p>
|
||
<div class=card>
|
||
<b>Pick a package (BTC)</b>
|
||
{''.join(f'<form action=/api/mail/create method=post style=display:inline;margin:0 0.5rem><input type=hidden name=days value={d}><input name=local placeholder="mailbox name" required style=width:140px><button>{n}</button></form>' for d,n,_,_ in MAIL_PACKS)}
|
||
<div style=color:var(--dim);font-size:.85rem;margin-top:.6rem>Type your desired mailbox name, pick a length, pay the invoice — the mailbox activates the moment the payment settles.</div></div>
|
||
{mine}
|
||
<div class=card style=color:var(--dim)>API: POST /api/mail/create (local, days) → invoice · GET /api/mail/inbox?addr= (needs login) — inbound via Cloudflare Email Routing → worker relay.</div>"""
|
||
return page("steg", body)
|
||
|
||
@app.route("/api/mail/create", methods=["POST"])
|
||
def api_mail_create():
|
||
uid = current_user_id()
|
||
local = re.sub(r"[^a-z0-9._-]", "", (param("local") or "").lower())[:30]
|
||
days = param("days") or "7"
|
||
pack = next((p for p in MAIL_PACKS if p[0] == str(days)), None)
|
||
if not pack: return jsonify({"ok": False, "error": "bad package"}), 400
|
||
if not local: return jsonify({"ok": False, "error": "mailbox name required"}), 400
|
||
if local in MAIL_RESERVED: return jsonify({"ok": False, "error": "reserved name"}), 400
|
||
addr = f"{local}@{MAIL_DOMAIN}"
|
||
con = db()
|
||
if con.execute("SELECT 1 FROM mailboxes WHERE address=?", (addr,)).fetchone():
|
||
return jsonify({"ok": False, "error": "mailbox name taken"}), 400
|
||
inv = btc_invoice(f"{pack[2]:.2f}")
|
||
if not inv.get("id"): return jsonify({"ok": False, "error": str(inv)[:200]}), 400
|
||
con.execute("INSERT INTO mailboxes(user_id,address,invoice_id,paid,expires,created,plan_days) VALUES(?,?,?,?,?,?,?)",
|
||
(uid or 0, addr, inv["id"], 0, 0, int(time.time()), pack[3]))
|
||
con.commit()
|
||
return jsonify({"ok": True, "address": addr, "checkoutLink": inv.get("checkoutLink"), "invoice_id": inv["id"]})
|
||
|
||
@app.route("/api/mail/inbound", methods=["POST"])
|
||
def api_mail_inbound():
|
||
d = request.get_json(silent=True) or {}
|
||
if d.get("secret") != MAIL_SECRET: return jsonify({"ok": False}), 403
|
||
addr = (d.get("mailbox") or "").lower().split("@")[0]
|
||
con = db()
|
||
m = con.execute("SELECT * FROM mailboxes WHERE address LIKE ? AND paid=1", (addr + "@%",)).fetchone()
|
||
if not m: return jsonify({"ok": False, "error": "unknown/expired mailbox"}), 404
|
||
con.execute("INSERT INTO mails(mailbox_id,sender,subject,body,ts) VALUES(?,?,?,?,?)",
|
||
(m["id"], esc(d.get("from") or "?"), esc(d.get("subject") or ""), esc(d.get("body") or ""), int(time.time())))
|
||
con.execute("UPDATE mailboxes SET cnt=cnt+1 WHERE id=?", (m["id"],))
|
||
con.commit()
|
||
return jsonify({"ok": True})
|
||
|
||
@app.route("/mail/view")
|
||
def mail_view():
|
||
uid = current_user_id()
|
||
if not uid: return page("inbox", "<div class=card>login required</div>")
|
||
addr = param("addr") or ""
|
||
con = db()
|
||
m = con.execute("SELECT * FROM mailboxes WHERE address=? AND user_id=?", (addr.lower(), uid)).fetchone()
|
||
if not m: return page("inbox", "<div class=card>not your mailbox</div>")
|
||
mails = con.execute("SELECT * FROM mails WHERE mailbox_id=? ORDER BY id DESC LIMIT 100", (m["id"],)).fetchall()
|
||
rows = "".join(f'<div class=msg><div class=who>{esc(x["sender"])} · {time.strftime("%b %d %H:%M", time.localtime(x["ts"]))}</div><b>{esc(x["subject"])}</b><br>{esc(x["body"])}</div>' for x in mails) or '<div style=color:var(--dim)>empty — waiting for mail…</div>'
|
||
left = max(0, m["expires"] - int(time.time()))
|
||
return page("steg", f"""
|
||
<h1>{esc(m['address'])}</h1><p class=sub><span id=cd style=color:var(--acc)></span> remaining — auto-refreshes every 15s.</p>
|
||
<div class=card>{rows}</div>
|
||
<script>
|
||
function tick(){{var s={left}-Math.floor((Date.now()-loaded)/1000);s=Math.max(0,s);var d=Math.floor(s/86400);document.getElementById('cd').textContent=d+'d '+Math.floor((s%86400)/3600)+'h '+Math.floor((s%3600)/60)+'m';}}
|
||
var loaded=Date.now();tick();setInterval(tick,1000);setInterval(function(){{location.reload()}},15000);
|
||
</script>""")
|
||
|
||
@app.route("/api/mail/inbox")
|
||
def api_mail_inbox():
|
||
uid = current_user_id()
|
||
if not uid: return jsonify({"ok": False, "error": "login required (POST /inbox act=login)"})
|
||
con = db(); addr = (param("addr") or "").lower()
|
||
m = con.execute("SELECT * FROM mailboxes WHERE address=? AND user_id=?", (addr, uid)).fetchone()
|
||
if not m: return jsonify({"ok": False, "error": "unknown mailbox"})
|
||
return jsonify([dict(r) for r in con.execute("SELECT sender,subject,body,ts FROM mails WHERE mailbox_id=? ORDER BY id DESC LIMIT 100", (m["id"],))])
|
||
|
||
# ---------- 6c. PASS — all-tools subscription ----------
|
||
PASS_PACKS = [("30","1 month — $10 BTC",10,30),("90","3 months — $25 (save 17%)",25,90),("365","1 year — $80 (save 33%)",80,365)]
|
||
|
||
def has_pass(uid):
|
||
if not uid: return False
|
||
con = db()
|
||
r = con.execute("SELECT 1 FROM passes WHERE user_id=? AND expires > ? AND paid=1", (uid, int(time.time()))).fetchone()
|
||
return bool(r)
|
||
|
||
@app.route("/pass", methods=["GET"])
|
||
def pass_page():
|
||
uid = current_user_id()
|
||
mine = ""
|
||
if uid:
|
||
con = db()
|
||
r = con.execute("SELECT * FROM passes WHERE user_id=? AND paid=1 ORDER BY expires DESC LIMIT 1", (uid,)).fetchone()
|
||
if r and r["expires"] > int(time.time()):
|
||
left = r["expires"] - int(time.time())
|
||
mine = f'<div class="card glow"><span class="tag ok">PASS ACTIVE</span> {left//86400} days {left%86400//3600}h left — all tools unlimited (proxy rentals still metered at the storefront), trackables free, burner mail discounts.</div>'
|
||
body = f"""
|
||
<h1>PASS <span>— ALL ACCESS</span></h1><p class=sub>One BTC payment. Near-unlimited everything on this site: unlimited SMS rentals (house caps still apply for sanity), free trackables, burner mail included, no per-tool payments.</p>
|
||
<div class=card>
|
||
{''.join(f'<form action=/api/pass/create method=post style=display:inline;margin:0 .4rem><input type=hidden name=days value={d}><button class=ghost>{n}</button></form>' for d,n,_,_ in PASS_PACKS)}
|
||
<div style=color:var(--dim);font-size:.85rem;margin-top:.6rem>Proxy rentals stay separate (they burn real upstream bandwidth — buy those at the storefront).</div></div>
|
||
{mine}
|
||
<div class=card style=color:var(--dim)>API: POST /api/pass/create (days=30|90|365) → invoice. Pass activates on payment settle via webhook.</div>"""
|
||
return page("sms", body)
|
||
|
||
@app.route("/api/pass/create", methods=["POST"])
|
||
def api_pass_create():
|
||
uid = current_user_id()
|
||
if not uid: return jsonify({"ok": False, "error": "login first (POST /inbox act=login)"}), 401
|
||
days = param("days") or "30"
|
||
pack = next((p for p in PASS_PACKS if p[0] == str(days)), None)
|
||
if not pack: return jsonify({"ok": False, "error": "bad package"}), 400
|
||
inv = btc_invoice(f"{pack[2]:.2f}")
|
||
if not inv.get("id"): return jsonify({"ok": False, "error": str(inv)[:200]}), 400
|
||
con = db()
|
||
con.execute("INSERT INTO passes(user_id,invoice_id,paid,expires,plan_days) VALUES(?,?,0,0,?)", (uid, inv["id"], pack[3]))
|
||
con.commit()
|
||
return jsonify({"ok": True, "checkoutLink": inv.get("checkoutLink"), "invoice_id": inv["id"]})
|
||
|
||
@app.route("/api/btcpay/webhook", methods=["POST"])
|
||
def btcpay_webhook():
|
||
sig = request.headers.get("BTCPay-Sig", "")
|
||
body = request.get_data()
|
||
expect = "sha256=" + hmac.new(BTCPAY_WHSEC.encode(), body, hashlib.sha256).hexdigest()
|
||
if sig != expect: return jsonify({"ok": False, "error": "bad sig"}), 400
|
||
d = jf(body) or {}
|
||
if d.get("type") == "InvoiceSettled" or (d.get("type") == "InvoicePaymentSettled"):
|
||
iid = d.get("invoiceId")
|
||
con = db()
|
||
con.execute("UPDATE trackables SET paid=1 WHERE invoice_id=?", (iid,))
|
||
r = con.execute("SELECT plan_days FROM mailboxes WHERE invoice_id=?", (iid,)).fetchone()
|
||
if r:
|
||
con.execute("UPDATE mailboxes SET paid=1, expires=? WHERE invoice_id=?", (int(time.time()) + 86400*int(r["plan_days"] or 7), iid))
|
||
r = con.execute("SELECT plan_days FROM passes WHERE invoice_id=?", (iid,)).fetchone()
|
||
if r:
|
||
con.execute("UPDATE passes SET paid=1, expires=? WHERE invoice_id=?", (int(time.time()) + 86400*int(r["plan_days"] or 30), iid))
|
||
con.commit()
|
||
return jsonify({"ok": True})
|
||
|
||
# ---------- 7. INBOX (no-KYC site-only messaging) ----------
|
||
def hash_pw(pw): return hashlib.scrypt(pw.encode(), salt=b"auriga-salt", n=16384, r=8, p=1).hex()
|
||
|
||
def current_user_id():
|
||
tok = request.cookies.get("auriga_tok")
|
||
if not tok: return None
|
||
con = db()
|
||
s = con.execute("SELECT user_id FROM sessions WHERE token=?", (tok,)).fetchone()
|
||
return s["user_id"] if s else None
|
||
|
||
@app.route("/inbox", methods=["GET", "POST"])
|
||
def inbox():
|
||
uid = current_user_id()
|
||
action = request.form.get("act") if request.method == "POST" else None
|
||
con = db()
|
||
if action == "register":
|
||
u, p = (request.form.get("u") or "").strip()[:32], request.form.get("p") or ""
|
||
if not u or len(p) < 4:
|
||
return page("inbox", "<h1>INBOX</h1><div class=card><span class=tag bad>username + password (4+ chars) required</span></div>")
|
||
try:
|
||
con.execute("INSERT INTO users(username,passhash,created) VALUES(?,?,?)", (u, hash_pw(p), int(time.time())))
|
||
con.commit()
|
||
except sqlite3.IntegrityError:
|
||
return page("inbox", "<h1>INBOX</h1><div class=card><span class=tag bad>name taken</span></div>")
|
||
tok = secrets.token_urlsafe(24)
|
||
con.execute("INSERT INTO sessions(token,user_id,created) VALUES(?,?,?)", (tok, con.execute("SELECT id FROM users WHERE username=?", (u,)).fetchone()["id"], int(time.time())))
|
||
con.commit()
|
||
resp = Response(status=302); resp.headers["Location"] = "/inbox"; resp.set_cookie("auriga_tok", tok, max_age=86400*30, httponly=True)
|
||
return resp
|
||
elif action == "login":
|
||
u, p = (request.form.get("u") or "").strip()[:32], request.form.get("p") or ""
|
||
r = con.execute("SELECT * FROM users WHERE username=?", (u,)).fetchone()
|
||
if r and r["passhash"] == hash_pw(p):
|
||
tok = secrets.token_urlsafe(24)
|
||
con.execute("INSERT INTO sessions(token,user_id,created) VALUES(?,?,?)", (tok, r["id"], int(time.time())))
|
||
con.commit()
|
||
resp = Response(status=302); resp.headers["Location"] = "/inbox"; resp.set_cookie("auriga_tok", tok, max_age=86400*30, httponly=True)
|
||
return resp
|
||
return page("inbox", "<h1>INBOX</h1><div class=card><span class=tag bad>bad login</span></div>")
|
||
elif action == "logout":
|
||
con.execute("DELETE FROM sessions WHERE token=?", (request.cookies.get("auriga_tok"),)); con.commit()
|
||
resp = Response(status=302); resp.headers["Location"] = "/inbox"; resp.set_cookie("auriga_tok", "", max_age=0)
|
||
return resp
|
||
elif action == "send" and uid:
|
||
body = (request.form.get("body") or "").strip()[:4000]
|
||
if body:
|
||
con.execute("INSERT INTO messages(user_id,sender,body,created) VALUES(?,?,?,?)", (uid, "user", esc(body), int(time.time())))
|
||
con.commit()
|
||
if not uid:
|
||
return page("inbox", f"""
|
||
<h1>INBOX <span>— no KYC</span></h1><p class=sub>Just a name + password. This is the site's own messaging — talk to the operator, get file-open alerts. Nothing leaves the site.</p>
|
||
<div class="grid2">
|
||
<div class=card><b>Login</b><form method=post><input type=hidden name=act value=login><input name=u placeholder=username style=width:100%><input name=p type=password placeholder=password style="width:100%;margin:.5rem 0"><button>Login</button></form></div>
|
||
<div class=card><b>Create account</b><form method=post><input type=hidden name=act value=register><input name=u placeholder=username style=width:100%><input name=p type=password placeholder="password (4+ chars)" style="width:100%;margin:.5rem 0"><button class=ghost>Create</button></form></div>
|
||
</div>""")
|
||
msgs = con.execute("SELECT * FROM messages WHERE user_id=? ORDER BY id DESC LIMIT 50", (uid,)).fetchall()
|
||
msgs_html = "".join(f'<div class="msg {"me" if m["sender"]=="user" else ""}"><div class=who>{"you" if m["sender"]=="user" else esc(m["sender"])} · {time.strftime("%b %d %H:%M", time.localtime(m["created"]))}</div>{m["body"]}</div>' for m in reversed(msgs)) or '<div style=color:var(--dim)>no messages yet — say hi.</div>'
|
||
files = con.execute("SELECT * FROM trackables WHERE user_id=? ORDER BY id DESC LIMIT 10", (uid,)).fetchall()
|
||
files_html = "".join(f"<tr><td>{esc(f['filename'])}</td><td>{'<a href=/api/track/events?token='+f['token']+'>events</a>' if f['paid'] else '—'}</td><td>{'paid ✓' if f['paid'] else 'unpaid'}</td><td>{time.strftime('%b %d', time.localtime(f['created']))}</td></tr>" for f in files)
|
||
body = f"""
|
||
<h1>INBOX</h1><p class=sub>Site-internal messaging with the operator + your file-open alerts.</p>
|
||
<div class=card><form method=post><input type=hidden name=act value=send>
|
||
<textarea name=body rows=3 style="width:100%" placeholder="message to the operator…"></textarea>
|
||
<button style=margin-top:.5rem>Send</button></form></div>
|
||
<div class=card><b>Conversation</b>{msgs_html}</div>
|
||
<div class=card><b>Your tracked files</b><table><tr><th>File</th><th>Events</th><th>Status</th><th>Created</th></tr>{files_html or '<tr><td colspan=4 style=color:var(--dim)>none yet</td></tr>'}</table></div>
|
||
<div class=card style="text-align:right"><form method=post><input type=hidden name=act value=logout><button class=ghost>Log out</button></form></div>
|
||
<div class=card style=color:var(--dim)>API: (cookie auth) POST /inbox act=send body=… · GET /api/inbox/messages</div>"""
|
||
return page("inbox", body)
|
||
|
||
@app.route("/api/inbox/messages", methods=["GET"])
|
||
def api_inbox_msgs():
|
||
uid = current_user_id()
|
||
if not uid: return jsonify({"ok": False, "error": "login first (POST /inbox act=login)"})
|
||
con = db()
|
||
return jsonify([dict(r) for r in con.execute("SELECT * FROM messages WHERE user_id=? ORDER BY id DESC LIMIT 100", (uid,))])
|
||
|
||
# ---------- 8. FREE TOOLS ----------
|
||
TOOLS_JS = """
|
||
function tab(n){document.querySelectorAll('.pane').forEach(p=>p.style.display='none');document.getElementById(n).style.display='block'}
|
||
async function dns(){const d=document.getElementById('dq').value;const o=await (await fetch('https://dns.google/resolve?name='+encodeURIComponent(d)+'&type=A')).json();document.getElementById('do').textContent=JSON.stringify(o,null,1)}
|
||
async function hdr(){const u=document.getElementById('hq').value;const r=await (await fetch('/api/hdr?url='+encodeURIComponent(u))).json();document.getElementById('ho').textContent=JSON.stringify(r,null,1)}
|
||
function jwt(){try{const t=document.getElementById('jq').value.trim().split('.');const d=s=>JSON.stringify(JSON.parse(atob(s.replace(/-/g,'+').replace(/_/g,'/'))),null,1);document.getElementById('jo').textContent='HEADER\\n'+d(t[0])+'\\n\\nPAYLOAD\\n'+d(t[1])}catch(e){document.getElementById('jo').textContent='Invalid JWT: '+e}}
|
||
async function genhash2(){const i=document.getElementById('hq2').value;const r=await(await fetch('/api/hash?s='+encodeURIComponent(i))).json();for(const k of ['md5','sha1','sha256','sha512'])document.getElementById('h_'+k).textContent=r[k]}
|
||
function uuids(){let o='';for(let i=0;i<5;i++)o+=crypto.randomUUID()+'\\n';document.getElementById('uo').textContent=o}
|
||
function pwgen(){const l=+document.getElementById('pl').value||24;const cs='abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789!@#$%^&*-_=+';const a=new Uint32Array(l);crypto.getRandomValues(a);document.getElementById('po').textContent=Array.from(a,x=>cs[x%cs.length]).join('')}
|
||
"""
|
||
|
||
@app.route("/api/hdr")
|
||
def api_hdr():
|
||
url = param("url") or ""
|
||
if "://" not in url: url = "http://" + url
|
||
try:
|
||
req = urllib.request.Request(url)
|
||
with urllib.request.urlopen(req, timeout=12) as r:
|
||
return jsonify({"status": r.status, "final_url": r.url, "headers": dict(r.headers)})
|
||
except Exception as e:
|
||
return jsonify({"error": str(e)})
|
||
|
||
@app.route("/api/hash")
|
||
def api_hash():
|
||
s = (param("s") or "").encode()
|
||
return jsonify({"md5": hashlib.md5(s).hexdigest(), "sha1": hashlib.sha1(s).hexdigest(),
|
||
"sha256": hashlib.sha256(s).hexdigest(), "sha512": hashlib.sha512(s).hexdigest()})
|
||
|
||
@app.route("/tools")
|
||
def tools():
|
||
body = f"""
|
||
<h1>FREE <span>TOOLS</span></h1><p class=sub>High-value, zero-cost, no signup. APIs underneath each.</p>
|
||
<style>.tbtn.on{{background:var(--acc);color:#111}}</style>
|
||
<div style=margin-bottom:1rem>
|
||
<button class="tbtn on" onclick="tab('dns_p');this.classList.add('on')">DNS Lookup</button>
|
||
<button class=tbtn onclick="tab('hdr_p');this.classList.add('on')">HTTP Headers</button>
|
||
<button class=tbtn onclick="tab('jwt_p');this.classList.add('on')">JWT Decoder</button>
|
||
<button class=tbtn onclick="tab('hash_p');this.classList.add('on')">Hasher</button>
|
||
<button class=tbtn onclick="tab('gen_p');this.classList.add('on')">Generators</button></div>
|
||
<script>{TOOLS_JS}</script>
|
||
<div id=dns_p class="card pane"><b>DNS Lookup</b> <span style=color:var(--dim)>(Google DoH)</span><br>
|
||
<input id=dq placeholder=thetempleofdoom.com style=width:70%><button onclick=dns()>Resolve</button>
|
||
<pre id=do style=white-space:pre-wrap></pre></div>
|
||
<div id=hdr_p class="card pane" style=display:none><b>HTTP Header Inspector</b><br>
|
||
<input id=hq placeholder=https://lynx.thetempleofdoom.com style=width:70%><button onclick=hdr()>Inspect</button>
|
||
<pre id=ho style=white-space:pre-wrap></pre></div>
|
||
<div id=jwt_p class="card pane" style=display:none><b>JWT Decoder</b> (token never leaves your browser)<br>
|
||
<textarea id=jq rows=3 style="width:100%">paste eyJ…</textarea><button onclick=jwt()>Decode</button>
|
||
<pre id=jo style=white-space:pre-wrap></pre></div>
|
||
<div id=hash_p class="card pane" style=display:none><b>Hasher</b><br>
|
||
<input id=hq2 placeholder="any string" style=width:70%><button onclick=genhash2()>Hash</button>
|
||
<table><tr><th>md5</th><td id=h_md5></td></tr><tr><th>sha1</th><td id=h_sha1></td></tr>
|
||
<tr><th>sha256</th><td id=h_sha256></td></tr><tr><th>sha512</th><td id=h_sha512></td></tr></table></div>
|
||
<div id=gen_p class="card pane" style=display:none><b>Generators</b><br>
|
||
<button onclick=uuids()>5× UUIDv4</button><pre id=uo></pre>
|
||
<label>password length</label> <input id=pl value=24 style=width:80px><button onclick=pwgen()>Generate</button>
|
||
<pre id=po style="font-size:1.2rem;color:var(--acc)"></pre></div>"""
|
||
return page("tools", body)
|
||
|
||
# ---------- 9. OPERATOR CONSOLE ----------
|
||
@app.route("/admin", methods=["GET", "POST"])
|
||
def admin():
|
||
if request.method == "POST" and request.form.get("pw") == ADMIN_PW:
|
||
resp = Response(status=302); resp.headers["Location"] = "/admin"
|
||
resp.set_cookie("auriga_admin", secrets.token_urlsafe(16), max_age=86400, httponly=True)
|
||
return resp
|
||
if not request.cookies.get("auriga_admin"):
|
||
return page("ip", '<h1>OPERATOR</h1><div class=card><form method=post><input name=pw type=password placeholder="operator password"><button>In</button></form></div>')
|
||
con = db()
|
||
msgs = con.execute("SELECT m.*, u.username FROM messages m JOIN users u ON u.id=m.user_id ORDER BY m.id DESC LIMIT 100").fetchall()
|
||
msgs_html = "".join(f'<div class=msg><div class=who>{esc(m["username"])} · {time.strftime("%b %d %H:%M", time.localtime(m["created"]))}</div>{m["body"]}</div>' for m in msgs) or '<div style=color:var(--dim)>empty</div>'
|
||
opens = con.execute("SELECT te.*, tr.filename FROM track_events te JOIN trackables tr ON tr.id=te.trackable_id ORDER BY te.id DESC LIMIT 30").fetchall()
|
||
opens_html = "".join(f"<tr><td>{esc(o['filename'])}</td><td>{esc(o['ip'])}</td><td>{esc(o['ua'][:50])}</td><td>{time.strftime('%b %d %H:%M', time.localtime(o['ts']))}</td></tr>" for o in opens)
|
||
return page("track", f"""
|
||
<h1>OPERATOR <span>CONSOLE</span></h1>
|
||
<div class=card><b>All customer messages</b>{msgs_html}</div>
|
||
<div class=card><b>File open events</b><table><tr><th>File</th><th>IP</th><th>Device</th><th>When</th></tr>{opens_html}</table></div>""")
|
||
|
||
# ---------- INDEX ----------
|
||
@app.route("/")
|
||
def index():
|
||
ip = request.headers.get("X-Real-IP") or request.remote_addr
|
||
st, b = http(f"http://ip-api.com/json/{ip}?fields=66846719")
|
||
d = jf(b) or {}
|
||
con = db()
|
||
n_sms = con.execute("SELECT COUNT(*) c FROM sms_rentals").fetchone()["c"]
|
||
n_px = con.execute("SELECT COUNT(*) c FROM proxy_checks").fetchone()["c"]
|
||
body = f"""
|
||
<h1>AURIGA <span>TOOLBOX</span></h1>
|
||
<p class=sub>One page. Every network weapon you actually use. You're connecting from <b style=color:var(--acc)>{esc(d.get('query','?'))}</b> — {esc(d.get('city',''))}, {esc(d.get('country',''))}.</p>
|
||
<div class=grid2>
|
||
<div class=card><h3>◈ IP Intel</h3><p style=color:var(--dim)>Geo, ASN, ISP, VPN flags, rDNS — auto for you, any target on demand.</p><a href=/ip><button>Open</button></a></div>
|
||
<div class=card><h3>◈ Card Check</h3><p style=color:var(--dim)>Luhn + BIN: issuer, brand, type, prepaid risk flags.</p><a href=/card><button>Open</button></a></div>
|
||
<div class=card><h3>◈ SMS Rental</h3><p style=color:var(--dim)>30-min numbers, cancel = refund. {n_sms} served.</p><a href=/sms><button>Open</button></a></div>
|
||
<div class=card><h3>◈ Proxy Lab</h3><p style=color:var(--dim)>Same gateway keys as the fleet. {n_px} checks.</p><a href=/proxy><button>Open</button></a></div>
|
||
<div class=card><h3>◈ Stego Lab</h3><p style=color:var(--dim)>Hide words in pictures. LSB depth, spread, passwords.</p><a href=/steg><button>Open</button></a></div>
|
||
<div class=card><h3>◈ Track File</h3><p style=color:var(--dim)>$1 BTC → tracked link + email pixel → opens ping your inbox.</p><a href=/track><button>Open</button></a></div>
|
||
<div class=card><h3>◈ Burner Mail</h3><p style=color:var(--dim)>Receive-only mailboxes, 7d/$3 → 90d/$20, live countdown.</p><a href=/mail><button>Open</button></a></div>
|
||
<div class=card><h3>◈ PASS</h3><p style=color:var(--dim)>$10/mo all-access (3mo $25 · 1yr $80) — every tool, proxy rentals excluded.</p><a href=/pass><button>Open</button></a></div>
|
||
<div class=card><h3>◈ Inbox</h3><p style=color:var(--dim)>No-KYC site messaging with the operator.</p><a href=/inbox><button>Open</button></a></div>
|
||
<div class=card><h3>◈ Free Tools</h3><p style=color:var(--dim)>DNS, headers, JWT, hasher, generators.</p><a href=/tools><button>Open</button></a></div>
|
||
</div>"""
|
||
return page("home", body)
|
||
|
||
@app.route("/health")
|
||
def health(): return jsonify({"ok": True, "service": "auriga", "version": "2.0"})
|
||
|
||
if __name__ == "__main__":
|
||
app.run(host="0.0.0.0", port=5000, threaded=True)
|