From 4b074e565a00d0c696e1571bee7a85c6c2350c2a Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 28 Sep 2026 17:42:50 +0800 Subject: [PATCH] =?UTF-8?q?fix(socket):=20CORS=20=E6=94=BE=E8=A1=8C?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E6=A0=B9=E5=9F=9F=E5=90=8E=E7=BC=80=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=EF=BC=8C=E4=BF=AE=E5=A4=8D=E5=AD=90=E5=9F=9F=E6=8F=A1?= =?UTF-8?q?=E6=89=8B=E8=A2=AB=E6=8B=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - engineio 不支持 'https://*.gvsds.com' 通配串,改为可调用对象 AllowOrigin - 按根域(gvsds.com 等)与本地主机放行,实测 gerp/www/api/localhost 通过 --- msync/sio.py | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/msync/sio.py b/msync/sio.py index 6f6d3e9..93580f6 100644 --- a/msync/sio.py +++ b/msync/sio.py @@ -38,22 +38,44 @@ import logging import threading import traceback +import urllib.parse import socketio logger = logging.getLogger(__name__) NS = '/msync' -sio = socketio.Server(async_mode='gevent', cors_allowed_origins=[ - 'https://*.gvsds.com', - 'https://*.gvsds.dev', - 'https://*.yc8z.org', - 'https://*.ycbz.org', - 'https://*.gvsds.org', - 'https://*.gvsds.studio', - 'http://localhost:*', - 'http://127.0.0.1:*', -], logger=True, engineio_logger=True) +#: 允许的前端来源根域(含其全部子域)——浏览器 WebSocket 握手会带 Origin,必须显式放行 +ALLOWED_ORIGIN_ROOTS = ( + 'gvsds.com', 'gvsds.dev', 'gvsds.org', 'gvsds.studio', 'yc8z.org', 'ycbz.org', +) +#: 本地开发来源主机(任意端口) +ALLOWED_ORIGIN_HOSTS = ('localhost', '127.0.0.1') + + +def AllowOrigin(origin, environ=None): + """CORS Origin 校验(供 engineio 以可调用对象方式调用) + + 背景:engineio 的 cors_allowed_origins 只支持「精确字符串 / '*' / 可调用对象」, + 不支持 'https://*.gvsds.com' 这类通配写法——那样写会被当成字面量, + 浏览器端(如 https://gerp.gvsds.com)握手会被判为 "not an accepted origin"。 + 这里按根域后缀统一放行,涵盖 gerp/www/api/viper 等全部子域。 + """ + if not origin: + return False + try: + host = (urllib.parse.urlsplit(origin).hostname or '').lower() + except ValueError: + return False + if not host: + return False + if host in ALLOWED_ORIGIN_HOSTS: + return True + return any(host == root or host.endswith('.' + root) for root in ALLOWED_ORIGIN_ROOTS) + + +sio = socketio.Server(async_mode='gevent', cors_allowed_origins=AllowOrigin, + logger=True, engineio_logger=True) _sid_service_map = {} _service_sid_map = {}