Fix session resume and auth helper fallbacks

This commit is contained in:
Jage9
2026-03-08 23:12:02 -04:00
parent b229e20ae2
commit d111146554
5 changed files with 54 additions and 4 deletions

View File

@@ -1,5 +1,11 @@
{
"sections": [
{
"date": "March 8, 2026",
"items": [
"Added a command palette with Shift+K, Shift+F10, or the Applications key to show all available commands."
]
},
{
"date": "February 28, 2026",
"items": [

View File

@@ -1,6 +1,6 @@
// Maintainer-controlled web client version metadata.
window.CHGRID_RELEASE_VERSION = "0.1.0";
window.CHGRID_BUILD_REVISION = "R344";
window.CHGRID_BUILD_REVISION = "R345";
window.CHGRID_WEB_VERSION = `${window.CHGRID_RELEASE_VERSION} ${window.CHGRID_BUILD_REVISION}`;
// Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid.
window.CHGRID_TIME_ZONE = "America/Detroit";

View File

@@ -156,6 +156,14 @@ export function createAuthController(deps: AuthControllerDeps): {
}
}
function resetSavedSessionHint(): void {
authUserId = '';
authUsername = '';
deps.saveAuthUsername('');
deps.dom.authUsername.value = '';
deps.dom.registerUsername.value = '';
}
function updateConnectAvailability(): void {
const hasSavedSessionHint = sanitizeAuthUsername(authUsername).length > 0;
const showLogout = deps.isRunning() || hasSavedSessionHint;
@@ -256,6 +264,10 @@ export function createAuthController(deps: AuthControllerDeps): {
deps.signalingSend(packet);
return;
}
if (sanitizeAuthUsername(authUsername).length > 0) {
resetSavedSessionHint();
setAuthMode('login');
}
deps.setConnecting(false);
updateConnectAvailability();
}
@@ -311,6 +323,7 @@ export function createAuthController(deps: AuthControllerDeps): {
deps.dom.registerPassword.value = '';
deps.dom.registerPasswordConfirm.value = '';
if (message.message.toLowerCase().includes('session')) {
resetSavedSessionHint();
void clearHttpOnlySessionCookie();
}
applyAuthPermissions('user', []);

View File

@@ -22,6 +22,7 @@ import uuid
from pathlib import Path
from typing import Literal
from urllib.error import URLError
from urllib.parse import urlsplit, urlunsplit
from zoneinfo import ZoneInfo
from pydantic import ValidationError, TypeAdapter
@@ -330,13 +331,26 @@ class SignalingServer:
if not self.host_origin:
return False
raw_origin = str(request.headers.get("Origin", "")).strip()
if not raw_origin:
if raw_origin:
try:
origin = normalize_origin(raw_origin)
except ValueError:
return False
return origin == self.host_origin
fetch_site = str(request.headers.get("Sec-Fetch-Site", "")).strip().lower()
if fetch_site == "same-origin":
return True
raw_referer = str(request.headers.get("Referer", "")).strip()
if not raw_referer:
return False
try:
origin = normalize_origin(raw_origin)
parts = urlsplit(raw_referer)
referer_origin = urlunsplit((parts.scheme, parts.netloc, "", "", ""))
return normalize_origin(referer_origin, field_name="referer") == self.host_origin
except ValueError:
return False
return origin == self.host_origin
@staticmethod
def _cookie_value(cookie_header: str, name: str) -> str:

View File

@@ -118,6 +118,23 @@ async def test_session_cookie_helpers_reject_wrong_origin() -> None:
assert response.status_code == 403
@pytest.mark.asyncio
async def test_session_cookie_helpers_accept_same_origin_referer_without_origin() -> None:
server = _server()
request = _request(
server.auth_session_cookie_clear_path,
headers={
AUTH_SESSION_COOKIE_CLIENT_HEADER: "1",
"Referer": "https://example.com/chgrid/",
},
)
response = await server._process_http_request(SimpleNamespace(), request)
assert response is not None
assert response.status_code == 200
def test_session_token_from_websocket_cookie_reads_named_cookie() -> None:
server = SignalingServer("127.0.0.1", 8765, None, None, base_path="/chgrid/")
websocket = SimpleNamespace(