Add agent one-call purchase API: POST /api/v1/proxy + GET /api/v1/order/<id>
This commit is contained in:
70
app.py
70
app.py
@@ -385,6 +385,8 @@ Sells residential SOCKS5 and HTTP CONNECT proxies with global geo-targeting
|
|||||||
## API
|
## API
|
||||||
- GET /api/v1/info -> service info (JSON)
|
- GET /api/v1/info -> service info (JSON)
|
||||||
- GET /api/v1/plans -> residential GB plans (JSON)
|
- GET /api/v1/plans -> residential GB plans (JSON)
|
||||||
|
- POST /api/v1/proxy -> one-call purchase (JSON: plan_id, country, city, username, password) -> creds + BTCPay checkout URL
|
||||||
|
- GET /api/v1/order/<id> -> payment status (pending/paid)
|
||||||
- GET /api/v1/dedicated/locations?product=9 -> ISP dedicated locations (JSON)
|
- GET /api/v1/dedicated/locations?product=9 -> ISP dedicated locations (JSON)
|
||||||
- GET /api/v1/dedicated/locations?product=3 -> datacenter dedicated locations (JSON)
|
- GET /api/v1/dedicated/locations?product=3 -> datacenter dedicated locations (JSON)
|
||||||
- Human signup: {SITE_HOST}/signup
|
- Human signup: {SITE_HOST}/signup
|
||||||
@@ -433,6 +435,74 @@ def api_plans():
|
|||||||
return jsonify({"plans": ps})
|
return jsonify({"plans": ps})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/api/v1/proxy", methods=["POST"])
|
||||||
|
def api_proxy():
|
||||||
|
"""Agent-facing one-call purchase: create account + invoice, return creds + checkout URL."""
|
||||||
|
data = request.get_json(silent=True) or {}
|
||||||
|
username = (data.get("username") or "").strip()
|
||||||
|
password = data.get("password") or ""
|
||||||
|
plan_id = data.get("plan_id") or data.get("plan")
|
||||||
|
country = (data.get("country") or "").strip().upper()
|
||||||
|
city = (data.get("city") or "").strip()
|
||||||
|
|
||||||
|
d = db.get_db()
|
||||||
|
plan = d.execute("SELECT * FROM plans WHERE id=?", (plan_id,)).fetchone() if plan_id else None
|
||||||
|
if not plan:
|
||||||
|
plan = d.execute("SELECT * FROM plans WHERE active=1 ORDER BY gb LIMIT 1").fetchone()
|
||||||
|
if not plan:
|
||||||
|
d.close()
|
||||||
|
return jsonify({"error": "no plans"}), 500
|
||||||
|
|
||||||
|
user_row = d.execute("SELECT * FROM users WHERE username=?", (username,)).fetchone() if username else None
|
||||||
|
if user_row is None:
|
||||||
|
username = username or ("u" + db.random_token(10))
|
||||||
|
password = password or db.random_token(16)
|
||||||
|
proxy_pass = db.random_token(18)
|
||||||
|
d.execute("INSERT INTO users (username,password_hash,proxy_password_hash,proxy_password_plain,"
|
||||||
|
"active,country,city,sticky,balance_gb,created_at) VALUES (?,?,?,?,0,?,?,1,0,?)",
|
||||||
|
(username, db.scrypt_hash(password), db.scrypt_hash(proxy_pass), proxy_pass,
|
||||||
|
country or "US", city, int(time.time())))
|
||||||
|
d.commit()
|
||||||
|
uid = d.execute("SELECT id FROM users WHERE username=?", (username,)).fetchone()["id"]
|
||||||
|
else:
|
||||||
|
uid = user_row["id"]
|
||||||
|
proxy_pass = user_row["proxy_password_plain"]
|
||||||
|
if country:
|
||||||
|
d.execute("UPDATE users SET country=?, city=? WHERE id=?", (country, city or "", uid))
|
||||||
|
d.commit()
|
||||||
|
|
||||||
|
order_id = db.random_token(12)
|
||||||
|
d.execute("INSERT INTO orders (user_id,plan_id,invoice_id,amount_sats,status,created_at) "
|
||||||
|
"VALUES (?,?,?,?,'pending',?)",
|
||||||
|
(uid, plan["id"], order_id, plan["price_sats"], int(time.time())))
|
||||||
|
d.commit()
|
||||||
|
d.close()
|
||||||
|
inv = create_invoice(plan["price_sats"], order_id)
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"username": username,
|
||||||
|
"password": password,
|
||||||
|
"proxy_password": proxy_pass,
|
||||||
|
"socks5": f"socks5://{username}:{proxy_pass}@{PROXY['host']}:{PROXY['socks_port']}",
|
||||||
|
"http": f"http://{username}:{proxy_pass}@{PROXY['host']}:{PROXY['http_port']}",
|
||||||
|
"country": country or "US",
|
||||||
|
"city": city,
|
||||||
|
"plan": {"id": plan["id"], "name": plan["name"], "gb": plan["gb"], "price_sats": plan["price_sats"]},
|
||||||
|
"invoice": {"id": order_id, "checkout_url": inv["checkoutLink"], "amount_sats": plan["price_sats"]},
|
||||||
|
"status_url": f"https://{SITE_HOST}/api/v1/order/{order_id}",
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/api/v1/order/<order_id>")
|
||||||
|
def api_order_status(order_id):
|
||||||
|
d = db.get_db()
|
||||||
|
o = d.execute("SELECT * FROM orders WHERE invoice_id=?", (order_id,)).fetchone()
|
||||||
|
d.close()
|
||||||
|
if not o:
|
||||||
|
return jsonify({"error": "not found"}), 404
|
||||||
|
return jsonify({"order_id": order_id, "status": o["status"], "amount_sats": o["amount_sats"]})
|
||||||
|
|
||||||
|
|
||||||
@app.route("/sitemap.xml")
|
@app.route("/sitemap.xml")
|
||||||
def sitemap():
|
def sitemap():
|
||||||
urls = [f"https://{SITE_HOST}/{p}" for p in ["", "plans", "signup", "login", "llms.txt"]]
|
urls = [f"https://{SITE_HOST}/{p}" for p in ["", "plans", "signup", "login", "llms.txt"]]
|
||||||
|
|||||||
27
router-forward.sh
Normal file
27
router-forward.sh
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Add Pleiades proxy port-forwards (CT777 .178): SOCKS5 :1080 + HTTP :8080.
|
||||||
|
# Appends to the JFFS firewall-start hook (reboot-persistent) + applies now.
|
||||||
|
|
||||||
|
cp /jffs/scripts/firewall-start /jffs/scripts/firewall-start.bak-pleiades-$(date +%s)
|
||||||
|
|
||||||
|
cat >> /jffs/scripts/firewall-start << 'EOF'
|
||||||
|
# Pleiades proxy store (CT777 .178): SOCKS5 :1080 + HTTP :8080 inbound
|
||||||
|
iptables -t nat -D VSERVER -p tcp --dport 1080 -j DNAT --to-destination 10.30.20.178:1080 2>/dev/null
|
||||||
|
iptables -t nat -A VSERVER -p tcp --dport 1080 -j DNAT --to-destination 10.30.20.178:1080
|
||||||
|
iptables -I FORWARD 1 -p tcp -d 10.30.20.178 --dport 1080 -j ACCEPT
|
||||||
|
iptables -t nat -D VSERVER -p tcp --dport 8080 -j DNAT --to-destination 10.30.20.178:8080 2>/dev/null
|
||||||
|
iptables -t nat -A VSERVER -p tcp --dport 8080 -j DNAT --to-destination 10.30.20.178:8080
|
||||||
|
iptables -I FORWARD 1 -p tcp -d 10.30.20.178 --dport 8080 -j ACCEPT
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# apply immediately
|
||||||
|
for P in "1080:1080" "8080:8080"; do
|
||||||
|
EXT=${P%%:*}; DPT=${P##*:}
|
||||||
|
iptables -t nat -A VSERVER -p tcp --dport $EXT -j DNAT --to-destination 10.30.20.178:$DPT
|
||||||
|
iptables -I FORWARD 1 -p tcp -d 10.30.20.178 --dport $DPT -j ACCEPT
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "=== VSERVER (pleiades) ==="
|
||||||
|
iptables -t nat -S VSERVER | grep -E "dport 1080|dport 8080"
|
||||||
|
echo "=== FORWARD (pleiades) ==="
|
||||||
|
iptables -S FORWARD | grep "10.30.20.178"
|
||||||
Reference in New Issue
Block a user