Initial release: cloud browser with auth and one-click deploy on port 32450

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-27 10:57:37 +08:00
commit 65f5caf4d9
20 changed files with 2118 additions and 0 deletions
+93
View File
@@ -0,0 +1,93 @@
import ipaddress
import os
import re
from urllib.parse import urlparse
BLOCKED_HOSTNAMES = {
"localhost",
"localhost.localdomain",
"metadata.google.internal",
}
PRIVATE_NETWORKS = [
ipaddress.ip_network("0.0.0.0/8"),
ipaddress.ip_network("10.0.0.0/8"),
ipaddress.ip_network("127.0.0.0/8"),
ipaddress.ip_network("169.254.0.0/16"),
ipaddress.ip_network("172.16.0.0/12"),
ipaddress.ip_network("192.168.0.0/16"),
ipaddress.ip_network("::1/128"),
ipaddress.ip_network("fc00::/7"),
ipaddress.ip_network("fe80::/10"),
]
ALLOWED_SCHEMES = {"http", "https"}
class SecurityError(ValueError):
pass
def _normalize_url(raw_url: str) -> str:
url = raw_url.strip()
if not url:
raise SecurityError("URL 不能为空")
if not re.match(r"^[a-zA-Z][a-zA-Z0-9+.-]*://", url):
url = f"https://{url}"
parsed = urlparse(url)
if parsed.scheme not in ALLOWED_SCHEMES:
raise SecurityError("仅允许 http/https 协议")
if not parsed.netloc:
raise SecurityError("URL 格式无效")
if parsed.username or parsed.password:
raise SecurityError("URL 中不允许包含用户名或密码")
hostname = parsed.hostname
if not hostname:
raise SecurityError("无法解析主机名")
hostname_lower = hostname.lower()
if hostname_lower in BLOCKED_HOSTNAMES:
raise SecurityError("不允许访问该主机")
if hostname_lower.endswith(".local") or hostname_lower.endswith(".internal"):
raise SecurityError("不允许访问内网域名")
try:
ip = ipaddress.ip_address(hostname)
except ValueError:
return url
for network in PRIVATE_NETWORKS:
if ip in network:
raise SecurityError("不允许访问内网或本地地址")
return url
def validate_url(raw_url: str) -> str:
return _normalize_url(raw_url)
def get_max_sessions() -> int:
return max(1, int(os.getenv("MAX_SESSIONS", "1")))
def get_idle_timeout() -> int:
return max(60, int(os.getenv("SESSION_IDLE_TIMEOUT", "1800")))
def get_viewport_size() -> tuple[int, int]:
width = max(800, int(os.getenv("VIEWPORT_WIDTH", "1280")))
height = max(600, int(os.getenv("VIEWPORT_HEIGHT", "720")))
return width, height
def get_screencast_quality() -> int:
quality = int(os.getenv("SCREENCAST_QUALITY", "80"))
return min(100, max(10, quality))