Wallet system (sats ledger + deposit + spend), HydraProxy fulfillment queue, paid IP-quality scorer (85/100 verified)

This commit is contained in:
drjones
2026-09-20 18:51:47 -07:00
parent 16dde93ce2
commit a7d6b98183
8 changed files with 481 additions and 12 deletions

View File

@@ -27,6 +27,31 @@
</form>
</div>
<div class="card" style="margin-top:18px">
<h3>HydraProxy fulfillment queue</h3>
{% if hydra_orders %}
<table style="width:100%;font-size:13px;border-collapse:collapse">
<tr style="color:var(--muted);text-align:left"><th>ID</th><th>User</th><th>Product</th><th>Location</th><th>Status</th></tr>
{% for h in hydra_orders %}
<tr style="border-top:1px solid var(--border)">
<td style="padding:4px">{{ h.id }}</td><td>{{ h.user_id }}</td><td>{{ h.product }}</td>
<td>{{ h.location or '—' }}</td>
<td style="color:{{ 'var(--ok)' if h.status=='active' else 'var(--warn)' }}">{{ h.status }}</td>
</tr>
{% endfor %}
</table>
{% else %}
<p class="muted">No HydraProxy orders yet.</p>
{% endif %}
<h3 style="margin-top:16px">Fulfill an order</h3>
<form method="post" action="/admin/hydraproxy/fulfill" style="display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap">
<div style="flex:1;min-width:140px"><label>Our order ID</label><input type="number" name="order_id" required></div>
<div style="flex:1;min-width:140px"><label>HydraProxy order ID</label><input type="text" name="hydra_order_id" required></div>
<input type="submit" value="Fulfill" style="width:auto;margin:0;padding:11px 20px">
</form>
<p class="muted" style="font-size:12px;margin-bottom:0">Buy the proxy at HydraProxy's dashboard, paste its order ID here — creds auto-pull via proxy-details and land on the customer's dashboard.</p>
</div>
<div class="dash-grid" style="margin-top:18px">
<div class="card">
<h3>Recent orders</h3>

View File

@@ -40,7 +40,7 @@
<a href="/plans">Residential</a>
<a href="/dedicated">Dedicated IPs</a>
<a href="/hydraproxy">HydraProxy</a>
{% if user %}<a href="/dashboard">Dashboard</a><a href="/logout">Logout</a>
{% if user %}<a href="/dashboard">Dashboard</a><a href="/wallet">Wallet</a><a href="/quality">Quality</a><a href="/logout">Logout</a>
{% else %}<a href="/login">Login</a><a class="cta" href="/signup">Get proxies</a>{% endif %}
</div>
</div>

View File

@@ -3,6 +3,7 @@
<h2>Dashboard</h2>
<div class="stats-row">
<div class="card stat"><span class="lbl">Balance</span><span class="val">{{ '%.2f'|format(user.balance_gb) }} GB</span></div>
<div class="card stat"><span class="lbl">Wallet</span><span class="val">{{ balance }} <span style="font-size:14px;color:var(--muted)">sats</span></span></div>
<div class="card stat"><span class="lbl">Used</span><span class="val">{{ '%.3f'|format(used_gb) }} GB</span></div>
<div class="card stat"><span class="lbl">Status</span>
<span class="val" style="color:{{ 'var(--ok)' if user.active else 'var(--danger)' }}">{{ 'ACTIVE' if user.active else 'INACTIVE' }}</span>
@@ -93,6 +94,29 @@
<p class="muted" style="margin-top:18px">No dedicated IPs yet — <a href="/dedicated">order one</a>.</p>
{% endif %}
{% if hydra %}
<div class="card" style="margin-top:18px">
<h3>HydraProxy orders <span class="muted" style="font-size:12px">(broker-fulfilled)</span></h3>
{% for h in hydra %}
<div style="border:1px solid var(--border);border-radius:8px;padding:12px;margin:10px 0">
<div style="display:flex;justify-content:space-between">
<strong style="color:var(--text)">{{ h.product }}{% if h.location %} · {{ h.location }}{% endif %}</strong>
<span style="color:{{ 'var(--ok)' if h.status=='active' else 'var(--warn)' }}">{{ h.status }}</span>
</div>
{% if h.status == 'active' %}
<label style="font-size:11px;color:var(--muted)">Proxy</label>
<div class="copy">
<input type="text" readonly value="{{ h.proxy_user }}:{{ h.proxy_pass }}@{{ h.proxy_host }}:{{ h.proxy_port }}" onclick="this.select()">
<button onclick="copy(this.previousElementSibling)">Copy</button>
</div>
{% elif h.status == 'pending_fulfillment' %}
<p class="muted" style="font-size:12px;margin:6px 0 0">Broker is fulfilling your order — your proxy appears here when ready.</p>
{% endif %}
</div>
{% endfor %}
</div>
{% endif %}
{% if orders %}
<div class="card" style="margin-top:18px">
<h3>Order history</h3>

53
templates/quality.html Normal file
View File

@@ -0,0 +1,53 @@
{% extends "base.html" %}
{% block title %}IP Quality Tester — Clean Proxys{% endblock %}
{% block body %}
<h2>IP Quality <span class="accent">Tester</span></h2>
<p class="sub">Check how clean a proxy is before you trust it. {{ price }} sats (~$0.15) per check, billed to your wallet.</p>
<div class="card">
<h3>Run a check</h3>
<p class="muted" style="font-size:14px">Leave blank to test your own Clean Proxys proxy, or paste any <span class="mono">socks5://</span> or <span class="mono">http://</span> proxy.</p>
<form id="qf" onsubmit="return runQuality(event)">
<label>Proxy (optional)</label>
<input type="text" id="proxy" placeholder="socks5://user:pass@host:1080" style="font-family:var(--mono)">
<input type="submit" value="Run quality check ({{ price }} sats)">
</form>
</div>
<div id="result" style="margin-top:18px"></div>
<script>
async function runQuality(e){
e.preventDefault();
const r = document.getElementById('result');
r.innerHTML = '<div class="card"><p class="muted">Running checks…</p></div>';
const fd = new FormData();
fd.append('proxy', document.getElementById('proxy').value);
let data;
try { data = await (await fetch('/quality/run', {method:'POST', body: fd})).json(); }
catch(err){ r.innerHTML = '<div class="flash warn">Check failed.</div>'; return false; }
if (data.error){
r.innerHTML = '<div class="flash warn">'+data.error+' — <a href="/wallet">deposit</a> first.</div>';
return false;
}
const b = data.breakdown || {};
const checksHtml = (data.checks||[]).map(c =>
'<tr><td>'+(c[1]?'✅':'❌')+'</td><td>'+c[0]+'</td><td class="muted" style="font-size:13px">'+c[2]+'</td></tr>'
).join('');
const scoreColor = data.score >= 70 ? 'var(--neon)' : (data.score >= 40 ? 'var(--warn)' : 'var(--danger)');
const bl = (b.blacklists && b.blacklists.length) ? b.blacklists.join(', ') : 'none';
r.innerHTML =
'<div class="card">'
+ '<div style="display:flex;align-items:center;gap:22px;flex-wrap:wrap">'
+ '<div style="font-size:54px;font-weight:800;font-family:var(--mono);color:'+scoreColor+'">'+data.score+'<span style="font-size:18px;color:var(--muted)">/100</span></div>'
+ '<div><div class="lbl" style="color:var(--muted)">'+ (b.geo||'') + ' · ' + (b.isp||'') + '</div>'
+ '<div class="muted" style="font-size:14px">egress <span class="mono">'+(b.egress_ip||'-')+'</span> · '+ (b.latency_ms||'') +'ms</div>'
+ '<div class="muted" style="font-size:13px">hosting: '+(b.hosting?'yes':'no')+' · proxy-flagged: '+(b.proxy_flagged?'yes':'no')+' · blacklists: '+bl+'</div></div>'
+ '</div>'
+ '<table style="width:100%;margin-top:18px"><tr><th></th><th>Check</th><th>Detail</th></tr>'+checksHtml+'</table>'
+ '<p class="muted" style="font-size:12px;margin-top:12px">charged '+data.charged_sats+' sats</p>'
+ '</div>';
return false;
}
</script>
{% endblock %}

45
templates/wallet.html Normal file
View File

@@ -0,0 +1,45 @@
{% extends "base.html" %}
{% block title %}Wallet — Clean Proxys{% endblock %}
{% block body %}
<h2>Wallet</h2>
<p class="sub">Deposit Bitcoin, spend sats on proxies and tools. No KYC, no email.</p>
<div class="statsbar">
<div class="s"><div class="n grad">{{ balance }}</div><div class="l">Balance (sats)</div></div>
<div class="s"><div class="n grad">{{ (balance / 1e8) | round(8, 'floor') }}</div><div class="l">BTC</div></div>
</div>
<div class="card" style="margin-top:18px">
<h3>Deposit</h3>
<p class="muted" style="font-size:14px">Pick an amount — funds credit instantly on payment confirmation.</p>
<form method="POST" action="/wallet/deposit">
<div class="cta-row" style="justify-content:flex-start;flex-wrap:wrap;gap:10px;margin:14px 0">
{% for amt in [10000, 50000, 100000, 250000] %}
<button type="button" class="btn btn-ghost" onclick="document.getElementById('sats').value={{ amt }}">{{ amt }} sats</button>
{% endfor %}
</div>
<label>Custom amount (sats)</label>
<input type="number" id="sats" name="sats" min="500" placeholder="e.g. 50000" required>
<input type="submit" value="Deposit via Bitcoin">
</form>
</div>
<div class="card" style="margin-top:18px">
<h3>Transactions</h3>
{% if txs %}
<table style="width:100%">
<tr><th>When</th><th>Type</th><th>Amount</th><th>Ref</th></tr>
{% for t in txs %}
<tr>
<td class="mono">{{ t.ts }}</td>
<td>{{ t.type }}</td>
<td class="mono" style="color:{% if t.amount_sats >= 0 %}var(--neon){% else %}var(--danger){% endif %}">{{ '+' if t.amount_sats >= 0 else '' }}{{ t.amount_sats }} sats</td>
<td class="mono" style="font-size:12px;color:var(--muted)">{{ t.ref }}</td>
</tr>
{% endfor %}
</table>
{% else %}
<p class="muted">No transactions yet — make your first deposit.</p>
{% endif %}
</div>
{% endblock %}