v2.0.7: security hardening, config sync, cleanup

- 6 new security audits (technical_debt_8 through 12)
- SNI rotation pool per session (5 sites)
- vless_ip pinned to hardcoded server IP
- TLS cert validation restored (domain-based)
- Swarm monitoring removed from public domain
- Xray routing blocks abuse ports (SMTP, NetBIOS, SSDP)
- flow: xtls-rprx-vision in add_vless_client
- TimerBox shows Connecting/Syncing spinner
- Outbound port blocking in Xray config
- Cleaned up comments, synced config templates
This commit is contained in:
esefxdz committed 2026-07-29 23:43:47 +03:00
1 parent f01a610182
commit f8abda9323
7 files changed
+109 -86

No files matched your search

+29 -23
View File
@@ -21,6 +21,7 @@ import subprocess
import threading
import json
import os
import random
import tempfile
import requests
import shlex
@@ -35,13 +36,11 @@ from cryptography.hazmat.primitives.serialization import load_pem_public_key
app = Flask(__name__)
# ── Log buffer for TUI / remote monitoring ────────────────────────────────
# Captures every print() into a ring buffer so the TUI dashboard can pull
# recent log lines without SSH. /api/log returns the last 200 lines.
# ── Stdout passthrough ──────────────────────────────────────────────────
# Ensures print() works inside gunicorn workers by forwarding to the real
# stdout. (The log buffer + /api/log endpoint were removed — monitoring
# now lives on a separate internal-only server.)
import sys
from collections import deque
_log_buffer = deque(maxlen=200)
class _TeeStdout:
def __init__(self, original):
@@ -49,10 +48,6 @@ class _TeeStdout:
def write(self, s):
self.original.write(s)
self.original.flush()
for line in s.splitlines():
stripped = line.rstrip()
if stripped:
_log_buffer.append(stripped)
def flush(self):
self.original.flush()
@@ -104,8 +99,13 @@ MAIN_AD_MINUTES = 60
# Support Ad Rewards (top-up)
SUPPORT_AD_MINUTES = 30
# ── Reality — returned to app in /session/status ────────────────────────
REALITY_SNI = "www.microsoft.com"
REALITY_SNI_POOL = [
"www.microsoft.com",
"www.cloudflare.com",
"www.google.com",
"www.amazon.com",
"www.yandex.ru",
]
VLESS_SERVER_IP = "204.168.246.88"
VLESS_REALITY_PORT = 8443
REALITY_PUBLIC_KEY = "GENERATE_ME_WITH_xray_x25519"
@@ -235,16 +235,17 @@ def health():
return jsonify({"ok": True})
@app.route('/api/swarm')
def swarm_status():
"""Returns sorted drone list — consumed by TUI dashboards and CLI tools."""
return jsonify(get_swarm_status())
@app.route('/api/log')
def log_tail():
"""Returns recent log lines — consumed by TUI dashboards."""
return jsonify(list(_log_buffer))
# ── Swarm / log endpoints REMOVED (2026-07-29) ──────────────────────────
# These exposed internal monitoring on the same domain as the public API.
# Moved to a separate internal-only server. See backups/swarm_watch.py.
#
# @app.route('/api/swarm')
# def swarm_status():
# return jsonify(get_swarm_status())
#
# @app.route('/api/log')
# def log_tail():
# return jsonify(list(_log_buffer))
@app.route('/api/session/status', methods=['GET'])
@@ -278,7 +279,7 @@ def session_status():
"vless_port": VLESS_REALITY_PORT + 1 if session.get("throttled") else VLESS_REALITY_PORT,
"reality_pbk": REALITY_PUBLIC_KEY,
"reality_sid": REALITY_SHORT_ID,
"reality_sni": REALITY_SNI,
"reality_sni": session.get("_sni", REALITY_SNI_POOL[0]),
"reality_fp": REALITY_FINGERPRINT,
"expires_in_seconds": int(remaining_secs),
"used_bytes": used_bytes,
@@ -333,6 +334,10 @@ def _start_or_extend_session(device_id, nonce=None):
existing = active_sessions.get(device_id)
vless_uuid = str(uuid.uuid4())
# Pick a random SNI for this session so every user looks
# like they're connecting to a different real website.
sni = random.choice(REALITY_SNI_POOL)
active_sessions[device_id] = {
"vless_uuid": vless_uuid,
"expires_at": now + (MAIN_AD_MINUTES * 60),
@@ -340,6 +345,7 @@ def _start_or_extend_session(device_id, nonce=None):
"throttled": False,
"_created_at": now,
"_prev_bytes": 0,
"_sni": sni,
}
if existing: