commit fd51fb7db31da65bfd86f0a1e15e3d2e2be00709 Author: drjones Date: Tue Sep 29 18:07:43 2026 -0700 AURIGA v1: IP intel, card check, SMS rentals, proxy lab, free tools diff --git a/README.md b/README.md new file mode 100644 index 0000000..969742d --- /dev/null +++ b/README.md @@ -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. diff --git a/app.py b/app.py new file mode 100644 index 0000000..2a42afc --- /dev/null +++ b/app.py @@ -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 = """ +AURIGA — Toolbox + +
{{body}}
+ + +""" + +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"
{k}
{v}
" for k, v in pairs) + return f'
{rows}
' + +# ---------- 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"{d.get('query', ip)}"), + ("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"{k}{v}" for k, v in hdrs.items()) + body = f""" +

WHATS MY IP

Every drop of intel we can legally scrape, always on.

+{kv(rows)} +
Headers you sent{hdr_rows}
+
Live check — your browser also resolved this page in +….
+
API: GET /api/ip → same data as JSON. Agent-friendly.
""" + 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(('LUHN VALID' if ok else 'LUHN INVALID — fake/dead number')) + 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('BIN DB no data — structure-only result') + 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'LENGTH {length} WRONG for {brand}') + else: tags.append(f'length {length} valid for {brand}') + result = f""" +{kv([("Brand",brand),("BIN",bin8),("Bank / Issuer",bank),("Country",country),("Type",str(ctype)),("Prepaid",str(prepaid))])} +
Fraud & structure flags
{' '.join(tags)} +{'
⚠ ' + ' · '.join(flags) if flags else ''}
+
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.
""" + body = f""" +

CARD CHECK

Is it real? Luhn + BIN intelligence: issuer, brand, type, country, prepaid risk flags.

+
+{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'
RENTED Your number: +{d.get("number")} · expires in 30 min · order #{d.get("purchase_id")}
' + else: + msg = f'
RENT FAILED
{b[:400]}
' + 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'
STATUS: {status} {"" + str(sms_txt) + "" if sms_txt else "no code yet — poll again in 10s"}
' + 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'
{"CANCELLED + REFUNDED" if ok else "CANCEL FAILED"}
' + st, b = sms_api("sms/instructions") + body = f""" +

SMS RENTAL

Disposable numbers, 30-minute windows. Cancel before a code arrives = full refund.

+
+
Rent a number +
+ + +
+
Check / manage +
+
+
{msg} +
API: POST /api/sms/rent (service,country) · /api/sms/check (pid) · /api/sms/cancel (pid)
""" + 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'
PROXY LIVE Egress: {j.get("query")} — {j.get("country")} / {j.get("city")} · ISP {j.get("isp")} · tz {j.get("timezone")}
' + 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'
AUTH/TUNNEL FAILED
{resp[:200]!r}
' + except Exception as e: + result = f'
ERROR {e}
' + body = f""" +

PROXY LAB

Rent residential proxies on the Pleiades rail — your existing gateway user:pass works here, same keys as everywhere.

+
+

+

+
+{result} +
Rent more — buy GB plans & geo-targeted sessions at the storefront: +{PLEIADES_APP}. Region/country/city suffixes on your password control geo; add +_session-XXXX_lifetime-30m for sticky 30-min IPs.
+
API: POST /api/proxy/test (user, pass) → egress IP + geo JSON.
""" + 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""" +

FREE TOOLS

High-value, zero-cost, no signup. Agent-friendly APIs underneath each.

+ +
+ + + + +
+ +
DNS Lookup (Google DoH)
+ +
API: /api/hdr style JSON via dns.google
+ + + +""" + 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""" +

AURIGA TOOLBOX

+

One page. Every network weapon you actually use. No signup, no fluff.

+
+

◈ Whats-My-IP MAX

You're connecting from {d.get('query','?')} — {d.get('city','')}, {d.get('country','')}. Full dump: geo, ASN, ISP, VPN flags, rDNS, headers.

+

◈ Card Check

Luhn + BIN: brand, issuer, country, type, prepaid risk flags. Nothing stored, nothing charged.

+

◈ SMS Rental

Disposable numbers, 30-minute windows, cancel = refund. {n_sms} rentals served.

+

◈ Proxy Lab

Test + rent residential proxies. Same gateway keys as the other sites. {n_px} checks run.

+

◈ Free Tools

DNS, HTTP headers, JWT, hasher, UUID/password generators.

+

◈ API-first

Every tool has a JSON API. Agents welcome — that's the point.

+
""" + 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)