From 027f04e58deb4e8a9c616a1c1af5c685ccc75dd7 Mon Sep 17 00:00:00 2001 From: Jage9 Date: Sat, 28 Feb 2026 04:52:44 -0500 Subject: [PATCH] Revert "Enforce websocket origin allowlist with secure-mode config" This reverts commit cf30229b37d376029e32f7340ade50f87dc575cf. --- README.md | 1 - docs/local.md | 1 - docs/protocol-notes.md | 1 - server/README.md | 3 --- server/app/config.py | 1 - server/app/server.py | 35 +----------------------------- server/config.example.toml | 4 ---- server/tests/test_config.py | 14 ------------ server/tests/test_origin_policy.py | 28 ------------------------ 9 files changed, 1 insertion(+), 87 deletions(-) delete mode 100644 server/tests/test_origin_policy.py diff --git a/README.md b/README.md index c765016..8bf5690 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,6 @@ npm run dev Notes: - Server defaults to `config.toml` when present. - Server bind/port defaults are `127.0.0.1:8765` unless changed in config or CLI flags. -- Server websocket origin checks use `network.allowed_origins`; in secure mode (`allow_insecure_ws=false`), configure your real `https://` site origins. - Client dev defaults to Vite local host/port (`localhost:5173`) unless flags override. - Auth requires `CHGRID_AUTH_SECRET` in server environment; `deploy/scripts/install_server.sh` creates `server/.env` with this value automatically if missing. - Saved login/session persistence uses a server-set `HttpOnly` cookie (`chgrid_session_token`). diff --git a/docs/local.md b/docs/local.md index c525315..4a1742a 100644 --- a/docs/local.md +++ b/docs/local.md @@ -20,7 +20,6 @@ Defaults: - Server reads `config.toml` automatically when present. - Server default bind/port is `127.0.0.1:8765`. - Server defaults to TLS-required unless you set `network.allow_insecure_ws=true` or pass `--allow-insecure-ws` for local/dev. -- In local/dev insecure mode (`allow_insecure_ws=true`), websocket Origin allowlist defaults to `http://localhost:5173` and `http://127.0.0.1:5173` when `network.allowed_origins` is empty. - Client dev default is `localhost:5173`. - Auth requires `CHGRID_AUTH_SECRET` in environment. - Saved login uses server-managed `HttpOnly` cookie (`chgrid_session_token`) via `GET /auth/session/set` and `GET /auth/session/clear` (both require `X-Chgrid-Auth-Client: 1`). diff --git a/docs/protocol-notes.md b/docs/protocol-notes.md index 3a08ea2..d39451b 100644 --- a/docs/protocol-notes.md +++ b/docs/protocol-notes.md @@ -111,7 +111,6 @@ This is a behavior guide for packet semantics beyond raw schemas. - Server is authoritative for all action validation and normalization. - Server is authoritative for movement acceptance (bounds + rate/delta checks). -- Server enforces websocket Origin allowlist at handshake (`network.allowed_origins`). - Server persists account state (last nickname + last position) and restores spawn from that state on auth login/resume. - Server also supports websocket handshake cookie resume: - reads `chgrid_session_token` from websocket `Cookie` header diff --git a/server/README.md b/server/README.md index 059c973..c6c9a3c 100644 --- a/server/README.md +++ b/server/README.md @@ -13,13 +13,10 @@ Key options: - `server.bind_ip`, `server.port` - `network.max_message_bytes` - `network.allow_insecure_ws` -- `network.allowed_origins` - `tls.cert_file`, `tls.key_file` If `network.allow_insecure_ws = false`, TLS cert/key are required and server runs as `wss://`. For local/dev without TLS, either set `network.allow_insecure_ws = true` or pass `--allow-insecure-ws`. -When insecure ws is disabled, `network.allowed_origins` must list your deployed `https://` origins. -When insecure ws is enabled and `network.allowed_origins` is empty, localhost dev origins are allowed automatically. ## Run diff --git a/server/app/config.py b/server/app/config.py index b90118b..1e9ceb9 100644 --- a/server/app/config.py +++ b/server/app/config.py @@ -20,7 +20,6 @@ class NetworkConfigSection(BaseModel): max_message_bytes: int = Field(default=2_000_000, gt=0) allow_insecure_ws: bool = False - allowed_origins: list[str] = Field(default_factory=list) class TlsConfigSection(BaseModel): diff --git a/server/app/server.py b/server/app/server.py index e59234f..50ffebe 100644 --- a/server/app/server.py +++ b/server/app/server.py @@ -127,7 +127,6 @@ AUTH_SESSION_COOKIE_CLEAR_PATH = "/auth/session/clear" AUTH_SESSION_COOKIE_CLIENT_HEADER = "X-Chgrid-Auth-Client" AUTH_LOGIN_FAILURE_MESSAGE = "We couldn't log you in. Check your details and try again." AUTH_RESUME_FAILURE_MESSAGE = "We couldn't restore your session. Please log in again." -LOCAL_DEV_ALLOWED_ORIGINS: tuple[str, ...] = ("http://localhost:5173", "http://127.0.0.1:5173") ADMIN_MENU_ACTION_DEFINITIONS: tuple[dict[str, str], ...] = ( {"id": "manage_roles", "label": "Role management", "permission": "role.manage"}, {"id": "change_user_role", "label": "Change user role", "permission": "user.change_role"}, @@ -145,7 +144,6 @@ class SignalingServer: port: int, ssl_cert: str | None, ssl_key: str | None, - allowed_origins: tuple[str, ...] | list[str] | None = None, auth_db_path: Path | None = None, auth_token_hash_secret: str = "dev-secret", password_min_length: int = 8, @@ -163,7 +161,6 @@ class SignalingServer: self.host = host self.port = port self.max_message_size = max_message_size - self.allowed_origins = tuple(allowed_origins or ()) self._ssl_context = self._build_ssl_context(ssl_cert, ssl_key) self.clients: dict[ServerConnection, ClientConnection] = {} resolved_auth_db_path = auth_db_path or Path.cwd() / "runtime" / "chatgrid.db" @@ -1305,7 +1302,6 @@ class SignalingServer: self._handle_client, self.host, self.port, - origins=self.allowed_origins if self.allowed_origins else None, ssl=self._ssl_context, max_size=self.max_message_size, process_request=self._process_http_request, @@ -2864,10 +2860,6 @@ def run() -> None: raise SystemExit( "TLS is required when insecure ws is disabled. Set tls.cert_file/tls.key_file in config.toml." ) - try: - allowed_origins = _resolve_allowed_origins(config.network.allowed_origins, allow_insecure_ws=allow_insecure_ws) - except ValueError as exc: - raise SystemExit(str(exc)) from exc auth_secret = os.getenv("CHGRID_AUTH_SECRET", "").strip() if not auth_secret: @@ -3000,31 +2992,6 @@ def run() -> None: grid_size=config.world.grid_size, state_save_debounce_ms=config.storage.state_save_debounce_ms, state_save_max_delay_ms=config.storage.state_save_max_delay_ms, - allowed_origins=allowed_origins, ) asyncio.run(server.start()) - - -def _resolve_allowed_origins(raw_origins: list[str], *, allow_insecure_ws: bool) -> tuple[str, ...]: - """Resolve websocket Origin allowlist from config and transport mode.""" - - normalized: list[str] = [] - for origin in raw_origins: - candidate = str(origin or "").strip() - if not candidate or candidate in normalized: - continue - normalized.append(candidate) - - if allow_insecure_ws: - if normalized: - return tuple(normalized) - return LOCAL_DEV_ALLOWED_ORIGINS - - if not normalized: - raise ValueError( - "network.allowed_origins must list your https web origin(s) when insecure ws is disabled." - ) - non_https = [origin for origin in normalized if not origin.lower().startswith("https://")] - if non_https: - raise ValueError("network.allowed_origins must use https origins when insecure ws is disabled.") - return tuple(normalized) + ItemClockAnnouncePacket, diff --git a/server/config.example.toml b/server/config.example.toml index 20b2862..64b02ec 100644 --- a/server/config.example.toml +++ b/server/config.example.toml @@ -9,10 +9,6 @@ port = 8765 max_message_bytes = 2000000 # Secure-by-default: TLS is required unless you explicitly set this to true for local/dev. allow_insecure_ws = false -# Allowed websocket request Origin values. -# Production: list your deployed https web origins explicitly. -# Local/dev: when allow_insecure_ws=true and this list is empty, localhost defaults are used. -allowed_origins = ["https://bestmidi.com", "https://www.bestmidi.com"] [tls] # Required when allow_insecure_ws = false. diff --git a/server/tests/test_config.py b/server/tests/test_config.py index 884c7de..a864a14 100644 --- a/server/tests/test_config.py +++ b/server/tests/test_config.py @@ -9,7 +9,6 @@ def test_load_config_defaults_when_path_none() -> None: cfg = load_config(None) assert cfg.server.bind_ip == "127.0.0.1" assert cfg.network.allow_insecure_ws is False - assert cfg.network.allowed_origins == [] assert cfg.storage.state_file == "runtime/items.json" assert cfg.storage.state_save_debounce_ms == 200 assert cfg.storage.state_save_max_delay_ms == 1000 @@ -44,16 +43,3 @@ state_save_max_delay_ms = 900 cfg = load_config(config_path) assert cfg.storage.state_save_debounce_ms == 150 assert cfg.storage.state_save_max_delay_ms == 900 - - -def test_load_config_reads_allowed_origins(tmp_path: Path) -> None: - config_path = tmp_path / "config.toml" - config_path.write_text( - """ -[network] -allow_insecure_ws = true -allowed_origins = ["https://bestmidi.com", "https://www.bestmidi.com"] -""".strip() - ) - cfg = load_config(config_path) - assert cfg.network.allowed_origins == ["https://bestmidi.com", "https://www.bestmidi.com"] diff --git a/server/tests/test_origin_policy.py b/server/tests/test_origin_policy.py deleted file mode 100644 index 67377cc..0000000 --- a/server/tests/test_origin_policy.py +++ /dev/null @@ -1,28 +0,0 @@ -from __future__ import annotations - -import pytest - -from app.server import LOCAL_DEV_ALLOWED_ORIGINS, _resolve_allowed_origins - - -def test_resolve_allowed_origins_defaults_localhost_for_insecure_mode() -> None: - origins = _resolve_allowed_origins([], allow_insecure_ws=True) - assert origins == LOCAL_DEV_ALLOWED_ORIGINS - - -def test_resolve_allowed_origins_requires_values_for_secure_mode() -> None: - with pytest.raises(ValueError): - _resolve_allowed_origins([], allow_insecure_ws=False) - - -def test_resolve_allowed_origins_requires_https_in_secure_mode() -> None: - with pytest.raises(ValueError): - _resolve_allowed_origins(["http://localhost:5173"], allow_insecure_ws=False) - - -def test_resolve_allowed_origins_normalizes_and_deduplicates() -> None: - origins = _resolve_allowed_origins( - [" https://bestmidi.com ", "https://bestmidi.com", "https://www.bestmidi.com"], - allow_insecure_ws=False, - ) - assert origins == ("https://bestmidi.com", "https://www.bestmidi.com")