420 lines
26 KiB
Python
420 lines
26 KiB
Python
#!/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 & 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 ----------
|
||
@app.route("/ip")
|
||
def ip_route(): return ip_lookup()
|
||
|
||
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 & 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 & 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 & 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)
|