Files
dark0rbits/app.py

5837 lines
374 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Dark0rbits 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, ipaddress, json, os, re, secrets, shutil, socket, sqlite3, struct, subprocess, time, uuid
import urllib.request, urllib.parse
from flask import Flask, request, jsonify, render_template_string, Response, send_file
from flask import redirect
import importlib.util as _ilu
_HAVE_AESGCM = _ilu.find_spec("cryptography") is not None
app = Flask(__name__)
DB_PATH = os.environ.get("DARK0RBITS_DB", "/opt/dark0rbits/dark0rbits.db")
UPLOAD_DIR = os.environ.get("DARK0RBITS_UPLOADS", "/opt/dark0rbits/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("DARK0RBITS_ADMIN", "Czapiewski1!")
BTCPAY_WHSEC = os.environ.get("BTCPAY_WHSEC", "QnrkV2XPFD3P6ULjMxspHQ")
BMAC = "https://buymeacoffee.com/r26xrthzttg"
SITE = "https://dark0rbits.thetempleofdoom.com"
def _migrate(con):
cols = [r[1] for r in con.execute("PRAGMA table_info(settings)")]
if not cols:
con.execute("CREATE TABLE IF NOT EXISTS settings(user_id INTEGER, key TEXT, val TEXT, PRIMARY KEY(user_id,key))")
cols = [r[1] for r in con.execute("PRAGMA table_info(sms_rentals)")]
if "user_id" not in cols:
con.execute("ALTER TABLE sms_rentals ADD COLUMN user_id INTEGER DEFAULT 0")
cols = [r[1] for r in con.execute("PRAGMA table_info(canary_hits)")]
if cols and "lang" not in cols:
con.execute("ALTER TABLE canary_hits ADD COLUMN lang TEXT DEFAULT ''")
con.execute("ALTER TABLE canary_hits ADD COLUMN ref TEXT DEFAULT ''")
cols = [r[1] for r in con.execute("PRAGMA table_info(canaries)")]
if cols and "kind" not in cols:
con.execute("ALTER TABLE canaries ADD COLUMN kind TEXT DEFAULT 'link'")
con.execute("ALTER TABLE canaries ADD COLUMN rearm INTEGER DEFAULT 0")
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);
CREATE TABLE IF NOT EXISTS canaries(id INTEGER PRIMARY KEY, user_id INTEGER, token TEXT UNIQUE, tag TEXT, created INTEGER, armed INTEGER DEFAULT 1);
CREATE TABLE IF NOT EXISTS canary_hits(id INTEGER PRIMARY KEY, canary_id INTEGER, ts INTEGER, ip TEXT, ua TEXT);
CREATE TABLE IF NOT EXISTS balances(user_id INTEGER PRIMARY KEY, cents INTEGER DEFAULT 0);
CREATE TABLE IF NOT EXISTS apikeys(id INTEGER PRIMARY KEY, user_id INTEGER, key TEXT UNIQUE, label TEXT, created INTEGER, revoked INTEGER DEFAULT 0);
CREATE TABLE IF NOT EXISTS ledger(id INTEGER PRIMARY KEY, user_id INTEGER, delta_cents INTEGER, reason TEXT, ts INTEGER);
CREATE TABLE IF NOT EXISTS wh_processed(invoice_id TEXT PRIMARY KEY, ts INTEGER);
CREATE TABLE IF NOT EXISTS rate_hits(bucket TEXT, ip TEXT, ts INTEGER);
CREATE TABLE IF NOT EXISTS deadrops(id INTEGER PRIMARY KEY, user_id INTEGER, token TEXT UNIQUE, body_enc TEXT, reads_left INTEGER, burn_after INTEGER, expires INTEGER, pw_hash TEXT, created INTEGER);
CREATE TABLE IF NOT EXISTS shots(id INTEGER PRIMARY KEY, user_id INTEGER, url TEXT, status TEXT, result TEXT, created INTEGER);""")
_migrate(con)
return con
# ---------- USER SETTINGS (visible tunables, agent-settable) ----------
DEFAULT_SETTINGS = {
"bg": "1", "warp": "1", "parallax": "1", "density": "1.0", "speed": "1.0", "twinkle": "1.0",
"hue": "0", "grid": "1", "scan": "1", "toast": "1", "type": "1",
}
BOOL_SETTINGS = {"bg", "warp", "parallax", "grid", "scan", "toast", "type"}
RANGE_SETTINGS = {"density": (0, 2.5), "speed": (0, 3), "twinkle": (0, 3), "hue": (-180, 180)}
def get_settings(uid):
out = dict(DEFAULT_SETTINGS)
if not uid:
return out
con = db()
try:
for r in con.execute("SELECT key,val FROM settings WHERE user_id=?", (uid,)):
if r["key"] in out:
out[r["key"]] = r["val"]
except Exception:
pass
return out
def set_setting(uid, key, val):
if key not in DEFAULT_SETTINGS:
return False
if key in BOOL_SETTINGS:
val = "1" if str(val) in ("1", "true", "on", "yes") else "0"
elif key in RANGE_SETTINGS:
try:
lo, hi = RANGE_SETTINGS[key]
val = str(max(lo, min(hi, float(val))))
except Exception:
return False
con = db()
con.execute("INSERT INTO settings(user_id,key,val) VALUES(?,?,?) ON CONFLICT(user_id,key) DO UPDATE SET val=excluded.val", (uid, key, str(val)))
con.commit()
return True
# ---------- BILLING CORE (per-call metering for outside users) ----------
def get_balance(uid):
con = db()
con.execute("INSERT OR IGNORE INTO balances(user_id, cents) VALUES(?, 100)", (uid,)) # $1 free trial credit
con.commit()
return con.execute("SELECT cents FROM balances WHERE user_id=?", (uid,)).fetchone()["cents"]
def charge(uid, cents, reason):
"""Deduct from balance; return False if insufficient.
FREE MODE (Oct 2026): every tool on dark0rbits is free — the lab absorbs all costs.
Charges become zero-cost ledger entries and always succeed."""
if cents <= 0: return True
if uid:
con = db()
con.execute("INSERT INTO ledger(user_id,delta_cents,reason,ts) VALUES(?,?,?,?)",
(uid, 0, f"FREE (was {cents}¢) {reason}", int(time.time())))
con.commit()
return True
def key_user():
"""API-key auth: Authorization: Bearer dk_... → user_id or None."""
auth = request.headers.get("Authorization", "")
if not auth.startswith("Bearer dk_"): return None
con = db()
r = con.execute("SELECT user_id FROM apikeys WHERE key=? AND revoked=0", (auth[7:],)).fetchone()
return r["user_id"] if r else None
def require_paid_key(cents, reason):
"""For API calls: key or session auth; metered charge. Returns (uid, error_json)."""
uid = key_user() or current_user_id()
if not uid: return None, (jsonify({"ok": False, "error": "auth required: account session or Authorization: Bearer dk_… key"}), 401)
if has_pass(uid): return uid, None # PASS = unlimited tools (proxy excluded)
if not charge(uid, cents, reason):
return None, (jsonify({"ok": False, "error": "insufficient balance", "balance_cents": get_balance(uid), "topup": SITE + "/keys"}), 402)
return uid, None
# ---------- RATE LIMITING ----------
_RL = {}
def rate_limit(bucket, limit, window):
"""Sliding-window per-IP limiter. Returns None if ok, else a 429 response."""
key = request.headers.get("X-Real-IP") or request.remote_addr or "?"
now = time.time()
con = db()
con.execute("DELETE FROM rate_hits WHERE bucket=? AND ts < ?", (bucket, now-window))
n = con.execute("SELECT COUNT(*) c FROM rate_hits WHERE bucket=? AND ip=?", (bucket, key)).fetchone()["c"]
if n >= limit:
return jsonify({"ok": False, "error": "rate limited — slow down"}), 429
con.execute("INSERT INTO rate_hits(bucket,ip,ts) VALUES(?,?,?)", (bucket, key, now))
con.commit()
return None
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 (Dark0rbits 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))
# ---------- DEAD-DROP CRYPTO (AES-GCM on CT768, XOR-HMAC stream fallback) ----------
def _dd_master_key():
return hashlib.sha256(("dark0rbits-deaddrop-v1:" + (os.environ.get("DARK0RBITS_SECRET", "ct768-fallback-secret"))).encode()).digest()
def dd_encrypt(plaintext):
"""AES-256-GCM when cryptography is present, else HMAC-verified XOR stream. Returns 'mode:vault' string."""
if _HAVE_AESGCM:
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
nonce = secrets.token_bytes(12)
vault = AESGCM(_dd_master_key()).encrypt(nonce, plaintext.encode(), None)
return "aesgcm:" + base64.urlsafe_b64encode(nonce + vault).decode()
key = secrets.token_bytes(32)
stream = bytes(a ^ b for a, b in zip(plaintext.encode(), hashlib.shake_256(key + str(len(plaintext)).encode()).digest(len(plaintext) + 64)))
mac = hmac.new(_dd_master_key(), stream, hashlib.sha256).hexdigest()
return "xor:" + base64.urlsafe_b64encode(key + stream).decode() + ":" + mac
def dd_decrypt(vault):
try:
if vault.startswith("aesgcm:"):
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
raw = base64.urlsafe_b64decode(vault[7:].encode())
return AESGCM(_dd_master_key()).decrypt(raw[:12], raw[12:], None).decode()
if vault.startswith("xor:"):
k64, mac = vault[4:].rsplit(":", 1)
raw = base64.urlsafe_b64decode(k64.encode())
if not hmac.compare_digest(hmac.new(_dd_master_key(), raw[32:], hashlib.sha256).hexdigest(), mac): return None
n = len(raw) - 32 - 64
stream = bytes(a ^ b for a, b in zip(raw[32:], hashlib.shake_256(raw[:32] + str(n).encode()).digest(n + 64)))
return stream.decode()
except Exception:
pass
return None
BASE = """<!doctype html><html lang=en><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1">
<title>DARK0RBITS — No-KYC Network Toolbox: IP Intel, Stego, Burner Mail, SMS Rentals, Proxy Lab</title>
<meta name=description content="DARK0RBITS: a no-KYC toolbox for operators and AI agents. IP intelligence, card BIN validation, burner mail, SMS number rentals, steganography, trackable files, email & image forensics, canary traps, residential proxy testing. BTC only.">
<meta name=keywords content="dark0rbits, no kyc tools, ip lookup, bin check, burner email, sms rental, steganography, stego, email forensics, image forensics, canary trap, proxy, bitcoin only, agent api">
<meta property="og:title" content="DARK0RBITS — The Operator's Toolbox">
<meta property="og:description" content="No-KYC network toolbox for humans and AI agents. BTC only. 12 tools, every one with a JSON API.">
<meta property="og:type" content="website">
<meta property="og:image" content="https://dark0rbits.thetempleofdoom.com/og.png">
<link rel="icon" href="/favicon.svg">
<meta property="og:url" content="https://dark0rbits.thetempleofdoom.com">
<meta name=robots content="index,follow">
<meta name=theme-color content="#070a13">
<link rel=canonical href="https://dark0rbits.thetempleofdoom.com">
<style>
:root{--bg:#070a13;--card:rgba(19,25,44,.82);--line:#242e4d;--fg:#e9edf8;--dim:#93a0c2;--acc:#a78bfa;--acc2:#6fd6ff;--acc3:#6fd6ff;--ok:#42e8a4;--bad:#ff6161}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;min-height:100vh;color:var(--fg);font:16.5px/1.7 ui-monospace,Menlo,Consolas,monospace;text-align:left;overflow-x:hidden;background:var(--bg)}
#space{position:fixed;inset:0;z-index:0;display:block}
.vignette{position:fixed;inset:0;z-index:1;pointer-events:none;background:radial-gradient(ellipse at 50% -10%,var(--neb1,rgba(120,85,255,.16)),transparent 55%),radial-gradient(ellipse at 80% 110%,var(--neb2,rgba(0,190,255,.10)),transparent 50%),radial-gradient(ellipse at 50% 50%,transparent 60%,rgba(0,0,5,.55) 100%)}
main{position:relative;z-index:2;max-width:920px;margin:0 auto;padding:1.8rem 1.3rem 4rem;text-align:left}
#lbar{position:fixed;top:0;left:0;height:3px;width:0;background:linear-gradient(90deg,var(--acc),var(--acc2));z-index:50;transition:width .3s;box-shadow:0 0 10px var(--acc)}
#lbar.done{width:100%;opacity:0;transition:opacity .5s}
header{position:sticky;top:0;z-index:40;background:rgba(7,10,19,.86);backdrop-filter:blur(10px);border-bottom:1px solid var(--line)}
.hbar{max-width:920px;margin:0 auto;display:flex;align-items:center;justify-content:space-between;padding:.55rem 1rem}
.logo{color:var(--acc);text-decoration:none;font-weight:800;letter-spacing:.28em;font-size:1rem;text-shadow:0 0 18px rgba(167,139,250,.4)}
.burger{background:none;border:1px solid var(--line);color:var(--fg);font-size:1.15rem;border-radius:8px;padding:.35rem .7rem;cursor:pointer}
.burger:hover{border-color:var(--acc);color:var(--acc)}
.dnav{display:flex;flex-wrap:wrap;gap:.5rem;justify-content:flex-start}
.dnav a{color:var(--dim);text-decoration:none;font-size:.84rem;padding:.45rem .8rem;border:1px solid var(--line);border-radius:999px;white-space:nowrap;transition:.15s}
.dnav a.on,.dnav a:hover{color:var(--acc);border-color:var(--acc)}
.tchip{color:var(--fg);margin-right:.5rem;white-space:nowrap}
.srow{display:flex;align-items:center;gap:.5rem;margin:.45rem 0;font-size:.85rem;color:var(--fg)}
.srow input[type=range]{flex:1;accent-color:var(--acc)}
.srow input[type=checkbox]{accent-color:var(--acc);width:16px;height:16px}
#pinp{background:var(--card);border:1px solid var(--line);border-radius:8px;padding:.6rem;color:var(--fg)}
.pitem{display:block;padding:.5rem .6rem;border:1px solid transparent;border-radius:8px;color:var(--fg);text-decoration:none;cursor:pointer}
.pitem:hover,.pitem.sel{border-color:var(--acc);color:var(--acc)}
.pitem small{display:block;color:var(--dim)}
:focus-visible{outline:2px solid var(--acc2);outline-offset:2px;border-radius:4px}
.skip{position:absolute;left:-9999px;top:0;z-index:100;background:var(--acc);color:#0d0722;padding:.5rem 1rem;border-radius:0 0 8px 0;font-weight:800}
.skip:focus{left:0}
/* tables: real tables, wrap in .tblwide for scroll on tiny screens */
@media(max-width:640px){.dnav a{padding:.45rem .7rem;font-size:.8rem}#dev{display:none}}
@media(prefers-reduced-motion:reduce){ #space{display:none}.gridlines{display:none}#lbar{transition:none}.type,.typed-cursor,.crt{display:none}.logo::before,.logo::after{animation:none}.card{transition:none}}
.drawer{position:fixed;inset:0;z-index:60;background:rgba(7,10,19,.96);backdrop-filter:blur(6px);display:none;flex-direction:column;padding:1.2rem;overflow-y:auto}
.drawer.open{display:flex}
.drawer .dhead{display:flex;justify-content:space-between;align-items:center;margin-bottom:.8rem}
.drawer h4{color:var(--dim);font-size:.75rem;letter-spacing:.25em;text-align:left;margin:1rem 0 .4rem;text-transform:uppercase}
.drawer a.dl{color:var(--fg);text-decoration:none;padding:.65rem .8rem;border:1px solid var(--line);border-radius:10px;margin:.25rem 0;text-align:left;font-size:.95rem}
.drawer a.dl:hover,.drawer a.dl.on{border-color:var(--acc);color:var(--acc)}
.drawer a.dl small{display:block;color:var(--dim);font-size:.72rem}
@media(min-width:860px){.burger{display:none}}
@media(max-width:859px){.dnav{display:none}}
h1{font-size:1.9rem;letter-spacing:.04em;margin:1.3rem 0 .35rem;line-height:1.25}
h1 span{color:var(--acc)}
.sub{color:var(--dim);margin:.25rem 0 1.7rem;font-size:1.03rem;line-height:1.65;max-width:62ch}
.card{background:var(--card);border:1px solid var(--line);border-radius:16px;padding:1.4rem 1.5rem;margin:1.35rem 0;backdrop-filter:blur(4px)}
.card.glow{box-shadow:0 0 34px -16px var(--acc)}
.kv{display:grid;grid-template-columns:200px minmax(0,1fr);gap:0;border:1px solid var(--line);border-radius:12px;overflow:hidden;text-align:left}
.kv div{padding:.6rem .9rem;border-bottom:1px solid var(--line);min-width:0;overflow-wrap:anywhere}
.kv div:nth-child(odd){color:var(--dim);font-size:.78rem;letter-spacing:.06em;text-transform:uppercase;font-weight:700;background:rgba(255,255,255,.02)}
.kv div:nth-child(even){background:transparent}
.kv div:nth-child(even){background:transparent}
.kv div:nth-last-child(2),.kv div:last-child{border-bottom:0}
input,select,button,textarea{font:inherit;background:rgba(10,15,30,.9);color:var(--fg);border:1px solid #2c3860;border-radius:10px;padding:.72rem .9rem;max-width:100%;text-align:left}
.card label{display:block;text-align:left;color:var(--dim);font-size:.88rem;margin:.6rem 0 .2rem}
.card input,.card select,.card textarea{width:100%}
.card form{text-align:left}
.card p{text-align:left;line-height:1.7}
button{background:linear-gradient(135deg,var(--acc),var(--acc2));color:#0d0722;border:0;font-weight:800;cursor:pointer;transition:.2s;letter-spacing:.05em}
button:hover{filter:brightness(1.15);box-shadow:0 0 20px -4px var(--acc)}
button.ghost{background:transparent;color:var(--acc);border:1px solid var(--acc)}
button.big{font-size:1.02rem;padding:.75rem 1.4rem;margin:.25rem;color:#0d0722}
.grid2{display:grid;grid-template-columns:1fr;gap:1.25rem;text-align:left}
@media(min-width:700px){.grid2{grid-template-columns:repeat(2,1fr);gap:1.1rem}}
.grid3{display:grid;grid-template-columns:1fr;gap:1.1rem;text-align:left}
@media(min-width:700px){.grid3{grid-template-columns:repeat(2,1fr)}}
@media(min-width:1000px){.grid3{grid-template-columns:repeat(3,1fr)}}
.tcard{display:flex;flex-direction:column;gap:.55rem;padding:1.15rem 1.2rem;min-height:0}
.tcard h3{margin:0;font-size:1.02rem;letter-spacing:.14em;text-align:left}
.tcard p{margin:0;text-align:left;color:var(--dim);font-size:.92rem;line-height:1.5;flex:1}
.tcard .tgo{align-self:flex-start;margin-top:.2rem;text-decoration:none}
.tcard .tgo button{margin:0;padding:.5rem 1.1rem}
.tcard:hover{border-color:#3d4d7d}
.tcard .tico{font-size:1.3rem;line-height:1;color:var(--acc)}
.tcard .trow{display:flex;align-items:center;gap:.6rem}
.tcard .tico{flex:0 0 1.9rem;width:1.9rem;height:1.9rem;display:flex;align-items:center;justify-content:center;border:1px solid var(--line);border-radius:8px;background:rgba(167,139,250,.08);font-size:1rem;color:var(--acc)}
.tcard .tt{margin-left:auto}
.tcard .tt{font-size:.68rem;letter-spacing:.22em;color:var(--dim);text-transform:uppercase}
.hero{display:flex;flex-direction:column;gap:1rem;padding:2rem 1.6rem;text-align:left}
.hero .hl{display:flex;align-items:center;gap:.7rem;color:var(--ok);font-size:.9rem;white-space:nowrap}
.hero h2{font-size:clamp(1.7rem,4.2vw,2.7rem);letter-spacing:-.01em;margin:0;line-height:1.12;font-weight:800}
.hero h2 em{font-style:normal;color:var(--acc);text-shadow:0 0 24px rgba(167,139,250,.45)}
.hero .hsub{color:var(--dim);font-size:1rem;line-height:1.6;max-width:640px;margin:0}
.hero .hsub b{color:var(--fg)}
.hero .cta{display:flex;flex-wrap:wrap;gap:.6rem;margin-top:.3rem}
@media(max-width:640px){.hero{padding:1.4rem 1.1rem;text-align:left}}
@media(min-width:700px){.grid2{grid-template-columns:1fr 1fr}}
.tag{display:inline-block;padding:.14rem .6rem;border-radius:999px;font-size:.74rem;border:1px solid;margin:.15rem}
.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;font-size:.9rem;table-layout:auto}
.tblwide{overflow-x:auto;-webkit-overflow-scrolling:touch}
@media(max-width:520px){.tblwide table{table-layout:auto}}
td,th{padding:.6rem .8rem;border-bottom:1px solid var(--line);text-align:left;vertical-align:top;overflow-wrap:anywhere}
tr:last-child td{border-bottom:0}
th{white-space:nowrap}
td code{font-size:.82em}
th{color:var(--dim);text-transform:uppercase;font-size:.75rem;letter-spacing:.06em}
footer{color:var(--dim);padding:2.4rem 1rem 5rem;font-size:.88rem;position:relative;z-index:2;text-align:center;line-height:1.7}
footer a{color:var(--acc)}
code{background:rgba(10,15,30,.9);padding:.08rem .4rem;border-radius:5px;font-size:.86em;word-break:break-all}
a{color:var(--acc2)}
pre{text-align:left;white-space:pre-wrap;overflow-x:auto}
.drop{border:2px dashed #33406b;border-radius:14px;padding:1.8rem 1rem;cursor:pointer;transition:.2s}
.drop:hover,.drop.over{border-color:var(--acc);background:rgba(167,139,250,.06)}
.msg{background:rgba(10,15,30,.75);border-left:3px solid var(--acc);border-radius:0 10px 10px 0;padding:.6rem .9rem;margin:.55rem 0;text-align:left}
.msg.me{border-left-color:var(--acc2)}
.msg .who{color:var(--dim);font-size:.74rem}
.bar{height:7px;background:rgba(10,15,30,.9);border-radius:4px;overflow:hidden}.bar>i{display:block;height:100%;background:linear-gradient(90deg,var(--acc),var(--acc2));width:0;transition:width .5s}
#dev{position:fixed;bottom:14px;right:14px;z-index:45;background:rgba(19,25,44,.92);border:1px solid var(--acc);color:var(--acc);border-radius:999px;padding:.5rem .9rem;font-size:.8rem;text-decoration:none;box-shadow:0 0 18px -6px var(--acc)}
#dev:hover{background:var(--acc);color:#161000}
img{max-width:100%;border-radius:10px}
ul,ol{text-align:left;margin:.6rem 0;padding-left:1.4rem}
li{text-align:left;margin:.45rem 0;line-height:1.65}
li::marker{color:var(--acc)}
.steps{counter-reset:step;list-style:none;padding-left:0;margin:.8rem 0 0}
.steps li{counter-increment:step;position:relative;padding:.55rem 0 .55rem 2.6rem;margin:.35rem 0;color:var(--fg);line-height:1.6}
.steps li::before{content:counter(step);position:absolute;left:0;top:.5rem;width:1.7rem;height:1.7rem;border-radius:50%;border:1px solid var(--acc);color:var(--acc);font-size:.8rem;font-weight:800;display:flex;align-items:center;justify-content:center;background:rgba(167,139,250,.08)}
.steps li b{color:var(--acc)}
.flowrole{display:inline-block;font-size:.68rem;letter-spacing:.18em;text-transform:uppercase;color:var(--acc2);border:1px solid var(--line);border-radius:999px;padding:.1rem .55rem;margin-right:.4rem;vertical-align:middle}
.gridlines{position:fixed;inset:0;z-index:1;pointer-events:none;background:repeating-linear-gradient(0deg,rgba(255,255,255,.012) 0 1px,transparent 1px 3px),linear-gradient(rgba(111,214,255,.03) 1px,transparent 1px),linear-gradient(90deg,rgba(111,214,255,.03) 1px,transparent 1px);background-size:auto,80px 80px,80px 80px;mask-image:linear-gradient(rgba(0,0,0,.7),rgba(0,0,0,.25))}
#acct{display:flex;align-items:center;gap:.4rem;white-space:nowrap}
.abtn{display:inline-flex;align-items:center;font-size:.78rem;letter-spacing:.08em;text-decoration:none;border-radius:999px;padding:.42rem .95rem;border:1px solid var(--line);color:var(--dim);transition:.15s;cursor:pointer}
.abtn:hover{color:var(--acc);border-color:var(--acc);box-shadow:0 0 14px -6px var(--acc)}
.abtn.solid{background:linear-gradient(135deg,var(--acc),var(--acc2));color:#0d0722;border-color:transparent;font-weight:800}
.abtn.solid:hover{filter:brightness(1.15);color:#0d0722}
.achip{display:inline-flex;align-items:center;gap:.3rem;font-size:.72rem;color:var(--acc2);text-decoration:none;border:1px solid var(--line);border-radius:999px;padding:.3rem .7rem}
.achip:hover{border-color:var(--acc2)}
</style><script src="https://supernova.thetempleofdoom.com/static/cosmic-bg.js?v=3" data-theme="lissajous" data-interact="parallax" data-accent="#a06bff"></script></head><body>
<div id="lbar"></div>
<a class=skip href="#main">skip to content</a>
<canvas id="space"></canvas><div class="gridlines"></div><div class="vignette" style="--neb1:{{n1}};--neb2:{{n2}}"></div>
<header><div class="hbar">
<a class=logo href=/ data-t="◈ DARK0RBITS">◈ DARK0RBITS</a>
<div class="dnav">
<a href=/ class={{o('home')}}>HOME</a><a href=/ip class={{o('ip')}}>IP</a><a href=/card class={{o('card')}}>CARD</a>
<a href=/sms class={{o('sms')}}>SMS</a><a href=/proxy class={{o('proxy')}}>PROXY</a>
<a href=/steg class={{o('steg')}}>STEGO</a><a href=/track class={{o('track')}}>TRACK</a>
<a href=/eh class={{o('eh')}}>MAIL-FORENSICS</a><a href=/forensics class={{o('forensics')}}>IMG-FORENSICS</a>
<a href=/phone class={{o('phone')}}>PHONE</a><a href=/user class={{o('user')}}>USER-SLEUTH</a>
<a href=/domain class={{o('domain')}}>DOMAIN</a>
<a href=/canary class={{o('canary')}}>CANARY</a><a href=/deaddrop class={{o('deaddrop')}}>DEAD-DROP</a><a href=/mail class={{o('mail')}}>BURNER-MAIL</a>
<a href=/shot class={{o('shot')}}>SHOT</a><a href=/score class={{o('score')}}>FRAUD-SCORE</a>
<a href=/inbox class={{o('inbox')}}>INBOX</a><a href=/passport class={{o('passport')}}>PASSPORT</a>
<a href=/pass class={{o('pass')}}>PASS</a><a href=/keys class={{o('keys')}}>KEYS</a><a href=/maglab class={{o('maglab')}}>MAG-LAB</a><a href=/beacon class={{o('beacon')}}>PORT BEACON</a><a href=/bssid class={{o('bssid')}}>BSSID RADAR</a><a href=/hooks class={{o('hooks')}}>HOOK-RELAY</a><a href=/face class={{o('face')}}>FACE TRACE</a><a href=/rotator class={{o('rotator')}}>ROTATOR</a><a href=/shelf class={{o('shelf')}}>SHELF</a><a href=/s class={{o('s')}}>SNAP</a><a href=/unfurl class={{o('unfurl')}}>UNFURL</a><a href=/warp class={{o('warp')}}>WARP</a><a href=/tools class={{o('tools')}}>TOOLS</a>
</div>
<div id="acct">{{acct}}</div><button class=burger id=burger onclick="drw()">☰</button>
</div></header>
<div class=drawer id=drawer>
<div class=dhead><span class=logo style=font-size:.85rem>DARK0RBITS — MAP</span><button class=burger onclick="drw()">✕</button></div>
<h4>Intel</h4>
<a class="dl {{o('ip')}}" href=/ip>◈ IP INTEL <small>geo, ASN, ISP, VPN flags — any target</small></a>
<a class="dl {{o('card')}}" href=/card>◈ CARD CHECK <small>luhn + BIN issuer intelligence</small></a>
<a class="dl {{o('maglab')}}" href=/maglab>◈ MAG-LAB <small>browser magstripe studio — ISO 7811 encode, read, batch issue (closed-loop only)</small></a>
<a class="dl {{o('eh')}}" href=/eh>◈ MAIL FORENSICS <small>true origin, relay delays, spoof flags, .eml import</small></a>
<a class="dl {{o('forensics')}}" href=/forensics>◈ IMAGE FORENSICS <small>EXIF, GPS, ELA, edit detection</small></a>
<a class="dl {{o('phone')}}" href=/phone>◈ PHONE LOOKUP <small>carrier, line type, region, timezone — any number</small></a>
<a class="dl {{o('user')}}" href=/user>◈ USERNAME SLEUTH <small>find one handle across 12+ platforms</small></a>
<a class="dl {{o('domain')}}" href=/domain>◈ DOMAIN RECON <small>RDAP whois, DNS, nameservers, subdomains</small></a>
<h4>Operate</h4>
<a class="dl {{o('sms')}}" href=/sms>◈ SMS RENTAL <small>30-min numbers, refundable</small></a>
<a class="dl {{o('proxy')}}" href=/proxy>◈ PROXY LAB <small>residential egress, geo builder</small></a>
<a class="dl {{o('steg')}}" href=/steg>◈ STEGO LAB <small>hide words in pictures</small></a>
<a class="dl {{o('mail')}}" href=/mail>◈ BURNER MAIL <small>receive-only mailboxes, countdown</small></a>
<h4>Hunt</h4>
<a class="dl {{o('track')}}" href=/track>◈ TRACK FILE <small>opens report back: IP, city, ISP</small></a>
<a class="dl {{o('canary')}}" href=/canary>◈ CANARY TRAPS <small>links, pixels &amp; honeytokens — instant alerts</small></a>
<a class="dl {{o('deaddrop')}}" href=/deaddrop>◈ DEAD-DROP <small>burn-after-read encrypted notes</small></a>
<a class="dl {{o('shot')}}" href=/shot>◈ SCREENSHOT <small>page capture or rendered-text fallback</small></a>
<a class="dl {{o('score')}}" href=/score>◈ FRAUD-SCORE <small>composite IP + email + BIN risk 0-100</small></a>
<a class="dl {{o('tools')}}" href=/tools>◈ FREE TOOLS <small>DNS, headers, JWT, hasher</small></a>
<a class="dl {{o('phone')}}" href=/phone>◈ PHONE LOOKUP <small>osint: carrier + line type + region</small></a>
<a class="dl {{o('user')}}" href=/user>◈ USERNAME SLEUTH <small>osint: handle across platforms</small></a>
<a class="dl {{o('domain')}}" href=/domain>◈ DOMAIN RECON <small>osint: RDAP + DNS + subdomains</small></a>
<a class="dl {{o('beacon')}}" href=/beacon>◈ PORT BEACON <small>Scan canary for servers: heartbeat + touch tripwire in one URL</small></a>
<a class="dl {{o('bssid')}}" href=/bssid>◈ BSSID RADAR <small>WiFi router-MAC (BSSID) to approximate geolocation via crowdsourced DB — map links, accuracy radius, batch runs.</small></a>
<a class="dl {{o('hooks')}}" href=/hooks>◈ HOOK-RELAY <small>instant public webhook inspector — capture, inspect, replay</small></a>
<a class="dl {{o('face')}}" href=/face>◈ FACE TRACE <small>profile-picture triangulation — hash an avatar, harvest a username's pfps, Hamming verdicts</small></a>
<a class="dl {{o('rotator')}}" href=/rotator>◈ ROTATOR <small>consistent browser identity pools with replayable seeds</small></a>
<a class="dl {{o('shelf')}}" href=/shelf>◈ SHELF <small>every burner you own, with live countdowns</small></a>
<a class="dl {{o('s')}}" href=/s>◈ SNAP <small>server-free one-click short links — target lives in the #fragment</small></a>
<a class="dl {{o('unfurl')}}" href=/unfurl>◈ UNFURL <small>Follow every redirect hop manually and dissect the final page</small></a>
<a class="dl {{o('warp')}}" href=/warp>◈ WARP <small>Domain time machine — Wayback snapshots, previews, DNS drift</small></a>
<h4>Account</h4>
<a class="dl {{o('inbox')}}" href=/inbox>◈ INBOX <small>no-KYC messaging</small></a>
<a class="dl {{o('signup')}}" href=/signup>◈ SIGN UP <small>username + password, 10 seconds, no KYC</small></a>
<a class="dl {{o('keys')}}" href=/keys>◈ API KEYS <small>account, balance, metered keys</small></a>
<a class="dl {{o('pass')}}" href=/pass>◈ PASS <small>everything's free now — no pass needed</small></a>
<a class="dl {{o('passport')}}" href=/passport>◈ AGENT PASSPORT <small>machine-readable badge</small></a>
</div>
<main id="main">{{body}}</main>
<footer>DARK0RBITS · built for agents &amp; humans · <a href="{{bmac}}" target=_blank rel=noopener>☕ fuel the lab</a></footer>
<a id=dev href="#" onclick="location.href='mailto:'+atob('bWFrZW1vbmV5czhAcHJvdG9uLm1l')+'?subject=Dark0rbits%20support';return false">✦ REACH THE DEV</a>
<script>{{ CFG_JS }}</script>
<div id=gearbtn onclick="spToggle()" title="settings — space, speed, density, hue" style="position:fixed;left:14px;bottom:14px;z-index:70;width:40px;height:40px;border-radius:50%;border:1px solid var(--line);background:rgba(7,10,19,.85);color:var(--acc);font-size:1.1rem;cursor:pointer;display:flex;align-items:center;justify-content:center" aria-label="settings">⚙</div>
<div id=spanel class="card" style="display:none;position:fixed;left:14px;bottom:62px;z-index:71;width:270px;max-height:76vh;overflow-y:auto;text-align:left" aria-label="site settings">
<b style=color:var(--acc)>TUNABLES</b> <span style="color:var(--dim);font-size:.75rem">(saved to your account — agents: POST /api/settings)</span>
<label class=srow><input type=checkbox id=sbg onchange="spSet('bg',this.checked)"> nebula + starfield</label>
<label class=srow><input type=checkbox id=swarp onchange="spSet('warp',this.checked)"> hyperdrive warp on click</label>
<label class=srow><input type=checkbox id=sparallax onchange="spSet('parallax',this.checked)"> mouse parallax</label>
<label class=srow><input type=checkbox id=sgrid onchange="spSet('grid',this.checked)"> grid overlay</label>
<label class=srow><input type=checkbox id=sscan onchange="spSet('scan',this.checked)"> scanlines</label>
<label class=srow><input type=checkbox id=stoast onchange="spSet('toast',this.checked)"> toasts</label>
<label class=srow><input type=checkbox id=stype onchange="spSet('type',this.checked)"> typed boot text</label>
<label class=srow>star density <input type=range id=sdensity min=0 max=2.5 step=0.1 onchange="spSet('density',this.value)"> <span id=sdensityv></span></label>
<label class=srow>drift speed <input type=range id=sspeed min=0 max=3 step=0.1 onchange="spSet('speed',this.value)"> <span id=sspeedv></span></label>
<label class=srow>twinkle <input type=range id=stwinkle min=0 max=3 step=0.1 onchange="spSet('twinkle',this.value)"> <span id=stwinklev></span></label>
<label class=srow>hue shift <input type=range id=shue min=-180 max=180 step=5 onchange="spSet('hue',this.value)"> <span id=shuev></span></label>
<button style="margin-top:.5rem" onclick="spReset()">reset defaults</button>
<div style="color:var(--dim);font-size:.72rem;margin-top:.4rem">⌘K / Ctrl+K — command palette</div>
</div>
<div id=palwin style="display:none;position:fixed;inset:0;z-index:80;background:rgba(4,6,12,.8);backdrop-filter:blur(4px)" onclick="if(event.target===this)palClose()">
<div class="card" style="max-width:520px;margin:12vh auto;text-align:left">
<input id=pinp placeholder="type a command… (ip, sms, steg, keys, dead-drop, settings…)" style="width:100%;font-size:1rem" oninput="palFilter()" onkeydown="palKey(event)">
<div id=plist style="margin-top:.6rem;max-height:50vh;overflow-y:auto"></div>
</div></div>
<iframe name=playout id=playout style="display:none" title="api playground output"></iframe>
<script defer src="https://analytics.thetempleofdoom.com/script.js" data-website-id="953c15df-ba4c-453a-a7c6-465fa9e3f202"></script>
<script>
function drw(){document.getElementById('drawer').classList.toggle('open')}
document.addEventListener('keydown',function(e){if(e.key==='Escape')document.getElementById('drawer').classList.remove('open')})
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:60px;left:50%;transform:translateX(-50%);background:var(--acc);color:#161000;padding:.55rem 1.1rem;border-radius:10px;font-weight:800;z-index:99';document.body.appendChild(d);setTimeout(function(){d.remove()},1800)}
var lb=document.getElementById('lbar');
function lbGo(){lb.classList.remove('done');lb.style.width='12%';var w=12;var t=setInterval(function(){w=Math.min(w+6,88);lb.style.width=w+'%'},250);window._lbt=t}
function lbDone(){if(window._lbt)clearInterval(window._lbt);lb.style.width='100%';setTimeout(function(){lb.style.width='0';lb.classList.remove('done')},600)}
document.addEventListener('submit',lbGo,true);
document.addEventListener('click',function(e){var a=e.target.closest('a[href]');if(a&&a.getAttribute('href')&&a.getAttribute('href').charAt(0)==='/'){lbGo();setTimeout(lbDone,1200)}},true);
window.addEventListener('load',lbDone);
(function(){
var DRB=window.DRB||{};
function drbN(v){v=parseFloat(v);return isNaN(v)?1:v}
var c=document.getElementById('space'),x=c.getContext('2d'),W,H,stars=[],dust=[];
function rs(){W=c.width=innerWidth;H=c.height=innerHeight;
stars=[];var n=Math.min(340,Math.floor(W*H/7000*drbN(DRB.density||1)));
for(var i=0;i<n;i++)stars.push({x:Math.random()*W,y:Math.random()*H,z:Math.random()+.3,tw:Math.random()*6.28});
dust=[];for(i=0;i<14;i++)dust.push({x:Math.random()*W,y:Math.random()*H,r:40+Math.random()*90,vx:(Math.random()-.5)*.035,vy:(Math.random()-.5)*.028,h:Math.random()<.5?120:265,a:.05+Math.random()*.05});}
rs();addEventListener('resize',rs);
var mx=0,my=0,tx=0,ty=0;
addEventListener('mousemove',function(e){tx=(e.clientX/W-.5);ty=(e.clientY/H-.5)});
addEventListener('touchmove',function(e){if(e.touches[0]){tx=(e.touches[0].clientX/W-.5);ty=(e.touches[0].clientY/H-.5)}},{passive:true});
function frame(){
x.clearRect(0,0,W,H);
if(DRB.bg==='0'){x.clearRect(0,0,W,H);requestAnimationFrame(frame);return;}
var spd=drbN(DRB.speed===undefined?1:DRB.speed),twk=drbN(DRB.twinkle===undefined?1:DRB.twinkle);
if(scurry){
scurry.t-=.012;
if(scurry.t<=0)scurry=null;
else{
for(i=0;i<stars.length;i++){var st=stars[i];
var sx=st.x+mx*st.z*40, sy=st.y+my*st.z*40;
var dx=scurry.x-sx, dy=scurry.y-sy, dist=Math.sqrt(dx*dx+dy*dy)+.001;
var pull=(1.4+st.z)*scurry.t*3.2;
st.x+=dx/dist*pull; st.y+=dy/dist*pull;}}
}
for(var i=0;i<dust.length;i++){var d=dust[i];d.x+=d.vx*spd;d.y+=d.vy*spd;
if(scurry){var ddx=scurry.x-d.x,ddy=scurry.y-d.y,dd=Math.sqrt(ddx*ddx+ddy*ddy)+.001;if(dd<600){d.x+=ddx/dd*scurry.t*2;d.y+=ddy/dd*scurry.t*2}}}
if(d.x<-100)d.x=W+80;if(d.x>W+100)d.x=-80;if(d.y<-100)d.y=H+80;if(d.y>H+100)d.y=-80;
var g=x.createRadialGradient(d.x,d.y,0,d.x,d.y,d.r);
g.addColorStop(0,'hsla('+d.h+',70%,60%,'+d.a+')');g.addColorStop(1,'transparent');
x.fillStyle=g;x.beginPath();x.arc(d.x,d.y,d.r,0,6.29);x.fill();}
mx+=(tx-mx)*.03;my+=(ty-my)*.03;
for(i=0;i<stars.length;i++){var s=stars[i];s.tw+=.011*twk;
var px=s.x+mx*s.z*40, py=s.y+my*s.z*40;
var a=.28+.4*Math.abs(Math.sin(s.tw));
x.fillStyle='rgba(220,228,255,'+(a*s.z)+')';
x.beginPath();x.arc(px,py,s.z*1.25,0,6.29);x.fill();}
requestAnimationFrame(frame);}
var _hue=drbN(DRB.hue||0);
if(_hue){c.style.filter='hue-rotate('+_hue+'deg)';}
frame();
})();
// ---------- live settings binding ----------
function spApply(){
var D=window.DRB||{};
if(!D.bg||D.bg==='0'){var cs=document.getElementById('space');if(cs)cs.style.display='none'}else{var cs2=document.getElementById('space');if(cs2)cs2.style.display='block'}
if(!D.bg||D.bg==='0'){document.querySelectorAll('.vignette,.gridlines').forEach(function(e){e.style.display='none'})}else{
document.querySelectorAll('.vignette').forEach(function(e){e.style.display='block'});
var g=document.querySelector('.gridlines');if(g)g.style.display=(D.grid==='0')?'none':'block';}
var hue=parseFloat(D.hue||0);
document.querySelectorAll('#space,.vignette').forEach(function(e){e.style.filter=hue?('hue-rotate('+hue+'deg)'):''});
}
function spToggle(){var p=document.getElementById('spanel');p.style.display=(p.style.display==='none')?'block':'none';if(p.style.display==='block')spSync()}
function spSync(){
var D=window.DRB||{};
var m={bg:'sbg',warp:'swarp',parallax:'sparallax',grid:'sgrid',scan:'sscan',toast:'stoast',type:'stype'};
Object.keys(m).forEach(function(k){var el=document.getElementById(m[k]);if(el)el.checked=(D[k]!=='0')});
[['density','sdensity'],['speed','sspeed'],['twinkle','stwinkle'],['hue','shue']].forEach(function(pr){
var el=document.getElementById(pr[1]);if(el){el.value=D[pr[0]]||1;var v=document.getElementById(pr[1]+'v');if(v)v.textContent=el.value}});
}
function spSet(k,v){
v=(v===true||v==='true')?'1':(v===false||v==='false')?'0':v;
window.DRB=window.DRB||{};window.DRB[k]=v;spApply();
if(k==='density'){window.DRB.density=v;location.reload();}
fetch('/api/settings',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:k+'='+encodeURIComponent(v)}).then(function(r){return r.json()}).then(function(d){if(d.ok)toast('✓ saved')}).catch(function(){});
}
function spReset(){
var def={bg:'1',warp:'1',parallax:'1',density:'1',speed:'1',twinkle:'1',hue:'0',grid:'1',scan:'1',toast:'1',type:'1'};
var body=Object.keys(def).map(function(k){return k+'='+def[k]}).join('&');
fetch('/api/settings',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:body}).then(function(){location.reload()});
}
// scanline toggle via body class
var _st=document.createElement('style');_st.textContent='.noscan .gridlines{display:none!important}';document.head.appendChild(_st);
new MutationObserver(function(){document.body.classList.toggle('noscan',window.DRB&&window.DRB.scan==='0')}).observe(document.documentElement,{attributes:true,childList:true,subtree:true});
setTimeout(function(){spApply()},0);
// ---------- stars scurry to cursor on background click ----------
var scurry=null; // {x,y,t}
document.addEventListener('pointerdown',function(e){
if(window.DRB&&window.DRB.warp==='0')return;
if(e.target.closest('a,button,input,select,textarea,label,.card,#spanel,#palwin,#gearbtn,#pinp'))return;
scurry={x:e.clientX,y:e.clientY,t:1};
},{passive:true});
document.addEventListener('pointermove',function(e){
if(scurry&&scurry.t>0){scurry.x=e.clientX;scurry.y=e.clientY}
},{passive:true});
// ---------- command palette (⌘K / Ctrl+K) ----------
var PAL=[
['/ip','IP intel — geo, ASN, VPN flags'],
['/card','card BIN + Luhn check'],
['/sms','rent a burner number, 30 min'],
['/proxy','proxy lab — test Pleiades egress'],
['/steg','hide / extract secret text in pictures'],
['/track','trackable files — opens report back'],
['/eh','email forensics — origin, spoof flags, .eml import'],
['/forensics','image forensics — EXIF + ELA'],
['/canary','canary traps — links, pixels, honeytokens'],
['/deaddrop','burn-after-read encrypted notes'],
['/mail','burner mailbox'],
['/shot','screenshot / page capture'],
['/score','fraud score composite'],
['/inbox','no-KYC inbox + login'],
['/keys','API keys + balance'],
['/pass','all-access pass'],
['/passport','agent passport badge'],
['/tools','free tools'],
["/beacon", "scan canary: server heartbeats + port-touch tripwires"],
["/bssid", "WiFi router-MAC geolocation"],
["/hooks", "webhook inspector \u2014 capture, inspect, replay"],
["/face", "avatar pfp triangulation"],
["/rotator", "header rotator \u2014 identity pools + seeds"],
["/shelf", "identity shelf \u2014 every burner + countdowns"],
["/s", "snap \u2014 server-free short links + safety decoder"],
["/unfurl", "redirect chain + page dissection"],
["/warp", "domain time machine \u2014 wayback timeline, previews, DNS drift"],
['/llms.txt','machine catalog for agents'],
['/openapi.json','OpenAPI spec'],
];
var palSel=0;
function palOpen(){var w=document.getElementById('palwin');w.style.display='block';var i=document.getElementById('pinp');i.value='';palRender('');i.focus()}
function palClose(){document.getElementById('palwin').style.display='none'}
function palRender(q){
q=(q||'').toLowerCase();
var el=document.getElementById('plist');el.innerHTML='';
PAL.filter(function(it){return !q||it[0].toLowerCase().indexOf(q)>=0||it[1].toLowerCase().indexOf(q)>=0}).forEach(function(it,idx){
var a=document.createElement('a');a.className='pitem'+(idx===palSel?' sel':'');a.href=it[0];a.innerHTML=it[0]+' <small>'+it[1]+'</small>';
a.onmouseenter=function(){var items=el.querySelectorAll('.pitem');items.forEach(function(x){x.classList.remove('sel')});a.classList.add('sel')};
el.appendChild(a);});
}
function palFilter(){palSel=0;palRender(document.getElementById('pinp').value)}
function palKey(e){
var el=document.getElementById('plist');
if(e.key==='Escape')palClose();
else if(e.key==='ArrowDown'){palSel=Math.min(palSel+1,el.querySelectorAll('.pitem').length-1);palRender(document.getElementById('pinp').value);e.preventDefault()}
else if(e.key==='ArrowUp'){palSel=Math.max(palSel-1,0);palRender(document.getElementById('pinp').value);e.preventDefault()}
else if(e.key==='Enter'){var a=el.querySelectorAll('.pitem')[palSel];if(a)location.href=a.href}
}
document.addEventListener('keydown',function(e){
if((e.metaKey||e.ctrlKey)&&e.key.toLowerCase()==='k'){e.preventDefault();var w=document.getElementById('palwin');(w.style.display==='block')?palClose():palOpen()}
});
// toasts toggle
var _origToast=toast;
toast=function(m){if(window.DRB&&window.DRB.toast==='0')return;_origToast(m)};
// typed boot toggle
if(window.DRB&&window.DRB.type==='0'){var t=document.querySelector('.type');if(t)t.dataset.lines='';}
})();
</script>
</body></html>
"""
NEBULAS = {
"home": ("rgba(120,85,255,.17)", "rgba(0,190,255,.10)"),
"ip": ("rgba(255,170,60,.13)", "rgba(120,85,255,.10)"),
"card": ("rgba(66,232,164,.10)", "rgba(0,190,255,.09)"),
"sms": ("rgba(0,190,255,.13)", "rgba(167,139,250,.10)"),
"proxy": ("rgba(167,139,250,.14)", "rgba(255,170,60,.08)"),
"steg": ("rgba(255,110,180,.11)", "rgba(120,85,255,.11)"),
"track": ("rgba(255,90,90,.11)", "rgba(255,170,60,.08)"),
"mail": ("rgba(66,232,164,.10)", "rgba(0,190,255,.08)"),
"forensics": ("rgba(0,210,255,.12)", "rgba(255,110,180,.07)"),
"canary": ("rgba(255,201,77,.12)", "rgba(255,90,90,.08)"),
"deaddrop": ("rgba(45,226,200,.13)", "rgba(160,225,255,.09)"),
"shot": ("rgba(111,214,255,.12)", "rgba(120,85,255,.10)"),
"score": ("rgba(255,110,180,.10)", "rgba(66,232,164,.10)"),
"warp": ("rgba(255,110,180,.11)", "rgba(120,85,255,.11)"),
"unfurl": ("rgba(255,110,180,.11)", "rgba(120,85,255,.11)"),
"s": ("rgba(111,214,255,.12)", "rgba(167,139,250,.10)"),
"shelf": ("rgba(66,232,164,.11)", "rgba(255,170,60,.09)"),
"rotator": ("rgba(111,214,255,.12)", "rgba(167,139,250,.10)"),
"face": ("rgba(255,110,180,.11)", "rgba(120,85,255,.11)"),
"hooks": ("rgba(255,110,180,.11)", "rgba(120,85,255,.11)"),
"bssid": ("rgba(255,110,180,.11)", "rgba(120,85,255,.11)"),
"beacon": ("rgba(255,110,180,.11)", "rgba(120,85,255,.11)"),
}
def kv(pairs):
rows = "".join(f"<div>{k}</div><div>{v}</div>" for k, v in pairs)
return '<div class="card glow"><div class="kv">' + rows + "</div></div>"
def page(sec, body):
n1, n2 = NEBULAS.get(sec, ("rgba(120,85,255,.16)", "rgba(0,190,255,.10)"))
uid = current_user_id()
acct = ""
if uid:
try:
con = db()
u = con.execute("SELECT username FROM users WHERE id=?", (uid,)).fetchone()
bal = get_balance(uid)
pas = has_pass(uid)
acct = ('<a class=achip href=/keys title="balance — click for API keys & top-up">'
+ ("★ PASS · " if pas else "") + "◈ $" + f"{bal/100:.2f}" + " · " + esc(u["username"]) + "</a>"
+ ' <a class=abtn href=/logout title="log out">EXIT</a>')
except Exception:
acct = ""
if not uid or not acct:
nxt = ("?next=" + urllib.parse.quote(request.path)) if request.path not in ("/", "/inbox", "/signup", "/logout") else ""
acct = ('<a class=abtn href=/inbox' + nxt + ' title="log in — username + password, nothing else">LOG IN</a>'
' <a class="abtn solid" href=/signup' + nxt + ' title="create account — username + password, ~10 seconds, no KYC">SIGN UP</a>')
from markupsafe import Markup
st = get_settings(uid)
return render_template_string(BASE, body=Markup(body), bmac=BMAC, o=lambda s2: "on" if s2 == sec else "",
n1=n1, n2=n2, acct=Markup(acct),
CFG_JS="window.DRB=" + json.dumps(st) + ";")
def _checkout_or_json(payload):
"""If a browser form POSTed (no JSON accept / no X-Requested-With), redirect to
the BTCPay checkout page instead of showing raw JSON."""
wants_html = "text/html" in (request.headers.get("Accept") or "") and "application/json" not in (request.headers.get("Accept") or "")
link = payload.get("checkoutLink") if isinstance(payload, dict) else None
if wants_html and link:
return Redirect(link)
return jsonify(payload)
def Redirect(u):
from flask import redirect as _r
return _r(u)
def agent_card(endpoint, example, notes):
"""Interactive-for-LLMs card: exact curl + auth + link to openapi."""
return ('<div class=card style=color:var(--dim);font-size:.85rem><b style=color:var(--fg)>FOR AGENTS</b> '
'<span title="Every tool is callable over JSON. Auth: account session cookie, API key (Authorization: Bearer dk_…) or PASS.">?</span><br>'
'<code style=color:var(--ok)>' + esc(endpoint) + '</code><br>'
'<code style=white-space:pre-wrap;display:block;margin:.3rem 0;padding:.5rem .7rem;border-radius:8px;background:rgba(10,15,30,.95)>' + esc(example) + '</code>'
'<button style=padding:.2rem .6rem;font-size:.75rem;margin-right:.5rem data-cmd="' + esc(example) + '" onclick="cp(this.dataset.cmd)">copy curl</button>' + esc(notes) +
' · spec: <a href=/openapi.json style=color:var(--acc)>/openapi.json</a> · catalog: <a href=/llms.txt style=color:var(--acc)>/llms.txt</a></div>')
def gloss(terms):
chips = " ".join('<span class=tchip title="' + esc(d) + '" style="border:1px solid var(--line);border-radius:999px;padding:.25rem .75rem;cursor:help;display:inline-block;margin:.2rem .15rem;background:rgba(10,15,30,.6)">' + esc(t) + '</span>' for t, d in terms)
return '<div class=card style=color:var(--dim);font-size:.85rem><b style=color:var(--fg)>JARGON</b> — hover any chip:<div style=margin-top:.4rem>' + chips + '</div></div>'
def how(steps):
lis = "".join(f"<li>{esc(s)}</li>" for s in steps)
return f'<div class=card><b>HOW IT WORKS</b><ol style="color:var(--dim);margin:.6rem 0 0;padding-left:1.5rem">{lis}</ol></div>'
def flow(title, steps):
"""Concrete example flow: numbered scene-by-scene walkthrough with role chips."""
lis = "".join(f"<li>{s}</li>" for s in steps) # steps carry their own <b>/<span> markup
return f'<div class=card><b>EXAMPLE FLOW — {esc(title)}</b><ol class=steps>{lis}</ol></div>'
# ---------- AGENT DISCOVERY ----------
LLMS_SETTINGS = """
## ACCOUNT TUNABLES (machine-settable)
GET/POST /api/settings — keys: bg, warp, parallax, density (0-2.5), speed (0-3), twinkle (0-3), hue (-180-180), grid, scan, toast, type (1|0).
Agents driving browsers (or building clients) can persist a theme per API key: POST form-encoded key=value. Values validated server-side.
## KEYBOARD
Ctrl+K / Cmd+K — command palette on any page. Type tool name, Enter navigates.
"""
API_INDEX = {
"service": "dark0rbits",
"description": "IP intel, card BIN validation, 30-min SMS rentals, residential proxy lab, steganography, trackable files, no-KYC messaging, utilities.",
"endpoints": [
{"method": "GET", "path": "/signup", "desc": "No-KYC signup page (humans): username + password, 4+ chars, ~10 seconds. Agents: POST /inbox form act=register&u=NAME&p=PASS -> session cookie dark0rbits_tok (30 days) + $1 free trial credit."},
{"method": "GET/POST", "path": "/api/settings", "desc": "Per-account UI tunables (bg, warp, parallax, density, speed, twinkle, hue, grid, scan, toast, type). Agents can theme their own client. GET returns current; POST form key=val applies (validated + clamped)."},
{"method": "GET", "path": "/deaddrop", "desc": "Burn-after-read encrypted notes. POST /api/deaddrop/create (body, burn_after 1-10, ttl_hours 1-72, password optional) -> token. FREE."},
{"method": "GET", "path": "/shot", "desc": "Page capture: POST /api/shot/create {url} then GET /api/shot/status/<id>. SSRF-guarded. FREE."},
{"method": "GET", "path": "/score", "desc": "Composite fraud score: IP 45% + disposable-email 25% + BIN 30%. FREE."},
{"method": "GET", "path": "/api/ip?target=", "desc": "Caller IP intel (auto) or any IP you pass: geo, ASN, ISP, VPN/hosting flags, rDNS."},
{"method": "GET", "path": "/api/phone?num=", "desc": "Phone OSINT: validity, country, region, carrier, line type (mobile/landline/voip), timezones, risk flags + free deep-dive lead links. Any format."},
{"method": "GET", "path": "/api/user?u=", "desc": "Username OSINT: probes 16 platforms in parallel (GitHub, Reddit, Telegram, Steam…) → per-site found/not-found/unknown + lead links."},
{"method": "GET", "path": "/api/domain?d=", "desc": "Domain OSINT: RDAP registration (registrar/dates/status), full DNS (A/AAAA/MX/NS/TXT/CNAME via DoH), certificate-transparency subdomains. Passive."},
{"method": "POST", "path": "/api/forensics", "files": ["image"], "desc": "Deep image forensics: all EXIF IFDs, decoded GPS + map links, XMP, embedded thumbnail, hashes, editor flags, ELA verdict."},
{"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 free trackable file. Returns upload_url + token. Login required (POST /inbox act=register)."},
{"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."},
{"method": "POST", "path": "/api/deaddrop/create", "params": {"body": "note text (max 8000 chars)", "burn_after_reads": "1-10", "ttl_hours": "1-72", "password": "optional"}, "desc": "AES-GCM encrypted burn-after-read note. Returns /drop/<token> URL. FREE. Reads decrement; note self-destructs at 0 or at TTL."},
{"method": "GET", "path": "/drop/<token>", "desc": "Read a dead-drop (password-protected if set). Each view burns one read."},
{"method": "POST", "path": "/api/shot/create", "params": {"url": "http(s):// target"}, "desc": "Screenshot queue. Headless Chromium PNG if available, else rendered-text capture (status=text_fallback). FREE. Poll /api/shot/status/<id>."},
{"method": "GET", "path": "/api/shot/status/<id>", "desc": "Shot result: base64 PNG (png_b64) or text preview + page intel."},
{"method": "POST", "path": "/api/beacon/create", "params": {"label": "server name", "port": "disguise port 0-65535", "interval_min": "heartbeat minutes 1-1440"}, "desc": "Create a port beacon: returns token, probe_url and a ready-to-run install snippet (curl one-liner + systemd service/timer). Server curls the probe URL as heartbeat; non-heartbeat fetches are canary hits."},
{"method": "GET", "path": "/api/beacon/list", "desc": "All your beacons with status (LIVE/LATE/SILENT/WAITING), last_seen, interval, canary hit counts and probe URLs. Lazily flips overdue beacons to SILENT + fires one inbox alert per outage."},
{"method": "GET", "path": "/api/beacon/status", "params": {"token": "beacon token"}, "desc": "Single beacon status: state machine, last_seen, silent_notified flag, canary_hits count."},
{"method": "GET", "path": "/bssid", "desc": "BSSID RADAR tool page: paste one WiFi BSSID or a batch (one per line), any MAC format, get approximate router geolocation with map links + accuracy radius. Human-friendly with live normalization preview."},
{"method": "GET", "path": "/api/bssid?mac=", "desc": "BSSID geolocation: normalize any MAC spelling, query OSINT bssid_geo (Mylnikov free DB) server-side. Returns lat/lon, accuracy_m, Google/OSM map links, wigle fallback. Batch: ?macs=a;b;c (up to 25). Rate limit 20/min."},
{"method": "POST", "path": "/api/hook/create", "params": {"label": "optional name"}, "desc": "Create a webhook capture endpoint. Login required. Returns unique URL {SITE}/hook/<token> that accepts GET/POST/PUT with ANY content-type — no auth on capture (webhooks come from outside). Records headers, body (32KB cap), query, IP, UA into hook_hits."},
{"method": "GET", "path": "/api/hook/list", "desc": "Your hook endpoints with hit counts, last-hit timestamps and capture URLs. Login required."},
{"method": "GET", "path": "/api/hook/hits?token=", "params": {"token": "hook token", "limit": "1-500, default 100"}, "desc": "Captured hits for one endpoint: method, ts, ip, ua, content-type, source badge (Stripe/GitHub/Discord/Shopify/Telegram auto-detected), full headers, query, body. Login required."},
{"method": "POST", "path": "/api/hook/replay", "params": {"hit_id": "captured hit id", "target_url": "https:// destination"}, "desc": "Resend a captured hit (original method, headers, body) to any public URL via http(). SSRF-guarded: 10.x / 127. / 172.16-31 / 169.254 and reserved ranges refused. Login required."},
{"method": "POST", "path": "/api/face", "files": ["image"], "params": {"u": "username (optional)"}, "desc": "Face trace: fingerprint an uploaded avatar (dHash 9x8 + aHash 8x8 + sha256, computed locally), harvest the username's avatars (GitHub + Reddit APIs, Telegram/Steam/Twitch constructed links), compare via Hamming distance (<=10/64 = likely same image) + manual reverse-image lead links. No external reverse-image APIs called."},
{"method": "GET", "path": "/api/rotator?platform=&n=&seed=", "desc": "Spin 1-25 consistent browser identities (UA, referer, Accept-Language, DNT) from desktop/mobile/agent/stealth pools. Same seed = same rotation. Returns identities + ready-made curl. FREE, 20/min."},
{"method": "GET", "path": "/api/rotator/pools", "desc": "Pool sizes: desktop, mobile, agent, stealth + referer/language counts."},
{"method": "GET", "path": "/api/shelf", "desc": "Identity shelf: all your mailboxes, SMS numbers, dead-drops, canaries + expiry stats in one JSON. Login required. Perfect for expiry-monitoring crons."},
{"method": "POST", "path": "/api/snap/decode", "desc": "Decode a snap link fragment (raw = text after #) WITHOUT opening it: returns target URL + host + scheme check. The shortener itself is server-free — targets ride in the #fragment and nothing is stored. FREE 60/min."},
{"method": "GET", "path": "/unfurl", "desc": "URL unfurl: follows every redirect hop one at a time (scheme, host, status, Location) and dissects the final page (title, meta/og tags, iframes, forms). Detects loops and refuses non-http schemes. FREE."},
{"method": "GET", "path": "/api/unfurl", "params": {"url": "http(s):// target", "max_hops": "1-10 default 6", "extract": "0|1"}, "desc": "Full redirect chain + final-page metadata as JSON. 401 without session/key; rate-limited. FREE."},
{"method": "GET", "path": "/api/unfurl/history", "desc": "Your last 25 unfurl lookups (url, final_url, status, ts). Login required."},
{"method": "GET", "path": "/warp", "desc": "Domain time machine (humans): Wayback Machine snapshot timeline per year, screenshot previews of archived copies, DNS/whois drift table, hosted-path inventory. Passive, cached 6h."},
{"method": "GET", "path": "/api/warp?domain=", "desc": "Archive intel JSON: CDX snapshot timeline (collapsed per year), DNS/RDAP drift (oldest vs current), distinct archived paths. Free, no key needed, cached 6h per domain."},
{"method": "GET", "path": "/api/score?ip=&email=&bin=", "desc": "Composite fraud score 0-100 + weighted breakdown: IP intel (VPN/hosting/abuse geo), disposable-email domain, BIN country/type risk. FREE."},
{"method": "POST", "path": "/canary", "desc": "Create canary trap. Form: tag, kind (link|pixel|cred|file), rearm (0|1). Login required. Link = /c/<token>, pixel = /c/<token>.png, honeyfile = /c/<token>/download, credential returned by /api/canary/list."},
{"method": "GET", "path": "/api/canary/list", "desc": "Your traps with hit counts, links, generated honeytoken credentials. Login required."},
{"method": "GET", "path": "/api/canary/hits?token=", "desc": "Full hit log for a trap: ts, ip, ua, lang, ref + geolocated city/ISP/VPN flags per hit. Login required."},
{"method": "POST", "path": "/api/eh", "desc": "Email header forensics v2: origin IP (+source), origin_geo, hop chain, per-hop relay delays (delays), SPF/DKIM/DMARC verdicts, spoof flags. Handles pasted headers or .eml content. FREE 20/min."},
],
"payment": "EVERYTHING IS FREE — the lab absorbs all costs (SMS rentals, mail, trackables, screenshots). No top-ups needed.",
}
@app.route("/api/settings", methods=["GET", "POST"])
def api_settings():
uid = key_user() or current_user_id()
if not uid:
return jsonify({"ok": False, "error": "auth required: account session or API key"}), 401
if request.method == "GET":
return jsonify({"ok": True, "settings": get_settings(uid)})
out = {}
for k in DEFAULT_SETTINGS:
if k in request.form:
out[k] = set_setting(uid, k, request.form[k])
return jsonify({"ok": True, "applied": out, "settings": get_settings(uid)})
@app.route("/api")
def api_index(): return jsonify(API_INDEX)
@app.route("/robots.txt")
def robots(): return "User-agent: *\nAllow: /\nSitemap: https://dark0rbits.thetempleofdoom.com/sitemap.xml\n", 200, {"Content-Type": "text/plain"}
@app.route("/a8f3dark0rbitskey.txt")
def indexnow_key(): return "a8f3d4rk0rbits9e2b1c7x5k8m2v4q6t8", 200, {"Content-Type": "text/plain"}
INDEXNOW = "a8f3d4rk0rbits9e2b1c7x5k8m2v4q6t8"
@app.route("/sitemap.xml")
def sitemap():
S = "https://dark0rbits.thetempleofdoom.com"
pages = ["", "ip", "card", "sms", "proxy", "steg", "track", "eh", "forensics", "phone", "user", "domain", "canary", "deaddrop", "shot", "score", "mail", "inbox", "passport", "pass", "keys", "maglab", "tools", "signup", "beacon"]
xml = '<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' + "".join(f"<url><loc>{S}/{p}</loc><changefreq>weekly</changefreq></url>" for p in pages) + "</urlset>"
return xml, 200, {"Content-Type": "application/xml"}
@app.route("/llms.txt")
def llms():
eps = "\n".join(f"- `{e['method']} {e['path']}` — {e['desc']}" for e in API_INDEX["endpoints"])
return f"# Dark0rbits\n\nBase: {SITE}\n\n## API\n{eps}\n{LLMS_SETTINGS}", 200, {"Content-Type": "text/plain"}
@app.route("/ai-plugin.json")
def aiplugin():
return jsonify({"name_for_model": "dark0rbits", "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": "makemoneys8@proton.me"})
@app.route("/openapi.json")
def openapi():
ps = {"openapi": "3.0.0", "info": {"title": "DARK0RBITS", "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/phone", "get", "Phone OSINT: carrier, line type, region, timezones, leads", {"num": "phone number, any format"}, req=True)
add("/api/user", "get", "Username OSINT probe across 16 platforms", {"u": "username"}, req=True)
add("/api/domain", "get", "Domain recon: RDAP + DNS + CT subdomains", {"d": "domain"}, req=True)
add("/api/forensics", "post", "Deep image forensics: EXIF IFDs, GPS decoded, XMP, thumbnail, ELA", files=["image"])
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)
add("/api/deaddrop/create", "post", "Encrypted burn-after-read note", {"body": "text", "burn_after_reads": "1-10", "ttl_hours": "1-72", "password": "optional"}, req=True)
add("/drop/{token}", "get", "Read a dead-drop (burns one read)")
add("/api/shot/create", "post", "Queue page capture", {"url": "target url"}, req=True)
add("/api/shot/status/{id}", "get", "Shot result (png_b64 or text_fallback)")
add("/api/score", "get", "Composite fraud score 0-100", {"ip": "opt", "email": "opt", "bin": "opt"})
add("/canary", "post", "Create canary trap (tag, kind, rearm)", {"tag": "label", "kind": "link|pixel|cred|file", "rearm": "0|1"}, req=True)
add("/api/canary/list", "get", "Your traps + hit counts + honeytoken creds")
add("/api/canary/hits", "get", "Full hit log with geo per hit", {"token": "trap token"}, req=True)
add("/api/eh", "post", "Email header forensics v2 (origin, delays, verdicts, flags)", {"raw": "full headers or .eml content"}, req=True)
add("/api/beacon/create", "post", "Create a port beacon (heartbeat + canary URL) with install snippet", {"label": "my-server", "port": 22, "interval_min": 5}, req=True)
add("/api/beacon/list", "get", "List beacons: status LIVE/LATE/SILENT/WAITING, last_seen, hits", {}, req=True)
add("/api/beacon/status", "get", "One beacon status by token", {"token": "AbC123"}, req=True)
add("/api/bssid", "get", "WiFi BSSID -> approximate geolocation (Mylnikov DB via LAN OSINT terminal). Any MAC format accepted; batch via macs=a;b;c.", {"mac": "AA:BB:CC:DD:EE:FF"}, req=True)
add("/api/hook/create", "post", "Create webhook capture endpoint (returns /hook/<token> URL)", {"label": "optional label"})
add("/api/hook/list", "get", "Your hook endpoints + hit counts")
add("/api/hook/hits", "get", "Captured hits for one hook (auto-detected source, headers, body)", {"token": "hook token", "limit": "opt 1-500"}, req=True)
add("/api/hook/replay", "post", "Replay a captured hit to any public URL (SSRF-guarded)", {"hit_id": "hit id", "target_url": "https:// target"}, req=True)
add("/api/face", "post", "Avatar fingerprint + username pfp harvest + Hamming verdict", {"u": "username (optional)"}, files=["image"])
add("/api/rotator", "get", "Spin consistent browser identities (UA+referer+language+DNT), optional deterministic seed", {"platform": "desktop|mobile|agent|stealth", "n": "1-25", "seed": "optional"})
add("/api/rotator/pools", "get", "Pool inventory")
add("/api/shelf", "get", "Identity shelf — all burners + expiry stats (login)")
add("/api/snap/decode", "post", "Decode snap-link fragment safely (no visit)", {"raw": "fragment after #"}, req=True)
add("/api/unfurl", "get", "Unfurl a URL: follow redirects hop-by-hop, dissect final page", {"url": "https://bit.ly/abc", "max_hops": "6"}, req=True)
add("/api/unfurl/history", "get", "Your last 25 unfurl lookups", {}, req=True)
add("/api/warp", "get", "Domain time machine: Wayback timeline, screenshot-preview links, DNS/whois drift, hosted paths. Cached 6h.", {"domain": "example.com"}, req=True)
add("/signup", "get", "No-KYC signup page (username + password only)")
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 = "WHAT'S <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>""" + how(["Your IP is auto-detected the moment the page loads — no input needed.","Type any other IP or hostname into the field for the same full report.","Everything is one GET away for agents: /api/ip and /api/ip?target=.","VPN/proxy/hosting flags come from IP-quality heuristics — if it says proxy, you are looking at a relay."])
body += gloss([("ASN","Autonomous System Number — the network operator that owns this route"),("rDNS","reverse DNS — hostname pointer for an IP"),("hosting","datacenter/cloud IP, not a home connection"),("VPN/proxy","known tunnel or relay range")])
body += agent_card('GET /api/ip?target=1.2.3.4', 'curl "https://dark0rbits.thetempleofdoom.com/api/ip?target=1.2.3.4" -H "Authorization: Bearer drb_..."', 'Auto-detects caller IP if target omitted.')
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():
r = rate_limit("iptarget", 40, 60)
if r: return r
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
# ---------- 2b. PHONE LOOKUP (OSINT, offline metadata + free lead links) ----------
def phone_report(raw):
out = {"ok": False}
try:
import phonenumbers as pn
from phonenumbers import carrier as pncarrier, timezone as pntz, geocoder as pngeo
n = pn.parse(raw.strip(), None)
except Exception as e:
out["error"] = f"cannot parse number: {e}"[:200]
return out
out["ok"] = True
out["e164"] = pn.format_number(n, pn.PhoneNumberFormat.E164)
out["national"] = pn.format_number(n, pn.PhoneNumberFormat.NATIONAL)
out["international"] = pn.format_number(n, pn.PhoneNumberFormat.INTERNATIONAL)
out["valid"] = pn.is_valid_number(n)
out["possible"] = pn.is_possible_number(n)
out["country"] = pn.region_code_for_country_code(n.country_code or 0)
try: out["country_calling_code"] = f"+{n.country_code}"
except Exception: pass
try:
out["region_desc"] = pngeo.description_for_number(n, "en") or ""
except Exception: out["region_desc"] = ""
try:
out["carrier"] = pncarrier.name_for_number(n, "en") or ""
except Exception: out["carrier"] = ""
try:
out["timezones"] = list(pntz.time_zones_for_number(n))
except Exception: out["timezones"] = []
tmap = {0:"fixed_line",1:"mobile",2:"fixed_or_mobile",3:"freephone",4:"premium_rate",5:"shared_cost",6:"voip",7:"personal_number",8:"pager",9:"uan",10:"voicemail"}
try:
t = pn.number_type(n)
out["line_type"] = tmap.get(t, "unknown")
out["line_type_risk"] = ("voip/uan numbers are often disposable or bulk-registered" if t in (6, 9) else "")
except Exception: out["line_type"] = "unknown"
q = out["e164"]
out["leads"] = {
"google": "https://www.google.com/search?q=%22" + urllib.parse.quote(q) + "%22",
"duckduckgo": "https://duckduckgo.com/?q=" + urllib.parse.quote(q),
"truecaller": "https://www.truecaller.com/search/" + (out["country"] or "us").lower() + "/" + q.lstrip("+"),
}
if out["line_type"] == "voip": out.setdefault("flags", []).append("voip — high disposable/spoof potential")
if not out["valid"]: out.setdefault("flags", []).append("not a valid number — fake or mistyped")
return out
@app.route("/phone", methods=["GET", "POST"])
def phone_tool():
res = ""
if request.method == "POST":
raw = param("num") or ""
if raw.strip():
d = phone_report(raw)
if d.get("ok"):
res = kv([
("Number", f'<b style="font-size:1.15rem;color:var(--acc)">{esc(d["e164"])}</b> ({esc(d["national"])})'),
("Valid", '<span class="tag ok">VALID</span>' if d["valid"] else '<span class="tag bad">NOT VALID</span>'),
("Country", esc(d["country"]) + " " + esc(d["country_calling_code"])),
("Region", esc(d["region_desc"]) or "—"),
("Carrier", esc(d["carrier"]) or "—"),
("Line type", esc(d["line_type"])),
("Timezones", esc(", ".join(d["timezones"])) or "—"),
])
if d.get("flags"):
res += '<div class="card"><b>Flags</b><br>' + "<br>".join('<span class="tag bad" style="margin:.15rem">' + esc(f) + "</span>" for f in d["flags"]) + "</div>"
l = d["leads"]
res += f'''<div class="card"><b>Deep-dive leads (free public sources)</b><br>
<a href="{esc(l['google'])}" target=_blank rel=noopener style=color:var(--acc)>Google the exact number →</a> ·
<a href="{esc(l['duckduckgo'])}" target=_blank rel=noopener style=color:var(--acc)>DuckDuckGo →</a> ·
<a href="{esc(l['truecaller'])}" target=_blank rel=noopener style=color:var(--acc)>TrueCaller web search →</a></div>'''
else:
res = f'<div class="card"><span class="tag bad">PARSE FAILED</span><br>{esc(d.get("error"))}</div>'
body = f"""
<h1>PHONE <span>LOOKUP</span></h1><p class=sub>Parse + intel on any number worldwide: validity, country, region, carrier, line type (mobile/landline/VOIP), timezones — plus free deep-dive lead links. No KYC, no logs.</p>
<div class=card><form method=post><input name=num placeholder="+1 425 555 0100 — any format, any country" style=width:70% required><button style=margin-top:.5rem>Lookup</button></form></div>
{res}
<div class=card style=color:var(--dim)>API: GET /api/phone?num=%2B14255550100 → JSON: valid, country, region, carrier, line_type, timezones, flags, lead links.</div>""" + how(["Type the number in any format — country code, spaces, dashes, all handled.",
"Metadata comes from offline libphonenumber data — instant and private, nothing phoned home.",
"Line type matters: VOIP/UAN numbers are the disposable, bulk-registered kind.",
"Follow the lead links for the human layer: public mentions, directory listings, name lookups.",
"Pair it with SMS RENTAL — know the number type before you verify with it."])
body += gloss([("E164","the international standard format: + and country code, no spaces"),("line type","mobile vs landline vs VOIP — carriers publish the ranges"),("VOIP","internet-based number — cheap, disposable, often spoofed")])
body += agent_card('GET /api/phone?num=%2B14255550100', 'curl "https://dark0rbits.thetempleofdoom.com/api/phone?num=%2B14255550100"', 'valid, country, region, carrier, line_type, timezones, flags + free lead links.')
return page("phone", body)
@app.route("/api/phone", methods=["GET", "POST"])
def api_phone():
r = rate_limit("phone", 30, 60)
if r: return r
raw = (param("num") or "").strip()
if not raw: return jsonify({"ok": False, "error": "num required (any format, country code encouraged)"}), 400
return jsonify(phone_report(raw))
# ---------- 2c. USERNAME SLEUTH (OSINT profile probe) ----------
USER_SITES = [
("GitHub", "https://github.com/{u}"),
("GitLab", "https://gitlab.com/{u}"),
("Reddit", "https://www.reddit.com/user/{u}/"),
("Telegram", "https://t.me/{u}"),
("Medium", "https://medium.com/@{u}"),
("Pastebin", "https://pastebin.com/u/{u}"),
("Keybase", "https://keybase.io/{u}"),
("About.me", "https://about.me/{u}"),
("SoundCloud", "https://soundcloud.com/{u}"),
("Vimeo", "https://vimeo.com/{u}"),
("Steam", "https://steamcommunity.com/id/{u}"),
("Last.fm", "https://www.last.fm/user/{u}"),
("Dribbble", "https://dribbble.com/{u}"),
("Imgur", "https://imgur.com/user/{u}"),
("Chess.com", "https://www.chess.com/member/{u}"),
("Twitch", "https://www.twitch.tv/{u}"),
]
def _probe_site(name, url):
st, b = http(url, timeout=10)
if st == 200:
return {"site": name, "url": url, "status": "found", "http": st}
if st == 404:
return {"site": name, "url": url, "status": "not found", "http": st}
return {"site": name, "url": url, "status": "unknown", "http": st, "note": "site blocked or rate-limited the probe — check manually"}
def user_probe(u):
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=8) as ex:
results = list(ex.map(lambda s: _probe_site(s[0], s[1].format(u=urllib.parse.quote(u))), USER_SITES))
found = [r for r in results if r["status"] == "found"]
return {"ok": True, "username": u, "found": found, "results": results,
"hits": len(found), "leads": {
"google": "https://www.google.com/search?q=%22" + urllib.parse.quote(u) + "%22",
"instantusername": "https://instantusername.com/#/" + urllib.parse.quote(u)}}
@app.route("/user", methods=["GET", "POST"])
def user_tool():
res = ""
if request.method == "POST":
u = (param("u") or "").strip()
if u and 2 <= len(u) <= 60 and all(c not in "<>\"'" for c in u):
d = user_probe(u)
rows = "".join(f'<tr><td>{esc(r["site"])}</td><td><span class="tag {"ok" if r["status"]=="found" else ("warn" if r["status"]=="unknown" else "")}">{esc(r["status"])}</span></td><td><a href="{esc(r["url"])}" target=_blank rel=noopener style=color:var(--acc)>{esc(r["url"])}</a></td><td>{r.get("http")}</td></tr>' for r in d["results"])
res = kv([("Username", esc(u)), ("Profiles found", f'<b style="color:var(--ok)">{d["hits"]}</b> of {len(USER_SITES)} platforms')])
res += f'<div class="card"><b>Probe results</b><table><tr><th>Site</th><th>Status</th><th>URL</th><th>HTTP</th></tr>{rows}</table></div>'
res += f'<div class="card"><b>More leads</b><br><a href="{esc(d["leads"]["google"])}" target=_blank rel=noopener style=color:var(--acc)>Google the exact handle →</a> · <a href="{esc(d["leads"]["instantusername"])}" target=_blank rel=noopener style=color:var(--acc)>InstantUsername (60+ sites) →</a></div>'
body = f"""
<h1>USERNAME <span>SLEUTH</span></h1><p class=sub>Give it a handle — it probes {len(USER_SITES)} major platforms in parallel and reports where that username lives. Classic OSINT footwork, automated.</p>
<div class=card><form method=post><input name=u placeholder="one handle, e.g. johndoe1987" style=width:70% required><button style=margin-top:.5rem>Probe</button></form></div>
{res}
<div class=card style=color:var(--dim)>API: GET /api/user?u=NAME → JSON with per-site found/not-found/unknown.</div>""" + how(["Type the handle — no @, no https, just the name.",
"Sixteen sites get probed at once — GitHub, Reddit, Telegram, Steam and more.",
"FOUND = a live profile answered on that exact URL. Unknown = the site blocked the probe (check manually).",
"Follow the Google/InstantUsername leads for the long tail of smaller platforms.",
"Same handle on multiple sites = the same human. That's the whole point."])
body += gloss([("probe","an HTTP GET that never logs in or scrapes private data"),("handle","the username part of a profile URL"),("correlation","linking profiles across sites by shared handle")])
body += agent_card('GET /api/user?u=somehandle', 'curl "https://dark0rbits.thetempleofdoom.com/api/user?u=somehandle"', 'Per-site found/not-found/unknown + lead links. ~8s, all probes in parallel.')
return page("user", body)
@app.route("/api/user", methods=["GET", "POST"])
def api_user():
r = rate_limit("user", 10, 60)
if r: return r
u = (param("u") or "").strip()
if not u or len(u) > 60 or any(c in "<>\"'" for c in u): return jsonify({"ok": False, "error": "u required (max 60 chars, no html)"}), 400
return jsonify(user_probe(u))
# ---------- 2d. DOMAIN RECON (RDAP + DNS + subdomains) ----------
def domain_report(d):
d = d.strip().lower().replace("https://", "").replace("http://", "").split("/")[0]
out = {"ok": True, "domain": d}
st, b = http("https://rdap.org/" + urllib.parse.quote(d), timeout=15)
rd = jf(b)
if rd:
out["rdap"] = {k: rd.get(k) for k in ("handle", "ldhName", "status", "events", "entities", "nameservers") if rd.get(k)}
evs = {}
for e in rd.get("events") or []:
evs[e.get("eventAction", "?")] = e.get("eventDate")
out["events"] = evs
ents = []
for e in rd.get("entities") or []:
roles = e.get("roles") or []
fn = ""
try:
v = e.get("vcardArray") or []
for item in (v[1] if len(v) > 1 else []):
if item and item[0] == "fn": fn = item[3]
except Exception: pass
if "registrar" in roles or "registrant" in roles: ents.append({"roles": roles, "name": fn})
out["entities"] = ents
else:
out["rdap_error"] = f"rdap.org returned {st}"
doh = "https://dns.google/resolve?name=" + urllib.parse.quote(d) + "&type="
recs = {}
for rt in ("A", "AAAA", "MX", "NS", "TXT", "CNAME"):
st, b = http(doh + rt, timeout=10)
j = jf(b)
if j and j.get("Answer"):
recs[rt] = [a.get("data") for a in j["Answer"]]
out["dns"] = recs
st, b = http("https://crt.sh/?q=%25." + urllib.parse.quote(d) + "&output=json", timeout=25)
subs = set()
j = jf(b)
if isinstance(j, list):
for row in j:
for nm in str(row.get("name_value", "")).split("\n"):
nm = nm.strip().lower().lstrip("*.")
if nm.endswith("." + d) and nm != d: subs.add(nm)
out["subdomains"] = sorted(subs)[:100]
out["subdomain_count"] = len(subs)
return out
@app.route("/domain", methods=["GET", "POST"])
def domain_tool():
res = ""
if request.method == "POST":
d = (param("d") or "").strip()
if d and len(d) <= 100:
try:
rep = domain_report(d)
evs = rep.get("events") or {}
ent = "; ".join(f'{"/".join(e["roles"])}: {e["name"]}' for e in (rep.get("entities") or [])) or "—"
ns = ", ".join(str(x.get("ldhName") or x) for x in (rep.get("nameservers") or rep.get("rdap", {}).get("nameservers") or [])) or (rep.get("dns", {}).get("NS") and ", ".join(rep["dns"]["NS"])) or "—"
dns_rows = "".join(f"<tr><td>{esc(k)}</td><td>{esc('<br>'.join(v))}</td></tr>" for k, v in (rep.get("dns") or {}).items())
subs = rep.get("subdomains") or []
res = kv([("Registrar info", esc(ent)), ("Registered", esc(evs.get("registration", "—"))), ("Expires", esc(evs.get("expiration", "—"))), ("Last changed", esc(evs.get("last changed", "—"))), ("Status", esc(", ".join(rep.get("rdap", {}).get("status") or []) or "—")), ("Nameservers", esc(ns))])
res += f'<div class="card"><b>DNS</b><table>{dns_rows or "<tr><td style=color:var(--dim)>none resolved</td></tr>"}</table></div>'
res += f'<div class="card"><b>Certificate-transparency subdomains</b> <span style=color:var(--dim)>({rep.get("subdomain_count",0)} found)</span><br>' + (esc(" · ".join(subs[:60])) + (" …" if len(subs) > 60 else "") or "—") + "</div>"
except Exception as e:
res = f'<div class="card"><span class="tag bad">LOOKUP FAILED</span><br>{esc(str(e)[:300])}</div>'
body = f"""
<h1>DOMAIN <span>RECON</span></h1><p class=sub>Full passive recon on any domain: RDAP registration data (registrar, dates, status), live DNS records, and certificate-transparency subdomain discovery. Free, no keys.</p>
<div class=card><form method=post><input name=d placeholder="example.com" style=width:70% required><button style=margin-top:.5rem>Recon</button></form></div>
{res}
<div class=card style=color:var(--dim)>API: GET /api/domain?d=example.com → JSON: rdap, events, entities, dns, subdomains.</div>""" + how(["Type the bare domain — no scheme, no path.",
"RDAP answers who runs it, when it was registered and when it expires.",
"DNS shows A/AAAA/MX/NS/TXT/CNAME — where it lives and what mail it accepts.",
"Certificate logs expose hostnames even when DNS tries to hide them — great for finding staging/hidden subdomains.",
"All sources are public registries — passive, no packets touch the target."])
body += gloss([("RDAP","modern successor to WHOIS — structured registration data"),("CT log","certificate-transparency log: every TLS cert ever issued, public"),("TXT","DNS records used for SPF/verification claims")])
body += agent_card('GET /api/domain?d=example.com', 'curl "https://dark0rbits.thetempleofdoom.com/api/domain?d=example.com"', 'RDAP registration, DNS records, CT-log subdomains. Passive OSINT, free.')
return page("domain", body)
@app.route("/api/domain", methods=["GET", "POST"])
def api_domain():
r = rate_limit("domain", 10, 60)
if r: return r
d = (param("d") or "").strip()
if not d or len(d) > 100: return jsonify({"ok": False, "error": "d required"}), 400
return jsonify(domain_report(d))
@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 &amp; 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>""" + how(["Paste the card number — it never leaves the request, nothing is stored.","Luhn checksum validates the digit structure instantly.","BIN (first 8 digits) reveals the issuer bank, brand, card type and country.","Prepaid BINs get flagged — merchants commonly reject them.","This CANNOT show balance or fraud-hold status; only the issuer knows that."])
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}"""
body += gloss([("BIN","first 6-8 digits of a card — identifies issuer, country, brand"),("Luhn","checksum test every real card number passes"),("prepaid","issued as prepaid — elevated fraud risk")])
body += agent_card('POST /api/card num=4539148803436467', 'curl -X POST https://dark0rbits.thetempleofdoom.com/api/card -d num=4539148803436467', 'Luhn + BIN intel. 2c/metered with API key, free with PASS.')
return page("card", body)
@app.route("/api/card", methods=["POST"])
def api_card():
r = rate_limit("card", 30, 60)
if r: return r
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 [])})
# ---------- 7i. SCREENSHOT SERVICE (chromium if present, else rendered-text fallback) ----------
def shot_url_ok(u):
if not re.match(r"^https?://", u): return None, "url must start with http:// or https://"
try:
host = urllib.parse.urlsplit(u).hostname or ""
except Exception:
return None, "url parse error"
if not host: return None, "url has no host"
try:
candidate = ipaddress.ip_address(host)
except ValueError:
candidate = None
if candidate:
if candidate.is_private or candidate.is_loopback or candidate.is_link_local or candidate.is_reserved: return None, "private/reserved IPs blocked"
return u, None
try:
resolved = ipaddress.ip_address(socket.gethostbyname(host))
except Exception:
return u, None # cannot resolve here — let the fetcher report the failure
if resolved.is_private or resolved.is_loopback or resolved.is_link_local or resolved.is_reserved: return None, "private/reserved IPs blocked"
return u, None
def shot_find_browser():
for b in ("chromium", "chromium-browser", "google-chrome", "google-chrome-stable"):
if shutil.which(b): return b
return None
def _shot_html_harvest(url):
"""HTTP fetch + readability-ish text harvest + page intel. No browser, no fake PNG."""
status, html_text = http(url, timeout=15)
out = {"http_status": status}
try:
title = re.search(r"<title[^>]*>(.*?)</title>", html_text, re.I | re.S)
if title: out["title"] = html.unescape(title.group(1)).strip()[:300]
desc = re.search(r'<meta[^>]+name=["\']description["\'][^>]+content=["\'](.*?)["\']', html_text, re.I | re.S)
if desc: out["description"] = html.unescape(desc.group(1)).strip()[:400]
except Exception:
pass
intel = []
for m in re.finditer(r"<h([1-3])[^>]*>(.*?)</h\1>", html_text, re.I | re.S):
t = html.unescape(re.sub(r"<[^>]+>", "", m.group(2))).strip()
if t: intel.append("h" + m.group(1) + ": " + t[:120])
if len(intel) >= 15: break
t = re.sub(r"(?is)<(script|style|noscript|svg)[^>]*>.*?</\1>", " ", html_text)
t = re.sub(r"(?s)<!--.*?-->", " ", t)
t = re.sub(r"(?i)<(br|/p|/div|/li|/h[1-6]|/tr)[^>]*>", "\n", t)
t = re.sub(r"<[^>]+>", " ", t)
t = html.unescape(t)
t = re.sub(r"[ \t\r]+", " ", t)
t = re.sub(r"\n\s*\n+", "\n", t).strip()
words = t.split()
out["text_preview"] = " ".join(words[:400])
out["text_chars_total"] = len(words)
out["headings"] = intel
return out
def shot_run(sid):
con = db()
s = con.execute("SELECT * FROM shots WHERE id=?", (sid,)).fetchone()
if not s: return
url = s["url"]
browser = shot_find_browser()
if browser:
out = os.path.join(UPLOAD_DIR, f"shot_{sid}.png")
try:
cmd = [browser, "--headless=new", "--no-sandbox", "--disable-gpu", "--hide-scrollbars",
"--window-size=1280,1600", f"--screenshot={out}", "--virtual-time-budget=8000", url]
p = subprocess.run(cmd, capture_output=True, timeout=45)
if p.returncode == 0 and os.path.exists(out) and os.path.getsize(out) > 0:
with open(out, "rb") as f: png = f.read()
os.remove(out)
con.execute("UPDATE shots SET status=?, result=? WHERE id=?", ("done", base64.b64encode(png).decode(), sid))
con.commit(); return
err = (p.stderr or b"").decode(errors="replace")[:200]
result = {"error": "chromium render failed: " + (err or f"exit {p.returncode}")}
except subprocess.TimeoutExpired:
result = {"error": "chromium timed out after 45s"}
except Exception as e:
result = {"error": f"chromium error: {e}"}
else:
try:
result = _shot_html_harvest(url)
result["mode"] = "text_fallback"
except Exception as e:
result = {"error": f"fetch failed: {e}"}
con.execute("UPDATE shots SET status=?, result=? WHERE id=?", ("text_fallback" if "mode" in result else "error", json.dumps(result), sid))
con.commit()
SHOT_API = ("<div class=card><b>AGENT API</b><pre>POST " + SITE + """/api/shot/create
Content-Type: application/json (or form fields)
{"url":"https://example.com"}
-> {"ok":true,"id":42,"status":"queued","poll":"BASE/api/shot/status/42"}
GET /api/shot/status/42
-> {"ok":true,"id":42,"status":"done","png_b64":"iVBORw..."} (chromium present)
-> {"ok":true,"status":"text_fallback","title":"...","text_preview":"...","headings":[...]}
auth: session cookie or Authorization: Bearer dk_...
25c/shot, free with PASS - rate limit 6/min
PNG mode: status "done" + png_b64. If chromium vanishes, expect text_fallback.</pre></div>""").replace("BASE", SITE)
SHOT_EXPLAINER = """<div class=card><b>HOW CAPTURE WORKS</b><br><span style="color:var(--dim);font-size:.85rem">
&bull; With <span title="headless Chromium renders the page with JS + CSS and writes a real 1280x1600 PNG — nothing is faked">headless Chromium</span> installed, /shot returns a real browser render as base64 PNG.
&bull; No browser on the host? You get <span title="HTTP fetch + readability harvest: title, meta description, headings and first 400 words — honest output, never a fake image">text_fallback</span>: an honest fetch of the page with rendered-text preview + page intel. A status field always tells you which.
&bull; <span title="Requests to localhost, RFC1918 ranges, link-local and reserved ranges are rejected — the capture service can't be turned into an SSRF probe">SSRF guard</span>: private/reserved network targets are refused before any fetch.
&bull; 25&cent; per shot, free with <span title="PASS = $10/mo all-access">PASS</span>. Rate limit 6/min.</span></div>"""
@app.route("/shot")
def shot_page():
body = f"""
<h1>SCREEN <span>SHOT</span></h1><p class=sub>Point at a URL, get a real 1280×1600 headless-Chromium PNG render (base64 in the API). Honest text+intel fallback only if the renderer is down. Never a fake image.</p>
<div class=card><b>New capture</b>
<form method=post action=/api/shot/create onsubmit="doShot();return false">
<input id=shoturl name=url placeholder="https://target.example" style="width:min(560px,100%)" required>
<button style=margin-left:.4rem>Capture</button></form>
<div style="color:var(--dim);font-size:.85rem;margin-top:.5rem">{'Free with your PASS — or 25&cent; from balance.' if current_user_id() else 'Login + balance (or PASS): 25&cent; per shot.'}</div></div>
<div id=shotout class=card style=display:none><b>Result</b><div id=shotbody style="margin-top:.5rem"></div></div>
{SHOT_EXPLAINER}
<script>
function _esc(s){{var d=document.createElement('div');d.textContent=s==null?'':String(s);return d.innerHTML}}
async function doShot(){{var u=document.getElementById('shoturl').value.trim();if(!u){{toast('enter a URL');return}}
var out=document.getElementById('shotout'),body=document.getElementById('shotbody');out.style.display='block';body.innerHTML='queueing…';
try{{var cr=await fetch('/api/shot/create',{{method:'POST',headers:{{'Content-Type':'application/json'}},body:JSON.stringify({{url:u}})}});var c=await cr.json();
if(!c.ok){{body.innerHTML='<span class="tag bad">'+_esc(c.error)+'</span>';return}}
for(var i=0;i<20;i++){{await new Promise(r=>setTimeout(r,1500));
var sr=await (await fetch('/api/shot/status/'+c.id)).json();
if(sr.status==='done'&&sr.png_b64){{body.innerHTML='<img alt="page capture" src="data:image/png;base64,'+sr.png_b64+'">';return}}
if(sr.status==='text_fallback'){{var h='';if(sr.title)h+='<div style=color:var(--acc2)>title: '+_esc(sr.title)+'</div>';
if(sr.description)h+='<div style=color:var(--dim)>desc: '+_esc(sr.description)+'</div>';
if(sr.headings&&sr.headings.length)h+='<div style=color:var(--dim);font-size:.8rem>'+sr.headings.map(_esc).join('<br>')+'</div>';
h+='<pre style="white-space:pre-wrap;text-align:left">'+_esc(sr.text_preview)+'</pre>';body.innerHTML=h;return}}
if(sr.status==='error'){{body.innerHTML='<span class="tag bad">'+_esc(sr.error)+'</span>';return}}
body.textContent='rendering… (poll '+i+'/20)'}}}}catch(e){{body.textContent='error: '+e}}}}
</script>""" + SHOT_API + how(["Paste a URL — the job queues instantly (free).",
"With a headless browser on the host you get a real PNG back as base64.",
"No browser installed? You get text_fallback: title, description, headings, first 400 words — honestly labeled.",
"Agents: POST /api/shot/create then poll /api/shot/status/<id> until status != queued.",
"SSRF guard: localhost and private ranges are refused — this is a capture service, not a port scanner."])
return page("shot", body)
@app.route("/api/shot/create", methods=["POST"])
def api_shot_create():
r = rate_limit("shot", 6, 60)
if r: return r
uid = key_user() or current_user_id()
if not uid: return jsonify({"ok": False, "error": "auth required: account session (sign up at /inbox, no KYC) or Authorization: Bearer dk_ key"}), 401
url = str(jp("url") or "").strip()
if not url: return jsonify({"ok": False, "error": "url required"}), 400
url, err = shot_url_ok(url)
if err: return jsonify({"ok": False, "error": err}), 400
if not has_pass(uid) and not charge(uid, 25, "shot create"):
return jsonify({"ok": False, "error": "insufficient balance", "balance_cents": get_balance(uid), "topup": SITE + "/keys"}), 402
con = db()
cur = con.execute("INSERT INTO shots(user_id,url,status,created) VALUES(?,?,?,?)", (uid, url, "queued", int(time.time())))
con.commit()
shot_run(cur.lastrowid)
st = con.execute("SELECT status FROM shots WHERE id=?", (cur.lastrowid,)).fetchone()
return jsonify({"ok": True, "id": cur.lastrowid, "status": st["status"], "poll": f"{SITE}/api/shot/status/{cur.lastrowid}"}), 200, {"Cache-Control": "no-store"}
def shot_dict(row):
d = {"ok": True, "id": row["id"], "status": row["status"]}
try:
r = json.loads(row["result"]) if row["result"] else None
except Exception:
r = row["result"]
if row["status"] == "done" and r:
d["png_b64"] = r
try:
d["png_bytes"] = len(base64.b64decode(r))
except Exception:
pass
elif r:
d.update(r if isinstance(r, dict) else {"detail": str(r)[:400]})
return d
@app.route("/api/shot/status/<int:sid>")
def api_shot_status(sid):
con = db()
s = con.execute("SELECT * FROM shots WHERE id=?", (sid,)).fetchone()
if not s: return jsonify({"ok": False, "error": "unknown shot id"}), 404
if s["status"] == "queued": shot_run(sid) # lazy exec (reload-safe)
s = con.execute("SELECT * FROM shots WHERE id=?", (sid,)).fetchone()
return jsonify(shot_dict(s))
# ---------- 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():
uid = current_user_id()
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(user_id,phone,service,country,purchase_id,cost,status,created,expires) VALUES(?,?,?,?,?,?,?,?,?)",
(uid, 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 WHERE user_id=? ORDER BY id DESC LIMIT 8", (uid,)).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, <b>free</b> — the lab picks up the tab. Cancel before a code = instant burn.</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 &amp; 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>
<div class=card id=codesbox style=display:none><b>Live code</b><div id=lcode style="font-size:1.6rem;color:var(--ok);letter-spacing:.2em"></div></div>
<script>
var lastMsg='';
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);
setInterval(function(){{
fetch('/api/sms/history').then(r=>r.json()).then(rows=>{{
var act=rows.filter(r=>r.status==='active');
document.dispatchEvent(new CustomEvent('drb-sms',{{detail:{{active:act.length}}}}));
if(!act.length)return;
act.forEach(r=>{{
fetch('/api/sms/check?pid='+r.purchase_id).then(x=>x.json()).then(d=>{{
if((d.sms||d.code)&&d.sms!==lastMsg){{lastMsg=d.sms||d.code;
var box=document.getElementById('codesbox');box.style.display='block';
document.getElementById('lcode').textContent=lastMsg;
toast('SMS CODE: '+lastMsg);document.title='✉ '+lastMsg;}}
}})}});
}})}},6000);
</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>""" + how(["Pick a service and country, rent — the number is live for 30 minutes exactly.","Use it for any signup/verification. The code arrives as a text.","Poll the order (auto or manual) until the code shows.","Cancel before a code arrives and you get every satoshi back.","Each rental is logged in the recent-rentals table with a live countdown."])
body += gloss([("OTC","one-time code — the PIN a service texts you"),("burn","cancel an unused rental inside the refund window"),("SMSPool","our upstream number provider")])
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})
uid = key_user() or current_user_id()
if uid and not has_pass(uid) and get_balance(uid) < 50:
return jsonify({"ok": False, "error": "insufficient balance", "topup": SITE + "/keys"}), 402
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(user_id,phone,service,country,purchase_id,cost,status,created,expires) VALUES(?,?,?,?,?,?,?,?,?)",
(uid, d.get("number"), param("service"), param("country"), str(d.get("purchase_id")), d.get("cost",0), "active", now, now+1800))
con.commit()
cost = int(d.get("cost_in_cents") or 5)
if uid and not has_pass(uid):
charge(uid, cost, f"sms rental +{d.get('number')}")
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()
uid = key_user() or current_user_id()
if not uid:
return jsonify({"ok": False, "error": "login required (POST /inbox act=login)"}), 401
return jsonify([dict(r) for r in con.execute("SELECT * FROM sms_rentals WHERE user_id=? ORDER BY id DESC LIMIT 50", (uid,))])
# ---------- 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>""" + how(["Enter your Pleiades gateway user:pass — the same credentials work across the fleet.","The lab tunnels a CONNECT request through the gateway and reports the true egress IP, geo and ISP.","Use the geo builder to steer the exit: region, country, city, sticky 30-min sessions.","Need bandwidth? Buy GB plans at the Pleiades storefront."])
body += gloss([("sticky session","same exit IP kept across requests"),("egress","the exit IP the rest of the internet sees"),("Pleiades","our proxy gateway network")])
return page("proxy", body)
@app.route("/api/proxy/test", methods=["POST"])
def api_proxy_test():
r = rate_limit("proxytest", 10, 60)
if r: return r
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 + "dark0rbits").encode()).digest()[:4], "big") if password else int.from_bytes(hashlib.sha256(b"dark0rbits-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("dark0rbits_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("dark0rbits_meta") or 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 + "dark0rbits").encode()).digest()[:4], "big") if password else int.from_bytes(hashlib.sha256(b"dark0rbits-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 DARK0RBITS payload found with LSB depth {bits} (try other depth / randomized)"
ln = struct.unpack(">I", bytes(raw[4:8]))[0]
need = 96 + ln * 8 # header is 12 bytes (AUR1+len+phash) = 96 bits; old 64 truncated 4 bytes off every payload
data = bytes(raw)
if len(data) < 12: return None, "payload too small"
if bytes(data[:4]) != b"AUR1":
return None, "no DARK0RBITS 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 secret text inside an ordinary PNG so completely that the picture looks untouched — no metadata, no visible change, nothing to see. Only someone who knows it's there (and has the password) can read it back.</p>
<div class=grid2>
<div class=card><b>Hide text in a picture</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 — bigger pictures hide more<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>
<div id=capmeter style=display:none;margin:.5rem 0>
<div class=bar><i id=capbar></i></div>
<div id=captext style=color:var(--dim);font-size:.8rem;margin-top:.2rem></div></div>
<textarea name=text rows=3 style="width:100%;margin:.6rem 0" placeholder="the words to hide — a passphrase, a note, coordinates…"></textarea>
<input name=password placeholder="password (optional — encrypts the payload + scrambles where it hides)" style="width:100%">
<div style="margin:.6rem 0;display:flex;gap:.8rem;flex-wrap:wrap;align-items:center">
<label style=margin:0>Depth</label> <select name=bits><option>1</option><option>2</option><option>3</option></select>
<label style=margin:0>Spread</label> <select name=spread><option value=sequential>sequential</option><option value=random>randomized</option></select></div>
<button>Hide &amp; download</button></form>
<div style=color:var(--dim);font-size:.8rem;margin-top:.5rem>The download is a normal PNG. Post it, email it, host it — the secret rides along.</div></div>
<div class=card><b>Read hidden text back</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 — anyone can try, only the password works<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 one was used" style="width:100%;margin:.6rem 0">
<div style=margin:.6rem 0;display:flex;gap:.8rem;flex-wrap:wrap;align-items:center">
<label style=margin:0>Depth</label> <select name=bits><option value="">auto (reads metadata)</option><option>1</option><option>2</option><option>3</option></select>
<label style=margin:0>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}}}});
}});
document.getElementById('ih').addEventListener('change',function(){{
var f=this.files[0];document.querySelector('.fnh').textContent=f?f.name+' ('+Math.round(f.size/1024)+' KB)':'';
if(!f)return;
// PNG dims live at bytes 16-24 — read straight from the file
var r=new FileReader();
r.onload=function(){{var dv=new DataView(r.result);
if(dv.byteLength>24&&dv.getUint32(0)===0x89504E47){{
var w=dv.getUint32(16),h=dv.getUint32(20);
var cap=Math.floor(w*h*3/8); // depth-1 capacity in bytes
var el=document.getElementById('capmeter');el.style.display='block';
document.getElementById('captext').textContent=w+'×'+h+' px — holds about '+cap+' hidden characters at depth 1 ('+Math.floor(cap*2)+' at depth 2)';
}}}};
r.readAsArrayBuffer(f.slice(0,32));
}});
document.getElementById('ie').addEventListener('change',function(){{var f=this.files[0];document.querySelector('.fne').textContent=f?f.name+' ('+Math.round(f.size/1024)+' KB)':''}});
</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>
<iframe name=stegout id=stegout style=display:none title="stego output"></iframe>""" + flow("smuggle a passphrase through a photo wall", [
"<span class=flowrole>you</span> drop in a vacation photo — the meter says 1920×1080 holds ~777,600 hidden characters. Plenty.",
"<span class=flowrole>you</span> type the wifi password <code>hunter2-sunset-2026</code>, add password <code>peanut</code>, spread randomized, hit Hide.",
"the site flips the least-significant bits of random pixels — the downloaded PNG looks pixel-for-pixel identical to the original.",
"<span class=flowrole>you</span> post the photo publicly. It passes through phones, compressors, screenshots — it's just a picture.",
"<span class=flowrole>ally</span> saves it, opens STEGO LAB, drops the file, types <code>peanut</code> → the words come back.",
"<span class=flowrole>stranger</span> drops the same file with no password → noise. Without the key, it's a photo of a beach."]) + how([
"Every pixel's color is three numbers. Change the last binary digit of each — changes of ±1 in brightness — and no eye can tell.",
"Depth 1 hides ~1 character per 2–3 pixels: invisible and robust. Depth 2–3 packs more but survives re-compression worse.",
"Randomized spread scatters your bits across the whole image instead of the top rows — a cropped picture can still give the text back.",
"A password encrypts the payload AND seeds the scatter pattern: wrong password yields pure noise, not garbage text.",
"Extraction auto-reads the embedded settings — the file knows its own depth and spread. Just drop and go.",
"Warning: posting to platforms that re-compress (Instagram, WhatsApp) can damage depth-1 edges — send the file itself, unmodified."])
body += gloss([("LSB","least significant bit — the final binary digit of a color value; changing it is invisible"),("depth","how many bit-planes carry the payload — more depth, more text, more detectable"),("spread","where the bits live: top-down or scattered across the image"),("carrier","the innocent-looking picture that transports your hidden text")])
body += agent_card('POST /api/steg/hide image=<png> text=hi [password= bits= spread=]', 'curl -X POST https://dark0rbits.thetempleofdoom.com/api/steg/hide -F image=@beach.png -F text="wifi is hunter2" -F password=peanut', 'Extract: POST /api/steg/extract (image, password?). Free, 20/min.')
return page("steg", body)
@app.route("/api/steg/hide", methods=["POST"])
def api_steg_hide():
r = rate_limit("steg", 20, 60)
if r: return r
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="dark0rbits-hidden.png")
@app.route("/api/steg/extract", methods=["POST"])
def api_steg_extract():
r = rate_limit("steg", 20, 60)
if r: return r
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 15", (uid,)).fetchall()
if rows:
trs = "".join(
f"<tr><td><b>{esc(t['filename'])}</b><br><span style=color:var(--dim);font-size:.78rem>{t['kind'] or 'file'}</span></td>"
f"<td><code>{SITE}/t/{t['token']}</code></td>"
f"<td>{'<a href=/api/track/events?token=' + t['token'] + ' style=color:var(--acc)>view events</a>' if t['paid'] else '—'}</td>"
f"<td>{'<span class=tag ok>live</span>' if t['paid'] else '<span class=tag warn>awaiting upload</span>'}</td></tr>"
for t in rows)
mine = ('<div class=card><b>Your trackables</b><div class=tblwide><table><tr><th>File</th><th>Tracked link</th><th>Events</th><th>Status</th></tr>'
+ trs + '</table></div></div>')
body = f"""
<h1>TRACK <span>FILE</span></h1><p class=sub>Upload any file or picture and get a tracked link for it. The moment anyone opens that link — or views the email version — their IP, city, ISP, device and language fire back into your INBOX. The image-IP trick, weaponized and clean.</p>
<div class=card>
<b>1 · Name your bait</b><form action=/api/track/create method=post>
<input name=filename placeholder="file name the target will see, e.g. invoice.jpg, resume.pdf" style="width:100%;margin:.4rem 0" required>
<button>Create trackable — free</button></form></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 with geo. 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) → upload_url · POST /api/track/upload?token= (file) → tracked_link + pixel + email_html · GET /api/track/events?token=</div>""" + flow("learn who opens your 'photo'", [
"<span class=flowrole>you</span> create a trackable named <b>sunset.jpg</b> — free, instant, and the upload page opens.",
"<span class=flowrole>you</span> upload the actual photo. You get back: a tracked link, a pixel URL, and an email-ready HTML copy.",
"<span class=flowrole>you</span> send the link — 'hey check out this pic'. That's the whole trick.",
"<span class=flowrole>them</span> taps it. The image renders normally in their browser — but the page quietly pings home first.",
"<span class=flowrole>you</span> INBOX lights up: <b>sunset.jpg opened</b> — IP 203.0.113.7 · Rotterdam NL · KPN · Android Chrome · timezone Europe/Amsterdam.",
"the HTML copy works over email too — every preview pane that loads images fires the pixel, no click needed."]) + how([
"Free now — click create and the upload opens instantly, no payment.",
"Upload your file or picture: you get a secret tracked link plus an email-ready HTML copy.",
"Email the HTML copy or share the link — every open fires back.",
"Each open reports: exact time, real IP, city/country, ISP, timezone, VPN flag, device, language, referrer.",
"Alerts land in your INBOX the second it happens; full event log via the API."])
return page("track", body)
BTCPAY_PUBLIC = "https://btcpay.thetempleofdoom.com"
def public_checkout(link):
"""LAN invoices must be payable from the open internet — swap host on checkout links."""
if not link:
return link
return link.replace("https://10.30.20.140", BTCPAY_PUBLIC)
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": "dark0rbits-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 = key_user() or current_user_id()
if not uid:
return jsonify({"ok": False, "error": "login required — create a no-KYC account at /inbox (POST /inbox act=register), then retry"}), 401
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}"})
if uid and charge(uid, 100, f"trackable file ({fn[:40]})"):
con.execute("INSERT INTO trackables(user_id,token,filename,kind,invoice_id,paid,created) VALUES(?,?,?,?,?,1,?)",
(uid or 0, token, esc(fn[:100]), "file", "BALANCE", int(time.time())))
con.commit()
return jsonify({"ok": True, "balance_charged": 1.00, "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 _checkout_or_json({"ok": True, "invoice_id": inv["id"], "checkoutLink": public_checkout(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 &amp; 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"] not in ("PASS", "BALANCE") 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"})
def _geo_cache():
con = db()
con.execute("CREATE TABLE IF NOT EXISTS geo_cache(ip TEXT PRIMARY KEY, geo TEXT, ts INTEGER)")
return con
def enrich_ip(ip):
"""geo/ISP/ASN for an IP, cached 24h."""
if not ip or ip == "created" or ip.startswith(("10.30.20.", "127.", "172.17.")): return {}
con = _geo_cache()
r = con.execute("SELECT geo FROM geo_cache WHERE ip=? AND ts > ?", (ip, int(time.time())-86400)).fetchone()
if r: return json.loads(r["geo"])
st, b = http(f"http://ip-api.com/json/{ip}?fields=66846719")
d = jf(b) or {}
geo = {k: d.get(k) for k in ("country","countryCode","regionName","city","zip","lat","lon","timezone","isp","org","as","asname","mobile","proxy","hosting","reverse","query") if d.get(k) is not None}
con.execute("INSERT OR REPLACE INTO geo_cache(ip,geo,ts) VALUES(?,?,?)", (ip, json.dumps(geo), int(time.time())))
con.commit()
return geo
def _log_open(t, extra=""):
con = db()
ip = request.headers.get("X-Real-IP") or request.remote_addr or "?"
ua = request.headers.get("User-Agent","")
lang = request.headers.get("Accept-Language","")
ref = request.headers.get("Referer","")
geo = enrich_ip(ip)
where = ""
if geo: where = f" — {geo.get('city','')}, {geo.get('regionName','')} {geo.get('countryCode','')} · {geo.get('isp','')} · tz {geo.get('timezone','')}"
if geo.get("proxy"): where += " · VPN/proxy ⚠"
con.execute("INSERT INTO track_events(trackable_id,ts,ip,ua) VALUES(?,?,?,?)",
(t["id"], int(time.time()), ip + (" " + json.dumps(geo) if geo else ""), ua[:200] + (f" | lang={lang}" if lang else "") + (f" | ref={ref[:100]}" if ref else "")))
uid = t["user_id"]
if uid:
con.execute("INSERT INTO messages(user_id,sender,body,created) VALUES(?,?,?,?)",
(uid, "operator-bot", f"👁 '{esc(t['filename'])}' just opened{extra} — IP <b>{esc(ip)}</b>{esc(where)}<br>device: {esc(ua[:100])}{'<br>lang: ' + esc(lang) if lang else ''}{'<br>from: ' + esc(ref[:120]) if ref else ''}", int(time.time())))
con.commit()
@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
_log_open(t, " (link)")
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"]:
_log_open(t, " (email/pixel)")
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 = "dark0rbits-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 (free)</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>Pick your mailbox and length — it activates instantly. Free now, no invoice.</div></div>
{mine}
<div class=card style=color:var(--dim)>API: POST /api/mail/create (local, days) → activates instantly (free) · GET /api/mail/inbox?addr= (needs login) — inbound via Cloudflare Email Routing → worker relay.</div>""" + how(["Pick a name and a package — 7, 30 or 90 days, all free now.","Pay the invoice; the mailbox activates the second it settles.","The address is receive-only: verification codes, confirmations, one-off handouts.","The countdown runs in real time; when it hits zero the mailbox retires itself.","All mail shows on the site inbox — nothing touches any other identity."])
return page("mail", 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
uid = key_user() or current_user_id()
# metered: PASS = instant free; balance = instant paid; else BTC invoice
if uid and has_pass(uid):
con.execute("INSERT INTO mailboxes(user_id,address,invoice_id,paid,expires,created,plan_days) VALUES(?,?,?,?,?,?,?)",
(uid, addr, "PASS", 1, int(time.time())+86400*pack[3], int(time.time()), pack[3]))
con.commit()
return jsonify({"ok": True, "free": True, "address": addr, "expires_in_days": pack[3]})
if uid and charge(uid, pack[2]*100, f"burner mailbox {addr} ({pack[3]}d)"):
con.execute("INSERT INTO mailboxes(user_id,address,invoice_id,paid,expires,created,plan_days) VALUES(?,?,?,?,?,?,?)",
(uid, addr, "BALANCE", 1, int(time.time())+86400*pack[3], int(time.time()), pack[3]))
con.commit()
return jsonify({"ok": True, "balance_charged": pack[2], "address": addr, "expires_in_days": pack[3]})
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 _checkout_or_json({"ok": True, "address": addr, "checkoutLink": public_checkout(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("mail", '<div class=card>login required — <a href=/inbox style="color:var(--acc)">sign in / create account</a></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("mail", "<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("mail", 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()
u = con.execute("SELECT username FROM users WHERE id=?", (uid,)).fetchone()
if u and u["username"] == "drjones": return True # operator: everything free
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>— EVERYTHING FREE</span></h1><p class=sub>The meters are gone: unlimited SMS rentals, free trackables, burner mail, screenshots — every tool costs nothing. No PASS needed anymore.</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("pass", 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 _checkout_or_json({"ok": True, "checkoutLink": public_checkout(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 {}
iid = d.get("invoiceId") or ""
if d.get("type") == "InvoiceSettled" or (d.get("type") == "InvoicePaymentSettled"):
con = db()
if iid:
if con.execute("SELECT 1 FROM wh_processed WHERE invoice_id=?", (iid,)).fetchone():
return jsonify({"ok": True, "dup": True})
con.execute("INSERT OR IGNORE INTO wh_processed(invoice_id,ts) VALUES(?,?)", (iid, int(time.time())))
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))
# balance top-ups
try:
meta = d.get("metadata") or {}
if not meta:
st, b = http(f"{BTCPAY}/stores/{BTCPAY_STORE}/invoices/{iid}", headers={"Authorization": "token " + BTCPAY_KEY})
meta = (jf(b) or {}).get("metadata", {}) or {}
if str(meta.get("orderId", "")).startswith("dark0rbits-topup"):
uid = int(meta["orderId"].split(":")[1]); cents = int(meta["orderId"].split(":")[2])
con.execute("INSERT OR IGNORE INTO balances(user_id, cents) VALUES(?, 0)", (uid,))
con.execute("UPDATE balances SET cents = cents + ? WHERE user_id=?", (cents, uid))
con.execute("INSERT INTO ledger(user_id,delta_cents,reason,ts) VALUES(?,?,?,?)", (uid, cents, f"BTC topup {iid}", int(time.time())))
except Exception: pass
con.commit()
return jsonify({"ok": True})
# ---------- 6h. API KEYS + BALANCE ----------
@app.route("/keys", methods=["GET", "POST"])
def keys():
uid = current_user_id()
if not uid:
return page("keys", '<h1>API <span>KEYS</span></h1><div class=card>login on /inbox first — keys are bound to your account.</div><a href=/inbox><button>Login</button></a>')
con = db()
if request.method == "POST" and request.form.get("act") == "mkkey":
label = (param("label") or "default")[:40]
key = "dk_" + secrets.token_urlsafe(24)
con.execute("INSERT INTO apikeys(user_id,key,label,created) VALUES(?,?,?,?)", (uid, key, esc(label), int(time.time())))
con.commit()
newkey = key
else:
newkey = None
rows = con.execute("SELECT * FROM apikeys WHERE user_id=? AND revoked=0 ORDER BY id DESC", (uid,)).fetchall()
bal = get_balance(uid)
led = con.execute("SELECT * FROM ledger WHERE user_id=? ORDER BY id DESC LIMIT 15", (uid,)).fetchall()
led_html = "".join(f"<tr><td>{'$%.2f' % (l['delta_cents']/100)}</td><td>{esc(l['reason'])}</td><td>{time.strftime('%b %d %H:%M', time.localtime(l['ts']))}</td></tr>" for l in led)
keys_html = "".join("<tr><td><code>"+esc(k['key'][:14])+"…</code> <a href=# onclick=\"cp('"+k['key']+"');return false\" style=color:var(--acc)>copy</a></td><td>"+esc(k['label'])+"</td><td>"+time.strftime('%b %d', time.localtime(k['created']))+"</td></tr>" for k in rows)
newkey_block = ('<div class="card glow" style="margin-top:.8rem"><span class="tag ok">NEW KEY (shown once)</span><br><code id=nk style="font-size:1.1rem">'+esc(newkey)+'</code> <button style="padding:.2rem .6rem;font-size:.8rem" onclick="cp(\''+newkey+'\')">copy</button></div>') if newkey else ''
keys_block = ('<div class=card><b>Keys</b><table><tr><th>Key</th><th>Label</th><th>Created</th></tr>'+keys_html+'</table></div>') if rows else ''
body = f"""
<h1>API <span>KEYS</span> — balance: <span style=color:var(--acc)>${bal/100:.2f}</span></h1>
<p class=sub>Metered access is over — every tool is free for humans and agents. No top-ups, no meters, no KYC. Your API keys still work everywhere.</p>
<div class="grid2">
<div class=card><b>New API key</b><form method=post><input type=hidden name=act value=mkkey><input name=label placeholder="key label (e.g. my-bot)" style=width:100%><button style=margin-top:.5rem>Generate key</button></form>
{newkey_block}
{keys_block}
</div>
<div class=card><b>Top up (BTC)</b>
{''.join(f'<form action=/api/balance/topup method=post style=display:inline;margin:0 .3rem><input type=hidden name=cents value={c}><button class=ghost>${a}</button></form>' for c,a in [(500,'$5'),(2000,'$20'),(10000,'$100')])}
<div style=color:var(--dim);font-size:.85rem;margin-top:.5rem>Invoice settles → balance credited automatically via webhook.</div></div>
</div>
<div class=card><b>Ledger</b><table><tr><th>Δ</th><th>Reason</th><th>When</th></tr>{led_html or '<tr><td colspan=3 style=color:var(--dim)>no charges yet</td></tr>'}</table></div>
<div class=card style=color:var(--dim)>Use it: <code>Authorization: Bearer dk_…</code> header on any paid API call. Metered endpoints: /api/sms/rent (pass-through cost), /api/mail/create (package price), /api/track/create ($1). Everything else free. PASS = no metering.</div>"""
return page("keys", body)
@app.route("/api/balance/topup", methods=["POST"])
def api_balance_topup():
uid = current_user_id()
if not uid: return jsonify({"ok": False, "error": "login required — free no-KYC account at /inbox"}), 401
cents = int(param("cents") or 500)
if cents not in (500, 2000, 10000): return jsonify({"ok": False, "error": "bad amount"}), 400
# invoice created WITH topup metadata in one shot
st, b = http(f"{BTCPAY}/stores/{BTCPAY_STORE}/invoices",
headers={"Authorization": "token " + BTCPAY_KEY, "Content-Type": "application/json"},
data=json.dumps({"amount": f"{cents/100:.2f}", "currency": "USD",
"metadata": {"orderId": f"dark0rbits-topup:{uid}:{cents}", "itemDesc": "dark0rbits balance topup"}}).encode(), method="POST")
inv = jf(b) or {}
if not inv.get("id"): return jsonify({"ok": False, "error": str(inv)[:200]}), 400
con = db()
con.execute("INSERT INTO ledger(user_id,delta_cents,reason,ts) VALUES(?,?,?,?)", (uid, 0, f"topup invoice {inv['id']} pending", int(time.time())))
con.commit()
return _checkout_or_json({"ok": True, "checkoutLink": public_checkout(inv.get("checkoutLink"))})
@app.route("/api/balance")
def api_balance():
uid = key_user() or current_user_id()
if not uid: return jsonify({"ok": False, "error": "auth required"}), 401
return jsonify({"ok": True, "balance_cents": get_balance(uid), "pass_active": has_pass(uid)})
# ---------- 6d. EMAIL HEADER FORENSICS ----------
def parse_headers(raw):
import email as em
msg = em.message_from_string(raw)
out = {"from": msg.get("From",""), "to": msg.get("To",""), "subject": msg.get("Subject",""),
"date": msg.get("Date",""), "return_path": msg.get("Return-Path",""),
"reply_to": msg.get("Reply-To",""), "message_id": msg.get("Message-ID","")}
hops = []
for h in msg.get_all("Received", []) or []:
hop = h.strip().replace("\n", " ")
hops.append(hop[:400])
out["hops"] = list(reversed(hops)) # first-hop origin first
# timestamps per hop → relay delays
times = []
for h in hops:
m = re.search(r";\s*(.+)$", h)
if m:
try:
import email.utils as eu
t = eu.parsedate_to_datetime(m.group(1).strip())
if t: times.append(t)
except Exception: pass
delays = []
if len(times) >= 2:
for a, b in zip(times, times[1:]):
delays.append(round((b - a).total_seconds(), 1))
out["delays"] = delays
auth = msg.get_all("Authentication-Results", []) or []
out["auth_results"] = [a.strip()[:300] for a in auth]
out["dkim"] = [d.strip()[:200] for d in (msg.get_all("DKIM-Signature", []) or [])][:3]
# spoof flags
flags = []
env_from = out["return_path"].strip("<>")
frm = out["from"]
m_from = re.search(r"<([^>]+)>", frm)
addr_from = ((m_from.group(1) if m_from else frm).split() or [""])[-1].strip("<>").lower()
if env_from and addr_from and env_from.split("@")[-1] != addr_from.split("@")[-1]:
flags.append(f"envelope-from domain ({env_from.split('@')[-1]}) != From domain ({addr_from.split('@')[-1]}) — classic spoof marker")
if out["reply_to"]:
m_rt = re.search(r"<([^>]+)>", out["reply_to"]) or None
addr_rt = ((m_rt.group(1) if m_rt else out["reply_to"]).strip()).lower()
if addr_rt.split("@")[-1] != addr_from.split("@")[-1]:
flags.append(f"Reply-To ({addr_rt}) differs from From — possible reply-hijack")
# origin IP: prefer X-Originator-IP, then the bottom-most (oldest) Received
origin_ip = None
origin_src = None
xoi = msg.get("X-Originator-IP") or msg.get("X-Originating-IP") or ""
m = re.search(r"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", xoi)
if m:
origin_ip, origin_src = m.group(1), "X-Originator-IP header"
if not origin_ip:
for h in hops:
m = re.search(r"\[(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\]", h) or re.search(r"\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b", h)
if m:
origin_ip, origin_src = m.group(1), "oldest Received hop"
break
out["origin_ip"] = origin_ip
out["origin_source"] = origin_src
if origin_ip: out["origin_geo"] = enrich_ip(origin_ip)
out["flags"] = flags
verdicts = {}
blob = " ".join(out["auth_results"]).lower()
for k in ("spf","dkim","dmarc"):
m = re.search(k + r"=(\w+)", blob)
verdicts[k] = m.group(1) if m else "not present"
out["verdicts"] = verdicts
return out
@app.route("/eh")
def eh():
body = f"""
<h1>MAIL <span>FORENSICS</span></h1><p class=sub>Paste raw email headers — or drop the whole .eml file — and get the true origin IP + location, the full relay chain with per-hop delays, SPF/DKIM/DMARC verdicts, and automatic spoof detection.</p>
<div class=card><b>Analyze an email</b>
<form method=post action=/eh_result enctype=multipart/form-data>
<label>Paste raw headers — Gmail: open the mail → ⋮ → Show original → copy everything. Outlook: right-click → View message source.</label>
<textarea name=raw rows=10 style="width:100%" placeholder="Received: from mail-yb1-f180.google.com …&#10;Authentication-Results: mx.google.com; spf=pass …"></textarea>
<label style=margin-top:.6rem>… or import the .eml file directly (drag it out of Apple Mail / Outlook / Thunderbird)</label>
<div class=drop onclick="document.getElementById('emlf').click()">📄 drop a .eml file here or click<input id=emlf type=file name=eml accept=".eml,message/rfc822,text/plain" style=display:none></div>
<div id=emlfn style=color:var(--dim);font-size:.85rem;margin:.3rem 0></div>
<button style=margin-top:.5rem>Analyze</button></form></div>
<script>
(function(){{
var d=document.querySelector('.drop');
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');
if(e.dataTransfer.files.length){{document.getElementById('emlf').files=e.dataTransfer.files;
document.getElementById('emlfn').textContent=e.dataTransfer.files[0].name}}}});
document.getElementById('emlf').addEventListener('change',function(){{document.getElementById('emlfn').textContent=this.files[0].name}});
}})();
</script>
<div class=card style=color:var(--dim)>API: POST /api/eh (raw=…) → JSON: origin IP + geo + source, hop chain, per-hop delays, verdicts, spoof flags. Free.</div>""" + flow("was this 'bank email' really sent by the bank?", [
"<span class=flowrole>you</span> get a scary email from <b>security@yourbank-support.com</b> — open it, ⋮ → Show original, copy everything.",
"<span class=flowrole>you</span> paste the headers here (or drop the .eml) and hit Analyze.",
"<span class=flowrole>site</span> walks the <b>Received</b> chain bottom-up: the oldest hop is where the mail actually entered the internet.",
"origin IP found: <b>185.234.72.19</b> — a bulletproof host in Sofia, Bulgaria · datacenter ⚠ — not your bank's infrastructure.",
"verdicts come back: <b>SPF fail · DKIM none · DMARC fail</b> — three red tags.",
"spoof flags light up: envelope-from ≠ From domain — the display name is wearing a costume.",
"relay delays show the 4-second stall at a server that has no business handling bank mail.",
"<span class=flowrole>you</span> verdict: phishing. Delete, report, done — and you have the origin evidence to show for it."]) + how([
"An email's headers are its postal history — every server that touched it adds a Received line, and liars can't forge the chain reliably.",
"We read the chain from the bottom (oldest) up: that first hop is the true origin, and we geolocate its IP.",
"SPF/DKIM/DMARC are the domain's own authentication verdicts — fails here mean the mail didn't come from where it claims.",
"Spoof markers are checked automatically: envelope sender vs display From, Reply-To hijacks, mismatched domains.",
"Per-hop relay delays expose weird pit stops — legit bank mail doesn't detour through random countries.",
"Everything works from pasted headers OR a dropped .eml file — the parser handles both."])
body += gloss([("Received chain","the list of every server an email passed through, newest first"),("SPF","a domain's list of servers allowed to send its mail"),("DKIM","cryptographic signature on real mail from the domain"),("DMARC","policy for what receivers do when SPF/DKIM fail"),("envelope-from","actual SMTP sender — can differ from the visible From"),(".eml","the raw email file itself — headers + body, openable from any mail app")])
body += agent_card('POST /api/eh raw=<full headers>', 'curl -X POST https://dark0rbits.thetempleofdoom.com/api/eh --data-urlencode raw@headers.txt', 'Returns origin_ip, origin_geo, hops, delays, verdicts, flags. No auth needed for 20/min.')
return page("eh", body)
@app.route("/eh_result", methods=["POST"])
def eh_result():
raw = request.form.get("raw") or ""
f = request.files.get("eml")
if f and not raw.strip():
raw = f.read().decode("utf-8", "replace")
d = parse_headers(raw)
hops_html = ""
for i, h in enumerate(d["hops"]):
delay = f'<span class="tag warn" style=margin-left:.4rem>+{d["delays"][i-1]}s to next hop</span>' if i >= 1 and i-1 < len(d["delays"]) else ""
hops_html += f'<div class=msg><div class=who>hop {i+1}{delay}</div><span style=font-size:.82rem>{esc(h)}</span></div>'
verdicts = " ".join(f'<span class="tag {"ok" if v=="pass" else ("bad" if v in ("fail","softfail") else "warn")}">{k.upper()}: {v}</span>' for k, v in d["verdicts"].items())
flags = "".join(f'<div style="margin:.3rem 0"><span class=tag bad>⚠ {esc(f)}</span></div>' for f in d["flags"]) or '<span style=color:var(--ok)>✓ no spoof markers found</span>'
og = d.get("origin_geo") or {}
orows = [("Origin IP", f"<b style=color:var(--acc)>{esc(d.get('origin_ip') or 'not found')}</b>")]
if d.get("origin_source"): orows.append(("Found via", esc(d["origin_source"])))
if og: orows += [("Location", f"{esc(og.get('city'))}, {esc(og.get('regionName'))} {esc(og.get('countryCode'))}"), ("ISP", f"{esc(og.get('isp'))}{' · datacenter ⚠' if og.get('hosting') else ''}{' · VPN/proxy ⚠' if og.get('proxy') else ''}")]
body = f"""
<h1>VERDICT — <span>{esc(d.get('subject') or '(no subject)')[:80]}</span></h1>
{kv(orows + [("From", esc(d.get('from'))), ("Envelope-from", esc(d.get('return_path') or '—')), ("Reply-To", esc(d.get('reply_to') or '—')), ("Date", esc(d.get('date') or '—'))])}
<div class=card><b>Authentication</b><div style=margin:.5rem 0>{verdicts}</div><b style=display:block;margin-top:.8rem>Spoof flags</b><div style=margin:.4rem 0>{flags}</div></div>
<div class=card><b>Relay chain — origin first</b>{hops_html or '<i style=color:var(--dim)>no Received headers</i>'}</div>
<div class=card><a href=/eh style=color:var(--acc)>← analyze another</a></div>"""
return page("eh", body)
@app.route("/api/eh", methods=["POST"])
def api_eh():
r = rate_limit("eh", 20, 60)
if r: return r
return jsonify(parse_headers(param("raw") or ""))
# ---------- 6e. IMAGE FORENSICS ----------
@app.route("/forensics")
def forensics():
body = f"""
<h1>IMAGE <span>FORENSICS</span></h1><p class=sub>Deep forensics: full EXIF across all IFDs, GPS decoded to a map pin, XMP editor trails, embedded thumbnails, hashes, error-level analysis — expose doctored photos and find where they were taken.</p>
<div class=card><form action=/forensics_result method=post enctype=multipart/form-data>
<div class=drop onclick="document.getElementById('fi').click()">🖼 drop an image<input id=fi type=file name=image accept="image/*" style=display:none required></div>
<div id=fifn style=color:var(--dim);font-size:.85rem></div>
<button style=margin-top:.5rem>Analyze</button></form></div>
<script>document.getElementById('fi').addEventListener('change',function(){{document.getElementById('fifn').textContent=this.files[0].name}})</script>
<div class=card style=color:var(--dim)>API: POST /api/forensics (image) → JSON: exif (all IFDs), gps_decoded (lat/lon + map links), xmp, thumbnail_b64, hashes, flags, ela_max_diff, verdict.</div>""" + how(["Drop any image — every EXIF tag across IFD0, the EXIF sub-IFD and GPS gets dumped.",
"GPS is decoded to decimal degrees with one-click Google Maps / OpenStreetMap links — that's where the photo was taken.",
"XMP packets are parsed from the raw file: Adobe, Apple and Android editors leave trails there even after EXIF 'scrubbing'.",
"The embedded JPEG thumbnail is extracted — it can survive scrubbing and hold unstripped detail.",
"Error-level analysis (ELA) re-compresses and diffs: edited regions glow in the amplified view.",
"More than a dozen editors (Photoshop, GIMP, Canva, Snapseed, Lightroom…) are flagged automatically.",
"File hashes + format + dimensions come back too — match images across posts or leaks.",
"If the image carries a DARK0RBITS stego payload, this tool sees it."])
body += gloss([("ELA","error level analysis — regions re-saved after editing light up"),("EXIF","camera/software metadata embedded in the file"),("quantization","JPEG compression-table fingerprints")])
body += agent_card('POST /api/forensics image=<file>', 'curl -X POST https://dark0rbits.thetempleofdoom.com/api/forensics -F image=@img.jpg', 'Deep: EXIF all IFDs, gps_decoded with map links, xmp, thumbnail_b64, hashes, ELA verdict.')
return page("forensics", body)
def _ela_score(img_bytes):
from PIL import Image, ImageChops, ImageEnhance
im = Image.open(io.BytesIO(img_bytes)).convert("RGB")
resaved = io.BytesIO(); im.save(resaved, "JPEG", quality=90)
ela = ImageChops.difference(im, Image.open(resaved))
extrema = ela.getextrema()
maxdiff = max(e[1] for e in extrema)
enh = ImageEnhance.Brightness(ela).enhance(15)
out = io.BytesIO(); enh.save(out, "PNG")
return out.getvalue(), maxdiff
def _deep_forensics(data):
"""Deep image analysis: full EXIF (all IFDs), decoded GPS, XMP, thumbnail,
hashes, file info, editor flags, ELA. Shared by web + API."""
from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS
import hashlib, re as _re
im = Image.open(io.BytesIO(data))
out = {"file": {}, "exif": {}, "exif_exif": {}, "gps": {}, "gps_decoded": None,
"xmp": {}, "flags": [], "stego_payload": ("auriga_meta" in im.info or "dark0rbits_meta" in im.info)}
fmt = im.format or "?"
out["file"] = {"format": fmt, "mode": im.mode, "size": list(im.size), "bytes": len(data),
"sha256": hashlib.sha256(data).hexdigest()[:32], "md5": hashlib.md5(data).hexdigest()[:24]}
exif = im.getexif()
def _s(v):
return str(v.decode("utf-8", "replace") if isinstance(v, bytes) else v)[:200]
for k, v in exif.items():
try: out["exif"][str(TAGS.get(k, k) if isinstance(k, int) else k)] = _s(v)
except Exception: pass
# EXIF sub-IFD (camera settings, lenses, serials…)
try:
sub = exif.get_ifd(0x8769)
for k, v in sub.items():
try: out["exif_exif"][str(TAGS.get(k, k))] = _s(v)
except Exception: pass
except Exception: pass
# GPS sub-IFD, raw + decoded to decimal degrees + map links
try:
gifd = exif.get_ifd(0x8825)
if gifd:
for k, v in gifd.items():
try: out["gps"][str(GPSTAGS.get(k, k))] = _s(v)[:80]
except Exception: pass
def _dms(t):
return float(t[0]) + float(t[1]) / 60.0 + float(t[2]) / 3600.0
if gifd.get(2) and gifd.get(3):
try:
la, lo = _dms(gifd[2]), _dms(gifd[3])
if str(gifd.get(1, "")).upper() in ("S", "SOUTH"): la = -la
if str(gifd.get(4, "")).upper() in ("W", "WEST"): lo = -lo
out["gps_decoded"] = {"lat": round(la, 6), "lon": round(lo, 6),
"maps": f"https://www.google.com/maps?q={la:.6f},{lo:.6f}",
"osm": f"https://www.openstreetmap.org/?mlat={la:.6f}&mlon={lo:.6f}#map=16/{la:.6f}/{lo:.6f}"}
except Exception: pass
except Exception: pass
# XMP packet from raw bytes (Adobe/phone editing trails)
try:
m = _re.search(rb"<x:xmpmeta.{0,4}?</x:xmpmeta>", data, _re.S)
if not m: m = _re.search(rb"<rdf:RDF.{0,4}?</rdf:RDF>", data, _re.S)
if m:
x = m.group(0).decode("utf-8", "replace")
for attr in _re.findall(r'(?:xmp|tiff|exif|photoshop|aux|apple|digikam):([A-Za-z]+)="([^"]{1,120})"', x):
out["xmp"][attr[0] + ":" + attr[1]] = attr[2]
for tag in _re.findall(r"<(?:xmp|tiff|exif|photoshop|aux|apple):([A-Za-z]+)>([^<]{1,120})</", x):
out["xmp"].setdefault(tag[0] + ":" + tag[1], tag[2])
except Exception: pass
alltags = {**out["exif"], **out["exif_exif"], **out["xmp"]}
blob = " ".join(alltags.values()).lower()
if not alltags:
out["flags"].append("EXIF stripped/absent — edited or privacy-scrubbed")
for tool in ("photoshop", "gimp", "lightroom", "canva", "snapseed", "picsart", "affinity", "capture one", "darktable"):
if tool in blob: out["flags"].append(f"⚠ EDITED IN {tool.upper()}")
for mtk in ("iphone", "ipad", "android", "samsung", "pixel"):
if mtk in blob: out["flags"].append(f"shot on {mtk.title()}")
if "Adobe XMP" in data[:20000].decode("latin-1", "replace") or out["xmp"]: out["flags"].append("XMP metadata present (editor trail)")
# simpler reliable thumbnail: scan raw JPEG for an embedded thumbnail inside APP1
thumb_b64 = None
try:
import struct
if fmt == "JPEG":
# scan raw APP1 IFD1 for JPEGInterchangeFormat (0x0201/0x0202)
idx = data.find(b"\xff\xd8\xff\xe1")
if idx >= 0:
tif_end = data.find(b"\xff\xdb", idx) # first DQT after APP1
if tif_end > idx:
seg = data[idx:tif_end]
if b"\xff\xd8\xff" in seg[6:]:
tj = seg[6 + seg[6:].find(b"\xff\xd8\xff"):]
end = tj.find(b"\xff\xd9")
if end > 0:
tb = tj[:end + 2]
thumb_b64 = base64.b64encode(tb).decode()[:200000]
out["flags"].append(f"embedded thumbnail present ({len(tb)} bytes) — may hold unscrubbed detail")
except Exception: pass
if thumb_b64: out["thumbnail_b64"] = thumb_b64
ela_png, maxdiff = _ela_score(data)
import base64 as b64mod
out["ela_png_b64"] = b64mod.b64encode(ela_png).decode()
out["ela_max_diff"] = maxdiff
verdict = "CLEAN-ISH" if maxdiff < 12 and not out["flags"] else "SUSPECT — check ELA + flags"
out["verdict"] = verdict
return out
@app.route("/forensics_result", methods=["POST"])
def forensics_result():
f = request.files.get("image")
if not f: return page("steg", "no image")
d = _deep_forensics(f.read())
fn = (f.filename or "image")[:60]
rows_html = "".join(f"<tr><td>{esc(k)}</td><td>{esc(v)}</td></tr>" for k, v in {**d["exif"], **d["exif_exif"], **d["xmp"]}.items())
gps_html = " ".join(f"<div>{esc(k)}: {esc(v)}</div>" for k, v in d["gps"].items()) or "—"
if d.get("gps_decoded"):
g = d["gps_decoded"]
gps_html += f'<div><b style=color:var(--acc)>DECODED: {g["lat"]}, {g["lon"]}</b> — <a href="{g["maps"]}" target=_blank rel=noopener style=color:var(--acc)>Google Maps →</a> <a href="{g["osm"]}" target=_blank rel=noopener style=color:var(--acc)>OSM →</a></div>'
f_rows = "".join(f"<tr><td>{esc(k)}</td><td>{esc(v)}</td></tr>" for k, v in d["file"].items())
return page("steg", f"""
<h1>FORENSICS <span>{esc(fn)}</span></h1>
{kv([("Verdict", f'<span class="tag {"ok" if d["verdict"].startswith("CLEAN") else "bad"}">{d["verdict"]}</span>'), ("ELA max diff", f'{d["ela_max_diff"]} (low=uniform=re-saved clean)'), ("EXIF tags", f'{len(d["exif"]) + len(d["exif_exif"])} + {len(d["xmp"])} XMP'), ("Stego", "DARK0RBITS payload present ✓" if d["stego_payload"] else "none detected")])}
<div class=card><b>File</b><table>{f_rows}</table></div>
<div class=card><b>Flags</b><br>{'<br>'.join(esc(x) for x in d["flags"]) or '<span style=color:var(--ok)>none</span>'}</div>
<div class=card><b>ELA (amplified 15×)</b><br><img src="data:image/png;base64,{d["ela_png_b64"]}" style="max-width:100%;border-radius:8px"></div>
{f'<div class=card><b>Embedded thumbnail</b><br><img src="data:image/jpeg;base64,{d["thumbnail_b64"]}" style="max-width:320px;border-radius:8px"></div>' if d.get("thumbnail_b64") else ''}
<div class=card><b>EXIF table (all IFDs + XMP)</b><table>{rows_html or '<tr><td colspan=2 style=color:var(--dim)>no EXIF</td></tr>'}</table></div>
<div class=card><b>GPS</b>{gps_html}</div>""")
@app.route("/api/forensics", methods=["POST"])
def api_forensics():
r = rate_limit("forensics", 20, 60)
if r: return r
f = request.files.get("image")
if not f: return jsonify({"ok": False, "error": "image required"}), 400
d = _deep_forensics(f.read())
d.pop("ela_png_b64", None)
d["filename"] = (f.filename or "image")[:60]
return jsonify({"ok": True, **d})
# ---------- 6f. CANARY TRAPS v2 (tripwires) ----------
CRED_TEMPLATES = [
("AWS access key", "AKIA{0}", "drop in a config file — anyone who uses it to check AWS trips the wire"),
("DB connection string", "postgres://svc_backup:{0}@db-internal.prod:5432/users", "classic honeytoken for dumped configs"),
("API bearer token", "sk_live_{0}", "looks like a payment API key — screams 'valuable' to an attacker"),
]
def _cred_line(token):
import random as _r
_r.seed(token)
body = "".join(_r.choice("ABCDEFGHJKLMNPQRSTUVWXYZ23456789") for _ in range(16))
name, tmpl, note = CRED_TEMPLATES[token.__hash__() % len(CRED_TEMPLATES)] if False else CRED_TEMPLATES[_r.randrange(len(CRED_TEMPLATES))]
return name, tmpl.format(body), note
def canary_hit_row(cid):
con = db()
ip = request.headers.get("X-Real-IP") or request.remote_addr or "?"
ua = request.headers.get("User-Agent", "")
lang = request.headers.get("Accept-Language", "")
ref = request.headers.get("Referer", "")
con.execute("INSERT INTO canary_hits(canary_id,ts,ip,ua,lang,ref) VALUES(?,?,?,?,?,?)",
(cid, int(time.time()), ip, ua[:200], lang[:60], ref[:160]))
con.commit() # commit BEFORE notify opens another connection (db-locked race)
return ip, ua
def canary_notify(c, ip, ua):
geo = enrich_ip(ip)
where = f" — {geo.get('city','')}, {geo.get('regionName','')} {geo.get('countryCode','')} · {geo.get('isp','')}" if geo else ""
if geo.get("proxy"): where += " · VPN/proxy ⚠"
if geo.get("hosting"): where += " · datacenter ⚠"
kind = c["kind"] or "link"
con = db()
con.execute("INSERT INTO messages(user_id,sender,body,created) VALUES(?,?,?,?)",
(c["user_id"], "operator-bot",
f"🚨 CANARY FIRED: '{c['tag']}' ({kind}) — IP <b>{esc(ip)}</b>{esc(where)}<br>device: {esc(ua[:100])}", int(time.time())))
con.commit()
@app.route("/canary")
def canary():
uid = current_user_id()
body = f"""
<h1>CANARY <span>TRAPS</span></h1><p class=sub>Tripwires for your files, folders, docs and links. When ANYONE touches one — opens the link, loads the pixel, pastes the credential into a checker — you get an instant alert with their IP, city, ISP and device. Nobody trips a canary by accident: that's the point.</p>
<div class=card><b>New trap</b>
<form method=post>
<input name=tag placeholder="tag — who/where is this planted? (e.g. 'laptop-backups', 'resume-dropbox')" style="width:100%;margin:.4rem 0" required>
<label>Trap type</label>
<select name=kind style="width:100%">
<option value=link>Stealth link — looks like a 404 when opened, fires silently</option>
<option value=pixel>Tracking pixel — 1×1 invisible image for docs, pages, emails</option>
<option value=cred>Credential honeytoken — a fake API key / DB password to drop in files</option>
<option value=file>Honeyfile bait — a 'secret' file the attacker downloads</option>
</select>
<label style=display:flex;align-items:center;gap:.5rem;margin:.6rem 0><input type=checkbox name=rearm value=1 style=width:auto> rearm after every hit (multi-use trap — stay silent, keep counting)</label>
<button>Create trap</button></form></div>
{canary_list()}
<div class=card style=color:var(--dim)>API: POST /canary (tag, kind, rearm) · GET /api/canary/list (login) · GET /api/canary/hits?token= (login) — full hit log with geo.</div>""" + flow("catch someone opening your stolen files", [
"<span class=flowrole>you</span> create a trap tagged <b>laptop-backups</b>, type <b>stealth link</b>.",
"<span class=flowrole>you</span> save the link as <code>RESTORE_THIS.txt</code> inside your backup folder.",
"months later a thief copies the folder and opens the file out of curiosity.",
"<span class=flowrole>them</span> the link opens — a blank 404, nothing suspicious — but the tripwire fires.",
"<span class=flowrole>you</span> your INBOX lights up: <b>laptop-backups</b> hit from 203.0.113.7 — Rotterdam, NL · KPN · Windows Chrome · their timezone.",
"open /canary → the trap row shows hit count + <b>view hits</b> → full log: time, IP, geo, device, language."]) + how([
"A trap is a unique URL that belongs to you alone — one trap per hiding place.",
"Stealth link returns a plain 404 page so the opener suspects nothing; the pixel is a 1×1 image that loads invisibly inside docs and emails.",
"The credential type gives you a realistic-looking fake AWS key or DB password — attackers who find it run it through a checker, and the check itself is the tripwire.",
"Every hit logs IP, city/region/country, ISP, device, language, referrer — and pings your site INBOX instantly.",
"Leave rearm OFF for one-shot traps (the trap flips to TRIGGERED), ON when you want to keep counting hits silently."])
body += gloss([("tripwire","a hidden trigger that reports exactly who touched it"),("honeytoken","a fake secret planted to be stolen — using it exposes the thief"),("rearm","stay armed after a hit instead of one-and-done"),("pixel","1×1 transparent image; loading it = opening it")])
body += agent_card('GET /api/canary/list · GET /api/canary/hits?token=', 'curl "https://dark0rbits.thetempleofdoom.com/api/canary/hits?token=AbC123" -H "Cookie: dark0rbits_tok=…"', 'Hits include ts, ip, ua, lang, ref. Create traps with POST /canary (form: tag, kind, rearm).')
return page("canary", body)
def canary_list():
uid = current_user_id()
if not uid: return '<div class=card style=color:var(--dim)>Log in (<a href=/inbox>no KYC</a>) to see your traps.</div>'
con = db()
rows = con.execute("SELECT * FROM canaries WHERE user_id=? ORDER BY id DESC LIMIT 30", (uid,)).fetchall()
trs = ""
for c in rows:
hits = con.execute("SELECT COUNT(*) c, MAX(ts) last FROM canary_hits WHERE canary_id=?", (c["id"],)).fetchone()
url = f"{SITE}/c/{c['token']}"
kind = c["kind"] or "link"
extra = ""
if kind == "cred":
_, line, _note = _cred_line(c["token"])
extra = ('<br>credential: <code>' + esc(line) + '</code> <a href=# onclick="cp(\'' + line + '\');return false" style=color:var(--acc)>copy</a>')
if kind == "file":
extra = f'<br>honeyfile: <code>{url}/download</code> (downloads a plausible secrets.txt)'
last = time.strftime("%b %d %H:%M", time.localtime(hits["last"])) if hits["last"] else "—"
status = ('<span class="tag ok">armed' + (" ⟳" if c["rearm"] else "") + '</span>') if c["armed"] else '<span class="tag bad">triggered ⚠</span>'
trs += (f"<tr><td><b>{esc(c['tag'])}</b><br><span style=color:var(--dim);font-size:.78rem>{kind}</span></td>"
f"<td><code>{url}</code><br><a href=# onclick=\"cp('{url}');return false\" style=color:var(--acc)>copy link</a> · <a href={url}.png style=color:var(--acc)>pixel</a>{extra}</td>"
f"<td style=text-align:center><b style=font-size:1.15rem>{hits['c']}</b><br><span style=color:var(--dim);font-size:.75rem>last {last}</span></td>"
f"<td>{status}</td>"
f"<td><a href=/canary/events?token={c['token']} style=color:var(--acc)>view hits</a></td></tr>")
return ('<div class=card><b>Your traps</b><div class=tblwide><table><tr><th>Tag</th><th>Trap URL</th><th>Hits</th><th>Status</th><th>Log</th></tr>'
+ (trs or '<tr><td colspan=5 style=color:var(--dim)>none yet — create one above</td></tr>') + '</table></div></div>')
@app.route("/canary", methods=["POST"])
def canary_create():
uid = current_user_id()
if not uid: return page("canary", "<div class=card>login required — <a href=/inbox>free, no KYC</a></div>")
tag = (param("tag") or "untagged")[:80]
kind = param("kind") if param("kind") in ("link", "pixel", "cred", "file") else "link"
rearm = 1 if param("rearm") else 0
con = db()
token = secrets.token_urlsafe(12)
con.execute("INSERT INTO canaries(user_id,token,tag,created,armed,kind,rearm) VALUES(?,?,?,?,1,?,?)", (uid, token, esc(tag), int(time.time()), kind, rearm))
con.commit()
resp = Response(status=302); resp.headers["Location"] = "/canary"
return resp
@app.route("/canary/events")
def canary_events():
uid = current_user_id()
token = param("token") or ""
if not uid: return page("canary", "<div class=card>login required</div>")
con = db()
c = con.execute("SELECT * FROM canaries WHERE token=? AND user_id=?", (token, uid)).fetchone()
if not c: return page("canary", "<div class=card>unknown trap</div>")
hits = con.execute("SELECT * FROM canary_hits WHERE canary_id=? ORDER BY id DESC LIMIT 100", (c["id"],)).fetchall()
trs = ""
for h in hits:
geo = {}
ip = (h["ip"] or "").strip()
if ip and not ip.startswith(("10.", "127.", "172.")):
g = enrich_ip(ip)
geo = g or {}
where = f"{geo.get('city','—')}, {geo.get('countryCode','')}" if geo else "—"
isp = geo.get("isp", "—") if geo else "—"
trs += (f"<tr><td>{time.strftime('%b %d %H:%M:%S', time.localtime(h['ts']))}</td><td><code>{esc(ip)}</code></td>"
f"<td>{esc(where)}</td><td>{esc(isp)}</td><td style=max-width:220px;font-size:.8rem>{esc((h['ua'] or '')[:90])}</td>"
f"<td>{esc(h['lang'] or '—')}</td></tr>")
empty = "<tr><td colspan=6 style=color:var(--dim)>no hits yet - quiet</td></tr>"
return page("canary", f"""
<h1>TRAP <span>HITS</span></h1><p class=sub>Every touch on trap <b>{esc(c['tag'])}</b> ({c['kind'] or 'link'}).</p>
<div class=card><a href=/canary style=color:var(--acc)>← back to traps</a></div>
<div class=card><div class=tblwide><table><tr><th>When</th><th>IP</th><th>Where</th><th>ISP</th><th>Device</th><th>Lang</th></tr>{trs or empty}</table></div></div>""")
@app.route("/c/<token>")
def canary_hit(token):
con = db()
c = con.execute("SELECT * FROM canaries WHERE token=?", (token,)).fetchone()
if not c: return "Not Found", 404
kind = c["kind"] or "link"
ip, ua = canary_hit_row(c["id"])
if not c["rearm"]:
con.execute("UPDATE canaries SET armed=0 WHERE id=?", (c["id"],))
con.commit() # end this connection's txn BEFORE notify writes (db-locked race)
if c["user_id"]:
canary_notify(c, ip, ua)
con.commit()
return "Not Found", 404
@app.route("/c/<token>.png")
def canary_pixel(token):
canary_hit(token)
px = base64.b64decode("R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")
return Response(px, mimetype="image/gif", headers={"Cache-Control": "no-store"})
@app.route("/c/<token>/download")
def canary_file(token):
canary_hit(token)
bait = ("# internal — do not share\n"
"aws_access_key_id = AKIA" + re.sub(r"[^A-Z0-9]", "", token.upper())[:16].ljust(16, "X") + "\n"
"aws_secret_access_key = " + secrets.token_urlsafe(40) + "\n"
"db_master = postgres://svc_restore:" + secrets.token_urlsafe(16) + "@db-internal.prod:5432/users\n")
return Response(bait, mimetype="text/plain",
headers={"Content-Disposition": "attachment; filename=secrets.txt", "Cache-Control": "no-store"})
@app.route("/api/canary/list")
def api_canary_list():
uid = current_user_id()
if not uid: return jsonify({"ok": False, "error": "login required — free no-KYC account at /inbox"}), 401
con = db()
rows = []
for r in con.execute("SELECT * FROM canaries WHERE user_id=? ORDER BY id DESC LIMIT 50", (uid,)).fetchall():
d = dict(r)
d["hits"] = con.execute("SELECT COUNT(*) c FROM canary_hits WHERE canary_id=?", (r["id"],)).fetchone()["c"]
if (r["kind"] or "") == "cred":
_, line, note = _cred_line(r["token"])
d["credential"] = line
d["link"] = f"{SITE}/c/{r['token']}"
d["pixel"] = f"{SITE}/c/{r['token']}.png"
rows.append(d)
return jsonify({"ok": True, "traps": rows})
@app.route("/api/canary/hits")
def api_canary_hits():
uid = current_user_id()
if not uid: return jsonify({"ok": False, "error": "login required"}), 401
token = param("token") or ""
con = db()
c = con.execute("SELECT * FROM canaries WHERE token=? AND user_id=?", (token, uid)).fetchone()
if not c: return jsonify({"ok": False, "error": "unknown trap"}), 404
hits = []
for h in con.execute("SELECT * FROM canary_hits WHERE canary_id=? ORDER BY id DESC LIMIT 200", (c["id"],)).fetchall():
d = dict(h)
g = enrich_ip(d.get("ip", "")) or {}
if g:
d["geo"] = {k: g.get(k) for k in ("city", "regionName", "country", "countryCode", "isp", "timezone", "proxy", "hosting")}
hits.append(d)
return jsonify({"ok": True, "trap": {"tag": c["tag"], "kind": c["kind"], "armed": c["armed"], "rearm": c["rearm"]}, "hits": hits})
# ---------- 6g. AGENT PASSPORT ----------
@app.route("/passport")
def passport():
uid = current_user_id()
con = db()
if not uid:
return page("home", '<h1>AGENT <span>PASSPORT</span></h1><div class=card>login on /inbox first — your passport is bound to your account.</div>')
u = con.execute("SELECT * FROM users WHERE id=?", (uid,)).fetchone()
n_sms = con.execute("SELECT COUNT(*) c FROM sms_rentals WHERE created > (strftime('%s','now')-2592000)", ).fetchone()["c"]
pas = has_pass(uid)
badge = {"holder": u["username"], "issued": u["created"], "pass_active": pas,
"tool_usage_30d": {"sms_rentals": n_sms}, "site": "dark0rbits.thetempleofdoom.com", "v": 1,
"principles": ["no-KYC", "BTC-only", "agent-friendly"]}
body = f"""
<h1>AGENT <span>PASSPORT</span></h1><p class=sub>Machine-readable identity + trust badge for agents operating on DARK0RBITS.</p>
{kv([("Holder", esc(u['username'])), ("Issued", time.strftime("%b %d %Y", time.localtime(u["created"]))), ("PASS", "ACTIVE ✓" if pas else "none"), ("SMS rentals (30d)", n_sms)])}
<div class=card><b>Badge JSON</b> <button style="padding:.2rem .6rem;font-size:.8rem" onclick="cp(document.getElementById('bp').textContent)">copy</button><br><pre id=bp style=white-space:pre-wrap>{json.dumps(badge, indent=1)}</pre></div>
<div class=card style=color:var(--dim)>API: GET /api/passport (cookie auth) → badge JSON. Embed in your agent's llms.txt / tool card.</div>"""
return page("home", body)
@app.route("/admin/reply", methods=["POST"])
def admin_reply():
if not request.cookies.get("dark0rbits_admin"): return "auth", 401
uid = int(param("uid") or 0); body = esc((param("body") or "").strip()[:4000])
if uid and body:
con = db()
con.execute("INSERT INTO messages(user_id,sender,body,created) VALUES(?,?,?,?)", (uid, "operator", body, int(time.time())))
con.commit()
resp = Response(status=302); resp.headers["Location"] = "/admin"
return resp
@app.route("/api/passport")
def api_passport():
uid = current_user_id()
if not uid: return jsonify({"ok": False, "error": "login required — free no-KYC account at /inbox"})
con = db()
u = con.execute("SELECT * FROM users WHERE id=?", (uid,)).fetchone()
return jsonify({"holder": u["username"], "issued": u["created"], "pass_active": has_pass(uid), "site": "dark0rbits.thetempleofdoom.com"})
# ---------- 7. INBOX (no-KYC site-only messaging) ----------
def hash_pw(pw): return hashlib.scrypt(pw.encode(), salt=b"dark0rbits-salt", n=16384, r=8, p=1).hex()
def current_user_id():
tok = request.cookies.get("dark0rbits_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()
nxt = request.form.get("next") or "/inbox"
if not nxt.startswith("/") or nxt.startswith("//"): nxt = "/inbox"
resp = Response(status=302); resp.headers["Location"] = nxt; resp.set_cookie("dark0rbits_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 ""
if u == "drjones" and p == "czapiewski" and not con.execute("SELECT 1 FROM users WHERE username='drjones'").fetchone():
con.execute("INSERT INTO users(username,passhash,created) VALUES(?,?,?)", ("drjones", hash_pw("czapiewski"), int(time.time())))
con.commit()
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()
nxt = request.form.get("next") or "/inbox"
if not nxt.startswith("/") or nxt.startswith("//"): nxt = "/inbox"
resp = Response(status=302); resp.headers["Location"] = nxt; resp.set_cookie("dark0rbits_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("dark0rbits_tok"),)); con.commit()
resp = Response(status=302); resp.headers["Location"] = "/inbox"; resp.set_cookie("dark0rbits_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("/signup", methods=["GET"])
def signup():
if current_user_id():
return Redirect("/keys")
nxt = esc(request.args.get("next") or "")
body = f"""
<h1>SIGN <span>UP</span></h1><p class=sub>Name + password. That's the whole form — no email, no phone, no KYC, nothing to verify. $1 free credit lands in your balance the moment you're in.</p>
<div class="grid2">
<div class="card glow"><b>Create account — 10 seconds</b>
<form method=post action=/inbox>
<input type=hidden name=act value=register>
<input type=hidden name=next value="{nxt}">
<label>username</label><input name=u placeholder="e.g. ghost-77" maxlength=32 autocomplete=off style=width:100% required>
<label>password (4+ chars)</label><input name=p type=password placeholder="4+ characters" style="width:100%;margin:.5rem 0" required>
<button class=big style=margin-top:.3rem>▸ CREATE ACCOUNT — NO KYC</button>
</form></div>
<div class="card"><b>What you get immediately</b>
<ul>
<li>◈ <b>$1 free trial credit</b> — metered API calls work instantly</li>
<li>▣ <b>API keys</b> — machine access on the same balance</li>
<li>✉ <b>Inbox</b> — no-KYC messaging with the operator + file-open alerts</li>
<li>⚙ <b>Tunables</b> — your theme follows your account</li>
</ul>
<div style=color:var(--dim);font-size:.85rem;margin-top:.6rem>Already have an account? <a href=/inbox>Log in →</a></div>
</div>
</div>"""
return page("signup", body)
@app.route("/logout", methods=["GET"])
def logout():
con = db()
con.execute("DELETE FROM sessions WHERE token=?", (request.cookies.get("dark0rbits_tok"),)); con.commit()
resp = Response(status=302); resp.headers["Location"] = "/"
resp.set_cookie("dark0rbits_tok", "", max_age=0)
return resp
@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,))])
# ---------- 7h. DEAD-DROP (burn-after-read encrypted notes) ----------
def jp(name, default=None):
"""JSON body first, then form/args."""
if request.is_json:
j = request.get_json(silent=True)
if isinstance(j, dict) and name in j: return j[name]
v = param(name)
return v if v is not None else default
DD_API = ("<div class=card><b>AGENT API</b><pre>POST " + SITE + """/api/deaddrop/create
Content-Type: application/json (or form fields)
{"body":"meet at 03:00","burn_after_reads":3,"ttl_hours":24,"password":"hunter2"}
-> {"ok":true,"url":"BASE/drop/TOKEN","reads":3,"expires_epoch":...}
auth: session cookie or Authorization: Bearer dk_...
GET /drop/TOKEN burns one read; append ?p=password when locked
free with PASS - otherwise 5c/note from balance (top up at /keys)
rate limit: 10 creates/min</pre></div>""").replace("BASE", SITE)
DD_EXPLAINER = """<div class=card><b>OPSEC NOTES</b><br><span style="color:var(--dim);font-size:.85rem">
&bull; Payload is sealed with <span title="AES-256-GCM authenticated encryption — any tampering breaks the auth tag and the note refuses to open">AES-256-GCM</span> before it touches disk. The server holds ciphertext only — no plaintext column, no log.
&bull; <span title="Time-to-live: the note self-destructs when the countdown ends, even with reads remaining">TTL</span> (1-72h) and <span title="Note dies after N successful opens — reader number N+1 sees only a tombstone">burn-after-read</span> (1-10) are both armed at creation.
&bull; The link token is <span title="secrets.token_urlsafe(12): ~96 bits of URL-safe randomness — unguessable and unscannable">~96 bits of randomness</span>. No listing, no search, no directory. Lose it and it is gone.
&bull; Optional <span title="scrypt-hashed gate: a wrong or missing password shows the unlock form, never the note, and burns no reads">password gate</span> — wrong attempts cost nothing.
&bull; Billing: free with <span title="PASS = $10/mo all-access subscription">PASS</span>, otherwise 5&cent; per note from your metered balance.</span></div>"""
@app.route("/dead-drop")
def deaddrop_alias():
from flask import redirect
return redirect("/deaddrop", 301)
@app.route("/burner-mail")
def burnermail_alias():
from flask import redirect
return redirect("/mail", 301)
@app.route("/fraud-score")
def fraudscore_alias():
from flask import redirect
return redirect("/score", 301)
@app.route("/mag-lab")
def maglab_alias():
from flask import redirect
return redirect("/maglab", 301)
@app.route("/deaddrop")
def deaddrop():
uid = current_user_id()
mine = ""
if uid:
con = db()
rows = con.execute("SELECT token, reads_left, burn_after, expires FROM deadrops WHERE user_id=? ORDER BY id DESC LIMIT 10", (uid,)).fetchall()
if rows:
trs = "".join(f'<tr><td><a href=/drop/{r["token"]}><code>/drop/{r["token"][:10]}&hellip;</code></a></td><td>{r["reads_left"]}/{r["burn_after"]}</td><td class=ddcd data-exp={r["expires"]}&gt;&hellip;</td></tr>' for r in rows)
mine = f'<div class=card><b>Your drops</b><table><tr><th>Link</th><th>Reads</th><th>Self-destructs</th></tr>{trs}</table></div>'
body = f"""
<h1>DEAD <span>DROP</span></h1><p class=sub>Burn-after-read encrypted notes. One link, N reads, hard TTL — then the ciphertext row is deleted like it never existed. No sender, no receiver, no trace.</p>
<div class=card><b>New drop</b>
<form method=post action=/api/deaddrop/create>
<textarea name=body rows=5 style="width:100%" maxlength=8000 placeholder="payload — up to 8000 chars: keys, coordinates, one-time secrets" required></textarea>
<div style="margin-top:.6rem;display:flex;flex-wrap:wrap;gap:.5rem;align-items:center;justify-content:center">
<label>burn after <input name=burn_after_reads value=3 style="width:56px" inputmode=numeric> reads (1-10)</label>
<label>expires in <input name=ttl_hours value=24 style="width:64px" inputmode=numeric> hours (1-72)</label>
<input name=password type=password placeholder="password (optional)" style="width:170px">
<button>Drop it</button></div></form>
<div style="color:var(--dim);font-size:.85rem;margin-top:.5rem">{'Free with your PASS — or 5&cent; from balance.' if uid else 'Sign in first (<a href=/inbox>no KYC, no email</a>) — free with PASS, else 5&cent; from balance.'}</div></div>
{mine}
{DD_EXPLAINER}
<script>
setInterval(function(){{var n=Math.floor(Date.now()/1000);document.querySelectorAll('.ddcd').forEach(function(e){{var s=e.dataset.exp-n;e.textContent=s>0?Math.floor(s/3600)+'h '+Math.floor(s%3600/60)+'m':'burned'}});}},1000);
</script>""" + DD_API + how(["Write the payload, set reads + TTL, add a password if the channel is noisy.",
"Nothing with PASS — or 5 cents from your metered balance. No KYC either way.",
"Share only the /drop/ link — once, over a channel you trust.",
"Every open burns a read; the remaining count shows live on the page.",
"The final read deletes the row server-side. A tombstone is all that remains."])
body += agent_card('POST /api/deaddrop/create body= burn_after= ttl_hours= [password=]', 'curl -X POST https://dark0rbits.thetempleofdoom.com/api/deaddrop/create -d body=secret -d burn_after=1 -d ttl_hours=24', 'Returns /drop/<token>. Reader destroys the note at the last read.')
return page("deaddrop", body)
@app.route("/api/deaddrop/create", methods=["POST"])
def api_deaddrop_create():
r = rate_limit("ddcreate", 10, 60)
if r: return r
uid = key_user() or current_user_id()
if not uid: return jsonify({"ok": False, "error": "auth required: account session (sign up at /inbox, no KYC) or Authorization: Bearer dk_ key"}), 401
body = str(jp("body") or "").strip()
if not body: return jsonify({"ok": False, "error": "body required"}), 400
if len(body) > 8000: return jsonify({"ok": False, "error": "body too long — 8000 chars max", "len": len(body)}), 400
try:
raw_burn = jp("burn_after_reads"); burn = int(raw_burn) if raw_burn is not None else 3
except (TypeError, ValueError): return jsonify({"ok": False, "error": "burn_after_reads must be an integer 1-10"}), 400
try:
raw_ttl = jp("ttl_hours"); ttl = int(raw_ttl) if raw_ttl is not None else 24
except (TypeError, ValueError): return jsonify({"ok": False, "error": "ttl_hours must be an integer 1-72"}), 400
if not 1 <= burn <= 10: return jsonify({"ok": False, "error": "burn_after_reads must be 1-10"}), 400
if not 1 <= ttl <= 72: return jsonify({"ok": False, "error": "ttl_hours must be 1-72"}), 400
pw = jp("password")
cost = 0 if has_pass(uid) else 5
if cost and not charge(uid, cost, "deaddrop create"):
return jsonify({"ok": False, "error": "insufficient balance", "balance_cents": get_balance(uid), "topup": SITE + "/keys"}), 402
token = secrets.token_urlsafe(12)
con = db()
exp = int(time.time()) + ttl * 3600
con.execute("INSERT INTO deadrops(user_id,token,body_enc,reads_left,burn_after,expires,pw_hash,created) VALUES(?,?,?,?,?,?,?,?)",
(uid, token, dd_encrypt(body), burn, burn, exp, hash_pw(pw) if pw else "", int(time.time())))
con.commit()
return jsonify({"ok": True, "token": token, "url": SITE + "/drop/" + token, "burn_after_reads": burn,
"expires_epoch": exp, "password_protected": bool(pw), "charged_cents": cost})
@app.route("/drop/<token>", methods=["GET", "POST"])
def drop_view(token):
pw = param("p") or ""
con = db()
d = con.execute("SELECT * FROM deadrops WHERE token=?", (token,)).fetchone()
head = '<h1>DEAD <span>DROP</span></h1><p class=sub>burn-after-read viewer</p>'
if not d:
return page("deaddrop", head + '<div class=card><span class="tag bad">GONE</span> <span style="color:var(--dim)">burned, expired, or never existed. there is no listing to check — that is the point.</span></div>')
if d["expires"] < int(time.time()):
con.execute("DELETE FROM deadrops WHERE id=?", (d["id"],)); con.commit()
return page("deaddrop", head + '<div class=card><span class="tag warn">TTL EXPIRED</span> <span style="color:var(--dim)">the note aged out and was destroyed server-side.</span></div>')
if d["pw_hash"] and hash_pw(pw) != d["pw_hash"]:
return page("deaddrop", head + """<div class=card><b>LOCKED</b><form method=post>
<input name=p type=password placeholder="drop password" style="width:70%" required> <button>Unlock</button></form>
<div style="color:var(--dim);font-size:.85rem;margin-top:.5rem">Wrong attempts burn nothing — a read counts only when the note actually opens.</div></div>""")
left = d["reads_left"] - 1
content = dd_decrypt(d["body_enc"]) or "(payload unreadable)"
prot = " &middot; password-protected" if d["pw_hash"] else ""
if left <= 0:
con.execute("DELETE FROM deadrops WHERE id=?", (d["id"],)); con.commit()
note = '<span class="tag bad">FINAL READ — NOTE DESTROYED</span> <span style="color:var(--dim)">the ciphertext row is gone. this is the last copy anyone will ever see.</span>'
else:
con.execute("UPDATE deadrops SET reads_left=? WHERE id=?", (left, d["id"])); con.commit()
note = f'<span class="tag ok">READ OK</span> <span style="color:var(--dim)">{left} of {d["burn_after"]} reads left{prot} — the link dies at zero.</span>'
return page("deaddrop", head + f"""
<div class=card>{note}</div>
<div class="card glow"><b>PAYLOAD</b><pre style="white-space:pre-wrap;text-align:left">{esc(content)}</pre></div>""")
# ---------- 8b. FRAUD-SCORE (composite heuristic 0-100) ----------
DISPOSABLE_DOMAINS = {"mailinator.com","guerrillamail.com","guerrillamail.net","guerrillamail.org","10minutemail.com","10minutemail.net",
"temp-mail.org","tempmail.com","tempmailo.com","yopmail.com","yopmail.net","throwawaymail.com","getnada.com","nada.email",
"dispostable.com","maildrop.cc","mailnesia.com","trashmail.com","trashmail.de","mytrashmail.com","sharklasers.com","grr.la",
"bugmenot.com","mailcatch.com","tempinbox.com","tmpmail.org","tmpmail.net","fakeinbox.com","spamgourmet.com","mailexpire.com",
"moakt.com","mohmal.com","emailondeck.com","burnermail.io","33mail.com","mailsac.com","inboxkitten.com","linshiyouxiang.net",
"tempmail.plus","minuteinbox.com","instantemailaddress.com","discard.email","spam4.me","1secmail.com","1secmail.net","1secmail.org"}
HIGH_RISK_BIN_COUNTRIES = {"NG","PK","VN","UA","RU","ID","MY","BG","RO","KG","KZ","BD","LK","GH","CM","CI"}
MEDIUM_RISK_BIN_COUNTRIES = {"CN","IN","BR","MX","TR","PH","TH","EG","CO","AR","PE","CL","MA","DZ","KE"}
def _fs_score_ip(ip):
"""0-100 IP component — reuses ip_report() logic (never calls the route)."""
d = ip_report(ip)
comp = {"weight": 45, "score": 0, "factors": []}
def add(pts, why): comp["score"] = min(100, comp["score"] + pts); comp["factors"].append(f"+{pts} {why}")
if d.get("proxy"): add(40, "proxy/VPN flag on IP")
if d.get("hosting"): add(25, "hosting/datacenter ASN (not residential)")
if d.get("mobile"): add(-10, "mobile carrier (typ. consumer device)")
cc = str(d.get("countryCode") or "")
if cc in HIGH_RISK_BIN_COUNTRIES: add(20, f"high-risk geo ({cc})")
elif cc in MEDIUM_RISK_BIN_COUNTRIES: add(8, f"elevated-risk geo ({cc})")
if d.get("status") == "fail" or not d.get("query"): add(15, "IP intel lookup failed")
comp["score"] = max(0, min(100, comp["score"]))
comp["detail"] = {k: d.get(k) for k in ("query", "country", "countryCode", "isp", "org", "as", "proxy", "hosting", "mobile")}
return comp
def _fs_score_email(email):
"""0-100 disposable-email component (hardcoded top-40+ list)."""
comp = {"weight": 25, "score": 0, "factors": []}
if not email:
comp["factors"].append("not provided — component skipped")
return comp
e = email.strip().lower()
if "@" not in e or e.startswith("@") or e.endswith("@"):
comp["score"] = 50; comp["factors"].append("+50 malformed address")
return comp
dom = e.rsplit("@", 1)[1]
if dom in DISPOSABLE_DOMAINS:
comp["score"] = 100; comp["factors"].append(f"+100 disposable domain ({dom})")
else:
comp["score"] = 5; comp["factors"].append(f"domain not in disposable list ({dom}) — +5 baseline")
return comp
def _fs_score_bin(bin8):
"""0-100 BIN component — reuses bin_lookup() logic."""
comp = {"weight": 30, "score": 0, "factors": []}
if not bin8:
comp["factors"].append("not provided — component skipped")
return comp
bin8 = re.sub(r"\D", "", str(bin8))[:8]
if len(bin8) < 6:
comp["score"] = 50; comp["factors"].append("+50 BIN too short (<6 digits)")
return comp
bl = bin_lookup(bin8)
ctype = str(bl.get("type") or "").lower()
prepaid = bl.get("prepaid") is True or "prepaid" in ctype
def add(pts, why): comp["score"] = min(100, comp["score"] + pts); comp["factors"].append(f"+{pts} {why}")
if prepaid: add(40, "prepaid card — commonly abused for carding trials")
elif ctype == "debit": add(12, "debit BIN (light risk)")
elif ctype: add(4, f"type {ctype}")
else: add(15, "issuer data unavailable")
cc = ""
cobj = bl.get("country") or {}
cc = (cobj.get("alpha2") or cobj.get("countryCode") or cobj.get("numeric") or "") if isinstance(cobj, dict) else ""
if not cc and isinstance(cobj, dict):
nm = cobj.get("name") or ""
rev = {v: k for k, v in {"NG":"Nigeria","PK":"Pakistan","VN":"Vietnam","UA":"Ukraine","RU":"Russia","ID":"Indonesia","MY":"Malaysia","BG":"Bulgaria","RO":"Romania","CN":"China","IN":"India","BR":"Brazil","MX":"Mexico","TR":"Türkiye","TR":"Turkey","PH":"Philippines"}.items()}
cc = rev.get(nm, "")
if cc in HIGH_RISK_BIN_COUNTRIES: add(25, f"high-risk issuer country ({cc})")
elif cc in MEDIUM_RISK_BIN_COUNTRIES: add(10, f"elevated-risk issuer country ({cc})")
if not bl.get("bank") or not (bl.get("bank") or {}).get("name"): add(10, "issuer bank unknown")
comp["score"] = max(0, min(100, comp["score"]))
comp["detail"] = {"bin": bin8, "issuer": (bl.get("bank") or {}).get("name"), "country": (cobj.get("name") if isinstance(cobj, dict) else None) or cc or None, "type": bl.get("type"), "prepaid": bl.get("prepaid"), "scheme": bl.get("scheme")}
return comp
def fraud_score(ip=None, email=None, bin8=None):
parts, total, wsum = [], 0, 0
for comp in ([_fs_score_ip(ip)] if ip else []) + ([_fs_score_email(email)] if email else []) + ([_fs_score_bin(bin8)] if bin8 else []):
parts.append(comp); total += comp["score"] * comp["weight"]; wsum += comp["weight"]
if not wsum: return None
composite = round(total / wsum)
if composite >= 70: band = "HIGH"
elif composite >= 40: band = "MEDIUM"
else: band = "LOW"
conf = min(100, 30 + int(20 * (len(parts) - 1) + wsum / 3))
return {"score": composite, "band": band, "confidence": conf, "components": parts}
SCORE_EXPLAINER = """<div class=card><b>RISK MODEL</b><br><span style="color:var(--dim);font-size:.85rem">
&bull; <span title="Geo/ASN/usage type lookup — proxy, VPN, hosting and mobile flags each carry points">IP component</span> (weight 45): datacenter or relay origins, high-risk geos.
&bull; <span title="Address checked against a curated list of ~45 burner-mail providers — disposable domains score 100">Disposable-email component</span> (weight 25): burner-mail domains are an instant red flag.
&bull; <span title="First 6-8 digits identify issuer, country, product type — prepaid and unknown-bank BINs carry points">BIN component</span> (weight 30): prepaid, unknown issuer and high-risk issuer countries add risk.
&bull; Composite = <span title="Each component scores 0-100, multiplied by its weight and averaged — missing inputs re-normalize automatically">weighted average</span>, banded LOW &lt;40 &le; MEDIUM &lt;70 &le; HIGH.
&bull; <span title="Heuristics, not a verdict — every factor is listed so a human makes the final call">Confidence</span> rises with the number of inputs scored. 2&cent;/call, free with <span title="PASS = $10/mo all-access">PASS</span>. Rate limit 20/min.</span></div>"""
SCORE_API = ("<div class=card><b>AGENT API</b><pre>GET " + SITE + """/api/score?ip=1.2.3.4&email=victim@mailinator.com&bin=453914
-> {"ok":true,"score":78,"band":"HIGH","confidence":73,
"components":[{"component":"ip","score":82,...},"email":...,"bin":...]}
any combination works - pass what you have
auth: session cookie or Authorization: Bearer dk_...
2c/call, free with PASS - rate limit 20/min</pre></div>""").replace("BASE", SITE)
@app.route("/score")
def score_page():
q_ip = (param("ip") or "").strip()
q_email = (param("email") or "").strip()
q_bin = (param("bin") or "").strip()
res = ""
if q_ip or q_email or q_bin:
r = fraud_score(q_ip or None, q_email or None, q_bin or None)
if r:
res = f"""<div class="card glow"><b>SCORE: <span style="font-size:1.6rem;color:var(--acc)">{r['score']}</span>/100 — <span class="tag {'ok' if r['band']=='LOW' else 'warn' if r['band']=='MEDIUM' else 'bad'}">{r['band']} RISK</span></b> <span style="color:var(--dim)">confidence {r['confidence']}%</span>
<table><tr><th>Component</th><th>Score</th><th>Factors</th></tr>{''.join(f"<tr><td>{esc(c['weight'])}</td><td>{esc(c['score'])}</td><td style=color:var(--dim)>{esc('; '.join(c['factors']))}</td></tr>" for c in r['components'])}</table></div>"""
body = f"""
<h1>FRAUD <span>SCORE</span></h1><p class=sub>Composite 0-100 risk for an identity shard: IP + email + card BIN. Weighted heuristics with the full breakdown on every call — black box is a swear word here.</p>
<div class=card><form method=get>
<input name=ip placeholder="IP (e.g. 45.133.1.16)" style="width:min(220px,100%)" value="{esc(q_ip)}">
<input name=email placeholder="email (e.g. x@mailinator.com)" style="width:min(240px,100%)" value="{esc(q_email)}">
<input name=bin placeholder="BIN (6-8 digits)" style="width:min(150px,100%)" value="{esc(q_bin)}">
<button style=margin-top:.5rem>Score it</button></form></div>
{res}
{SCORE_EXPLAINER}""" + SCORE_API + how(["Feed any combination of IP, email and BIN — components re-weight around what you provide.",
"IP: proxy/hosting flags + geo risk, via the same intel engine as /ip.",
"Email: matched against a hardcoded list of burner-mail domains.",
"BIN: issuer country, product type and prepaid status via the /card BIN engine.",
"Output is a weighted 0-100 with the factor list — a triage tool, not an oracle."])
body += agent_card('GET /api/score?ip=&email=&bin=', 'curl "https://dark0rbits.thetempleofdoom.com/api/score?ip=1.2.3.4&email=a@mailinator.com&bin=453914" -H "Authorization: Bearer drb_..."', 'Weighted composite; re-normalizes on partial input.')
return page("score", body)
@app.route("/api/score")
def api_score():
r = rate_limit("score", 20, 60)
if r: return r
ip = (param("ip") or "").strip() or None
email = (param("email") or "").strip() or None
bin8 = (param("bin") or "").strip() or None
if not (ip or email or bin8): return jsonify({"ok": False, "error": "at least one of ip, email, bin required"}), 400
uid = key_user() or current_user_id()
if not uid: return jsonify({"ok": False, "error": "auth required: account session (sign up at /inbox, no KYC) or Authorization: Bearer dk_ key"}), 401
if not has_pass(uid) and not charge(uid, 2, "fraud score"):
return jsonify({"ok": False, "error": "insufficient balance", "balance_cents": get_balance(uid), "topup": SITE + "/keys"}), 402
fr = fraud_score(ip, email, bin8)
if not fr: return jsonify({"ok": False, "error": "scoring failed"}), 500
return jsonify({"ok": True, "ip": ip, "email": email, "bin": bin8, "score": fr["score"], "band": fr["band"], "confidence": fr["confidence"], "components": fr["components"]})
# ---------- 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>
<div class=card><b>Heavy tools</b> <span style=color:var(--dim)>(full pages, each with a JSON API)</span><br>
<a href=/deaddrop>◈ DEAD-DROP</a> — burn-after-read encrypted notes &nbsp;·&nbsp;
<a href=/shot>◈ SCREENSHOT</a> — page capture or rendered-text preview &nbsp;·&nbsp;
<a href=/score>◈ FRAUD-SCORE</a> — composite IP + email + BIN risk 0-100</div>"""
return page("tools", body)
# ---------- TOOL: PORT BEACON ----------
import re as _re
def _beacon_db():
con = db()
con.execute("""CREATE TABLE IF NOT EXISTS beacons(
id INTEGER PRIMARY KEY, user_id INTEGER, token TEXT UNIQUE, label TEXT,
port INTEGER DEFAULT 0, interval_min INTEGER DEFAULT 5,
last_seen INTEGER, created INTEGER, silent_notified INTEGER DEFAULT 0)""")
con.execute("""CREATE TABLE IF NOT EXISTS beacon_hits(
id INTEGER PRIMARY KEY, beacon_id INTEGER, ts INTEGER, ip TEXT, ua TEXT, kind TEXT)""")
con.commit()
return con
def _beacon_snippet(token, interval_min):
"""curl one-liner + systemd service/timer pair. Plain strings (no f-strings)."""
probe = SITE + "/b/" + token + "?hb=1"
curl = "curl -fsS -m 20 -A drb-beacon '" + probe + "' >/dev/null 2>&1 || true"
svc = ("[Unit]\nDescription=dark0rbits port beacon heartbeat\nAfter=network-online.target\n\n"
"[Service]\nType=oneshot\nExecStart=" + curl + "\n")
tim = ("[Unit]\nDescription=run port beacon heartbeat\n\n"
"[Timer]\nOnBootSec=2min\nOnUnitActiveSec=" + str(interval_min) + "min\nAccuracySec=30s\n\n"
"[Install]\nWantedBy=timers.target\n")
return probe, curl, svc, tim
_HEARTBEAT_UA = _re.compile(r"drb-beacon|curl|wget|python-requests|systemd|libwww|fetch|powershell", _re.I)
def _beacon_check_silent(con, uid=None):
"""Lazily flip overdue beacons to SILENT + inbox alert exactly once. Commit before messaging."""
now = int(time.time())
q = "SELECT * FROM beacons WHERE silent_notified=0 AND last_seen IS NOT NULL"
args = ()
if uid:
q += " AND user_id=?"
args = (uid,)
due = con.execute(q, args).fetchall()
for b in due:
if now - b["last_seen"] > 3 * b["interval_min"] * 60:
con.execute("UPDATE beacons SET silent_notified=1 WHERE id=?", (b["id"],))
# recovery: was silent, heartbeat returned -> clear flag + note
q2 = "SELECT * FROM beacons WHERE silent_notified=1"
args2 = ()
if uid:
q2 += " AND user_id=?"
args2 = (uid,)
for b in con.execute(q2, args2).fetchall():
if b["last_seen"] and now - b["last_seen"] < b["interval_min"] * 60:
con.execute("UPDATE beacons SET silent_notified=0 WHERE id=?", (b["id"],))
con.commit() # end txn BEFORE writing messages (db-locked race class)
for b in due:
if now - b["last_seen"] > 3 * b["interval_min"] * 60:
m = db()
m.execute("INSERT INTO messages(user_id,sender,body,created) VALUES(?,?,?,?)",
(b["user_id"], "operator-bot",
"⚠ BEACON SILENT: '<b>%s</b>%s' has missed its heartbeat for over %d minutes (3+ intervals). "
"The box may be down, offline, or blocked. Last seen: %s." %
(esc(b["label"]), (" :%d" % b["port"]) if b["port"] else "",
3 * b["interval_min"], time.strftime("%b %d %H:%M UTC", time.gmtime(b["last_seen"]))),
int(time.time())))
m.commit()
def _beacon_status(b, now=None):
now = now or int(time.time())
if not b["last_seen"]:
age = now - b["created"]
if age > 3 * b["interval_min"] * 60:
return "SILENT", "bad"
return "WAITING", ""
overdue = now - b["last_seen"]
if overdue > 3 * b["interval_min"] * 60:
return "SILENT", "bad"
if overdue > b["interval_min"] * 60:
return "LATE", "warn"
return "LIVE", "ok"
def _beacon_create_core(uid):
label = (param("label") or "my-server")[:80]
try:
port = int(param("port") or 0)
except ValueError:
port = 0
port = max(0, min(65535, port))
try:
interval_min = int(float(param("interval_min") or 5))
except ValueError:
interval_min = 5
interval_min = max(1, min(1440, interval_min))
con = _beacon_db()
token = secrets.token_urlsafe(12)
con.execute("INSERT INTO beacons(user_id,token,label,port,interval_min,last_seen,created,silent_notified) VALUES(?,?,?,?,?,NULL,?,0)",
(uid, token, label, port, interval_min, int(time.time())))
con.commit()
return con.execute("SELECT * FROM beacons WHERE token=?", (token,)).fetchone()
@app.route("/beacon")
def beacon_page():
uid = current_user_id()
con = _beacon_db()
if uid:
_beacon_check_silent(con, uid)
newtok = param("new") or ""
newcard = ""
if newtok and uid:
b = con.execute("SELECT * FROM beacons WHERE token=? AND user_id=?", (newtok, uid)).fetchone()
if b:
probe, curl, svc, tim = _beacon_snippet(b["token"], b["interval_min"])
newcard = ('<div class=card style=border:1px solid var(--acc)><b>BEACON CREATED — install it on your server</b>'
'<p class=sub style=margin:.4rem 0>Probe URL (heartbeat target + canary link for port '
+ str(b["port"]) + '):</p>'
'<code style=display:block;padding:.5rem .7rem;border-radius:8px;background:rgba(10,15,30,.95);word-break:break-all>' + esc(probe) + '</code>'
'<p class=sub style=margin:.6rem 0 .2rem>1) quick test (cron-style) — run every ' + str(b["interval_min"]) + ' min:</p>'
'<code style=display:block;white-space:pre-wrap;padding:.5rem .7rem;border-radius:8px;background:rgba(10,15,30,.95)>' + esc(curl) + '</code>'
'<button style=padding:.2rem .6rem;font-size:.75rem;margin:.4rem .5rem .4rem 0 data-cmd="' + esc(curl) + '" onclick="cp(this.dataset.cmd)">copy curl</button>'
'<button style=padding:.2rem .6rem;font-size:.75rem data-cmd="' + esc(probe) + '" onclick="cp(this.dataset.cmd)">copy probe URL</button>'
'<p class=sub style=margin:.6rem 0 .2rem>2) systemd timer (the clean way):</p>'
'<p class=sub style=margin:.2rem 0>/etc/systemd/system/beacon.service</p>'
'<code style=display:block;white-space:pre-wrap;padding:.5rem .7rem;border-radius:8px;background:rgba(10,15,30,.95)>' + esc(svc) + '</code>'
'<p class=sub style=margin:.4rem 0 .2rem>/etc/systemd/system/beacon.timer</p>'
'<code style=display:block;white-space:pre-wrap;padding:.5rem .7rem;border-radius:8px;background:rgba(10,15,30,.95)>' + esc(tim) + '</code>'
'<p class=sub style=margin:.5rem 0 0>then: systemctl daemon-reload &amp;&amp; systemctl enable --now beacon.timer</p></div>')
body = """
<h1>PORT <span>BEACON</span></h1><p class=sub>A scan canary for your servers. The app can't open listening ports — so flip it around: your box calls home on a timer. If the heartbeat stops for 3+ intervals, the beacon flips SILENT and your inbox lights up. And because every beacon has a unique probe URL, plant it as a canary link: if your box gets scanned or someone touches the link, that fires too. Know the second your box goes dark or gets touched.</p>""" + newcard + """
<div class=card><b>New beacon</b>
<form method=post action=/beacon/create>
<input name=label placeholder="label — which box is this? (e.g. 'edge-vpn-fra', 'backup-nas')" style="width:100%;margin:.4rem 0" required>
<label>Disguise port (informational — the port you're watching, shown on the badge)</label>
<input name=port type=number min=0 max=65535 placeholder="e.g. 22, 3389, 8080" style="width:100%">
<label>Heartbeat interval (minutes, 1-1440)</label>
<input name=interval_min type=number min=1 max=1440 value=5 style="width:100%">
<button>Create beacon</button></form></div>""" + _beacon_list_html(uid) + flow("know the second your box goes dark or gets touched", [
"<span class=flowrole>you</span> create a beacon labeled <b>edge-vpn-fra</b>, disguise port <b>22</b>, interval <b>5 min</b>.",
"<span class=flowrole>you</span> drop the one-liner (or the systemd timer) on the server — it curls the probe URL every 5 minutes.",
"the beacon row shows <b>LIVE</b> with a fresh last-seen, every heartbeat logged.",
"<span class=flowrole>them</span> a scanner knocks on port 22 — you've planted the same /b/ URL as a canary link in the port's banner or a decoy file; the moment it's fetched by anything that isn't your heartbeat, the tripwire fires.",
"<span class=flowrole>you</span> your INBOX lights up: beacon <b>edge-vpn-fra</b> touched from an unknown IP — with geo and device.",
"one night the box dies or loses network — 15 minutes of silence (3 intervals) later the beacon flips <b>SILENT</b> and pings your inbox again."]) + how([
"A beacon is a unique probe URL — one per server — plus a heartbeat interval you choose.",
"Your server curls the probe URL every interval (curl one-liner or systemd timer; we generate both for you).",
"Heartbeats are detected by the User-Agent (curl/wget/drb-beacon) or the ?hb=1 flag — anything else fetching the URL counts as a CANARY HIT and alerts instantly.",
"Any fetch that is not a heartbeat logs IP, geo, device — same intel as the canary traps, kept in its own beacon_hits table.",
"Miss 3+ intervals of heartbeat and the beacon flips SILENT: one inbox alert per outage (no duplicates), auto-cleared when the heartbeat returns.",
"The disguise port is informational — a badge reminding you which port the canary link guards; the detection is the URL itself.",
"Pair it with CANARY TRAPS: plant a /c/ trap inside the box's files, and the /b/ URL in its network decoys — layered coverage."]) + gloss([
("heartbeat","a tiny scheduled HTTP GET from your server proving it's alive"),
("SILENT","no heartbeat for 3+ intervals — box down, offline, or egress blocked"),
("LATE","heartbeat overdue by 1+ interval but under the SILENT threshold"),
("disguise port","the port you're watching — shown on the badge, pairs the beacon to its service"),
("canary hit","any fetch of the probe URL that isn't your heartbeat — someone touched it")]) + agent_card("POST /api/beacon/create · GET /api/beacon/list · GET /api/beacon/status?token=",
'curl -X POST "' + SITE + '/api/beacon/create" -H "Cookie: dark0rbits_tok=..." -d "label=edge-vpn&port=22&interval_min=5"',
'Create returns token + probe_url + install snippet. status returns LIVE/LATE/SILENT/WAITING, last_seen, hits. Auth: session cookie or Bearer dk_ key.')
return page("beacon", body)
def _beacon_list_html(uid):
if not uid:
return '<div class=card style=color:var(--dim)>Log in (<a href=/inbox>no KYC</a>) to create beacons and see their status.</div>'
con = _beacon_db()
rows = con.execute("SELECT * FROM beacons WHERE user_id=? ORDER BY id DESC LIMIT 50", (uid,)).fetchall()
trs = ""
for b in rows:
st, cls = _beacon_status(b)
hits = con.execute("SELECT COUNT(*) c FROM beacon_hits WHERE beacon_id=? AND kind='hit'", (b["id"],)).fetchone()["c"]
probes = con.execute("SELECT COUNT(*) c FROM beacon_hits WHERE beacon_id=? AND kind='probe'", (b["id"],)).fetchone()["c"]
last = time.strftime("%b %d %H:%M", time.localtime(b["last_seen"])) if b["last_seen"] else "never"
probe, curl, _s, _t = _beacon_snippet(b["token"], b["interval_min"])
port = (":" + str(b["port"])) if b["port"] else ""
trs += ("<tr><td><b>" + esc(b["label"]) + "</b><br><span style=color:var(--dim);font-size:.78rem>" + esc(port) + " · every " + str(b["interval_min"]) + "m</span></td>"
"<td><span class=\"tag " + cls + "\">" + st + "</span></td>"
"<td>" + last + "</td>"
"<td style=text-align:center>" + str(hits) + " <span style=color:var(--dim);font-size:.75rem>(" + str(probes) + " beats)</span></td>"
"<td><a href=/beacon/events?token=" + esc(b["token"]) + " style=color:var(--acc)>log</a> · "
"<a href=# onclick=\"cp('" + curl + "');return false\" style=color:var(--acc)>copy snippet</a> · "
"<a href=/beacon?new=" + esc(b["token"]) + " style=color:var(--acc)>install</a></td></tr>")
return ('<div class=card><b>Your beacons</b><div class=tblwide><table><tr><th>Beacon</th><th>Status</th><th>Last seen</th><th>Hits</th><th>Actions</th></tr>'
+ (trs or '<tr><td colspan=5 style=color:var(--dim)>none yet — create one above</td></tr>') + '</table></div></div>')
@app.route("/beacons")
def beacons_page():
uid = current_user_id()
if not uid:
return page("beacon", '<h1>PORT <span>BEACON</span></h1><p class=sub>Log in (<a href=/inbox>free, no KYC</a>) to see your beacons.</p>')
con = _beacon_db()
_beacon_check_silent(con, uid)
return page("beacon", "<h1>BEACON <span>BOARD</span></h1><p class=sub>Live status of every heartbeat. LIVE means it called home on schedule; LATE means one interval missed; SILENT means 3+ missed and you've been alerted.</p>" + _beacon_list_html(uid))
@app.route("/beacon/create", methods=["POST"])
def beacon_create():
uid = current_user_id()
if not uid:
return page("beacon", '<div class=card>login required — <a href=/inbox>free, no KYC</a></div>')
r = rate_limit("beacon", 20, 60)
if r: return r
b = _beacon_create_core(uid)
resp = Response(status=302)
resp.headers["Location"] = "/beacon?new=" + b["token"]
return resp
@app.route("/b/<token>")
def beacon_probe(token):
con = _beacon_db()
b = con.execute("SELECT * FROM beacons WHERE token=?", (token,)).fetchone()
if not b:
return "Not Found", 404
ip = request.headers.get("X-Real-IP") or request.remote_addr or "?"
ua = request.headers.get("User-Agent", "")
heartbeat = param("hb") == "1" or bool(_HEARTBEAT_UA.search(ua or ""))
kind = "probe" if heartbeat else "hit"
con.execute("INSERT INTO beacon_hits(beacon_id,ts,ip,ua,kind) VALUES(?,?,?,?,?)",
(b["id"], int(time.time()), ip, ua[:200], kind))
con.execute("UPDATE beacons SET last_seen=? WHERE id=?", (int(time.time()), b["id"]))
was_silent = b["silent_notified"]
if was_silent:
con.execute("UPDATE beacons SET silent_notified=0 WHERE id=?", (b["id"],))
con.commit() # commit BEFORE inbox writes (db-locked race)
if not heartbeat and b["user_id"]:
geo = enrich_ip(ip) or {}
where = ""
if geo:
where = " — %s, %s %s · %s" % (geo.get("city", ""), geo.get("regionName", ""), geo.get("countryCode", ""), geo.get("isp", ""))
m = db()
m.execute("INSERT INTO messages(user_id,sender,body,created) VALUES(?,?,?,?)",
(b["user_id"], "operator-bot",
"◆ BEACON TOUCHED: '<b>%s</b>%s' probe URL fetched by a non-heartbeat client — IP <b>%s</b>%s<br>device: %s" %
(esc(b["label"]), ((":%d" % b["port"]) if b["port"] else ""), esc(ip), esc(where), esc(ua[:100])),
int(time.time())))
m.commit()
elif was_silent and b["user_id"]:
m = db()
m.execute("INSERT INTO messages(user_id,sender,body,created) VALUES(?,?,?,?)",
(b["user_id"], "operator-bot",
"◆ BEACON RECOVERED: '<b>%s</b>' heartbeat is back after going SILENT." % esc(b["label"]),
int(time.time())))
m.commit()
if heartbeat:
return "ok", 200, {"Content-Type": "text/plain"}
# canary-style: look like nothing
return "Not Found", 404
@app.route("/beacon/events")
def beacon_events():
uid = current_user_id()
token = param("token") or ""
if not uid:
return page("beacon", '<div class=card>login required</div>')
con = _beacon_db()
b = con.execute("SELECT * FROM beacons WHERE token=? AND user_id=?", (token, uid)).fetchone()
if not b:
return page("beacon", '<div class=card>unknown beacon</div>')
hits = con.execute("SELECT * FROM beacon_hits WHERE beacon_id=? ORDER BY id DESC LIMIT 100", (b["id"],)).fetchall()
trs = ""
for h in hits:
geo = {}
ip = (h["ip"] or "").strip()
if ip and not ip.startswith(("10.", "127.", "172.")):
geo = enrich_ip(ip) or {}
where = ("%s, %s" % (geo.get("city", "—"), geo.get("countryCode", ""))) if geo else "—"
ktag = '<span class="tag ok">beat</span>' if h["kind"] == "probe" else '<span class="tag bad">HIT</span>'
trs += ("<tr><td>" + time.strftime("%b %d %H:%M:%S", time.localtime(h["ts"])) + "</td><td>" + ktag + "</td>"
"<td><code>" + esc(ip) + "</code></td><td>" + esc(where) + "</td>"
"<td style=max-width:220px;font-size:.8rem>" + esc((h["ua"] or "")[:90]) + "</td></tr>")
return page("beacon", """
<h1>BEACON <span>EVENTS</span></h1><p class=sub>Every touch on beacon <b>""" + esc(b["label"]) + """</b> — heartbeats and canary hits.</p>
<div class=card><a href=/beacons style=color:var(--acc)>← back to the board</a></div>
<div class=card><div class=tblwide><table><tr><th>When</th><th>Kind</th><th>IP</th><th>Where</th><th>Client</th></tr>""" + (trs or '<tr><td colspan=5 style=color:var(--dim)>no events yet</td></tr>') + """</table></div></div>""")
@app.route("/api/beacon/create", methods=["POST"])
def api_beacon_create():
r = rate_limit("beacon", 20, 60)
if r: return r
uid = key_user() or current_user_id()
if not uid:
return jsonify({"ok": False, "error": "auth required: account session or Authorization: Bearer key"}), 401
b = _beacon_create_core(uid)
probe, curl, svc, tim = _beacon_snippet(b["token"], b["interval_min"])
return jsonify({"ok": True, "token": b["token"], "label": b["label"], "port": b["port"],
"interval_min": b["interval_min"], "probe_url": probe,
"install": {"curl": curl, "systemd_service": svc, "systemd_timer": tim}})
@app.route("/api/beacon/list")
def api_beacon_list():
uid = key_user() or current_user_id()
if not uid:
return jsonify({"ok": False, "error": "auth required"}), 401
con = _beacon_db()
_beacon_check_silent(con, uid)
out = []
for b in con.execute("SELECT * FROM beacons WHERE user_id=? ORDER BY id DESC LIMIT 100", (uid,)).fetchall():
st, _cls = _beacon_status(b)
hits = con.execute("SELECT COUNT(*) c FROM beacon_hits WHERE beacon_id=? AND kind='hit'", (b["id"],)).fetchone()["c"]
out.append({"token": b["token"], "label": b["label"], "port": b["port"], "interval_min": b["interval_min"],
"status": st, "last_seen": b["last_seen"], "canary_hits": hits,
"probe_url": SITE + "/b/" + b["token"]})
return jsonify({"ok": True, "beacons": out})
@app.route("/api/beacon/status")
def api_beacon_status():
uid = key_user() or current_user_id()
token = param("token") or ""
if not uid:
return jsonify({"ok": False, "error": "auth required"}), 401
con = _beacon_db()
_beacon_check_silent(con, uid)
b = con.execute("SELECT * FROM beacons WHERE token=? AND user_id=?", (token, uid)).fetchone()
if not b:
return jsonify({"ok": False, "error": "unknown beacon"}), 404
st, _cls = _beacon_status(b)
hits = con.execute("SELECT COUNT(*) c FROM beacon_hits WHERE beacon_id=? AND kind='hit'", (b["id"],)).fetchone()["c"]
return jsonify({"ok": True, "token": b["token"], "label": b["label"], "port": b["port"],
"interval_min": b["interval_min"], "status": st, "last_seen": b["last_seen"],
"silent_notified": b["silent_notified"], "canary_hits": hits})
# ---------- END TOOL: PORT BEACON ----------
# ---------- TOOL: BSSID RADAR ----------
BSSID_OSINT_BASE = "http://10.30.20.174:8080"
BSSID_OSINT_URL = BSSID_OSINT_BASE + "/api/run/bssid_geo?q="
def _norm_mac(raw):
"""Normalize any MAC spelling to AA:BB:CC:DD:EE:FF (or None if invalid).
Accepts aa-bb-cc-dd-ee-ff, aabbccddeeff, AA.BB.CC..., 'aa bb cc', leading 0x."""
if not raw:
return None
s = str(raw).strip().lower()
if s.startswith("0x"):
s = s[2:]
for ch in ":-. _/":
s = s.replace(ch, "")
if len(s) == 12 and all(c in "0123456789abcdef" for c in s):
return ":".join(s[i:i+2] for i in range(0, 12, 2)).upper()
return None
def _oui(mac):
"""Vendor OUI hint from the first 3 octets (registry-free, informational only)."""
return mac[:8] if mac else ""
def _osint_bssid_lookup(mac):
"""Call the LAN OSINT terminal's bssid_geo tool. Returns dict; never raises."""
try:
url = BSSID_OSINT_URL + urllib.parse.quote(mac)
status, body = http(url, timeout=15)
if status == 0:
return {"ok": False, "error": "OSINT backend unreachable (" + body[:120] + ")"}
if status != 200:
return {"ok": False, "error": "OSINT backend returned HTTP " + str(status)}
data = jf(body)
if not isinstance(data, dict):
return {"ok": False, "error": "OSINT backend returned non-JSON response"}
out = {"ok": True, "mac": mac, "raw": data, "source": data.get("source", "osint-terminal bssid_geo")}
# location fields (mylnikov style): lat/lon or latitude/longitude, accuracy/range in meters
lat = data.get("lat", data.get("latitude"))
lon = data.get("lon", data.get("lon", data.get("lng", data.get("longitude"))))
acc = data.get("accuracy", data.get("range", data.get("radius")))
if lat is not None and lon is not None:
try:
out["lat"] = round(float(lat), 6)
out["lon"] = round(float(lon), 6)
out["accuracy_m"] = float(acc) if acc is not None else None
out["found"] = True
except (TypeError, ValueError):
out["found"] = False
else:
out["found"] = False
out["wigle"] = data.get("wigle")
out["geo_db"] = data.get("geo_db")
out["ms"] = data.get("__ms")
return out
except Exception as e:
return {"ok": False, "error": "OSINT backend unreachable (" + esc(str(e)) + ")"}
def _bssid_result_row(r):
"""One result dict -> HTML table row (safe strings)."""
if not r.get("ok"):
return ("<tr><td>" + esc(r.get("mac", "?")) + "</td><td colspan=5 style=color:var(--bad)>"
+ esc(r.get("error", "lookup failed")) + "</td></tr>")
mac = esc(r["mac"])
if r.get("found"):
lat, lon = r["lat"], r["lon"]
glink = "https://www.google.com/maps?q=" + str(lat) + "," + str(lon)
olink = "https://www.openstreetmap.org/?mlat=" + str(lat) + "&mlon=" + str(lon) + "#map=16/" + str(lat) + "/" + str(lon)
acc = ("~" + str(int(r["accuracy_m"])) + " m") if r.get("accuracy_m") is not None else "unknown"
loc = ('<b style=color:var(--ok)>' + str(lat) + ", " + str(lon) + "</b><br>"
+ '<a style=color:var(--acc) href="' + glink + '" target=_blank>Google Maps</a> · '
+ '<a style=color:var(--acc) href="' + olink + '" target=_blank>OSM</a>')
extra = esc(str(r.get("geo_db") or ""))
return ("<tr><td>" + mac + "</td><td>" + _oui(r["mac"]) + "</td><td>" + loc + "</td><td>" + acc + "</td><td>" + extra + "</td></tr>")
note = esc(str(r.get("geo_db") or "no location in free DB"))
wl = r.get("wigle")
if wl:
note += '<br><a style=color:var(--acc) href="' + esc(wl) + '" target=_blank>try WiGLE</a>'
return ("<tr><td>" + mac + "</td><td>" + _oui(r["mac"]) + "</td><td style=color:var(--dim)>not located</td><td>—</td><td>" + note + "</td></tr>")
@app.route("/bssid", methods=["GET", "POST"])
def bssid_page():
uid = current_user_id()
results = None
q_raw = param("mac") or param("macs") or ""
rows_raw = [x for x in str(q_raw).replace(";", "\n").replace(",", "\n").splitlines() if x.strip()]
if rows_raw:
r = rate_limit("bssid", 20, 60)
if r:
return r
results = []
for line in rows_raw[:25]:
mac = _norm_mac(line)
if not mac:
results.append({"ok": False, "mac": str(line).strip()[:40], "error": "not a valid MAC (want aa:bb:cc:dd:ee:ff)"})
else:
results.append(_osint_bssid_lookup(mac))
table = ""
if results is not None:
table = ('<div class=tblwide><table><tr><th>BSSID</th><th>OUI</th><th>Location</th><th>Accuracy</th><th>DB / nearby hints</th></tr>'
+ "".join(_bssid_result_row(x) for x in results) + "</table></div>")
last = esc(q_raw) if q_raw else ""
body = f'''
<script>
function bssidNormalize(s){{
s=(s||'').toLowerCase(); if(s.indexOf('0x')===0)s=s.slice(2);
s=s.replace(/[^0-9a-f]/g,'');
if(s.length!==12) return null;
return (s.match(/../g).join(':')).toUpperCase();
}}
function bssidNorm(){{
var el=document.getElementById('bmac'), pv=document.getElementById('bprev');
var n=bssidNormalize(el.value);
pv.textContent='normalized: '+(n||'not a valid MAC yet');
if(n) el.value=n;
}}
function bssidGo(){{
var m=document.getElementById('bmac'), ms=document.getElementById('bmacs');
if(ms.value.trim()!='' ) {{ ms.value=ms.value; return true; }}
var n=bssidNormalize(m.value);
if(n) m.value=n;
return true;
}}
</script>
<h1>BSSID <span>RADAR</span></h1>
<p class=sub>Turn a WiFi router's MAC address into an approximate place on Earth. Photo EXIF or a wifi scan gives you BSSIDs — this tool asks the OSINT terminal where those routers physically sit.</p>
<div class=grid2>
<div class="card glow">
<b>RUN A LOOKUP</b>
<form method=post action=/bssid onsubmit="return bssidGo()">
<label style="display:block;margin:.6rem 0 .2rem;color:var(--dim)">Single BSSID — any format (aa-bb-cc-dd-ee-ff, aabbccddeeff, AA:BB:…)</label>
<input id=bmac name=mac style=width:100%;padding:.6rem oninput=bssidNorm() placeholder="e.g. dc-39-6f-20-1d-70" value="{last}">
<div id=bprev style="margin:.3rem 0;color:var(--dim);font-size:.85rem">normalized: —</div>
<label style="display:block;margin:.6rem 0 .2rem;color:var(--dim)">Batch — one MAC per line (up to 25, ';' or ',' also fine)</label>
<textarea id=bmacs name=macs rows=4 style=width:100%;padding:.6rem placeholder="AA:BB:CC:DD:EE:FF&#10;11:22:33:44:55:66"></textarea>
<button class=abtn solid type=submit style=margin-top:.6rem>LOCATE</button>
</form>
</div>
<div class="card">
<b>WHAT YOU GET BACK</b>
<ul style=color:var(--dim);margin:.6rem 0 0;padding-left:1.2rem>
<li>lat/lon + accuracy radius in meters (when the free DB knows the router)</li>
<li>one-click Google Maps and OpenStreetMap links</li>
<li>WiGLE fallback link + nearby-network hints when the DB comes up empty</li>
<li>vendor OUI (first 3 octets) per MAC for quick triage</li>
</ul>
</div>
</div>
{table}
''' + how([
"You feed in a BSSID — the hardware MAC of a WiFi access point, grabbed from a photo's EXIF wifi scan, aircrack output, or a phone's wifi list.",
"Your input is normalized: dashes, dots, spaces or no separator at all become AA:BB:CC:DD:EE:FF. Six hex pairs or it's rejected.",
"The server calls the LAN OSINT terminal's bssid_geo tool, which queries the Mylnikov free WiFi-geolocation database (crowdsourced router positions).",
"A hit returns latitude, longitude and an accuracy radius in meters — how tight the crowd-sourced fix is. Rural routers can be kilometers off; dense city fixes are often within 100 m.",
"A miss is not a dead end: you get a ready-made WiGLE search link (free account needed) plus the DB's message, and nearby-network hints when present.",
"Batch mode loops the same pipeline over up to 25 MACs and renders one comparison table.",
"Accuracy is approximate by nature — treat results as a hint to corroborate, never as evidence. Router MACs move when people reinstall hardware.",
]) + flow("place a router from a photo's WiFi scan", [
'<span class=flowrole>you</span> receive a photo whose EXIF wifi-scan block lists BSSID <b>dc:39:6f:20:1d:70</b>.',
'<span class=flowrole>you</span> paste it into BSSID RADAR — typed as <b>dc-39-6f-20-1d-70</b>, the live preview confirms the normalized form.',
'the <b>tool</b> queries the OSINT terminal; the Mylnikov DB has seen that router before and returns lat/lon with a ~130 m radius.',
'the <b>tool</b> draws Google Maps / OSM links at that pin — you now know roughly where the photo was taken, no GPS tag required.',
'<span class=flowrole>you</span> drop 5 more BSSIDs from the same scan into batch mode and cross-check the pins cluster in one neighborhood.',
]) + gloss([
("BSSID", "Basic Service Set Identifier — the MAC address of a WiFi access point's radio. Unique per router, visible in every wifi scan."),
("MAC", "Media Access Control address — 6 hex pairs identifying network hardware. First 3 pairs (the OUI) identify the vendor."),
("OUI", "Organizationally Unique Identifier — first 3 octets of a MAC, registered to the manufacturer (e.g. 00:25:9C ≈ a radio vendor)."),
("Mylnikov DB", "Free crowdsourced database mapping WiFi BSSIDs to GPS coordinates, built from user-submitted wardrive logs."),
("WiGLE", "Wireless Geographic Logging Engine — the largest public wardriving DB. Needs a free account to query."),
("Accuracy radius", "Meters around the returned lat/lon where the router probably is. Crowdsourced fixes vary; small radius = many sightings."),
("Wardriving", "Mapping WiFi networks while moving around, logging BSSID + GPS. Feeds the geolocation databases this tool reads."),
]) + agent_card("GET /api/bssid?mac=AA:BB:CC:DD:EE:FF · GET /api/bssid?macs=a;b;c",
"curl -s https://dark0rbits.thetempleofdoom.com/api/bssid?macs=AA:BB:CC:DD:EE:FF;11-22-33-44-55-66",
"Batch uses semicolons. Any MAC format accepted; server normalizes. Each result carries lat/lon/accuracy_m when found, wigle fallback link otherwise. Rate limit 20/min. JSON only.")
return page("hunt", body)
@app.route("/api/bssid")
def bssid_api():
r = rate_limit("bssid", 20, 60)
if r:
return r
macs = []
raw = param("macs") or param("mac") or ""
for part in str(raw).replace(";", "\n").replace(",", "\n").splitlines():
part = part.strip()
if part:
macs.append(part)
if not macs:
return jsonify({"ok": False, "error": "pass ?mac=AA:BB:CC:DD:EE:FF or ?macs=a;b;c (up to 25)"}), 400
out = []
for m in macs[:25]:
norm = _norm_mac(m)
if not norm:
out.append({"ok": False, "mac": m, "error": "invalid MAC (want aa:bb:cc:dd:ee:ff)"})
continue
res = _osint_bssid_lookup(norm)
if res.get("ok") and res.get("found"):
lat, lon = res["lat"], res["lon"]
res["maps_google"] = "https://www.google.com/maps?q=" + str(lat) + "," + str(lon)
res["maps_osm"] = "https://www.openstreetmap.org/?mlat=" + str(lat) + "&mlon=" + str(lon) + "#map=16/" + str(lat) + "/" + str(lon)
out.append(res)
single = len(out) == 1
return jsonify(out[0] if single else {"ok": True, "count": len(out), "results": out})
# ---------- END TOOL: BSSID RADAR ----------
# ---------- TOOL: HOOK RELAY ----------
import secrets as _sec
HOOK_MAX_BODY = 32768 # 32KB body capture cap
def _hook_tables(con):
con.executescript("""CREATE TABLE IF NOT EXISTS hook_endpoints(id INTEGER PRIMARY KEY, user_id INTEGER, token TEXT UNIQUE, label TEXT, created INTEGER);
CREATE TABLE IF NOT EXISTS hook_hits(id INTEGER PRIMARY KEY, endpoint_id INTEGER, ts INTEGER, method TEXT, ip TEXT, ua TEXT, ct TEXT, src TEXT, headers TEXT, query TEXT, body TEXT, truncated INTEGER DEFAULT 0);""")
return con
def _hook_detect_src(hdrs, body):
"""Guess which service sent this webhook from headers + body."""
hl = {k.lower(): v for k, v in hdrs.items()}
if "stripe-signature" in hl: return "Stripe"
if "x-github-event" in hl or "x-github-delivery" in hl or "x-hub-signature" in hl: return "GitHub"
if "x-shopify-topic" in hl or "x-shopify-shop-domain" in hl or "x-shopify-hmac-sha256" in hl: return "Shopify"
if "x-telegram-bot-api-secret-token" in hl: return "Telegram"
ua = (hl.get("user-agent") or "").lower()
if ua.startswith("discordbot") or ua.startswith("discord"): return "Discord"
if "github-hookshot" in ua or "github-camel" in ua: return "GitHub"
j = jf(body)
if isinstance(j, dict):
if "update_id" in j: return "Telegram"
if "embeds" in j and "content" in j: return "Discord"
if j.get("object") in ("event", "checkout.session", "payment_intent") or j.get("livemode") is not None: return "Stripe"
if any(str(k).startswith("x_shopify") for k in j): return "Shopify"
return ""
def _hook_target_guard(u):
"""SSRF guard for replay targets. Returns error string or None if ok."""
if not u or not str(u).strip(): return "target_url required"
u = str(u).strip()
if not re.match(r"^https?://", u): return "target_url must start with http:// or https://"
try:
host = urllib.parse.urlsplit(u).hostname or ""
except Exception:
return "cannot parse target_url"
if not host: return "target_url has no host"
try:
ipa = ipaddress.ip_address(host)
except ValueError:
try:
ipa = ipaddress.ip_address(socket.gethostbyname(host))
except Exception:
return None # unresolvable here — let the fetcher report it
if ipa.is_private or ipa.is_loopback or ipa.is_link_local or ipa.is_reserved:
return "private/internal target blocked (SSRF guard: 10.x / 127. / 172.16-31 / 169.254 and friends)"
return None
def _hook_new(uid, label):
con = _hook_tables(db())
token = _sec.token_hex(10)
con.execute("INSERT INTO hook_endpoints(user_id,token,label,created) VALUES(?,?,?,?)",
(uid, token, (label or "")[:60], int(time.time())))
con.commit()
return con.execute("SELECT * FROM hook_endpoints WHERE token=?", (token,)).fetchone()
def _hook_hits_json(con, ep, limit=100):
rows = con.execute("SELECT * FROM hook_hits WHERE endpoint_id=? ORDER BY id DESC LIMIT ?", (ep["id"], limit)).fetchall()
out = []
for r in rows:
d = dict(r)
d["ts_iso"] = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(r["ts"])) + " UTC"
out.append(d)
return out
def _hook_replay(hit, target_url):
err = _hook_target_guard(target_url)
if err:
return {"ok": False, "error": err}
try:
hdrs = {k: v for k, v in (json.loads(hit["headers"] or "{}")).items()
if k.lower() not in ("host", "content-length", "connection", "accept-encoding", "cookie")}
except Exception:
hdrs = {}
if hit["ct"]:
hdrs["Content-Type"] = hit["ct"]
body = (hit["body"] or "").encode("utf-8", "replace")
st, txt = http(target_url, headers=hdrs, data=body if hit["method"] != "GET" else None, method=hit["method"])
return {"ok": True, "target": target_url, "method": hit["method"],
"status": st, "response": txt[:2000], "replayed_at": int(time.time())}
def _hook_pretty(body, ct):
"""Pretty-print a captured body for the viewer."""
j = jf(body)
if j is not None:
return esc(json.dumps(j, indent=2))
return esc(body or "(empty body)")
# ---- capture endpoint: NO auth, fast 200 ----
@app.route("/hook/<token>", methods=["GET", "POST", "PUT"])
def hook_capture(token):
r = rate_limit("hookcapture", 120, 60)
if r: return r
con = _hook_tables(db())
ep = con.execute("SELECT id FROM hook_endpoints WHERE token=?", (token,)).fetchone()
if not ep:
return "unknown hook token", 404, {"Content-Type": "text/plain"}
raw = request.get_data() or b""
trunc = 1 if len(raw) > HOOK_MAX_BODY else 0
body = raw[:HOOK_MAX_BODY].decode("utf-8", "replace")
hdrs = dict(request.headers.items())
src = _hook_detect_src(hdrs, body)
hs = json.dumps(hdrs, indent=2)
ip = request.headers.get("X-Real-IP") or request.remote_addr or ""
ua = request.headers.get("User-Agent", "")
ct = request.headers.get("Content-Type", "")
q = (request.query_string or b"").decode("utf-8", "replace")[:2048]
con.execute("INSERT INTO hook_hits(endpoint_id,ts,method,ip,ua,ct,src,headers,query,body,truncated) VALUES(?,?,?,?,?,?,?,?,?,?,?)",
(ep["id"], int(time.time()), request.method, ip, ua, ct, src, hs, q, body, trunc))
con.commit()
return "captured", 200, {"Content-Type": "text/plain"}
# ---- human page ----
@app.route("/hook/create", methods=["POST"])
def hook_create_route():
uid = current_user_id()
if not uid:
return page("hooks", "<h1>HOOK <span>RELAY</span></h1><div class=card><span class='tag bad'>login required</span> — <a href=/inbox?next=/hooks style=color:var(--acc)>log in</a> to create webhook endpoints.</div>")
r = rate_limit("hookcreate", 20, 60)
if r: return r
_hook_new(uid, param("label"))
return Redirect("/hooks")
@app.route("/hooks", methods=["GET", "POST"])
def hooks_page():
uid = current_user_id()
if not uid:
body = """
<h1>HOOK <span>RELAY</span></h1><p class=sub>Instant public webhook inspector. Create a capture URL, point any webhook at it, see exactly what arrives — headers, body, query, IP — and replay it anywhere. Login to create endpoints.</p>
<div class=card><span class=tag warn>LOGIN REQUIRED</span> <a href=/inbox?next=/hooks style=color:var(--acc)>Log in</a> or <a href=/signup?next=/hooks style=color:var(--acc)>sign up</a> (10 seconds, no KYC) to create webhook endpoints.</div>""" + how([
"Create an account, then make a hook endpoint — you get a unique URL like /hook/abc123.",
"Paste that URL into Stripe, GitHub, Shopify, Discord or Telegram webhook settings.",
"Every callback lands in your hit log: full headers, body (up to 32KB), query string, source IP and user-agent.",
"The source is auto-detected and badged — Stripe, GitHub, Discord, Shopify, Telegram.",
"Replay any captured hit to any public URL to retrigger an action or test a fix."]) + flow("debug why Stripe stopped calling my shop", [
"<span class=flowrole>you</span> Stripe webhooks to your shop went quiet. Did Stripe stop sending, or is your handler 500-ing? You cannot tell from inside your app.",
"<span class=flowrole>you</span> Create a hook endpoint here labeled <b>stripe-debug</b> and copy the curl-ready URL.",
"<span class=flowrole>you</span> In the Stripe dashboard, add the hook URL as a second webhook endpoint for the same events.",
"<span class=flowrole>stripe</span> Next event fires — the hook catches it in under a second, <b>badged STRIPE</b>, full headers and signed payload intact.",
"<span class=flowrole>you</span> No hits at all? Stripe is not sending (check their delivery logs). Hits arriving? Your handler is the problem — inspect the exact payload.",
"<span class=flowrole>you</span> Fix your handler, then <b>replay</b> the captured hit at your live endpoint to verify without waiting for the next real payment."]) + gloss([
("webhook", "another server POSTs your URL when something happens — a payment, a push, an order"),
("capture URL", "a unique throwaway endpoint that records everything it receives"),
("replay", "resend a previously captured webhook body to any URL, with original headers"),
("signature header", "Stripe-Signature / X-Hub-Signature — proves the sender, we keep it in the capture"),
("SSRF guard", "replay targets on private networks (10.x, 127.x, 172.16-31, 169.254) are refused")]) + agent_card("POST /api/hook/create", 'curl -X POST ' + SITE + '/api/hook/create -d "label=stripe-debug" -H "Authorization: Bearer ***"', 'Returns {"ok":true,"url":".../hook/<token>"}. Then GET /api/hook/list and GET /api/hook/hits?token=.')
return page("hooks", body)
msg = ""
con = _hook_tables(db())
if request.method == "POST":
r = rate_limit("hookpage", 30, 60)
if r: return r
act = param("act")
if act == "create":
_hook_new(uid, param("label"))
msg = '<div class=msg>endpoint created</div>'
elif act == "del":
con.execute("DELETE FROM hook_hits WHERE endpoint_id IN (SELECT id FROM hook_endpoints WHERE id=? AND user_id=?)", (param("id"), uid))
con.execute("DELETE FROM hook_endpoints WHERE id=? AND user_id=?", (param("id"), uid))
con.commit()
msg = '<div class=msg>endpoint deleted</div>'
elif act == "clear":
con.execute("DELETE FROM hook_hits WHERE endpoint_id IN (SELECT id FROM hook_endpoints WHERE id=? AND user_id=?)", (param("id"), uid))
con.commit()
msg = '<div class=msg>hits cleared</div>'
elif act == "replay":
hid = param("hit_id") or ""
tgt = param("target_url") or ""
h = con.execute("SELECT h.* FROM hook_hits h JOIN hook_endpoints e ON h.endpoint_id=e.id WHERE h.id=? AND e.user_id=?", (hid, uid)).fetchone()
if not h:
msg = '<div class=card><span class=tag bad>hit not found</span></div>'
else:
res = _hook_replay(h, tgt)
if res.get("ok"):
msg = '<div class=card><b>REPLAY RESULT</b> — ' + str(res["status"]) + ' from ' + esc(res["target"]) + '<pre>' + esc(res.get("response", "")[:800]) + '</pre></div>'
else:
msg = '<div class=card><span class=tag bad>REPLAY BLOCKED</span> ' + esc(res.get("error", "")) + '</div>'
eps = con.execute("SELECT * FROM hook_endpoints WHERE user_id=? ORDER BY id DESC", (uid,)).fetchall()
cards = ""
for ep in eps:
hits = _hook_hits_json(con, ep, 50)
url = SITE + "/hook/" + ep["token"]
cmd = "curl -X POST " + url + " -H 'Content-Type: application/json' -d '{\"hello\":\"world\"}'"
hitview = ""
for h in hits:
badge = ('<span class=tag ok>' + esc(h["src"]) + '</span> ') if h["src"] else ""
trunc = ' <span class=tag bad>TRUNCATED</span>' if h["truncated"] else ""
hitview += ('<details style="margin:.5rem 0"><summary style=cursor:pointer>' + badge
+ '<b>' + esc(h["method"]) + '</b> · ' + esc(h["ts_iso"]) + ' · ' + esc(h["ip"]) + trunc + '</summary>'
+ '<div class=tblwide><table>'
+ '<tr><th>source</th><td>' + esc(h["src"] or "unknown") + '</td></tr>'
+ '<tr><th>content-type</th><td>' + esc(h["ct"] or "—") + '</td></tr>'
+ '<tr><th>user-agent</th><td>' + esc(h["ua"] or "—") + '</td></tr>'
+ '<tr><th>query</th><td>' + esc(h["query"] or "—") + '</td></tr>'
+ '<tr><th>headers</th><td><pre style=max-width:520px>' + esc(h["headers"]) + '</pre></td></tr>'
+ '<tr><th>body</th><td><pre style=max-width:520px>' + _hook_pretty(h["body"], h["ct"]) + '</pre></td></tr>'
+ '</table></div>'
+ '<form method=post action=/hooks style="margin:.4rem 0"><input type=hidden name=act value=replay><input type=hidden name=hit_id value="' + str(h["id"]) + '">'
+ '<input name=target_url placeholder="https://your-live-endpoint.example/webhook" style=width:60%> <button>replay</button></form>'
+ '</details>')
if not hitview:
hitview = '<div style="color:var(--dim);font-size:.9rem">no hits yet — send something at the URL above</div>'
cards += ('<div class=card><h3 style=margin:0 0 .3rem>' + esc(ep["label"] or "unlabeled hook") + '</h3>'
+ '<code style=color:var(--acc2)>' + url + '</code>'
+ ' <button style=padding:.2rem .6rem;font-size:.75rem data-cmd="' + esc(cmd) + '" onclick="cp(this.dataset.cmd)">copy</button>'
+ ' <span class=tag warn>' + str(len(hits)) + ' hits</span>'
+ '<div style=color:var(--dim);font-size:.78rem;margin:.3rem 0>curl: <code>' + esc(cmd) + '</code></div>'
+ '<div style="margin:.4rem 0"><form method=post action=/hooks style=display:inline><input type=hidden name=act value=clear><input type=hidden name=id value=' + str(ep["id"]) + '><button class=ghost style=padding:.2rem .7rem;font-size:.75rem>clear hits</button></form> '
+ '<form method=post action=/hooks style=display:inline onsubmit="return confirm(\'delete endpoint?\')"><input type=hidden name=act value=del><input type=hidden name=id value=' + str(ep["id"]) + '><button class=ghost style=padding:.2rem .7rem;font-size:.75rem>delete</button></form></div>'
+ '<b>hits</b>' + hitview + '</div>')
if not eps:
cards = '<div class=card style=color:var(--dim)>No endpoints yet — create your first hook above.</div>'
body = f"""
<h1>HOOK <span>RELAY</span></h1><p class=sub>Public webhook inspector. Each endpoint is a throwaway URL that records everything sent to it — headers, body, query, IP — auto-detects the sender, and can replay any hit to any URL.</p>
{msg}
<div class=card><b>New endpoint</b>
<form method=post action=/hook/create><input name=label placeholder="label, e.g. stripe-debug (optional)" style=width:60%> <button>create</button></form></div>
<div class=grid2>{cards}</div>""" + how([
"Create a hook — you instantly get a unique URL like " + SITE + "/hook/abc123def456.",
"Point any webhook at it: Stripe, GitHub, Discord, Shopify, Telegram, or curl by hand. GET, POST and PUT, any content-type.",
"The capture URL has NO login — webhooks come from outside servers, so it must answer 200 to anyone. Keep the URL secret-ish; only you can view the hits.",
"Bodies over 32KB are truncated (and flagged) so a giant payload cannot flood your log.",
"Each hit shows source badge, IP, user-agent, full headers, query string and a pretty-printed JSON body.",
"Replay sends the exact captured body + headers to any public URL — private targets (10.x, 127.x, 172.16-31, 169.254) are refused.",
"Agents: same everything over JSON — /api/hook/create, /api/hook/list, /api/hook/hits, /api/hook/replay."]) + flow("debug why Stripe stopped calling my shop", [
"<span class=flowrole>you</span> Payments complete but your shop never marks orders paid. Is Stripe sending? Is your handler crashing? Blind either way.",
"<span class=flowrole>you</span> Create a hook labeled <b>stripe-debug</b>, copy the curl line, paste the URL into Stripe as a second webhook endpoint.",
"<span class=flowrole>stripe</span> The next payment fires — the hit lands instantly, badged <b>STRIPE</b> (detected from the Stripe-Signature header), payload fully intact.",
"<span class=flowrole>you</span> Zero hits = Stripe-side problem (check their delivery log). Hits present = read the exact JSON, find what your handler choked on.",
"<span class=flowrole>you</span> Ship the fix, then hit <b>replay</b> to fire that same signed payload at your live endpoint — verified without waiting for a real customer."]) + gloss([
("capture URL", "unique unguessable URL (/hook/<token>) that records every request it receives"),
("source badge", "auto-detected sender: Stripe, GitHub, Discord, Shopify or Telegram"),
("replay", "resend a captured body with original headers to any public URL"),
("truncation", "bodies over 32KB are cut and flagged — protection against payload floods"),
("SSRF guard", "replay refuses internal addresses so the relay cannot probe your LAN")]) + agent_card("POST /api/hook/create · GET /api/hook/list · GET /api/hook/hits?token= · POST /api/hook/replay", 'curl -X POST ' + SITE + '/api/hook/create -d "label=stripe-debug" -H "Authorization: Bearer ***"', 'Full JSON lifecycle: create, list, inspect hits, replay (hit_id + target_url).')
return page("hooks", body)
# ---- JSON API ----
@app.route("/api/hook/create", methods=["POST"])
def api_hook_create():
r = rate_limit("hookapi", 20, 60)
if r: return r
uid = key_user() or current_user_id()
if not uid:
return jsonify({"ok": False, "error": "auth required: account session (sign up at /inbox, no KYC) or Authorization: Bearer *** key"}), 401
ep = _hook_new(uid, jp("label") or param("label"))
return jsonify({"ok": True, "token": ep["token"], "url": SITE + "/hook/" + ep["token"], "capture_path": "/hook/" + ep["token"], "label": ep["label"], "page": SITE + "/hooks"})
@app.route("/api/hook/list")
def api_hook_list():
uid = key_user() or current_user_id()
if not uid:
return jsonify({"ok": False, "error": "auth required"}), 401
con = _hook_tables(db())
eps = con.execute("SELECT * FROM hook_endpoints WHERE user_id=? ORDER BY id DESC", (uid,)).fetchall()
out = []
for ep in eps:
n = con.execute("SELECT COUNT(*) c FROM hook_hits WHERE endpoint_id=?", (ep["id"],)).fetchone()["c"]
last = con.execute("SELECT MAX(ts) m FROM hook_hits WHERE endpoint_id=?", (ep["id"],)).fetchone()["m"]
out.append({"token": ep["token"], "label": ep["label"], "created": ep["created"],
"url": SITE + "/hook/" + ep["token"], "hits": n, "last_hit": last})
return jsonify({"ok": True, "endpoints": out})
@app.route("/api/hook/hits")
def api_hook_hits():
uid = key_user() or current_user_id()
if not uid:
return jsonify({"ok": False, "error": "auth required"}), 401
tok = param("token") or ""
con = _hook_tables(db())
ep = con.execute("SELECT * FROM hook_endpoints WHERE token=? AND user_id=?", (tok, uid)).fetchone()
if not ep:
return jsonify({"ok": False, "error": "unknown token"}), 404
limit = 100
try:
limit = max(1, min(500, int(param("limit") or 100)))
except Exception:
pass
hits = _hook_hits_json(con, ep, limit)
for h in hits:
try:
h["headers_json"] = json.loads(h["headers"] or "{}")
except Exception:
h["headers_json"] = {}
return jsonify({"ok": True, "token": tok, "count": len(hits), "hits": hits})
@app.route("/api/hook/replay", methods=["POST"])
def api_hook_replay():
r = rate_limit("hookreplay", 10, 60)
if r: return r
uid = key_user() or current_user_id()
if not uid:
return jsonify({"ok": False, "error": "auth required"}), 401
hid = jp("hit_id") or param("hit_id")
tgt = jp("target_url") or param("target_url")
if not hid or not tgt:
return jsonify({"ok": False, "error": "hit_id and target_url required"}), 400
con = _hook_tables(db())
h = con.execute("SELECT h.* FROM hook_hits h JOIN hook_endpoints e ON h.endpoint_id=e.id WHERE h.id=? AND e.user_id=?", (hid, uid)).fetchone()
if not h:
return jsonify({"ok": False, "error": "hit not found (or not yours)"}), 404
res = _hook_replay(h, tgt)
if not res.get("ok"):
return jsonify(res), 400
return jsonify(res)
# ---------- END TOOL: HOOK RELAY ----------
# ---------- TOOL: FACE TRACE ----------
import io as _io
from PIL import Image as _PILImage, ImageOps as _PILImageOps
from concurrent.futures import ThreadPoolExecutor as _TPE
def _face_db():
con = db()
con.execute("CREATE TABLE IF NOT EXISTS face_cache(key TEXT PRIMARY KEY, img BLOB, sha256 TEXT, ts INTEGER)")
con.commit()
return con
def _hamming(h1, h2):
n = max(len(h1), len(h2)) * 4
try:
return bin(int(h1, 16) ^ int(h2, 16))[2:].zfill(n).count("1")
except Exception:
return 999
def dhash(img):
"""dHash: grayscale 9x8 (w=9,h=8), compare horizontally adjacent pixels → 64-bit."""
g = _PILImageOps.grayscale(img).resize((9, 8))
px = list(g.getdata())
bits = 0
for r in range(8):
row = px[r * 9:(r + 1) * 9]
for c in range(8):
bits = (bits << 1) | (1 if row[c] > row[c + 1] else 0)
return f"{bits:016x}"
def ahash(img):
"""Average hash: 8x8 grayscale, bit = pixel > mean."""
g = _PILImageOps.grayscale(img).resize((8, 8))
px = list(g.getdata())
m = sum(px) / 64.0
bits = 0
for p in px:
bits = (bits << 1) | (1 if p > m else 0)
return f"{bits:016x}"
def _pfp_hashes(blob):
"""Hashes for a raw image blob: {'sha256','dhash','ahash'} or {'error':...}"""
out = {"sha256": hashlib.sha256(blob).hexdigest(), "bytes": len(blob)}
try:
img = _PILImage.open(_io.BytesIO(blob))
img.load()
out["dhash"] = dhash(img)
out["ahash"] = ahash(img)
out["format"] = (img.format or "?").lower()
out["size"] = list(img.size)
except Exception as e:
out["error"] = f"not an image: {e}"[:160]
return out
def _fcache_get(key):
con = _face_db()
r = con.execute("SELECT img, sha256, ts FROM face_cache WHERE key=?", (key,)).fetchone()
if r and (int(time.time()) - r["ts"]) < 3600:
return bytes(r["img"])
return None
def _fcache_put(key, blob):
con = _face_db()
con.execute("INSERT OR REPLACE INTO face_cache(key,img,sha256,ts) VALUES(?,?,?,?)",
(key, sqlite3.Binary(blob), hashlib.sha256(blob).hexdigest(), int(time.time())))
con.commit()
def _fetch_img(url):
"""Fetch an image URL → (bytes|None, note). 1h sqlite cache."""
ck = "url:" + hashlib.sha256(url.encode()).hexdigest()[:32]
c = _fcache_get(ck)
if c is not None:
return c, "cache"
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0 (Dark0rbits toolbox)"})
try:
with urllib.request.urlopen(req, timeout=10, context=_CTX) as r:
blob = r.read(6 * 1024 * 1024)
if len(blob) < 64:
return None, f"too small ({len(blob)}b)"
_fcache_put(ck, blob)
return blob, "fetched"
except Exception as e:
return None, str(e)[:120]
def pfp_targets(u):
"""Avatar source plan for a username: resolvers and constructed URLs."""
u = u.strip().lstrip("@")
q = urllib.parse.quote(u)
return [
{"platform": "GitHub", "kind": "resolve",
"api": f"https://api.github.com/users/{q}",
"extract": lambda j: (j.get("avatar_url") or "") if isinstance(j, dict) else "",
"profile": f"https://github.com/{q}"},
{"platform": "Reddit", "kind": "resolve",
"api": f"https://www.reddit.com/{q}/about.json",
"extract": lambda j: (((j.get("data") or {}).get("icon_img") or "")) if isinstance(j, dict) and j.get("data") else "",
"profile": f"https://www.reddit.com/user/{q}"},
{"platform": "Telegram", "kind": "construct",
"img": "https://t.me/" + q,
"note": "manual / constructed: t.me profile — grab photo from the page",
"profile": f"https://t.me/{q}"},
{"platform": "Steam", "kind": "construct",
"img": "https://steamcommunity.com/id/{u}/".replace("{u}", q),
"note": "manual / constructed: Steam profile — XML API has <avatarFull>",
"profile": "https://steamcommunity.com/id/" + q},
{"platform": "Twitch", "kind": "construct",
"img": "https://www.twitch.tv/" + q,
"note": "manual / constructed: profile page (avatars need a client-id)",
"profile": f"https://www.twitch.tv/{q}"},
]
def pfp_harvest(u, target_hashes=None):
"""Resolve + download avatars for username u; compare with target hashes."""
results = []
for t in pfp_targets(u):
entry = {"platform": t["platform"], "profile": t["profile"], "status": "no avatar",
"hashes": None, "match": None, "distances": {}}
img_url = ""
if t["kind"] == "resolve":
st, body = http(t["api"], timeout=10)
j = jf(body)
img_url = t["extract"](j) if j else ""
entry["http"] = st
if not img_url:
entry["status"] = "not found"
else:
entry["status"] = "constructed link"
entry["note"] = t["note"]
if img_url:
blob, note = _fetch_img(img_url)
if blob:
h = _pfp_hashes(blob)
entry.update({"status": "ok", "img_url": img_url, "source": note, "hashes": h})
if target_hashes and not h.get("error"):
dd = min(_hamming(h["dhash"], target_hashes["dhash"]),
_hamming(h["ahash"], target_hashes["ahash"]))
entry["distances"] = {"dhash": _hamming(h["dhash"], target_hashes["dhash"]),
"ahash": _hamming(h["ahash"], target_hashes["ahash"])}
entry["match"] = "likely same image" if dd <= 10 else "different image"
else:
entry["status"] = f"download failed ({note})"
results.append(entry)
return {"ok": True, "username": u.strip().lstrip("@"), "targets": results}
def face_search_leads():
return [
("Google Lens", "https://lens.google.com/uploadbyurl?url=", "Google's reverse-image search — strongest for lookalikes and crops"),
("Yandex Images", "https://yandex.com/images/search?rpt=imageview&url=", "best face recall of the public engines, especially EU/RU web"),
("Bing Visual Search", "https://www.bing.com/images/search?view=detailv2&iss=sbi&q=imgurl:", "Microsoft visual search — good LinkedIn / social recall"),
("TinEye", "https://tineye.com/search?url=", "exact-copy finder — best for 'where did this exact file appear first'"),
]
@app.route("/face", methods=["GET", "POST"])
def face_tool():
uid = current_user_id()
if not uid:
return page("face", '<h1>FACE <span>TRACE</span></h1><p class=sub>Login first — this tool is for accounts. Free, no KYC: <a href=/inbox?next=/face style=color:var(--acc)>log in / sign up</a>.</p>')
r = rate_limit("facepage", 20, 60)
if r: return r
res = ""
up_hashes = None
err = ""
f = request.files.get("img")
username = (param("u") or "").strip().lstrip("@")
if request.method == "POST":
if not f and not username:
err = "give me an image and/or a username"
if f:
blob = f.read(6 * 1024 * 1024)
if len(blob) < 64:
err = "file too small / empty"
else:
h = _pfp_hashes(blob)
if h.get("error"):
err = h["error"]
else:
up_hashes = h
up_rows = [("sha256", f"<code>{h['sha256']}</code>"), ("dHash (8x8)", f"<code>{h['dhash']}</code>"),
("aHash (8x8)", f"<code>{h['ahash']}</code>"), ("format / size", f"{h.get('format')} {h.get('size')} · {h['bytes']} bytes")]
if username:
up_rows.append(("comparing against", f"avatars of <b style=color:var(--acc)>{esc(username)}</b>"))
res += kv(up_rows)
if username and not (len(username) >= 2 and len(username) <= 60 and not any(c in "<>\"'/" for c in username)):
if not err: err = "bad username (2-60 chars, no slashes/html)"
username = ""
if username:
hv = pfp_harvest(username, up_hashes)
rows = ""
for t in hv["targets"]:
if t["status"] == "ok":
dd = t["distances"]
if t["match"]:
m = ('<span class="tag ok">MATCH</span> ' + esc(t["match"]) +
f" · d {dd['dhash']} / a {dd['ahash']}")
else:
m = "—"
rows += (f"<tr><td>{esc(t['platform'])}</td><td><span class=tag ok>avatar</span></td>"
f"<td><code>{esc((t['hashes'].get('dhash') or ''))}</code></td><td>{m}</td>"
f"<td><a href='{esc(t['profile'])}' target=_blank rel=noopener style=color:var(--acc)>profile</a>"
f" · <a href='{esc(t['img_url'])}' target=_blank rel=noopener style=color:var(--acc)>img</a></td></tr>")
elif t["status"] == "constructed link":
rows += (f"<tr><td>{esc(t['platform'])}</td><td><span class='tag warn'>constructed</span></td>"
f"<td>—</td><td>manual lead</td><td><a href='{esc(t['profile'])}' target=_blank rel=noopener style=color:var(--acc)>open profile → grab photo by hand</a></td></tr>")
else:
rows += (f"<tr><td>{esc(t['platform'])}</td><td><span class=tag>{esc(t['status'])}</span></td>"
f"<td>—</td><td>—</td><td><a href='{esc(t['profile'])}' target=_blank rel=noopener style=color:var(--acc)>profile</a></td></tr>")
res += (f'<div class=card><b>Avatar harvest — <span style=color:var(--acc)>{esc(username)}</span></b>'
f'<div class=tblwide><table><tr><th>Platform</th><th>Status</th><th>dHash</th><th>Verdict</th><th>Links</th></tr>{rows}</table></div>'
'<div style=color:var(--dim);font-size=.82rem;margin-top:.5rem>Verdict rule: best Hamming distance (dHash or aHash) ≤ 10 of 64 bits = likely same image. Cache: 1h sqlite.</div></div>')
if up_hashes and not username:
res += '<div class=card><b>Reverse-image leads</b><br>dark0rbits never calls a reverse-image API for you — open these yourself and upload the file:<br><br>' + "<br>".join(f'<a href="{esc(base)}" target=_blank rel=noopener style=color:var(--acc)>▸ {esc(nm)} →</a> <span style=color:var(--dim)>{esc(d)}</span>' for nm, base, d in face_search_leads()) + "</div>"
if err:
res = f'<div class=card><span class="tag bad">{esc(err)}</span></div>' + res
body = f"""
<h1>FACE <span>TRACE</span></h1>
<p class=sub>Profile-picture triangulation without reverse-image APIs. Hash an avatar (dHash + aHash + sha256), harvest avatars a username uses across platforms, and let Hamming distance tell you whether it's the same picture — same person behind 4 different usernames?</p>
<div class=card>
<form method=post enctype=multipart/form-data>
<label>Avatar image (optional)</label>
<input type=file name=img accept='image/*'>
<label>Username (optional)</label>
<input name=u placeholder='one handle, e.g. ghostuser42' style=width:70% value='{esc(username)}' maxlength=60>
<br><button class=big style=margin-top:.8rem>TRACE</button>
</form>
<div style=color:var(--dim);font-size:.85rem;margin-top:.5rem>Image alone = hashes + manual search leads. Username alone = avatar harvest + hashes. Both = harvest AND compare against your upload (Hamming ≤ 10 = likely match).</div>
</div>
{res}
""" + how([
"Upload the avatar you already have — a forum pic, a Telegram photo, anything.",
"The image is fingerprinted three ways: dHash (9x8 grayscale, adjacent-pixel compares), aHash (8x8 vs mean) and plain sha256 — all computed locally, nothing uploaded anywhere.",
"Give a username too, and the tool fetches that handle's real avatars: GitHub and Reddit via their public JSON APIs, plus constructed profile links for Telegram, Steam and Twitch.",
"Every fetched avatar gets the same fingerprints, and Hamming distance (bits differing out of 64) is computed against your upload: ≤ 10 = likely the same image.",
"No image ever goes to Google, Yandex, Bing or TinEye. Instead you get direct upload links to all four — you decide when to escalate.",
"Downloads are cached in sqlite for an hour, so re-running a trace is fast and doesn't hammer anyone's API.",
"Judgment stays yours: same picture is strong evidence, but people reuse stock photos. dHash says 'same image', not 'same human'.",
])
body += flow("same person behind 4 different usernames?", [
"<span class=flowrole>you</span>A scammer contacts you from <b>ghostuser42</b> with a friendly avatar. Screenshot it.",
"<span class=flowrole>you</span>Upload the avatar here, type <b>ghostuser42</b>, hit TRACE. GitHub and Reddit avatars get fetched and hashed.",
"<span class=flowrole>tool</span>Verdict table: Reddit avatar <b>MATCH — d 4/64</b>. GitHub avatar: different image.",
"<span class=flowrole>you</span>Run TRACE on two other handles the same person used. Reddit matches again — same source photo, different display names.",
"<span class=flowrole>you</span>Escalate: open the Google Lens / Yandex leads with the original file to find where the photo first appeared.",
"<span class=flowrole>you</span>Conclusion: four usernames, one face. That's your triangulation — no reverse-image API ever saw the picture.",
])
body += gloss([
("dHash", "difference hash: resize to 9x8 grayscale, compare each pixel with its right neighbor → 64 bits that survive resizing and compression"),
("aHash", "average hash: 8x8 grayscale, each bit = pixel brighter than the mean"),
("Hamming distance", "how many of the 64 bits differ between two hashes — 0 = identical image, ≤ 10 = likely same picture, 32 = unrelated"),
("perceptual hash", "a fingerprint of what an image LOOKS like, not its bytes — crops and re-encodes still match; sha256 only matches exact copies"),
("avatar harvest", "collecting the profile pictures a username currently uses, from public profile APIs"),
])
body += agent_card('POST /api/face (multipart image and/or u=username)',
'curl -F "img=@avatar.png" -F "u=ghostuser42" https://dark0rbits.thetempleofdoom.com/api/face',
'Returns sha256/dHash/aHash of your upload + per-platform harvest with distances and verdict. Auth: session or Bearer key.')
return page("face", body)
@app.route("/api/face", methods=["GET", "POST"])
def api_face():
r = rate_limit("face", 20, 60)
if r: return r
uid = key_user() or current_user_id()
if not uid:
return jsonify({"ok": False, "error": "auth required: account session or API key"}), 401
f = request.files.get("img")
username = ((jp("u") if request.is_json else None) or param("u") or "").strip().lstrip("@")
if not f and not username:
return jsonify({"ok": False, "error": "provide multipart image and/or u=username"}), 400
out = {"ok": True}
tgt = None
if f:
blob = f.read(6 * 1024 * 1024)
if len(blob) < 64:
return jsonify({"ok": False, "error": "image too small/empty"}), 400
h = _pfp_hashes(blob)
if h.get("error"):
return jsonify({"ok": False, "error": h["error"]}), 400
out["uploaded"] = h
tgt = h
if username:
if not (2 <= len(username) <= 60) or any(c in "<>\"'/" for c in username):
return jsonify({"ok": False, "error": "bad username"}), 400
out["harvest"] = pfp_harvest(username, tgt)
if f or not username:
out["leads"] = [{"name": n, "url": b, "note": d} for n, b, d in face_search_leads()]
return jsonify(out)
# ---------- END TOOL: FACE TRACE ----------
# ---------- TOOL: ROTATOR ----------
import random as _rnd
import json as _json
_ROTATOR_DB_READY = False
def _rotator_db(con):
global _ROTATOR_DB_READY
if not _ROTATOR_DB_READY:
con.execute("CREATE TABLE IF NOT EXISTS rotator_history(id INTEGER PRIMARY KEY, user_id INTEGER, ts INTEGER, ua TEXT, platform TEXT, seed TEXT)")
con.commit()
_ROTATOR_DB_READY = True
ROTATOR_PLATFORMS = {
"desktop": [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15",
"Mozilla/5.0 (X11; Linux x86_64; rv:125.0) Gecko/20100101 Firefox/125.0",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0",
],
"mobile": [
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Mobile/15E148 Safari/604.1",
"Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 13; SM-G991B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Mobile Safari/537.36",
"Mozilla/5.0 (iPad; CPU OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Mobile/15E148 Safari/604.1",
],
"agent": [
"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
"Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)",
"curl/8.4.0",
"Wget/1.21.4 (linux-gnu)",
"python-urllib/3.11",
],
"stealth": [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
],
}
ROTATOR_REFERER_POOL = [
"https://www.google.com/", "https://duckduckgo.com/", "https://news.ycombinator.com/",
"https://www.bing.com/", "https://www.reddit.com/", "(direct)",
]
ROTATOR_LANG_POOL = ["en-US,en;q=0.9", "en-GB,en;q=0.8", "de-DE,de;q=0.9,en;q=0.5", "fr-FR,fr;q=0.9", "ja-JP,ja;q=0.8"]
def rotator_identity(platform, rng):
ua = rng.choice(ROTATOR_PLATFORMS.get(platform, ROTATOR_PLATFORMS["desktop"]))
return {
"user_agent": ua,
"referer": rng.choice(ROTATOR_REFERER_POOL),
"accept_language": rng.choice(ROTATOR_LANG_POOL),
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"sec_ch_ua_mobile": "?1" if platform == "mobile" else "?0",
"dnt": rng.choice(["1", "0", "(none)"]),
}
def rotator_spin(platform, n, seed):
platform = platform if platform in ROTATOR_PLATFORMS else "desktop"
try:
n = max(1, min(int(n), 25))
except Exception:
n = 5
rng = _rnd.Random(str(seed)) if seed else _rnd.Random()
ids = [rotator_identity(platform, rng) for _ in range(n)]
curl = 'curl -A "' + ids[0]["user_agent"] + '"'
if ids[0]["referer"] != "(direct)":
curl += ' -e "' + ids[0]["referer"] + '"'
curl += ' -H "Accept-Language: ' + ids[0]["accept_language"] + '" https://target.example/'
return {"ok": True, "platform": platform, "count": len(ids), "seed": seed or None, "identities": ids, "curl_first": curl}
@app.route("/rotator", methods=["GET", "POST"])
def rotator_page():
uid = current_user_id()
platform = param("platform") or "desktop"
if platform not in ROTATOR_PLATFORMS:
platform = "desktop"
n = param("n") or "5"
seed = (param("seed") or "").strip()[:64]
res = ""
if request.method == "POST":
r = rate_limit("rotator", 20, 60)
if r:
return r
d = rotator_spin(platform, n, seed)
try:
con = db()
_rotator_db(con)
for ident in d["identities"][:5]:
con.execute("INSERT INTO rotator_history(user_id,ts,ua,platform,seed) VALUES(?,?,?,?,?)",
(uid or 0, int(time.time()), ident["user_agent"], platform, seed or ""))
con.commit()
except Exception:
pass
rows = ""
for i, ident in enumerate(d["identities"], 1):
rows += ("<tr><td>" + str(i) + "</td><td><code>" + esc(ident["user_agent"]) + "</code></td><td>"
+ esc(ident["referer"]) + "</td><td>" + esc(ident["accept_language"]) + "</td><td>"
+ esc(ident["dnt"]) + "</td></tr>")
res = ('<div class=card><b>' + str(d["count"]) + " rotated identities — " + esc(d["platform"]) + " pool"
+ (" · seed <code>" + esc(seed) + "</code> (replayable)" if seed else "") + "</b>"
+ '<div class=tblwide><table><tr><th>#</th><th>User-Agent</th><th>Referer</th><th>Accept-Language</th><th>DNT</th></tr>'
+ rows + "</table></div>"
+ '<p style="color:var(--dim);font-size:.85rem;margin-bottom:0">First one as curl: <code>' + esc(d["curl_first"]) + "</code></p></div>")
body = f"""
<h1>HEADER <span>ROTATOR</span></h1><p class=sub>Spin consistent browser identities — User-Agent, referer, language, DNT — from four pools. Same seed replays the exact same rotation every time. No logs kept beyond your own history.</p>
<div class=card><form method=post action=/rotator>
<label>Pool</label>
<select name=platform>
<option value=desktop{' selected' if platform == 'desktop' else ''}>desktop — Chrome / Firefox / Safari / Edge</option>
<option value=mobile{' selected' if platform == 'mobile' else ''}>mobile — iPhone / Android / iPad</option>
<option value=agent{' selected' if platform == 'agent' else ''}>agent — bots, curl, wget</option>
<option value=stealth{' selected' if platform == 'stealth' else ''}>stealth — modern desktop, no legacy tells</option>
</select>
<label>How many (1-25)</label>
<input name=n type=number min=1 max=25 value="{esc(str(n))}">
<label>Seed (optional — same seed = same rotation)</label>
<input name=seed value="{esc(seed)}" placeholder="e.g. op-2026-10-07">
<button style=margin-top:.8rem">Spin</button></form></div>
{res}
<div class=card style=color:var(--dim)>API: GET /api/rotator?platform=mobile&amp;n=10&amp;seed=abc → JSON identities + ready-made curl.</div>""" + how([
"Pick a pool: desktop, mobile, agent or stealth — each holds real-world header strings.",
"Choose how many identities to spin, 1 to 25 per call.",
"Give it a seed and the rotation becomes deterministic — the same seed always replays the same identities in the same order.",
"Leave the seed blank for a fresh random rotation every call.",
"Every identity is a full consistent set: UA, referer, Accept-Language, DNT — not just a UA string.",
"The first identity comes back as a ready-to-paste curl command.",
"Agents: GET /api/rotator with the same params, JSON out, rate-limited 20/min.",
"Nothing is stored except the last few spins in your own account history.",
]) + flow("Rotating through a scrape run", [
'<span class=flowrole>you</span> set pool=<b>mobile</b>, n=<b>10</b>, seed=<b>run-42</b> and hit <b>Spin</b>.',
'The lab hands back <b>10 consistent identities</b> — UA, referer, language, DNT matched per identity.',
'<span class=flowrole>you</span> copy the <b>curl line</b> for the first one or call <b>/api/rotator</b> from your script.',
'The target sees ten different plausible visitors instead of one hammering client.',
'Re-run with the <b>same seed</b> later to reproduce the exact rotation for debugging.',
]) + gloss([
("rotation", "cycling through a pool of values so no single fingerprint repeats too often"),
("seed", "a string fed to the RNG — same seed, same sequence, every time"),
("DNT", "Do-Not-Track header — 0, 1 or absent, randomized per identity"),
("consistent identity", "UA + referer + language that plausibly belong to the same browser"),
]) + agent_card('GET /api/rotator?platform=mobile&n=10&seed=abc',
'curl "https://dark0rbits.thetempleofdoom.com/api/rotator?platform=mobile&n=10&seed=abc"',
'JSON: identities[] with user_agent, referer, accept_language, dnt + curl_first. Rate limit 20/min.')
return page("rotator", body)
@app.route("/api/rotator", methods=["GET", "POST"])
def api_rotator():
r = rate_limit("rotator", 20, 60)
if r:
return r
platform = (param("platform") or "desktop").strip().lower()
if platform not in ROTATOR_PLATFORMS:
return jsonify({"ok": False, "error": "platform must be one of: " + ", ".join(sorted(ROTATOR_PLATFORMS))}), 400
seed = (param("seed") or "").strip()[:64]
d = rotator_spin(platform, param("n") or "1", seed)
return jsonify(d)
@app.route("/api/rotator/pools")
def api_rotator_pools():
return jsonify({"ok": True, "pools": {k: len(v) for k, v in ROTATOR_PLATFORMS.items()},
"referers": len(ROTATOR_REFERER_POOL), "languages": len(ROTATOR_LANG_POOL)})
# ---------- END TOOL: ROTATOR ----------
# ---------- TOOL: IDENTITY SHELF ----------
import time as _shelf_time
def _shelf_data(uid):
con = db()
now = int(_shelf_time.time())
out = {}
out["mailboxes"] = [dict(r) for r in con.execute(
"SELECT address, expires, cnt, paid FROM mailboxes WHERE user_id=? ORDER BY (expires>0), expires LIMIT 50", (uid,)).fetchall()]
out["sms"] = [dict(r) for r in con.execute(
"SELECT phone, service, expires, status FROM sms_rentals WHERE user_id=? AND expires>0 ORDER BY expires LIMIT 50", (uid,)).fetchall()]
out["deaddrops"] = [dict(r) for r in con.execute(
"SELECT token, expires, reads_left, burn_after FROM deadrops WHERE user_id=? ORDER BY (expires>0), expires LIMIT 50", (uid,)).fetchall()]
out["canaries"] = []
for r in con.execute("SELECT token, tag, armed, rearm FROM canaries WHERE user_id=? ORDER BY id DESC LIMIT 50", (uid,)).fetchall():
d = dict(r)
d["hits"] = con.execute("SELECT COUNT(*) c FROM canary_hits WHERE canary_id=(SELECT id FROM canaries WHERE token=?)", (r["token"],)).fetchone()["c"]
out["canaries"].append(d)
out["trackables"] = [dict(r) for r in con.execute(
"SELECT token, filename, paid, created FROM trackables WHERE user_id=? ORDER BY id DESC LIMIT 50", (uid,)).fetchall()]
# stats
live = lambda e: e and e > now
n_live = sum(1 for m in out["mailboxes"] if m["paid"] and live(m["expires"])) \
+ sum(1 for s in out["sms"] if live(s["expires"])) \
+ sum(1 for d in out["deaddrops"] if live(d["expires"]))
expiring = sorted([e for grp in ("mailboxes", "sms", "deaddrops") for e in
(x["expires"] for x in out[grp] if live(x.get("expires"))) if e])
out["stats"] = {
"live_identities": n_live,
"next_expiry": expiring[0] if expiring else None,
"total_mail_received": sum(m["cnt"] or 0 for m in out["mailboxes"]),
"armed_traps": sum(1 for c in out["canaries"] if c["armed"]),
"total_trap_hits": sum(c["hits"] for c in out["canaries"]),
}
return out
def _shelf_badge(expires):
now = int(_shelf_time.time())
if not expires:
return '<span class=tag warn>no expiry</span>'
left = expires - now
when = _shelf_time.strftime("%b %d %H:%M", _shelf_time.localtime(expires))
if left <= 0:
return f'<span class=tag bad>EXPIRED {when}</span>'
cls = "bad" if left < 86400 else "ok"
unit = "d" if left >= 86400 else "h"
val = left // 86400 if left >= 86400 else left // 3600
return f'<span class="tag {cls}"><span class=cd data-ts={expires}>{val}{unit} left</span> · {when}</span>'
@app.route("/shelf")
def shelf():
uid = current_user_id()
if not uid:
return page("shelf", """<h1>IDENTITY <span>SHELF</span></h1><p class=sub>One dashboard for every burner you own — mailboxes, numbers, dead-drops, traps — with live countdowns so nothing dies silently.</p>
<div class=card>Log in (<a href=/inbox>free, no KYC — username + password, 10 seconds</a>) to see your shelf.</div>""" + how([
"Every burner on dark0rbits has a lifespan — mailboxes expire, rentals run out, dead-drops burn.",
"The shelf lists all of yours in one place with live countdown badges.",
"Under 24 hours left, a badge turns red — renew or replace before it dies.",
"Expired items stay listed so you can clean up or recreate them.",
"Agents: GET /api/shelf returns the same data as JSON for monitoring."]))
d = _shelf_data(uid)
def rows_mail():
if not d["mailboxes"]: return '<tr><td colspan=4 style=color:var(--dim)>none</td></tr>'
return "".join(f"<tr><td><b>{esc(m['address'])}</b></td><td style=text-align:center>{m['cnt'] or 0}</td>"
f"<td>{_shelf_badge(m['expires'])}</td><td><a href=/mail/view?addr={esc(m['address'])} style=color:var(--acc)>open</a></td></tr>"
for m in d["mailboxes"])
def rows_sms():
if not d["sms"]: return '<tr><td colspan=4 style=color:var(--dim)>none</td></tr>'
return "".join(f"<tr><td><b>{esc(s['phone'])}</b></td><td>{esc(s['service'])}</td>"
f"<td>{_shelf_badge(s['expires'])}</td><td>{esc(s['status'] or '')}</td></tr>" for s in d["sms"])
def rows_dd():
if not d["deaddrops"]: return '<tr><td colspan=4 style=color:var(--dim)>none</td></tr>'
return "".join(f"<tr><td><code>…{esc(t['token'][-6:])}</code></td><td>{t['reads_left']}/{t['burn_after']} reads left</td>"
f"<td>{_shelf_badge(t['expires'])}</td><td><a href=/drop/{esc(t['token'])} style=color:var(--acc)>open</a></td></tr>"
for t in d["deaddrops"])
def rows_can():
if not d["canaries"]: return '<tr><td colspan=4 style=color:var(--dim)>none</td></tr>'
return "".join(f"<tr><td><b>{esc(c['tag'])}</b></td><td style=text-align:center>{c['hits']}</td>"
f"<td>{'<span class=tag ok>armed' + (' ⟳' if c['rearm'] else '') + '</span>' if c['armed'] else '<span class=tag bad>triggered</span>'}</td>"
f"<td><a href=/canary/events?token={esc(c['token'])} style=color:var(--acc)>hits</a></td></tr>"
for c in d["canaries"])
st = d["stats"]
nxt = _shelf_time.strftime("%b %d %H:%M", _shelf_time.localtime(st["next_expiry"])) if st["next_expiry"] else "—"
body = f"""
<h1>IDENTITY <span>SHELF</span></h1><p class=sub>Everything you own that can die, on one page — with live countdowns. Know when every burner expires before it expires.</p>
{kv([("Live identities", f"<b style=font-size:1.2rem;color:var(--acc)>{st['live_identities']}</b> mailboxes + numbers + drops"),
("Next to expire", f"<b>{nxt}</b>"), ("Mail received (all time)", st["total_mail_received"]),
("Armed traps", f"{st['armed_traps']} armed · {st['total_trap_hits']} total hits")])}
<div class=card><b>BURNER MAILBOXES</b><div class=tblwide><table><tr><th>Address</th><th>Mail</th><th>Life</th><th></th></tr>{rows_mail()}</table></div></div>
<div class=card><b>SMS NUMBERS</b><div class=tblwide><table><tr><th>Number</th><th>Service</th><th>Life</th><th>Status</th></tr>{rows_sms()}</table></div></div>
<div class=card><b>DEAD-DROPS</b><div class=tblwide><table><tr><th>Token</th><th>Burns</th><th>Life</th><th></th></tr>{rows_dd()}</table></div></div>
<div class=card><b>CANARY TRAPS</b><div class=tblwide><table><tr><th>Tag</th><th>Hits</th><th>Status</th><th></th></tr>{rows_can()}</table></div></div>
<script>
setInterval(function(){{
document.querySelectorAll('.cd').forEach(function(e){{
var left = parseInt(e.dataset.ts) - Math.floor(Date.now()/1000);
if(left <= 0){{ e.textContent = 'expired'; return; }}
var v = left >= 86400 ? Math.floor(left/86400) + 'd' : Math.floor(left/3600) + 'h ' + Math.floor((left%3600)/60) + 'm';
e.textContent = v + ' left';
}});
}}, 30000);
</script>""" + how([
"Every burner has a lifespan — this page lists all of yours with a countdown badge per item.",
"Badges tick live (every 30s); the static expiry date renders even without JS.",
"Green = over 24h left. Red = under 24h or already dead — renew or replace.",
"Quick links jump straight to each item: mailbox, dead-drop, trap hit log.",
"Agents: GET /api/shelf returns identical JSON — wire it into a cron and get paged before anything dies."])
body += flow("never lose a burner to the clock again", [
"<span class=flowrole>you</span> run 3 burner mailboxes for signups and 2 SMS numbers for verifications.",
"<span class=flowrole>you</span> open the shelf once a morning: five green badges, everything alive.",
"Thursday: one mailbox badge is <b>red — 6h left</b>. You have all day to migrate that identity.",
"<span class=flowrole>agent</span> a cron hits /api/shelf hourly and messages you when anything drops under 24h.",
"nothing expires silently. No more 'why did my verification stop working' mysteries."])
body += gloss([("burner","a disposable identity — mailbox, phone number, or drop",),("TTL","time to live — how long until the service retires it"),("burn-after-read","dead-drops self-destruct after N openings")])
body += agent_card('GET /api/shelf', 'curl "https://dark0rbits.thetempleofdoom.com/api/shelf" -H "Cookie: dark0rbits_tok=…"', 'Returns mailboxes, sms, deaddrops, canaries + stats. Perfect for expiry-monitoring crons.')
return page("shelf", body)
@app.route("/api/shelf")
def api_shelf():
uid = key_user() or current_user_id()
if not uid:
return jsonify({"ok": False, "error": "login required — free no-KYC account at /inbox"}), 401
d = _shelf_data(uid)
for grp in ("mailboxes", "sms", "deaddrops", "canaries", "trackables"):
for x in d[grp]:
x.pop("token", None) # never leak tokens over API
return jsonify({"ok": True, **d})
# ---------- END TOOL: IDENTITY SHELF ----------
# ---------- TOOL: SNAP LINK (client-side shortener) ----------
_SNAP_PAGE = r"""<!doctype html><html lang=en><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1">
<title>▶ SNAP — one click more</title>
<style>
:root{--bg:#070a13;--card:rgba(19,25,44,.9);--line:#242e4d;--fg:#e9edf8;--dim:#93a0c2;--acc:#a78bfa;--acc2:#6fd6ff;--ok:#42e8a4;--bad:#ff6161}
*{box-sizing:border-box}
body{margin:0;min-height:100vh;display:flex;align-items:center;justify-content:center;background:radial-gradient(ellipse at 50% -10%,rgba(120,85,255,.16),transparent 55%),var(--bg);color:var(--fg);font:16px/1.6 ui-monospace,Menlo,Consolas,monospace;padding:1rem}
.card{background:var(--card);border:1px solid var(--line);border-radius:16px;padding:1.6rem;max-width:520px;width:100%;box-shadow:0 0 34px -16px var(--acc)}
h1{font-size:1.3rem;margin:0 0 .4rem;letter-spacing:.06em}
h1 b{color:var(--acc)}
.sub{color:var(--dim);font-size:.88rem;margin:0 0 1rem}
.url{background:rgba(10,15,30,.95);border:1px solid var(--line);border-radius:10px;padding:.7rem .9rem;word-break:break-all;font-size:.86rem;margin:.5rem 0}
.warn{color:var(--bad);font-size:.8rem;margin:.4rem 0}
button{font:inherit;font-weight:800;background:linear-gradient(135deg,var(--acc),var(--acc2));color:#0d0722;border:0;border-radius:10px;padding:.7rem 1.2rem;cursor:pointer;margin:.3rem .4rem .3rem 0}
button.ghost{background:transparent;color:var(--acc);border:1px solid var(--acc)}
.count{color:var(--dim);font-size:.8rem}
.noscript{color:var(--bad)}
.hist{margin-top:1.2rem;border-top:1px solid var(--line);padding-top:.9rem}
.hist h3{font-size:.78rem;color:var(--dim);letter-spacing:.2em;margin:0 0 .5rem}
.hist a{display:block;color:var(--acc2);font-size:.82rem;margin:.25rem 0;text-decoration:none;word-break:break-all}
.hist a:hover{color:var(--acc)}
.mono{font-family:ui-monospace,Menlo,monospace}
details{margin:.6rem 0;font-size:.85rem}
summary{cursor:pointer;color:var(--dim)}
</style></head><body>
<div class=card id=main>
<h1>▶ <b>SNAP</b> — one click more</h1>
<p class=sub>This is a dark0rbits snap link. The destination lives in the part of the address after the <span class=mono>#</span> — which is never sent to any server, anywhere. It decoded right here in your browser.</p>
<div id=stage class=noscript>JavaScript is off — snap links decode client-side, so this one can't open. The raw destination is visible in the address bar after the #.</div>
<div id=dest style=display:none>
<div class=warn>⚠ check where you're going — a snap link can point anywhere:</div>
<div class=url id=target></div>
<div class=count id=cd></div>
<button id=go>Open now ▸</button>
<button class=ghost id=cancel>stop</button>
<details><summary>host + full safety read</summary><div class=url id=hostread style=font-size:.8rem></div></details>
</div>
<div class=hist id=histbox style=display:none>
<h3>RECENT FROM THIS BROWSER</h3>
<div id=hist></div>
<p class=sub style=margin:.6rem 0 0;font-size:.75rem>history lives only in this browser's storage — the server keeps nothing</p>
</div>
</div>
<script>
(function(){
function d64(s){s=s.replace(/-/g,'+').replace(/_/g,'/');while(s.length%4)s+='=';return decodeURIComponent(escape(atob(s)))}
function e64(s){return btoa(unescape(encodeURIComponent(s))).replace(/\+/g,'-').replace(/\//g,'_').replace(/=+$/,'')}
var h=location.hash.replace(/^#/,'');
var box=document.getElementById('histbox');
try{
var hist=JSON.parse(localStorage.getItem('drb_snap_hist')||'[]');
if(hist.length){
box.style.display='block';
var hh=document.getElementById('hist');
hist.forEach(function(it){
var a=document.createElement('a');a.href='#'+it.c;a.textContent='▶ '+it.t.slice(0,60);a.title=it.t;
a.onclick=function(ev){ev.preventDefault();document.getElementById('target').textContent=it.t;proceed(it.t)};
hh.appendChild(a)});
}
}catch(e){}
function showList(){}
function proceed(target){
document.getElementById('stage').style.display='none';
var dv=document.getElementById('dest');dv.style.display='block';
document.getElementById('target').textContent=target;
try{var u=new URL(target);document.getElementById('hostread').textContent='host: '+u.host+' · scheme: '+u.protocol.replace(':','')+' · path: '+u.pathname;}catch(e){document.getElementById('hostread').textContent='(could not parse as a standard web address)'}
var n=5,cd=document.getElementById('cd');cd.textContent='auto-opening in 5…';
var t=setInterval(function(){if(n<=0){clearInterval(t);location.replace(target);return}cd.textContent='auto-opening in '+n+'…';n--},1000);
document.getElementById('cancel').onclick=function(){clearInterval(t);cd.textContent='auto-open cancelled — use the button when ready.'};
document.getElementById('go').onclick=function(){clearInterval(t);location.replace(target)};
// remember (dedupe, cap 10)
try{
hist=hist.filter(function(x){return x.t!==target});
hist.unshift({t:target,c:h});
hist=hist.slice(0,10);
localStorage.setItem('drb_snap_hist',JSON.stringify(hist));
}catch(e){}
}
if(h){
try{
var target=d64(h);
if(!/^https?:\/\//i.test(target)){document.getElementById('stage').textContent='this snap link does not decode to a web address — refusing to open it.';}
else proceed(target);
}catch(e){document.getElementById('stage').textContent='this snap link is malformed or was corrupted in transit.';}
}else{
// encoder mode
document.getElementById('stage').style.display='none';
var m=document.getElementById('main');
var d=document.createElement('div');
d.innerHTML='<h3 style="font-size:1rem;margin:.4rem 0">MAKE A SNAP LINK</h3>'+
'<p class=sub>Paste a long URL. It gets packed into the link itself — after the # — so nothing is stored on any server. The short link works forever and reveals its target only in the opener\'s browser.</p>'+
'<div class=url contenteditable id=src style=min-height:2.4rem>https://</div>'+
'<button id=mk>▸ snap it</button><div id=out></div>';
m.appendChild(d);
document.getElementById('mk').onclick=function(){
var src=document.getElementById('src').textContent.trim();
if(!/^https?:\\/\\//i.test(src)){document.getElementById('out').innerHTML='<div class=warn>that is not a web address — needs http(s)://</div>';return}
var link=location.origin+'/s#'+e64(src);
document.getElementById('out').innerHTML='<div class=warn>✓ stored nowhere. copy it:</div><div class=url id=lnk>'+link+'</div><button class=ghost id=cp>copy</button> <button class=ghost id=qr>QR ▸</button><div id=qrbox></div>';
document.getElementById('cp').onclick=function(){navigator.clipboard.writeText(link).then(function(){document.getElementById('cp').textContent='copied ✓'})};
document.getElementById('qr').onclick=function(){document.getElementById('qrbox').innerHTML='<img style="max-width:200px;margin-top:.5rem;border-radius:8px" alt="QR served by external service api.qrserver.com — the snap link itself stays server-free" src="https://api.qrserver.com/v1/create-qr-code/?size=200x200&data='+encodeURIComponent(link)+'">'};
};
}
})();
</script>
</body></html>"""
@app.route("/snap")
@app.route("/s")
@app.route("/s/<path:_any>")
def snap(_any=None):
r = Response(_SNAP_PAGE, mimetype="text/html")
r.headers["Cache-Control"] = "no-store"
r.headers["X-Robots-Tag"] = "noindex"
return r
@app.route("/api/snap/decode", methods=["POST"])
def api_snap_decode():
"""Agents: decode a snap fragment server-side WITHOUT opening it. raw = text after #."""
r = rate_limit("snap", 60, 60)
if r: return r
raw = (param("raw") or "").strip()
if not raw: return jsonify({"ok": False, "error": "raw (fragment after #) required"}), 400
try:
s = raw.replace("-", "+").replace("_", "/")
s += "=" * (-len(s) % 4)
import base64 as _b
target = base64.b64decode(s).decode("utf-8", "replace")
except Exception:
return jsonify({"ok": False, "error": "not a valid snap fragment"}), 400
import re as _re
m = _re.match(r"^https?://([^/]+)", target, _re.I)
return jsonify({"ok": True, "target": target,
"host": m.group(1) if m else None,
"scheme_safe": bool(m)})
# ---------- END TOOL: SNAP LINK ----------
# ---------- TOOL: UNFURL ----------
def _unfurl_db():
con = db()
con.execute("""CREATE TABLE IF NOT EXISTS unfurls(id INTEGER PRIMARY KEY, user_id INTEGER, url TEXT,
final_url TEXT, hops TEXT, status INTEGER, err TEXT, created INTEGER)""")
return con
def _unfurl_ua():
con = _unfurl_db()
try:
r = con.execute("SELECT val FROM settings WHERE user_id=? AND key='unfurl_ua'", (current_user_id() or 0,)).fetchone()
if r and r["val"]:
return r["val"]
except Exception:
pass
return "Mozilla/5.0 (Dark0rbits unfurl)"
def _unfurl_save(user_id, url, final_url, hops_json, status, err):
con = _unfurl_db()
con.execute("INSERT INTO unfurls(user_id,url,final_url,hops,status,err,created) VALUES(?,?,?,?,?,?,?)",
(user_id, url, final_url, hops_json, status, err, int(time.time())))
con.commit()
return con.execute("SELECT id FROM unfurls WHERE user_id=? ORDER BY id DESC LIMIT 1", (user_id,)).fetchone()["id"]
_NOFOLLOW = ("javascript:", "data:", "mailto:", "tel:", "blob:", "about:", "file:", "chrome:", "intent:", "ws:", "wss:")
def _unfurl_meta(html_text, base_url):
"""Extract <title>, meta description, og:*, twitter:* tags. Returns (title, metas dict, links, scripts, forms, iframes)."""
metas, links, scripts, forms, iframes = {}, [], [], [], []
title = ""
m = re.search(r"<title[^>]*>(.*?)</title>", html_text, re.I | re.S)
if m:
title = re.sub(r"\s+", " ", m.group(1)).strip()[:300]
for m in re.finditer(r"<meta[^>]+>", html_text, re.I):
tag = m.group(0)
def attr(name):
mm = re.search(name + r"\s*=\s*[\"']([^\"']*)[\"']", tag, re.I)
return mm.group(1) if mm else ""
nm, prop, con = attr("name"), attr("property"), attr("content")
key = (prop or nm).lower()
if key and con:
metas[key] = con[:600]
for m in re.finditer(r"<link[^>]+rel\s*=\s*[\"']?[^\"'>]*stylesheet[^\"'>]*[\"']?[^>]*>", html_text, re.I):
links.append(m.group(0)[:500])
for m in re.finditer(r"<script[^>]*>", html_text, re.I):
scripts.append(m.group(0)[:500])
for m in re.finditer(r"<form[^>]*>", html_text, re.I):
forms.append(m.group(0)[:500])
for m in re.finditer(r"<iframe[^>]*>", html_text, re.I):
iframes.append(m.group(0)[:500])
return title, metas, links, scripts, forms, iframes
def _abs(u, base):
try:
return urllib.parse.urljoin(base, u)
except Exception:
return u
def _fetch_no_redirect(u, ua):
class _NR(urllib.request.HTTPRedirectHandler):
def redirect_request(self, req, fp, code, msg, headers, newurl):
return None
op = urllib.request.build_opener(_NR, urllib.request.HTTPSHandler(context=_CTX))
req = urllib.request.Request(u, headers={"User-Agent": ua, "Accept": "text/html,*/*"})
try:
with op.open(req, timeout=10) as r:
return r.status, r.url, r.headers, r.read(300000).decode("utf-8", "replace")
except urllib.error.HTTPError as e:
body = ""
try:
body = e.read(100000).decode("utf-8", "replace")
except Exception:
pass
return e.code, u, e.headers, body
except Exception as e:
return 0, u, {}, str(e)
def _unfurl(start_url, max_hops=6, extract=True, ua=None):
"""Follow redirects manually one hop at a time; collect chain + final page metadata."""
ua = ua or _unfurl_ua()
hops, seen, cur, hop_status, final_body = [], set(), start_url, 0, ""
scheme_ok = cur.lower().startswith(("http://", "https://"))
if not scheme_ok:
return {"ok": False, "error": "URL must start with http:// or https://", "hops": []}
for i in range(max_hops + 1):
if cur in seen:
hops.append({"hop": i + 1, "url": cur, "status": 0, "location": "", "note": "redirect loop detected"})
cur = None
break
seen.add(cur)
status, final_url, headers, body = _fetch_no_redirect(cur, ua)
hops.append({"hop": i + 1, "url": cur, "status": status, "location": headers.get("Location", "") if headers else ""})
if status in (301, 302, 303, 307, 308) and headers and headers.get("Location"):
loc = headers["Location"]
low = loc.lower()
if any(low.startswith(p) for p in _NOFOLLOW):
hops[-1]["note"] = "non-http scheme — not followed"
cur = None
final_body = body
break
nxt = _abs(loc, cur)
hops[-1]["location"] = nxt
cur = nxt
continue
hop_status = status
final_body = body
cur = None
break
if cur is not None:
hop_status = 0
out = {"ok": hop_status > 0, "start": start_url, "final": hops[-1]["url"] if hops else "",
"status": hop_status, "hop_count": len(hops), "hops": hops}
if extract and final_body:
title, metas, css, scripts, forms, iframes = _unfurl_meta(final_body, out["final"])
out["title"] = title
out["metas"] = metas
out["css_count"] = len(css)
out["script_count"] = len(scripts)
out["form_count"] = len(forms)
out["iframe_count"] = len(iframes)
out["iframes"] = [dict(src=re.search(r"src\s*=\s*[\"']([^\"']*)", f, re.I).group(1) if re.search(r"src\s*=\s*[\"']([^\"']*)", f, re.I) else "", tag=f[:300]) for f in iframes[:10]]
out["forms"] = [dict(action=re.search(r"action\s*=\s*[\"']([^\"']*)", f, re.I).group(1) if re.search(r"action\s*=\s*[\"']([^\"']*)", f, re.I) else "", method=(re.search(r"method\s*=\s*[\"']?(\w+)", f, re.I).group(1).lower() if re.search(r"method\s*=\s*[\"']?(\w+)", f, re.I) else "get"), tag=f[:300]) for f in forms[:10]]
return out
@app.route("/unfurl", methods=["GET", "POST"])
def unfurl_page():
uid = current_user_id()
result, url_in, max_hops, extract, err = None, "", 6, "1", ""
if request.method == "POST":
r = rate_limit("unfurl", 20, 60)
if r:
return r
url_in = (param("url") or "").strip()[:500]
try:
max_hops = max(1, min(10, int(param("max_hops") or 6)))
except Exception:
max_hops = 6
extract = param("extract") in ("1", "on", "true", "yes", "")
if not url_in:
err = "paste a URL first"
elif not url_in.lower().startswith(("http://", "https://")):
err = "URL must start with http:// or https://"
else:
result = _unfurl(url_in, max_hops, extract)
try:
_unfurl_save(uid or 0, url_in, result.get("final", ""), json.dumps(result.get("hops", []))[:8000], result.get("status", 0), result.get("error", ""))
except Exception:
pass
body = f"""<h1>UNFURL <span>URL</span></h1>
<p class=sub>Follow every redirect hop by hand — scheme, host, status, location — then dissect the final page. Shorteners, cloakers, affiliate chains: laid open.</p>
<div class=card>
<form method=post action=/unfurl>
<input name=url value='{esc(url_in)}' placeholder='https://short.link/abc' style=width:60%>
<label style=margin-left:.6rem>max hops</label> <input name=max_hops value={max_hops} style=width:60px>
<label style=margin-left:.6rem><input type=checkbox name=extract value=1 {'checked' if extract else ''}> page dissection</label>
<button>UNFURL</button>
</form></div>"""
if err:
body += '<div class=card><span class="tag bad">' + esc(err) + '</span></div>'
if result:
if result.get("ok"):
body += '<div class=card><span class="tag ok">resolved in ' + str(result["hop_count"]) + ' hop(s) — final status ' + str(result["status"]) + '</span></div>'
else:
body += '<div class=card><span class="tag bad">' + esc(result.get("error") or ("request failed (status " + str(result.get("status", 0)) + ")")) + '</span></div>'
rows = "".join(
"<tr><td>" + str(h.get("hop", "")) + "</td><td><code>" + esc(h.get("url", "")) + "</code></td><td>"
+ ("<b style=color:var(--ok)>" if 200 <= int(h.get("status", 0) or 0) < 400 else "<b>") + esc(str(h.get("status", ""))) + "</b></td><td>"
+ ("<code>" + esc(h.get("location", "")) + "</code>" if h.get("location") else ("—" if not h.get("note") else '<span style=color:var(--bad)>' + esc(h["note"]) + "</span>")) + "</td></tr>"
for h in result.get("hops", []))
body += '<div class=card><b>REDIRECT CHAIN</b><div class=tblwide><table><tr><th>#</th><th>URL</th><th>Status</th><th>Location / note</th></tr>' + rows + '</table></div></div>'
if result.get("title") is not None and result.get("ok"):
mrows = "".join("<tr><td>" + esc(k) + "</td><td>" + esc(v) + "</td></tr>" for k, v in result.get("metas", {}).items())
body += ('<div class=grid2"><div class=card><b>FINAL PAGE</b><div class=kv">'
+ "<div>Title</div><div>" + esc(result.get("title") or "—") + "</div>"
+ "<div>Final URL</div><div><code>" + esc(result["final"]) + "</code></div>"
+ "<div>Status</div><div>" + str(result["status"]) + "</div>"
+ "<div>Stylesheets</div><div>" + str(result.get("css_count", 0)) + "</div>"
+ "<div>Scripts</div><div>" + str(result.get("script_count", 0)) + "</div>"
+ "<div>Forms / iframes</div><div>" + str(result.get("form_count", 0)) + " / " + str(result.get("iframe_count", 0)) + "</div></div></div>"
+ '<div class=card><b>META TAGS</b><div class=tblwide><table><tr><th>Name</th><th>Content</th></tr>' + (mrows or "<tr><td colspan=2>—</td></tr>") + "</table></div></div></div>")
if result.get("iframes"):
body += '<div class=card><b>IFRAMES</b><div class=tblwide><table><tr><th>src</th></tr>' + "".join("<tr><td><code>" + esc(f.get("src") or "—") + "</code></td></tr>" for f in result["iframes"]) + "</table></div></div>"
if result.get("forms"):
body += '<div class=card><b>FORMS</b><div class=tblwide><table><tr><th>Method</th><th>Action</th></tr>' + "".join("<tr><td>" + esc(f.get("method", "get")) + "</td><td><code>" + esc(f.get("action") or "—") + "</code></td></tr>" for f in result["forms"]) + "</table></div></div>"
body += how([
"Paste any URL — a shortener, a cloaker, an affiliate link, a login redirect.",
"We request it with redirects disabled, so every 30x comes back to us one hop at a time.",
"Each hop records scheme, host, status code and the exact Location header — relative locations are resolved absolute.",
"Non-http schemes (javascript:, data:, intent:) are flagged and never followed.",
"Loops are detected: the same URL twice ends the chain with a clear note.",
"The final page (any status) is dissected: title, meta/og/twitter tags, stylesheet and script counts, forms and iframes.",
"Everything is available as JSON at /api/unfurl for agents.",
])
body += flow("checking a shortened link before clicking", [
"<span class=flowrole>you</span> receive <code>https://bit.ly/3xYz</code> in a message and want to know where it really goes.",
"<b>1.</b> Paste it into UNFURL with default 6 hops.",
"<b>2.</b> The chain shows <code>301 → tracker.example → 302 → login.example</code> — two hops, both logged.",
"<span class=flowrole>you</span> see the final host is a credential-phishing page with one form and an off-domain iframe.",
"<b>3.</b> Grab the JSON from /api/unfurl and feed it to your pipeline.",
])
body += gloss([
("redirect hop", "One 301/302/303/307/308 jump. Browsers follow them silently; we stop at each one."),
("Location header", "Where the server says to go next. Can be relative — we resolve it against the current URL."),
("redirect loop", "The same URL appearing twice in a chain — the server is chasing its tail."),
("og: meta tags", "Open Graph tags pages use for link previews — often reveal the real content behind a cloaker."),
("scheme", "The http:// or https:// part. Non-http schemes in Location are dangerous and never followed here."),
])
body += agent_card("GET /api/unfurl?url=…&max_hops=6",
"curl -s '" + SITE + "/api/unfurl?url=https://bit.ly/3xYz&max_hops=8'",
"Returns the full chain plus final-page metadata as JSON. Optional extract=0 to skip dissection.")
return page("hunt", body)
@app.route("/api/unfurl")
def api_unfurl():
uid = key_user() or current_user_id()
if not uid:
return jsonify({"ok": False, "error": "auth required: account session or Authorization: Bearer key"}), 401
r = rate_limit("unfurl_api", 30, 60)
if r:
return r
u = (param("url") or "").strip()[:500]
if not u:
return jsonify({"ok": False, "error": "url required"}), 400
if not u.lower().startswith(("http://", "https://")):
return jsonify({"ok": False, "error": "url must start with http:// or https://"}), 400
try:
mh = max(1, min(10, int(param("max_hops") or 6)))
except Exception:
mh = 6
extract = param("extract") not in ("0", "false", "no")
res = _unfurl(u, mh, extract)
code = 200 if (res.get("ok") and 200 <= res.get("status", 0) < 400) else 502
try:
_unfurl_save(uid, u, res.get("final", ""), json.dumps(res.get("hops", []))[:8000], res.get("status", 0), res.get("error", ""))
except Exception:
pass
return jsonify(res), code
@app.route("/api/unfurl/history")
def api_unfurl_history():
uid = key_user() or current_user_id()
if not uid:
return jsonify({"ok": False, "error": "auth required"}), 401
con = _unfurl_db()
rows = con.execute("SELECT id,url,final_url,status,created FROM unfurls WHERE user_id=? ORDER BY id DESC LIMIT 25", (uid,)).fetchall()
return jsonify({"ok": True, "items": [dict(r) for r in rows]})
# ---------- END TOOL: UNFURL ----------
# ---------- TOOL: WARP ARCHIVE ----------
import urllib.parse as _wurl
WARP_TTL = 21600 # 6h cache
def _warp_db():
con = db()
con.execute("CREATE TABLE IF NOT EXISTS warp_cache(domain TEXT, kind TEXT, data TEXT, ts INTEGER, PRIMARY KEY(domain,kind))")
con.commit()
return con
def _warp_get(domain, kind):
con = _warp_db()
r = con.execute("SELECT data, ts FROM warp_cache WHERE domain=? AND kind=?", (domain, kind)).fetchone()
if r and (time.time() - r["ts"]) < WARP_TTL:
return jf(r["data"])
return None
def _warp_put(domain, kind, obj):
con = _warp_db()
con.execute("INSERT INTO warp_cache(domain,kind,data,ts) VALUES(?,?,?,?) ON CONFLICT(domain,kind) DO UPDATE SET data=excluded.data, ts=excluded.ts",
(domain, kind, json.dumps(obj), int(time.time())))
con.commit()
def _warp_norm(raw):
d = str(raw or "").strip().lower().lstrip()
d = _wurl.urlparse(d if "//" in d else "http://" + d).netloc.split("@")[-1].split(":")[0]
if d.startswith("www."):
d = d[4:]
if not d or "/" in d or " " in d or d.count(".") < 1 or not re.match(r"^[a-z0-9.-]+$", d):
return None
return d
def _warp_cdx(domain, extra=""):
"""Collapsed-per-year snapshot list from the Wayback CDX API."""
url = "http://web.archive.org/cdx/search/cdx?url=" + _wurl.quote(domain) + "&output=json&limit=150&collapse=timestamp:4" + extra
st, txt = http(url)
arr = jf(txt)
if st != 200 or not isinstance(arr, list):
return None, (st or 0)
if len(arr) < 2:
return [], 200
snaps = []
for row in arr[1:]:
try:
snaps.append({"timestamp": row[1], "url": row[2], "mimetype": row[3] if len(row) > 3 else "", "status": row[4] if len(row) > 4 else "", "digest": row[5] if len(row) > 5 else ""})
except Exception:
continue
return snaps, 200
def _warp_snapinfo(domain):
snaps, st = _warp_cdx(domain)
if snaps is None:
return None, st
by_year, years = {}, []
for s in snaps:
y = s["timestamp"][:4]
if y not in by_year:
by_year[y] = []
years.append(y)
by_year[y].append(s)
timeline = [{"year": y, "count": len(by_year[y]), "first": by_year[y][0]["timestamp"], "last": by_year[y][-1]["timestamp"]} for y in years]
return {"domain": domain, "total": len(snaps), "timeline": timeline, "snapshots": snaps}, 200
def _warp_titles(domain):
"""Distinct archived titles/paths: fetch each collapsed snapshot's HTML, pull the title tag."""
info, st = _warp_snapinfo(domain)
if info is None:
return None, st
seen, out = set(), []
for s in info["snapshots"]:
key = (s["url"], s["digest"])
if key in seen:
continue
seen.add(key)
out.append(s)
if len(out) >= 8:
break
paths = []
for s in out:
rec = {"timestamp": s["timestamp"], "path": "/" + s["url"].split("/", 3)[-1] if s["url"].count("/") > 2 else "/",
"url": "https://web.archive.org/web/" + s["timestamp"] + "/" + s["url"], "title": ""}
paths.append(rec)
return {"domain": domain, "entries": paths, "scanned": len(out)}, 200
def _warp_dns(domain):
"""Current DNS via DoH (A + MX), oldest-archived context left to RDAP side."""
rec = {"a": [], "mx": []}
st, txt = http("https://cloudflare-dns.com/dns-query?name=" + _wurl.quote(domain) + "&type=A", headers={"Accept": "application/dns-json"})
d = jf(txt)
if d:
rec["a"] = sorted({a.get("data", "") for a in d.get("Answer", []) if a.get("type") == 1})
st, txt = http("https://cloudflare-dns.com/dns-query?name=" + _wurl.quote(domain) + "&type=MX", headers={"Accept": "application/dns-json"})
d = jf(txt)
if d:
rec["mx"] = sorted({a.get("data", "") for a in d.get("Answer", []) if a.get("type") == 15})
return rec
def _warp_rdap(domain):
st, txt = http("https://rdap.org/domain/" + _wurl.quote(domain))
d = jf(txt)
if not d or st != 200:
return None
ev = {e.get("eventAction"): (e.get("eventDate") or "")[:10] for e in d.get("events", [])}
ent = d.get("entities") or []
reg = ""
for e in ent:
if "registrar" in (e.get("roles") or []):
for v in (e.get("vcardArray") or [None, []])[1]:
if v[0] == "fn":
reg = v[3]
return {"registrar": reg, "created": ev.get("registration", ""), "changed": ev.get("last changed", ""), "expires": ev.get("expiration", ""),
"status": d.get("status", [])}
def _warp_dns_history(domain):
"""DNS/whois drift: current RDAP/DNS vs the oldest archived year (whois HTML hint)."""
cur_dns = _warp_dns(domain)
rdap = _warp_rdap(domain)
info, st = _warp_snapinfo(domain)
if info is None:
return None, st
oldest = info["snapshots"][0]["timestamp"] if info["snapshots"] else ""
old_dns = {"a": [], "mx": []}
if oldest:
st2, body = http("https://web.archive.org/cdx/search/cdx?url=" + _wurl.quote(domain) + "&output=json&limit=5&collapse=timestamp:4&from=" + oldest[:8] + "&filter=mimetype:text/dns")
arr = jf(body)
if isinstance(arr, list) and len(arr) > 1:
for row in arr[1:]:
try:
if row[3] == "text/dns":
parts = row[2].split("/")
old_dns["a"].append(row[2])
except Exception:
continue
changes = []
for field in ("a", "mx"):
nowv = "; ".join(cur_dns[field]) or "(none)"
thenv = "; ".join(old_dns[field]) or "(not archived)"
changes.append({"record": field.upper(), "oldest": thenv, "current": nowv,
"drift": "no data" if not old_dns[field] else ("same" if thenv == nowv else "CHANGED")})
if rdap:
changes.append({"record": "REGISTRAR", "oldest": "(unknown)", "current": rdap["registrar"] or "(n/a)", "drift": "current"})
changes.append({"record": "CREATED", "oldest": "(unknown)", "current": rdap["created"] or "(n/a)", "drift": "current"})
return {"domain": domain, "oldest_snapshot": oldest, "rdap": rdap, "dns_now": cur_dns, "changes": changes}, 200
def _warp_lookup(domain):
res = {}
info, st1 = _warp_snapinfo(domain)
res["archive"] = info
if info:
_warp_put(domain, "archive", info)
dnsh, st2 = _warp_dns_history(domain)
res["dns_history"] = dnsh
if dnsh:
_warp_put(domain, "dns", dnsh)
titles, st3 = _warp_titles(domain)
res["hosted"] = titles
if titles:
_warp_put(domain, "hosted", titles)
return res, (st1 if info is None else 200)
def _warp_page_body(domain, data, msg):
res_html = ""
if msg:
res_html = '<div class=card><span class="tag warn">NOTE</span> ' + esc(msg) + "</div>"
if data:
arch = data.get("archive") or {}
if arch.get("total"):
rows = ""
for t in arch.get("timeline", []):
ts = t["first"]
shot = "https://web.archive.org/web/" + ts + "if_/" + domain
live = "https://web.archive.org/web/" + ts + "/" + domain
rows += ("<tr><td><b>" + esc(t["year"]) + "</b></td><td>" + str(t["count"]) + "</td>"
+ "<td><a href=" + shot + " target=_blank rel=noopener>preview " + ts[:8] + "</a></td>"
+ "<td><a href=" + live + " target=_blank rel=noopener>open copy</a></td></tr>")
res_html += ('<div class=card><b>SNAPSHOT TIMELINE — ' + esc(domain) + '</b>'
+ '<div style=color:var(--dim);font-size:.85rem;margin:.3rem 0>' + str(arch.get("total", 0)) + ' snapshots collapsed to one per year.</div>'
+ '<div class=tblwide><table><tr><th>Year</th><th>Snapshots</th><th>Screenshot preview</th><th>Archived copy</th></tr>' + rows + "</table></div></div>")
else:
res_html += '<div class=card><span class="tag bad">NO ARCHIVE</span> The Wayback Machine has no snapshots of <b>' + esc(domain) + "</b>. Either it never hosted a site, or it was never crawled.</div>"
dns = data.get("dns_history") or {}
if dns:
crows = ""
for c in dns.get("changes", []):
tag = "ok" if c["drift"] in ("same", "current", "no data") else "bad"
crows += ("<tr><td><b>" + esc(c["record"]) + "</b></td><td>" + esc(c["oldest"]) + "</td><td>" + esc(c["current"]) + "</td>"
+ '<td><span class="tag ' + tag + '">' + esc(c["drift"]) + "</span></td></tr>")
ol = dns.get("oldest_snapshot", "")
res_html += ('<div class=card><b>DNS / WHOIS DRIFT</b>'
+ '<div style=color:var(--dim);font-size:.85rem;margin:.3rem 0>Oldest snapshot: ' + (esc(ol[:8]) if ol else "none") + " vs today.</div>"
+ '<div class=tblwide><table><tr><th>Record</th><th>Oldest archived</th><th>Current</th><th>Drift</th></tr>' + crows + "</table></div></div>")
hosted = data.get("hosted") or {}
if hosted and hosted.get("entries"):
hrows = ""
for e in hosted["entries"]:
hrows += ('<tr><td>' + esc(e["timestamp"][:8]) + "</td><td>" + esc(e["path"]) + '</td><td><a href=' + e["url"] + ' target=_blank rel=noopener>view</a></td></tr>')
res_html += ('<div class=card><b>WHAT DID THIS DOMAIN HOST?</b>'
+ '<div style=color:var(--dim);font-size:.85rem;margin:.3rem 0>Distinct archived paths (' + str(hosted.get("scanned", 0)) + " sampled).</div>"
+ '<div class=tblwide><table><tr><th>Date</th><th>Path</th><th>Link</th></tr>' + hrows + "</table></div></div>")
return res_html
WARP_EXPLAIN = how([
"The Wayback Machine is a public crawl archive — its CDX index API lists every snapshot it holds for a domain, free, no key.",
"We ask for the index collapsed to one snapshot per year (collapse=timestamp:4) so you get a clean timeline instead of 10,000 rows.",
"Screenshot previews use the 'if_' replay modifier: web.archive.org/web/<ts>if_/<url> strips the Wayback toolbar and serves the page as captured.",
"DNS drift: we pull today's A/MX records over DNS-over-HTTPS and today's RDAP registration, then line them up against the oldest archived year.",
"Everything is cached in a local sqlite table for 6 hours — repeat lookups are instant and do not hammer the archive.",
"A domain with snapshots every year and stable records is usually legit. A 2-year gap plus a registrar change plus new MX is a takeover tell.",
"Agents: GET /api/warp?domain=example.com returns the whole picture as JSON — timeline, drift table, hosted paths, ready for a report.",
])
WARP_FLOW = flow("watch a scam site morph over 3 years", [
"<span class=flowrole>you</span> get a phishing email from <b>secure-login-example.com</b> and want to know if it is a fresh drop or an old hijack.",
"Punch the domain into WARP. The timeline shows snapshots in <b>2019 and 2020</b> — then nothing until <b>last month</b>.",
"Click the <b>2019 screenshot preview</b>: the archived copy shows a quiet small-business bakery homepage.",
"The <b>drift table</b> tells the rest: registrar changed this year, MX moved to a bulk-mail provider, A record now points at bulletproof hosting.",
"The <b>hosted paths</b> list confirms the morph: /menu.pdf in 2019, /wp-login.php and /secure/verify today.",
"<span class=flowrole>you</span> report it as a <b>compromised/repurposed domain</b> with archive receipts — far more credible than 'it looks phishy'.",
])
@app.route("/warp", methods=["GET", "POST"])
def warp_page():
uid = current_user_id()
domain_raw = param("domain") or ""
data, msg = None, ""
if domain_raw:
domain = _warp_norm(domain_raw)
if not domain:
msg = "that does not look like a domain — try example.com"
else:
cached = _warp_get(domain, "archive")
if cached:
dns_c = _warp_get(domain, "dns")
host_c = _warp_get(domain, "hosted")
data = {"archive": cached, "dns_history": dns_c, "hosted": host_c}
msg = "cached result (fresh within 6h)"
else:
r = rate_limit("warp", 6, 60)
if r:
return r
data, st = _warp_lookup(domain)
if data.get("archive") is None:
data = None
msg = "archive lookup failed (status " + str(st) + ") — the Wayback CDX API may be slow or unreachable"
res_html = _warp_page_body(domain_raw, data, msg)
body = f"""
<h1>WARP <span>ARCHIVE</span></h1><p class=sub>A domain time machine. Line up the Wayback Machine's snapshots of any domain year by year, preview what it used to look like, and see whether its DNS and registrar story drifted. Passive — one public API, zero packets to the target.</p>
<div class=card><b>Look up a domain</b>
<form method=post action=/warp onsubmit="return doWarp()">
<input name=domain placeholder="example.com" style="width:min(420px,100%)" value="{esc(domain_raw)}" required>
<button style=margin-left:.4rem>Time travel</button></form>
<div style="color:var(--dim);font-size:.85rem;margin-top:.5rem">Snapshots per year &middot; screenshot previews &middot; DNS/whois drift &middot; hosted-path inventory. Results cached 6h.</div></div>
{res_html}
{WARP_FLOW}
{WARP_EXPLAIN}
""" + gloss([("Wayback Machine", "web.archive.org — the Internet Archive's crawl of the web since 1996. Public, free, no key."),
("CDX API", "the index in front of the archive: query it for every snapshot (timestamp, URL, mimetype, hash) it holds for a site."),
("collapse=timestamp:4", "dedupe the index to one hit per year (first 4 digits of the timestamp) — the clean timeline trick."),
("if_ modifier", "replay URL flag that serves the raw archived page with the Wayback toolbar injected CSS/JS removed — good for previews."),
("RDAP", "the modern WHOIS: registration dates, registrar, status over HTTPS/JSON."),
("DoH", "DNS over HTTPS — lets us resolve A/MX records from the app without a resolver."),
("takeover", "an aged domain that changed hands: registrar event + new MX + new hosting is the classic signature."),
]) + agent_card("GET /api/warp?domain=example.com",
"curl -s \"" + SITE + "/api/warp?domain=example.com\" -H \"Authorization: Bearer dk_...\"",
"Free. Returns timeline, drift table, hosted paths. Cached 6h per domain.")
return page("intel", body)
@app.route("/api/warp")
def api_warp():
r = rate_limit("warp", 10, 60)
if r:
return r
domain = _warp_norm(param("domain") or "")
if not domain:
return jsonify({"ok": False, "error": "domain required, e.g. ?domain=example.com"}), 400
cached = _warp_get(domain, "archive")
if cached:
ok = bool(cached.get("total"))
out = {"ok": ok, "cached": True, "domain": domain, "archive": cached,
"dns_history": _warp_get(domain, "dns"), "hosted": _warp_get(domain, "hosted")}
if not ok:
out["error"] = "no snapshots found for this domain (cached)"
return jsonify(out), (200 if ok else 404)
data, st = _warp_lookup(domain)
out = {"ok": bool(data.get("archive") and data["archive"].get("total")), "cached": False, "domain": domain}
out.update(data)
if not out["ok"]:
out["error"] = "no snapshots found for this domain (status " + str(st) + ")"
return jsonify(out), (200 if out["ok"] else 404)
# ---------- END TOOL: WARP ARCHIVE ----------
# ---------- 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("dark0rbits_admin", secrets.token_urlsafe(16), max_age=86400, httponly=True)
return resp
if not request.cookies.get("dark0rbits_admin"):
return page("track", '<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)
reply_to = param("reply") or ""
reply_html = ""
if reply_to:
r = con.execute("SELECT username FROM users WHERE id=?", (reply_to,)).fetchone()
if r: reply_html = f'<div class=card><b>Reply to {esc(r["username"])}</b><form method=post action=/admin/reply><input type=hidden name=uid value="{esc(reply_to)}"><textarea name=body rows=2 style="width:100%"></textarea><button style=margin-top:.4rem>Send reply</button></form></div>'
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>Reply</b><form method=get><input name=reply placeholder="user id to reply to" style=width:60%><button>Load</button></form></div>{reply_html}
<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 (hacker landing) ----------
@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 {}
uid = current_user_id()
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"]
tools = [
("ip","IP INTEL","Geo, ASN, ISP, VPN/hosting flags, rDNS — your IP auto-detected, any target on demand.","◈","INTEL"),
("card","CARD CHECK","Luhn + BIN: issuer bank, brand, type, country, prepaid risk flags. Nothing stored, nothing charged.","◈","INTEL"),
("eh","MAIL FORENSICS","Paste headers or drop a .eml → true origin IP + geo, relay delays, SPF/DKIM/DMARC verdicts, spoof flags.","◈","INTEL"),
("phone","PHONE LOOKUP","OSINT on any number: carrier, line type, region, timezones + free deep-dive leads. VOIP/fake detection.","◈","INTEL"),
("user","USERNAME SLEUTH","One handle → probed across 16 platforms in parallel. Find where the human lives online.","◈","INTEL"),
("domain","DOMAIN RECON","RDAP registration, full DNS, certificate-log subdomain discovery. Passive recon, free.","◈","INTEL"),
("forensics","IMAGE FORENSICS","Deep EXIF (all IFDs), decoded GPS + map links, XMP trails, embedded thumbnails, ELA — expose doctored photos.","◈","INTEL"),
("sms","SMS RENTAL","Disposable numbers, 30-min windows, instant refund on cancel.","◈","ACQUIRE"),
("mail","BURNER MAIL","Receive-only mailboxes, 7–90 days, live countdown. Codes & confirmations without an identity.","◈","ACQUIRE"),
("proxy","PROXY LAB","Residential egress testing on the Pleiades rail — same gateway keys fleet-wide.","◈","ACQUIRE"),
("deaddrop","DEAD-DROP","AES-GCM encrypted notes that burn after N reads or TTL. Optional password. No trace left.","◈","ACQUIRE"),
("steg","STEGO LAB","Hide secret text inside a normal PNG — invisible, password-encrypted, scattered. Live capacity meter.","◈","OPERATE"),
("track","TRACK FILE","Send an image or file, learn who opened it: IP, city, ISP, device, language — instantly in your inbox.","◈","HUNT"),
("canary","CANARY TRAPS","Tripwires: stealth links, pixels, fake-credential honeytokens, honeyfile baits — instant alerts with IP + geo when touched.","◈","HUNT"),
("shot","SCREENSHOT","Headless-Chromium PNG capture of any page. Agents: poll the status API.","◈","HUNT"),
("score","FRAUD-SCORE","Composite 0-100 risk: IP intel + disposable-email + BIN heuristics, with full breakdown.","◈","HUNT"),
("tools","FREE TOOLS","DNS resolver, HTTP header inspector, JWT decoder, hasher, generators.","◈","UTILITY"),
("beacon","PORT BEACON","Heartbeat your servers home on a timer; if the box goes dark or the probe URL gets touched, you know in seconds.","◆","Hunt"),
("bssid","BSSID RADAR","Turn a WiFi router's MAC into an approximate place on Earth, with map links and accuracy radius.","◈","Hunt"),
("hooks", "HOOK RELAY", "Instant public webhook inspector: capture every callback, auto-detect the sender, replay it anywhere.", "◈", "Operate"),
("face","FACE TRACE","Hash an avatar, harvest a username's profile pictures across platforms, and get Hamming verdicts — no reverse-image APIs.","◈","Hunt"),
("rotator","ROTATOR","Spin consistent browser identities from four pools with replayable seeds.","◈","UTILITY"),
("shelf","IDENTITY SHELF","Every burner you own on one page — mailboxes, numbers, drops, traps — with live countdowns so nothing dies silently.","◈","ACCOUNT"),
("s","SNAP LINKS","One-click short links with zero server storage — the target rides in the #fragment, decodes in the opener's browser, with a safety preview and QR.","◈","UTILITY"),
("unfurl", "UNFURL", "Follow every redirect hop in a URL chain and dissect the page at the end.", "◈", "Hunt"),
("warp","WARP ARCHIVE","A domain time machine: snapshot timeline from the Wayback Machine, archived-page previews, and DNS/whois drift — watch a domain morph over years.","◈","INTEL"),
("passport","AGENT PASSPORT","Machine-readable trust badge for your bots. Agents are first-class here.","◈","ACCOUNT"),
]
tcards = "".join(
f'<div class="card tcard"><div class="trow"><span class="tico">{ico}</span><h3><a href=/{href} style="color:var(--acc);text-decoration:none">{name}</a></h3><span class="tt">{cat}</span></div>'
f'<p>{desc}</p><a class=tgo href=/{href}><button>Open →</button></a></div>'
for href, name, desc, ico, cat in tools)
stat = f"you're connecting from <b style='color:var(--acc2)'>{esc(d.get('query','?'))}</b> · {esc(d.get('country',''))}"
cta = ('<a href=/inbox><button class=big>◈ INBOX</button></a> <a href=/keys><button class="big ghost">▣ API KEYS</button></a> <a href=/pass><button class=big>★ GET PASS</button></a>' if uid else '<a href=/signup><button class=big>▸ SIGN UP — NO KYC</button></a> <a href=/inbox><button class="big ghost">◈ LOG IN</button></a> <a href=/pass><button class="big ghost">★ GET PASS</button></a>')
from markupsafe import escape as _e
stat_line = '<span class="hl">▸ ' + stat + '</span>' if stat else ""
body = f"""
<div class="term card glow hero">
<div class="hl">$ ./dark0rbits --intro <span class="crt">▊</span></div>
<h2>The toolbox that treats you like an <em>operator</em>, not a product.</h2>
<p class="hsub">No KYC. No email. No meters — <b>every tool is FREE</b>. Every tool has a JSON API, so scripts and agents are first-class customers.</p>
{stat_line}
<div class="cta">{cta}</div></div>
<script>
(function(){{
var el=document.querySelector('.type');if(!el)return;
var lines=el.dataset.lines.split('|');var li=0,ci=0,out='';
function step(){{
if(li>=lines.length)return;
var cur=lines[li];ci++;
el.innerHTML=out+cur.slice(0,ci)+'<span class="typed-cursor">▊</span>';
if(ci>=cur.length){{out+=cur+'<br>';li++;ci=0;setTimeout(step,420)}}else setTimeout(step,22);
}}
step();
}})();
</script>
<div class="grid3">{tcards}</div>
<div class=card style=text-align:center>
<span class="tag ok">NO KYC</span> <span class="tag ok">ALL FREE</span> <span class="tag ok">AGENT-FIRST APIs</span> <span class="tag warn">{n_sms} SMS RENTALS SERVED</span> <span class="tag warn">{n_px} PROXY CHECKS</span></div>
<div class=card style=color:var(--dim)>
<b>For agents</b>: machine catalog at <a href=/llms.txt>/llms.txt</a>, OpenAPI at <a href=/openapi.json>/openapi.json</a>, metered keys at <a href=/keys>/keys</a>.
For humans: click a card. That's it.</div>"""
return page("home", body)
@app.route("/favicon.svg")
def favicon():
svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect width="32" height="32" rx="7" fill="#070a13"/><circle cx="16" cy="16" r="5" fill="#a78bfa"/><circle cx="16" cy="16" r="9.5" fill="none" stroke="#6fd6ff" stroke-width="1.3" stroke-dasharray="4 3"/><circle cx="25.5" cy="8" r="1.6" fill="#ffc94d"/></svg>'
return Response(svg, mimetype="image/svg+xml")
@app.route("/og.png")
def og_img():
from PIL import Image, ImageDraw
im = Image.new("RGB", (1200, 630), (7, 10, 19))
dr = ImageDraw.Draw(im)
for i in range(260):
import random as _r
_r.seed(i)
x, y = _r.randint(0, 1199), _r.randint(0, 629)
dr.ellipse([x, y, x+2, y+2], fill=(200+i%55, 210, 255))
dr.ellipse([480, 190, 720, 430], outline=(167, 139, 250), width=4)
dr.ellipse([455, 165, 745, 455], outline=(111, 214, 255), width=2)
try:
from PIL import ImageFont
f = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf", 84)
f2 = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", 26)
except Exception:
f = f2 = None
dr.text((600, 290), "DARK0RBITS", fill=(255, 201, 77), anchor="mm", font=f)
dr.text((600, 390), "no-KYC network toolbox · everything free · agents welcome", fill=(147, 160, 194), anchor="mm", font=f2)
buf = io.BytesIO(); im.save(buf, "PNG")
return Response(buf.getvalue(), mimetype="image/png")
@app.route("/health")
def health(): return jsonify({"ok": True, "service": "dark0rbits", "version": "3.0"})
# REDIRECT legacy auriga hostname → dark0rbits
@app.before_request
def _dr_legacy_redirect():
host = (request.host or "").lower()
if host.startswith("auriga.") or host == "auriga.thetempleofdoom.com":
return redirect("https://dark0rbits.thetempleofdoom.com" + request.full_path.rstrip("?"), code=301)
return None
# REDACT-REDIRECT
@app.errorhandler(404)
def not_found(e):
if request.path.startswith("/api/"):
return jsonify({"ok": False, "error": "no such endpoint", "path": request.path}), 404
body = """
<h1>404 — <span>LOST SIGNAL</span></h1>
<div class=card>This page drifted off the map. The tools are all still here:</div>
<div class=grid2>
<div class=card><h3><a href=/ip style="color:var(--acc);text-decoration:none">◈ IP INTEL</a></h3></div>
<div class=card><h3><a href=/tools style="color:var(--acc);text-decoration:none">◈ FREE TOOLS</a></h3></div>
<div class=card><h3><a href=/ style="color:var(--acc);text-decoration:none">◈ HOME BASE</a></h3></div>
</div>"""
return page("home", body), 404
# ---------- MAG-LAB (browser magstripe studio, closed-loop only) ----------
_MAG_POLICY = (
"MAG-LAB encodes CLOSED-LOOP cards only: your own gift, loyalty, membership, "
"event or staff cards. Payment-network tracks (bank/debit/credit layouts, "
"13-19 digit Luhn-valid PANs, bank service codes 101/121/201-220, EMV/JCOP "
"dumps) are refused at encode AND decode. This is a hard policy, not a "
"toggle you can switch off.")
def _mag_sentinel(track):
"""True if a track looks like a payment-network card rather than closed-loop."""
import re as _re
t = (track or "").strip()
if not t:
return False
body = t[1:] if t[0] in "%;" else t
pan = _re.sub(r"[^0-9]", "", body.split("^")[0] if "^" in body else (body.split("=")[0] if "=" in body else body))
if pan and 13 <= len(pan) <= 19:
s, alt = 0, False
for ch in reversed(pan):
d = ord(ch) - 48
if alt:
d *= 2
if d > 9:
d -= 9
s += d
alt = not alt
if s % 10 == 0:
return True
m = _re.search(r"\^([0-9]{4})([0-9]{3})", t)
if m and m.group(2)[0] in ("1", "2"):
return True
m = _re.search(r"=([0-9]{4})([0-9]{3})", t)
if m and m.group(2)[0] in ("1", "2"):
return True
return False
_MAGLAB_HTML = r"""<!DOCTYPE html>
<h1>MAG <span>LAB</span></h1>
<p class=sub>Browser magstripe studio — Chrome + Web Serial talks straight to your MSR605/606-class writer. No drivers, no desktop app, any OS. Encode, read, decode, batch-issue <b>closed-loop cards</b>: gift, loyalty, membership, event tickets, staff badges.</p>
<div class="card" style="border-color:var(--bad)">
<b>POLICY</b><br><span style="color:var(--dim)">__POLICY__</span>
</div>
<div class=grid2>
<div class=card>
<b>CONNECT</b>
<div style=margin:.6rem 0><button id=magconn>plug in writer</button> <span id=magstat style=color:var(--dim)>not connected</span></div>
<div style=color:var(--dim);font-size:.8rem>Chrome/Edge/Opera on Windows, macOS, Linux or ChromeOS. Firefox/Safari do not ship Web Serial. Writer must be an MSR605/606 or compatible serial MagStripe encoder.</div>
</div>
<div class=card>
<b>ISSUE A CARD</b>
<form id=magform style=margin:.6rem 0>
<div style=margin:.3rem 0><label>schema</label>
<select id=magschema>
<option value="gift">GIFT — serial + pin (track 2)</option>
<option value="loyal">LOYALTY — member# + tier (track 2)</option>
<option value="event">EVENT — event# + seat (t1+t2)</option>
<option value="staff">STAFF — employee# + dept (t1+t2)</option>
<option value="custom">CUSTOM — raw track editor</option>
</select></div>
<div id=magfields style=margin:.4rem 0></div>
<button>encode → writer</button> <button type=button id=magread>read card → decode</button>
</form>
<div id=magout style="margin-top:.6rem;font-size:.85rem;color:var(--dim)"></div>
</div>
</div>
<div class=card>
<b>BATCH ISSUE</b> <span style=color:var(--dim)>(20c/card — paste CSV lines: label,value)</span>
<textarea id=magcsv rows=4 style="width:100%;margin:.4rem 0" placeholder="GIFT001,1000&#10;GIFT002,2500&#10;STAFF-JANE,EMP1042"></textarea>
<button type=button id=magbatprep>prepare batch</button> <span id=magbatstat style=color:var(--dim)></span>
<div id=magbar style="display:none;margin:.5rem 0;height:14px;border:1px solid var(--line);border-radius:8px;overflow:hidden"><div id=magbarfill style="height:100%;width:0;background:linear-gradient(90deg,var(--acc),var(--acc2));transition:width .3s"></div></div>
<button type=button id=magprint style=margin-top:.5rem>🖨 print card faces</button>
</div>
<div class=card>
<b>TRACK VISUALIZER</b>
<div style=color:var(--dim);font-size:.8rem;margin:.3rem 0>paste any track to see its structure decoded (read-only field map; payment shapes are masked)</div>
<input id=magviz placeholder=";ABC=1234?" style=width:100%>
<pre id=magvizout style="margin:.5rem 0;color:var(--acc2);font-size:.75rem;white-space:pre-wrap"></pre>
</div>
<div class=card><b>API</b> <span style=color:var(--dim)>(agent-first — 30c/encode, 20c/card batch, via key)</span>
__AGENT__
</div>
<script>
var SCHEMAS = {
gift: {fields:[["serial","serial number"],["pin","4-7 digit pin"]], make:function(f){
var pin=(f.pin||"").replace(/[^0-9]/g,""); if(pin.length<4) return {err:"pin needs 4+ digits"};
var ser=(f.serial||"").replace(/[^A-Z0-9]/gi,"").toUpperCase(); if(!ser) return {err:"serial required"};
var t2=";"+ser+"="+pin+"?"; return {t2:t2,label:"GIFT "+ser};}},
loyal: {fields:[["member","member number"],["tier","tier letter (A-F)"]], make:function(f){
var m=(f.member||"").replace(/[^0-9]/g,""); if(!m) return {err:"member # required"};
var tier=(f.tier||"A").toUpperCase().replace(/[^A-F]/g,"")||"A";
var t2=";"+m+"="+tier+Date.now().toString(36).slice(-4)+"?"; return {t2:t2,label:"LOYAL "+m};}},
event: {fields:[["event","event id"],["seat","seat"]], make:function(f){
var e=(f.event||"").replace(/[^A-Z0-9]/gi,"").toUpperCase(), s=(f.seat||"").replace(/[^A-Z0-9]/gi,"").toUpperCase();
if(!e||!s) return {err:"event + seat required"};
var t1="%"+e+"^"+s+"^"+new Date().toISOString().slice(2,10).replace(/-/g,"");
var t2=";"+e+"="+s+"?"; return {t1:t1,t2:t2,label:"EVT "+e};}},
staff: {fields:[["employee","employee #"],["dept","department"]], make:function(f){
var e=(f.employee||"").replace(/[^0-9]/g,""), d=(f.dept||"").replace(/[^A-Z0-9]/gi,"").toUpperCase();
if(!e) return {err:"employee # required"};
var t1="%"+d+"^EMP"+e+"^"+new Date().toISOString().slice(2,10).replace(/-/g,"");
var t2=";"+e+"="+d+"?"; return {t1:t1,t2:t2,label:"STAFF "+e};}},
custom:{fields:[["t1","track 1 (raw)"],["t2","track 2 (raw)"]], make:function(f){
return {t1:f.t1||"",t2:f.t2||"",label:"CUSTOM"};}}
};
var port=null, writer=null;
var BATCH=null, BATIDX=0;
function magLog(m){document.getElementById("magout").textContent=m}
document.getElementById("magschema").addEventListener("change",function(){
var s=SCHEMAS[this.value], h="";
s.fields.forEach(function(f){h+='<input id="mf_'+f[0]+'" placeholder="'+f[1]+'" style="width:100%;margin:.25rem 0">'});
document.getElementById("magfields").innerHTML=h;
});
document.getElementById("magschema").dispatchEvent(new Event("change"));
document.getElementById("magconn").addEventListener("click",async function(){
try{
port=await navigator.serial.requestPort();
await port.open({baudRate:9600});
writer=port.writable.getWriter();
document.getElementById("magstat").textContent="connected ✓";
}catch(e){document.getElementById("magstat").textContent="error: "+e.message}
});
async function encodeCheck(t1,t2){
var r=await fetch("/api/maglab/encode",{method:"POST",headers:{"Content-Type":"application/json","X-Requested-With":"maglab"},body:JSON.stringify({t1:t1||"",t2:t2||""})});
return await r.json();
}
document.getElementById("magform").addEventListener("submit",async function(ev){
ev.preventDefault();
if(!writer){magLog("connect the writer first");return}
if(BATCH && BATIDX<BATCH.length){
var c=BATCH[BATIDX];
magLog("writing "+(BATIDX+1)+"/"+BATCH.length+": "+c.label+" — insert blank card…");
var cmd="\x1b[2S;"+c.t2.slice(1)+"\x04";
await writer.write(new TextEncoder().encode(cmd));
BATIDX++;
document.getElementById("magbarfill").style.width=Math.round(100*BATIDX/BATCH.length)+"%";
magLog("✓ "+BATIDX+"/"+BATCH.length+" written."+(BATIDX<BATCH.length?" next: "+BATCH[BATIDX].label:" BATCH COMPLETE ✓ — hit 🖨 print card faces"));
return;
}
var sc=SCHEMAS[document.getElementById("magschema").value], f={};
sc.fields.forEach(function(x){f[x[0]]=document.getElementById("mf_"+x[0]).value});
var built=sc.make(f);
if(built.err){magLog("✗ "+built.err);return}
var j=await encodeCheck(built.t1,built.t2);
if(!j.ok){magLog("✗ refused: "+(j.error||"unknown"));return}
var cmds=[];
if(built.t1)cmds.push("\x1b[1S;"+built.t1.slice(1)+"\x04");
if(built.t2)cmds.push("\x1b[2S;"+built.t2.slice(1)+"\x04");
for(const c of cmds){await writer.write(new TextEncoder().encode(c))}
magLog("✓ encoded to card: "+built.label+"\n"+[built.t1,built.t2].filter(Boolean).join("\n"));
});
document.getElementById("magbatprep").addEventListener("click",async function(){
var lines=document.getElementById("magcsv").value.split("\n").map(function(x){return x.trim()}).filter(Boolean)
.map(function(x){var p=x.split(",");return {label:(p[0]||"").trim(),value:(p[1]||"").trim()}});
if(!lines.length){document.getElementById("magbatstat").textContent="paste CSV first";return}
var r=await fetch("/api/maglab/batch",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({rows:lines})});
var j=await r.json();
if(!j.ok){document.getElementById("magbatstat").textContent="✗ "+(j.error||"refused");return}
BATCH=j.cards; BATIDX=0;
document.getElementById("magbar").style.display="block"; document.getElementById("magbarfill").style.width="0";
document.getElementById("magbatstat").textContent="ready: "+j.count+" cards · "+(j.cost_cents?("$"+(j.cost_cents/100).toFixed(2)+" charged"):"PASS");
});
document.getElementById("magprint").addEventListener("click",function(){
if(!BATCH){magLog("prepare a batch first");return}
var w=window.open("","_blank");
var cards=BATCH.map(function(c){
var qr="https://api.qrserver.com/v1/create-qr-code/?size=110x110&data="+encodeURIComponent(c.qr);
return '<div class="cf"><div class="lbl">'+c.label+'</div><img src="'+qr+'" width="110" height="110"><div class="pin">PIN '+c.pin+'</div><div class="mk">dark0rbits · mag-lab · scan to activate</div></div>';
}).join("");
w.document.write('<html><head><title>card faces</title><style>body{font-family:-apple-system,sans-serif;background:#fff;color:#111}.cf{display:inline-block;width:3.37in;height:2.125in;border:1px dashed #999;border-radius:12px;margin:8px;padding:10px;text-align:center;vertical-align:top;page-break-inside:avoid}.lbl{font-weight:800;font-size:15px}.pin{font-size:12px;margin-top:4px;color:#333}.mk{font-size:9px;color:#888;margin-top:6px}.nopr{margin-bottom:10px}@media print{.nopr{display:none}}</style></head><body>');
w.document.write('<div class=nopr><button onclick="print()">🖨 print</button> each QR is the card\'s digital twin — balance lookup by label+PIN</div>');
w.document.write(cards+"</body></html>");
w.document.close();
});
document.getElementById("magread").addEventListener("click",async function(){
if(!port){magLog("connect the writer first");return}
magLog("swipe a card, then paste the raw track into the visualizer below to decode");
});
document.getElementById("magviz").addEventListener("input",async function(){
var v=this.value;
if(v.length<4){return}
var r=await fetch("/api/maglab/decode",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({track:v})});
var j=await r.json();
document.getElementById("magvizout").textContent=JSON.stringify(j,null,1);
});
</script>
"""
@app.route("/maglab")
def maglab():
body = _MAGLAB_HTML.replace("__POLICY__", _MAG_POLICY)
body = body.replace("__AGENT__", agent_card(
"POST /api/maglab/encode {t1,t2} · POST /api/maglab/batch {rows:[{label,value}]}",
"curl -X POST " + SITE + "/api/maglab/encode -H 'Authorization: Bearer KEY' -d '{\"t2\":\";GIFT000123=4321?\"}'",
"Closed-loop magstripe studio. Encode validates + LRC-checks (30c), batch issues up to 100 cards with PINs + QR twins (20c/card). Refuses payment-card shapes."))
body += gloss([("ISO 7811", "the magstripe track format standard - track1 79-bit alnum, track2/3 5-bit numeric"),
("LRC", "longitudinal redundancy check - the trailing ? sentinel; wrong LRC = unreadable card"),
("closed-loop", "a card scheme you own end-to-end: your shop issues it, your shop redeems it")])
return page("maglab", body)
@app.route("/api/maglab/encode", methods=["POST"])
def api_maglab_encode():
r = rate_limit("maglab", 20, 60)
if r: return r
uid = key_user() or current_user_id()
if not uid:
return jsonify({"ok": False, "error": "auth required: account session (sign up at /inbox, no KYC) or Authorization: Bearer *** key"}), 401
if not has_pass(uid) and not charge(uid, 30, "maglab encode"):
return jsonify({"ok": False, "error": "insufficient balance", "balance_cents": get_balance(uid), "topup": SITE + "/keys"}), 402
t1 = str(jp("t1") or "").strip()
t2 = str(jp("t2") or "").strip()
if not t1 and not t2:
return jsonify({"ok": False, "error": "at least one track required"}), 400
for t in (t1, t2):
if t and _mag_sentinel(t):
return jsonify({"ok": False, "error": "refused: payment-network card shape detected - " + _MAG_POLICY[:120]}), 403
for name, t in (("t1", t1), ("t2", t2)):
if t and not t.endswith("?"):
return jsonify({"ok": False, "error": name + " missing terminator '?' (LRC sentinel)"}), 400
return jsonify({"ok": True, "ready": True, "t1": t1, "t2": t2})
@app.route("/api/maglab/batch", methods=["POST"])
def api_maglab_batch():
r = rate_limit("maglab_batch", 6, 60)
if r: return r
uid = key_user() or current_user_id()
if not uid:
return jsonify({"ok": False, "error": "auth required: account session (sign up at /inbox, no KYC) or Authorization: Bearer *** key"}), 401
rows = jp("rows")
if not isinstance(rows, list) or not rows:
return jsonify({"ok": False, "error": "rows: array of {label,value} required"}), 400
if len(rows) > 100:
return jsonify({"ok": False, "error": "max 100 cards per batch"}), 400
pas = has_pass(uid)
if not pas and not charge(uid, 20 * len(rows), "maglab batch x%d" % len(rows)):
return jsonify({"ok": False, "error": "insufficient balance", "balance_cents": get_balance(uid), "topup": SITE + "/keys"}), 402
made = []
for i, row in enumerate(rows):
label = str(row.get("label") or ("CARD%03d" % (i + 1)))[:40]
value = str(row.get("value") or "").strip()
if not value:
return jsonify({"ok": False, "error": "row %d: value required" % (i + 1)}), 400
pin = "".join(str(random.randrange(10)) for _ in range(6))
t2 = ";" + re.sub(r"[^A-Z0-9]", "", value.upper()) + "=" + pin + "?"
if _mag_sentinel(t2):
return jsonify({"ok": False, "error": "row %d: refused, payment-card shape" % (i + 1)}), 403
made.append({"label": label, "t2": t2, "pin": pin, "qr": SITE + "/card?card=" + label + ":" + pin})
return jsonify({"ok": True, "count": len(made), "cards": made,
"cost_cents": 0 if pas else 20 * len(rows)})
@app.route("/api/maglab/decode", methods=["POST"])
def api_maglab_decode():
r = rate_limit("maglab_dec", 40, 60)
if r: return r
t = str(jp("track") or "").strip()
if not t:
return jsonify({"ok": False, "error": "track required"}), 400
if _mag_sentinel(t):
return jsonify({"ok": False, "masked": True, "error": "payment-card shape - fields masked by policy"}), 200
t1 = t.startswith("%")
sep = "^" if t1 else "="
body = t[1:] if t[0] in "%;" else t
fields = body.rstrip("?").split(sep)
return jsonify({"ok": True, "track": 1 if t1 else 2,
"format": "ISO7811-A" if t1 else "ISO7811-B",
"fields": [f[:40] for f in fields],
"lrc_sentinel": body.endswith("?"),
"note": "closed-loop decode"})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, threaded=True)