SMS abuse guard: balance floor, concurrency cap, hourly/daily caps, auto-expire

This commit is contained in:
2026-09-30 06:03:48 -07:00
parent ae219fad90
commit c7f40bea76

36
app.py
View File

@@ -278,6 +278,28 @@ def api_card():
"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 [])})
# ---------- SMS ABUSE GUARD ----------
def sms_guard():
"""Return None if allowed, else a JSON-able reason string."""
con = db(); now = int(time.time())
ip = request.headers.get("X-Real-IP") or request.remote_addr or "?"
# balance: refuse if house SMSPool balance below $5
st, b = sms_api("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"
# per-IP: max 1 active rental, 3/hour, 8/day
row = con.execute("SELECT COUNT(*) c FROM sms_rentals WHERE status='active' AND purchase_id IN (SELECT purchase_id FROM sms_rentals WHERE created > ?)", (now-86400*7,)).fetchone()
# active count overall (any IP) cap 3 concurrent
act = con.execute("SELECT COUNT(*) c FROM sms_rentals WHERE status='active' AND expires > ?", (now,)).fetchone()["c"]
if act >= 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 >= 6: return "hourly rental cap reached"
d = con.execute("SELECT COUNT(*) c FROM sms_rentals WHERE created > ?", (now-86400,)).fetchone()["c"]
if d >= 15: return "daily rental cap reached"
return None
# ---------- 3. SMS RENTALS ----------
SMSP = "https://api.smspool.net"
SERVICES = [("google","Google"),("discord","Discord"),("telegram","Telegram"),("whatsapp","WhatsApp"),("other","Other/Any")]
@@ -296,6 +318,10 @@ def sms():
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:
svc, ctry = request.form["service"], request.form["country"]
st, b = sms_api("purchase/sms", service=svc, country=ctry)
d = jf(b) or {}
@@ -360,12 +386,14 @@ if(d.sms||d.code){{toast('CODE: '+(d.sms||d.code));document.title='✉ CODE '+(d
@app.route("/api/sms/rent", methods=["POST"])
def api_sms_rent():
st, b = sms_api("purchase/sms", service=request.form["service"], country=request.form["country"])
guard = sms_guard()
if guard: return jsonify({"success": 0, "message": guard, "paused": True})
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(phone,service,country,purchase_id,cost,status,created,expires) VALUES(?,?,?,?,?,?,?,?)",
(d.get("number"), request.form["service"], request.form["country"], str(d.get("purchase_id")), d.get("cost",0), "active", now, now+1800))
(d.get("number"), param("service"), param("country"), str(d.get("purchase_id")), d.get("cost",0), "active", now, now+1800))
con.commit()
return jsonify(d)
@@ -381,7 +409,9 @@ def api_sms_cancel():
@app.route("/api/sms/history")
def api_sms_history():
con = db()
con = db(); now = int(time.time())
con.execute("UPDATE sms_rentals SET status='expired' WHERE status='active' AND expires < ?", (now,))
con.commit()
rows = con.execute("SELECT * FROM sms_rentals ORDER BY id DESC LIMIT 50").fetchall()
return jsonify([dict(r) for r in rows])