AURIGA v1: IP intel, card check, SMS rentals, proxy lab, free tools

This commit is contained in:
2026-09-29 18:07:43 -07:00
commit fd51fb7db3
2 changed files with 427 additions and 0 deletions

11
README.md Normal file
View File

@@ -0,0 +1,11 @@
# AURIGA — Toolbox
One-page network toolbox: https://auriga.thetempleofdoom.com
- **Whats-My-IP MAX** — geo, ASN, ISP, VPN/proxy/hosting flags, rDNS, headers. API: `GET /api/ip`
- **Card Check** — Luhn + BIN (brand/issuer/country/prepaid flags). Nothing stored or charged. `POST /card`
- **SMS Rental** — disposable numbers, 30-min windows, cancel = refund (SMSPool). `POST /api/sms/rent|check|cancel`
- **Proxy Lab** — test Pleiades gateway `user:pass` (same keys fleet-wide), see egress IP/geo. `POST /api/proxy/test`
- **Free Tools** — DNS (DoH), HTTP header inspector, JWT decoder, hasher, UUID/password gen. `GET /api/hash`, `GET /api/hdr`
CT 768 @ 10.30.20.216, Flask :5000 behind nginx. Stack: single-file Flask + SQLite.

416
app.py Normal file
View File

@@ -0,0 +1,416 @@
#!/usr/bin/env python3
"""AURIGA — homelab toolbox: IP intel, card validator, SMS rentals, proxy tools."""
import base64, binascii, hashlib, json, os, re, secrets, socket, sqlite3, string, struct, time, uuid
import urllib.request, urllib.parse
from flask import Flask, request, jsonify, render_template_string, g
app = Flask(__name__)
DB_PATH = os.environ.get("AURIGA_DB", "/opt/auriga/auriga.db")
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", "http://10.30.20.178:5000")
BMAC = "https://buymeacoffee.com/r26xrthzttg"
def db():
con = sqlite3.connect(DB_PATH); con.row_factory = sqlite3.Row
con.execute("""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)""")
con.execute("""CREATE TABLE IF NOT EXISTS proxy_checks(
id INTEGER PRIMARY KEY, user_key TEXT, egress_ip TEXT, geo TEXT, ok INTEGER, ts INTEGER)""")
return con
def http(url, headers=None, data=None, method="GET", timeout=12):
req = urllib.request.Request(url, headers=headers or {}, data=data, method=method)
try:
with urllib.request.urlopen(req, timeout=timeout) 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
BASE = """<!doctype html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1">
<meta name=robots content="noindex"><title>AURIGA — Toolbox</title>
<style>
:root{--bg:#0b0e17;--card:#141a2b;--fg:#e8ecf7;--dim:#8b95b3;--acc:#f0b429;--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}
nav{display:flex;flex-wrap:wrap;gap:.4rem;padding:1rem 1.4rem;border-bottom:1px solid #232b45;position:sticky;top:0;background:var(--bg);z-index:5}
nav a{color:var(--dim);text-decoration:none;padding:.45rem .9rem;border:1px solid #232b45;border-radius:999px}
nav a.on,nav a:hover{color:var(--acc);border-color:var(--acc)}
main{max-width:960px;margin:0 auto;padding:2rem 1.4rem}
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}
.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}
button:hover{filter:brightness(1.1)}
.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)}
.spin{display:inline-block;animation:r 1s linear infinite}@keyframes r{to{transform:rotate(360deg)}}
</style></head><body>
<nav>
<a href=/ class={{o(ip)}}>◈ WHATS-MY-IP</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=/tools class={{o(tools)}}>◈ FREE TOOLS</a>
</nav><main>{{body}}</main>
<footer>Built for agents &amp; 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>
</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"><div class="kv">{rows}</div></div>'
# ---------- 1. WHAT'S MY IP ----------
def ip_lookup():
ip = request.headers.get("X-Real-IP") or request.remote_addr or ""
st, b = http(f"http://ip-api.com/json/{ip}?fields=66846719")
d = jf(b) or {}
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","x-real-ip")}
proxy_hint = any(k.lower().startswith(("x-forwarded","via","proxy")) for k in request.headers)
rows = [
("YOUR IP", f"<b style='font-size:1.3rem;color:var(--acc)'>{d.get('query', ip)}</b>"),
("Country", f"{d.get('country','?')} ({d.get('countryCode','?')}) 🏴 {d.get('flag') if 'flag' in d else ''}".strip()),
("Region / City", f"{d.get('regionName','?')} / {d.get('city','?')} {d.get('zip','')}"),
("Lat, Lon", f"{d.get('lat','?')}, {d.get('lon','?')} · TZ: {d.get('timezone','?')} · UTC offset {d.get('offset','?')}s"),
("ISP", d.get('isp','?')), ("Organization", d.get('org','?')), ("AS", d.get('as','?') if d.get('as') else d.get('asname','?')),
("Reverse DNS", str(d.get('reverse','—'))),
("Connection", f"mobile: {d.get('mobile')} · proxy/VPN: {d.get('proxy')} · hosting: {d.get('hosting')}"),
("Local guess", d.get('district') or '—'),
("Proxy headers seen", "YES ⚠ (you're behind a relay)" if proxy_hint else "none — looks direct"),
("Currency", d.get('currency','?')),
]
hdr_rows = "".join(f"<tr><td>{k}</td><td>{v}</td></tr>" for k, v in hdrs.items())
body = f"""
<h1>WHATS <span>MY IP</span></h1><p class=sub>Every drop of intel we can legally scrape, always on.</p>
{kv(rows)}
<div class=card><b>Headers you sent</b><table>{hdr_rows}</table></div>
<div class=card><b>Live check</b> — your browser also resolved this page in
<span id=ms>…</span>. <script>t=performance.timing.responseStart-performance.timing.requestStart;
document.getElementById('ms').textContent=Math.max(0,t)+' ms';</script></div>
<div class=card>API: <code>GET /api/ip</code> → same data as JSON. Agent-friendly.</div>"""
return page("ip", body)
@app.route("/api/ip")
def api_ip():
ip = request.headers.get("X-Real-IP") or request.remote_addr or ""
st, b = http(f"http://ip-api.com/json/{ip}?fields=66846719")
d = jf(b) or {}
d["headers_seen"] = {k: v for k, v in request.headers.items()}
return jsonify(d)
# ---------- 2. CARD CHECK ----------
def luhn_ok(num):
digits = [int(c) for c in num]
odd = digits[-1::-2]; even = digits[-2::-2]
s = sum(odd)
for d in even:
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"
@app.route("/card", methods=["GET", "POST"])
def card():
result = ""
num = re.sub(r"\D", "", request.form.get("num", ""))[:19]
if num:
tags = []
ok = luhn_ok(num)
tags.append(('<span class="tag ok">LUHN VALID</span>' if ok else '<span class="tag bad">LUHN INVALID — fake/dead number</span>'))
brand = brand_of(num)
bin8 = num[:8]
st, b = http(f"https://lookup.binlist.net/{bin8}", headers={"Accept-Version": "3"})
bl = jf(b) or {}
bank = (bl.get("bank") or {}).get("name", "—")
country = (bl.get("country") or {}).get("name", "—")
ctype = bl.get("type", "—")
prepaid = bl.get("prepaid", "—")
if not bl: tags.append('<span class="tag warn">BIN DB no data — structure-only result</span>')
flags = []
if ctype == "prepaid" or prepaid is True: flags.append("PREPAID — commonly flagged by merchants")
if ctype == "debit": flags.append("DEBIT")
if ctype == "credit": flags.append("CREDIT")
length = len(num)
rng = {"Visa":(13,16,19),"Mastercard":(16,),"Amex":(15,),}.get(brand, (13,15,16,19))
if length not in rng: tags.append(f'<span class="tag bad">LENGTH {length} WRONG for {brand}</span>')
else: tags.append(f'<span class="tag ok">length {length} valid for {brand}</span>')
result = f"""
{kv([("Brand",brand),("BIN",bin8),("Bank / Issuer",bank),("Country",country),("Type",str(ctype)),("Prepaid",str(prepaid))])}
<div class=card><b>Fraud &amp; structure flags</b><br>{' '.join(tags)}
{'<br>⚠ ' + ' · '.join(flags) if flags else ''}</div>
<div class=card style=color:var(--dim)>Nothing is stored. No charge, no auth, no $0 check — this is BIN + math validation only.
It cannot tell you if a card has available funds. Fraud "flagged" status lives at the issuer, not in any database we can legally query.</div>"""
body = f"""
<h1>CARD <span>CHECK</span></h1><p class=sub>Is it real? Luhn + BIN intelligence: issuer, brand, type, country, prepaid risk flags.</p>
<div class=card><form method=post><input name=num placeholder="4539 1488 0343 6467" style="width:70%" value="{num}"> <button>Check</button></form></div>
{result}"""
return page("card", body)
# ---------- 3. SMS RENTALS ----------
SMSP = "http://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
data = urllib.parse.urlencode(kw).encode()
return http(f"{SMSP}/{path}", data=data, method="POST")
return http(f"{SMSP}/{path}?key={SMSP_KEY}")
@app.route("/sms", methods=["GET", "POST"])
def sms():
msg, listing = "", ""
if request.method == "POST":
act = request.form.get("act")
if act == "rent":
svc, ctry = request.form["service"], request.form["country"]
st, b = sms_api("purchase/sms", service=svc, country=ctry)
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"), svc, ctry, 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> · expires in 30 min · order #{d.get("purchase_id")}</div>'
else:
msg = f'<div class="card"><span class="tag bad">RENT FAILED</span><br><pre>{b[:400]}</pre></div>'
elif act == "check":
pid = request.form["pid"]
st, b = sms_api("sms/check", purchase_id=pid)
d = jf(b) or {}
sms_txt = d.get("sms") or d.get("code") or ""
status = d.get("status", "?")
color = "ok" if sms_txt else "warn"
msg = f'<div class="card"><span class="tag {color}">STATUS: {status}</span> {"<b style=color:var(--ok)>" + str(sms_txt) + "</b>" if sms_txt else "no code yet — poll again in 10s"}</div>'
elif act == "cancel":
pid = request.form["pid"]
st, b = sms_api("sms/cancel", purchase_id=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", 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>'
st, b = sms_api("sms/instructions")
body = f"""
<h1>SMS <span>RENTAL</span></h1><p class=sub>Disposable numbers, 30-minute windows. Cancel before a code arrives = 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 # (purchase_id)" 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 &amp; refund</button></form></div>
</div>{msg}
<div class=card style=color:var(--dim)>API: POST /api/sms/rent (service,country) · /api/sms/check (pid) · /api/sms/cancel (pid)</div>"""
return page("sms", body)
@app.route("/api/sms/rent", methods=["POST"])
def api_sms_rent():
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()
return jsonify(d)
@app.route("/api/sms/check", methods=["POST"])
def api_sms_check():
st, b = sms_api("sms/check", purchase_id=request.form["pid"])
return jf(b) or jsonify({"error": b[:200]})
@app.route("/api/sms/cancel", methods=["POST"])
def api_sms_cancel():
st, b = sms_api("sms/cancel", purchase_id=request.form["pid"])
return jf(b) or jsonify({"error": b[:200]})
# ---------- 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","")
test_url = request.form.get("target", "http://ip-api.com/json/?fields=66846719")
pauth = base64.b64encode(f"{user}:{pw}".encode()).decode()
try:
pu = urllib.parse.urlparse(test_url if "://" in test_url else "http://"+test_url)
req_line = f"GET {pu.path or '/'} HTTP/1.1\r\nHost: {pu.hostname}\r\nConnection: close\r\n\r\n"
s = socket.create_connection((PLEIADES_GW.split(":")[0], int(PLEIADES_GW.split(":")[1])), timeout=15)
s.sendall(f"CONNECT {pu.hostname}:80 HTTP/1.1\r\nHost: {pu.hostname}: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(req_line.encode())
data = b""
while True:
c = s.recv(8192)
if not c: break
data += c
s.close()
body = data.split(b"\r\n\r\n",1)[-1].decode("utf-8","replace")
j = jf(body) 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)>{j.get("query")}</b> — {j.get("country")} / {j.get("city")} · ISP {j.get("isp")} · tz {j.get("timezone")}</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>{resp[:200]!r}</pre></div>'
except Exception as e:
result = f'<div class="card"><span class="tag bad">ERROR</span> {e}</div>'
body = f"""
<h1>PROXY <span>LAB</span></h1><p class=sub>Rent residential proxies on the Pleiades rail — your existing gateway <code>user:pass</code> works here, same 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="gw_… or 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>Rent more</b> — buy GB plans &amp; geo-targeted sessions at the storefront:
<a href="{PLEIADES_APP}" style=color:var(--acc)>{PLEIADES_APP}</a>. Region/country/city suffixes on your password control geo; add
<code>_session-XXXX_lifetime-30m</code> for sticky 30-min IPs.</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 = 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" 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. FREE TOOLS ----------
TOOLS_JS = """
function tab(n){document.querySelectorAll('.pane').forEach(p=>p.style.display='none');document.getElementById(n).style.display='block';
document.querySelectorAll('.tbtn').forEach(b=>b.classList.remove('on'));event.target.classList.add('on')}
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])+'\\n\\n(signature: '+t[2]+')'}catch(e){document.getElementById('jo').textContent='Invalid JWT: '+e}}
function genhash(){const i=document.getElementById('hq2').value;['md5','sha1','sha256','sha512'].forEach(a=>{document.getElementById('h_'+a).textContent=hashlib(a,i)})}
function hashlib(a,s){return a}
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 = request.args.get("url","")
if "://" not in url: url = "http://" + url
try:
req = urllib.request.Request(url, headers={"User-Agent":"Auriga/1.0"})
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 = request.args.get("s","").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. Agent-friendly 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')">DNS Lookup</button>
<button class=tbtn onclick="tab('hdr_p')">HTTP Headers</button>
<button class=tbtn onclick="tab('jwt_p')">JWT Decoder</button>
<button class=tbtn onclick="tab('hash_p')">Hasher</button>
<button class=tbtn onclick="tab('gen_p')">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 style=color:var(--dim)>API: /api/hdr style JSON via dns.google</div></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 style=color:var(--dim)>API: GET /api/hdr?url=…</div></div>
<div id=jwt_p class="card pane" style=display:none><b>JWT Decoder</b> (client-side, 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 style=color:var(--dim)>API: GET /api/hash?s=…</div></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)
@app.route("/")
def index():
st, b = http(f"http://ip-api.com/json/{request.headers.get('X-Real-IP') or request.remote_addr}?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. No signup, no fluff.</p>
<div class=grid2>
<div class=card><h3>◈ Whats-My-IP MAX</h3><p style=color:var(--dim)>You're connecting from <b style=color:var(--acc)>{d.get('query','?')}</b> — {d.get('city','')}, {d.get('country','')}. Full dump: geo, ASN, ISP, VPN flags, rDNS, headers.</p><a href=/ip><button>Open</button></a> <a href=/api/ip><button style=background:#232b45;color:var(--fg)>API</button></a></div>
<div class=card><h3>◈ Card Check</h3><p style=color:var(--dim)>Luhn + BIN: brand, issuer, country, type, prepaid risk flags. Nothing stored, nothing charged.</p><a href=/card><button>Open</button></a></div>
<div class=card><h3>◈ SMS Rental</h3><p style=color:var(--dim)>Disposable numbers, 30-minute windows, cancel = refund. {n_sms} rentals served.</p><a href=/sms><button>Open</button></a></div>
<div class=card><h3>◈ Proxy Lab</h3><p style=color:var(--dim)>Test + rent residential proxies. Same gateway keys as the other sites. {n_px} checks run.</p><a href=/proxy><button>Open</button></a></div>
<div class=card><h3>◈ Free Tools</h3><p style=color:var(--dim)>DNS, HTTP headers, JWT, hasher, UUID/password generators.</p><a href=/tools><button>Open</button></a></div>
<div class=card><h3>◈ API-first</h3><p style=color:var(--dim)>Every tool has a JSON API. Agents welcome — that's the point.</p></div>
</div>"""
return page("ip", body)
@app.route("/health")
def health(): return jsonify({"ok": True, "service": "auriga"})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, threaded=True)