Pleiades proxy store: SOCKS5 gateway + Flask storefront + BTCPay checkout
This commit is contained in:
312
app.py
Normal file
312
app.py
Normal file
@@ -0,0 +1,312 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Pleiades storefront — Flask app: signup/login, plans, BTCPay checkout, dashboard."""
|
||||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import time
|
||||
from functools import wraps
|
||||
|
||||
import requests
|
||||
from flask import (Flask, abort, flash, jsonify, redirect, render_template,
|
||||
request, session, url_for)
|
||||
|
||||
import db
|
||||
|
||||
CFG = db.CFG
|
||||
app = Flask(__name__)
|
||||
app.secret_key = CFG["secret_key"]
|
||||
|
||||
BTCPAY = CFG["btcpay"]
|
||||
PROXY = CFG["proxy_public"]
|
||||
SITE_HOST = CFG.get("site_host", "clean-proxys.thetempleofdoom.com")
|
||||
|
||||
PRICE_USD_PER_GB = CFG.get("price_usd_per_gb", 8.0) # display only
|
||||
|
||||
|
||||
# ---------- auth ----------
|
||||
def current_user():
|
||||
uid = session.get("uid")
|
||||
if not uid:
|
||||
return None
|
||||
d = db.get_db()
|
||||
row = d.execute("SELECT * FROM users WHERE id=?", (uid,)).fetchone()
|
||||
d.close()
|
||||
return dict(row) if row else None
|
||||
|
||||
|
||||
def login_required(f):
|
||||
@wraps(f)
|
||||
def wrapper(*a, **kw):
|
||||
if not current_user():
|
||||
flash("Log in first.", "warn")
|
||||
return redirect(url_for("login"))
|
||||
return f(*a, **kw)
|
||||
return wrapper
|
||||
|
||||
|
||||
# ---------- BTCPay ----------
|
||||
def create_invoice(amount_sats, order_id):
|
||||
data = {
|
||||
"amount": amount_sats / 1e8,
|
||||
"currency": "BTC",
|
||||
"checkout": {
|
||||
"redirectURL": f"https://{SITE_HOST}/order/{order_id}",
|
||||
"redirectAutomatically": True,
|
||||
},
|
||||
"metadata": {"orderId": order_id},
|
||||
}
|
||||
r = requests.post(
|
||||
f"{BTCPAY['url']}/api/v1/stores/{BTCPAY['store_id']}/invoices",
|
||||
headers={"Authorization": f"token {BTCPAY['api_key']}"},
|
||||
json=data, timeout=20, verify=False,
|
||||
)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
||||
|
||||
def verify_webhook():
|
||||
sig = request.headers.get("BTCPay-Sig", "")
|
||||
if not sig.startswith("sha256="):
|
||||
return False
|
||||
expected = sig.split("=", 1)[1]
|
||||
calc = hmac.new(BTCPAY["webhook_secret"].encode(), request.get_data(),
|
||||
hashlib.sha256).hexdigest()
|
||||
return hmac.compare_digest(calc, expected)
|
||||
|
||||
|
||||
# ---------- routes ----------
|
||||
@app.route("/")
|
||||
def index():
|
||||
return render_template("index.html", user=current_user())
|
||||
|
||||
|
||||
@app.route("/signup", methods=["GET", "POST"])
|
||||
def signup():
|
||||
if request.method == "POST":
|
||||
username = request.form.get("username", "").strip()
|
||||
password = request.form.get("password", "")
|
||||
if len(username) < 3 or len(password) < 6:
|
||||
flash("Username 3+ chars, password 6+ chars.", "warn")
|
||||
return render_template("signup.html")
|
||||
d = db.get_db()
|
||||
exists = d.execute("SELECT 1 FROM users WHERE username=?", (username,)).fetchone()
|
||||
if exists:
|
||||
d.close()
|
||||
flash("Username taken.", "warn")
|
||||
return render_template("signup.html")
|
||||
proxy_pass = db.random_token(18)
|
||||
d.execute(
|
||||
"INSERT INTO users (username,password_hash,proxy_password_hash,proxy_password_plain,"
|
||||
"active,region,country,city,sticky,balance_gb,created_at) VALUES (?,?,?,?,0,'','US','',1,0,?)",
|
||||
(username, db.scrypt_hash(password), db.scrypt_hash(proxy_pass), proxy_pass,
|
||||
int(time.time())))
|
||||
d.commit()
|
||||
uid = d.execute("SELECT id FROM users WHERE username=?", (username,)).fetchone()["id"]
|
||||
d.close()
|
||||
session["uid"] = uid
|
||||
flash(f"Account created. Proxy password: {proxy_pass} (save it)", "ok")
|
||||
return redirect(url_for("dashboard"))
|
||||
return render_template("signup.html")
|
||||
|
||||
|
||||
@app.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
if request.method == "POST":
|
||||
username = request.form.get("username", "").strip()
|
||||
password = request.form.get("password", "")
|
||||
d = db.get_db()
|
||||
row = d.execute("SELECT * FROM users WHERE username=?", (username,)).fetchone()
|
||||
d.close()
|
||||
if row and db.verify_hash(password, row["password_hash"]):
|
||||
session["uid"] = row["id"]
|
||||
return redirect(url_for("dashboard"))
|
||||
flash("Bad credentials.", "warn")
|
||||
return render_template("login.html")
|
||||
|
||||
|
||||
@app.route("/logout")
|
||||
def logout():
|
||||
session.clear()
|
||||
return redirect(url_for("index"))
|
||||
|
||||
|
||||
@app.route("/plans")
|
||||
def plans():
|
||||
d = db.get_db()
|
||||
ps = [dict(r) for r in d.execute("SELECT * FROM plans WHERE active=1 ORDER BY gb")]
|
||||
d.close()
|
||||
return render_template("plans.html", plans=ps, user=current_user())
|
||||
|
||||
|
||||
@app.route("/buy/<int:plan_id>", methods=["POST"])
|
||||
@login_required
|
||||
def buy(plan_id):
|
||||
d = db.get_db()
|
||||
plan = d.execute("SELECT * FROM plans WHERE id=?", (plan_id,)).fetchone()
|
||||
d.close()
|
||||
if not plan:
|
||||
abort(404)
|
||||
order_id = db.random_token(12)
|
||||
d = db.get_db()
|
||||
d.execute("INSERT INTO orders (user_id,plan_id,invoice_id,amount_sats,status,created_at) "
|
||||
"VALUES (?,?,?,?,'pending',?)",
|
||||
(current_user()["id"], plan_id, order_id, plan["price_sats"], int(time.time())))
|
||||
d.commit()
|
||||
d.close()
|
||||
inv = create_invoice(plan["price_sats"], order_id)
|
||||
return redirect(inv["checkoutLink"])
|
||||
|
||||
|
||||
@app.route("/order/<order_id>")
|
||||
@login_required
|
||||
def order(order_id):
|
||||
d = db.get_db()
|
||||
o = d.execute("SELECT * FROM orders WHERE invoice_id=? AND user_id=?",
|
||||
(order_id, current_user()["id"])).fetchone()
|
||||
d.close()
|
||||
if not o:
|
||||
abort(404)
|
||||
return render_template("order.html", order=dict(o), user=current_user())
|
||||
|
||||
|
||||
@app.route("/webhook/btcpay", methods=["POST"])
|
||||
def webhook_btcpay():
|
||||
if not verify_webhook():
|
||||
abort(401)
|
||||
payload = request.get_json(force=True)
|
||||
if payload.get("type") not in ("InvoiceSettled", "InvoiceProcessing"):
|
||||
return "ok"
|
||||
order_id = (payload.get("metadata") or {}).get("orderId")
|
||||
if not order_id:
|
||||
return "ok"
|
||||
d = db.get_db()
|
||||
o = d.execute("SELECT * FROM orders WHERE invoice_id=?", (order_id,)).fetchone()
|
||||
if o and o["status"] != "paid":
|
||||
plan = d.execute("SELECT * FROM plans WHERE id=?", (o["plan_id"],)).fetchone()
|
||||
d.execute("UPDATE orders SET status='paid', paid_at=? WHERE id=?", (int(time.time()), o["id"]))
|
||||
d.execute("UPDATE users SET balance_gb=balance_gb+?, active=1 WHERE id=?",
|
||||
(plan["gb"], o["user_id"]))
|
||||
d.commit()
|
||||
d.close()
|
||||
return "ok"
|
||||
|
||||
|
||||
@app.route("/dashboard")
|
||||
@login_required
|
||||
def dashboard():
|
||||
u = current_user()
|
||||
d = db.get_db()
|
||||
used = d.execute("SELECT COALESCE(SUM(bytes),0) s FROM usage_log WHERE user_id=?", (u["id"],)).fetchone()["s"]
|
||||
d.close()
|
||||
socks = f"socks5://{u['username']}:{u['proxy_password_plain']}@{PROXY['host']}:{PROXY['socks_port']}"
|
||||
http = f"http://{u['username']}:{u['proxy_password_plain']}@{PROXY['host']}:{PROXY['http_port']}"
|
||||
return render_template("dashboard.html", user=u, used_gb=used / 1e9,
|
||||
socks=socks, http=http)
|
||||
|
||||
|
||||
@app.route("/dashboard/location", methods=["POST"])
|
||||
@login_required
|
||||
def set_location():
|
||||
u = current_user()
|
||||
country = request.form.get("country", "").strip().upper()
|
||||
city = request.form.get("city", "").strip()
|
||||
region = request.form.get("region", "").strip()
|
||||
sticky = 1 if request.form.get("sticky") else 0
|
||||
d = db.get_db()
|
||||
d.execute("UPDATE users SET country=?, city=?, region=?, sticky=? WHERE id=?",
|
||||
(country, city, region, sticky, u["id"]))
|
||||
d.commit()
|
||||
d.close()
|
||||
flash("Location updated.", "ok")
|
||||
return redirect(url_for("dashboard"))
|
||||
|
||||
|
||||
@app.route("/dashboard/rotate", methods=["POST"])
|
||||
@login_required
|
||||
def rotate():
|
||||
u = current_user()
|
||||
newpass = db.random_token(18)
|
||||
d = db.get_db()
|
||||
d.execute("UPDATE users SET proxy_password_hash=?, proxy_password_plain=? WHERE id=?",
|
||||
(db.scrypt_hash(newpass), newpass, u["id"]))
|
||||
d.commit()
|
||||
d.close()
|
||||
flash(f"New proxy password: {newpass}", "ok")
|
||||
return redirect(url_for("dashboard"))
|
||||
|
||||
|
||||
# ---------- agent discovery ----------
|
||||
@app.route("/llms.txt")
|
||||
def llms_txt():
|
||||
body = f"""# {SITE_HOST}
|
||||
|
||||
> Clean residential SOCKS5/HTTP proxies. No KYC. Crypto checkout. Encrypted backend.
|
||||
|
||||
## What this service does
|
||||
Sells residential SOCKS5 and HTTP CONNECT proxies with global geo-targeting
|
||||
(country/city/region). Buy with Bitcoin (no KYC). Instant activation.
|
||||
|
||||
## Key facts
|
||||
- Protocol: SOCKS5 (port {PROXY['socks_port']}), HTTP CONNECT (port {PROXY['http_port']})
|
||||
- Auth: per-user username + password
|
||||
- Geo: country, city, region targeting
|
||||
- Sessions: sticky or rotating
|
||||
- Billing: pay-per-GB, Bitcoin (BTCPay)
|
||||
- Signup: username + password only (no email, no KYC)
|
||||
|
||||
## API
|
||||
- GET /api/v1/info -> service info (JSON)
|
||||
- GET /api/v1/plans -> available plans (JSON)
|
||||
- Human signup: {SITE_HOST}/signup
|
||||
|
||||
## Connect (after signup + top-up)
|
||||
socks5://USER:PASS@{PROXY['host']}:{PROXY['socks_port']}
|
||||
"""
|
||||
return app.response_class(body, mimetype="text/plain")
|
||||
|
||||
|
||||
@app.route("/robots.txt")
|
||||
def robots():
|
||||
return app.response_class(
|
||||
"User-agent: *\nAllow: /\nSitemap: https://%s/sitemap.xml\n" % SITE_HOST,
|
||||
mimetype="text/plain")
|
||||
|
||||
|
||||
@app.route("/api/v1/info")
|
||||
def api_info():
|
||||
return jsonify({
|
||||
"name": "Clean Proxys",
|
||||
"host": SITE_HOST,
|
||||
"protocols": ["socks5", "http"],
|
||||
"socks_port": PROXY["socks_port"],
|
||||
"http_port": PROXY["http_port"],
|
||||
"auth": "username:password",
|
||||
"billing": "bitcoin (btcpay), pay-per-GB",
|
||||
"kyc": False,
|
||||
"signup": f"https://{SITE_HOST}/signup",
|
||||
"docs": f"https://{SITE_HOST}/llms.txt",
|
||||
})
|
||||
|
||||
|
||||
@app.route("/api/v1/plans")
|
||||
def api_plans():
|
||||
d = db.get_db()
|
||||
ps = [dict(r) for r in d.execute("SELECT id,name,gb,price_sats FROM plans WHERE active=1 ORDER BY gb")]
|
||||
d.close()
|
||||
return jsonify({"plans": ps})
|
||||
|
||||
|
||||
@app.route("/sitemap.xml")
|
||||
def sitemap():
|
||||
urls = [f"https://{SITE_HOST}/{p}" for p in ["", "plans", "signup", "login", "llms.txt"]]
|
||||
body = '<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n'
|
||||
for u in urls:
|
||||
body += f" <url><loc>{u}</loc></url>\n"
|
||||
body += "</urlset>"
|
||||
return app.response_class(body, mimetype="application/xml")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
db.init_db()
|
||||
app.run(host="127.0.0.1", port=5000, debug=False)
|
||||
Reference in New Issue
Block a user