djust 1.0.9

Stable Security Released
Install
pip install djust==1.0.9

A 1.0 patch release that includes security fixes; upgrading from 1.0.8 is recommended. The 1.0 line is no longer maintained, so moving to 1.2 or later is advised.

Security

  • The signed state_snapshot token no longer carries the raw session key. The token is signed, not encrypted, and the client stores it, so the session key was readable from the page. The envelope now holds a keyed digest of the session key (the same change as in 1.1 and later). Tokens issued before the upgrade no longer verify: the view falls back to one normal mount() and issues a new token.
  • reauth_on_event re-check now fails closed. With LIVEVIEW_CONFIG["reauth_on_event"] on, LiveViewConsumer.handle_event caught any exception from the per-event authorization re-check (Http404 or DoesNotExist out of check_permissions, a failing session or auth backend), logged it at DEBUG and ran the event, so a user whose access had been revoked could still dispatch. The re-check now lives in LiveViewConsumer._reauth_recheck and denies on any exception: one WARNING naming only the exception type and view class (never the message or a traceback), navigate-to-login and close 4403 (both best effort, so a dead peer cannot turn the denial into an allow), and the handler does not run. Clean pass/fail results and the default-off behaviour are unchanged. Affects 1.0.4 through 1.0.8. Tests in python/djust/tests/test_reauth_fail_closed.py.
  • reauth_on_event now also covers frames the server sends on its own. With LIVEVIEW_CONFIG["reauth_on_event"] on, a WebSocket whose user was logged out or lost a permission was refused on its next client event but kept receiving server_push / push_to_view, db_notify, tick, presence and start_async result frames for a view with login_required or permission_required. Each such turn now runs the same fresh-principal check as an event, under the render lock and before the hook runs; on failure the socket gets navigate-to-login and close 4403 and nothing is rendered or sent. A passed check covers the socket for LIVEVIEW_CONFIG["reauth_server_turn_interval"] seconds (default 5; 0 re-checks every turn), so ticking views do not read the session store on every tick. A check that raises denies and logs only the exception type and view class at WARNING. Off by default; behaviour with reauth_on_event off is unchanged. Tests in python/djust/tests/test_server_turn_reauth.py.
  • Debug panel and client-dev.js now escape interpolated values. The in-browser debug panel (loaded only when settings.DEBUG is true) built its Events, Network, Patches, Components, Handlers, Variables and Warnings tabs, the element badge, and the hot-reload error toast as HTML strings without escaping, so text from application data (for example another user's input in a shared view) was parsed as markup in the developer's browser. Every interpolated value is now escaped (including attribute positions, via a quote-escaping escapeHtml), warning docs_url links are limited to http(s)/relative URLs, and the toast uses textContent. The generated debug-panel.js / debug-panel.min.js bundles (and their .gz/.br/.map siblings) are rebuilt with scripts/build-client.sh. Production pages (DEBUG = False) never load the panel and were not affected. Tests in tests/js/debug_panel_xss_escape.test.js.

Fixed

  • Saved view state and the signed state_snapshot token of a TenantMixin view are bound to the tenant (#3328). The state backend entry, the Django-session entry (liveview_<path> and its __private, _components and __sticky__ siblings) and the back-navigation token are keyed by tenant:<id>, so one session that reaches two tenants on the same URL keeps separate state and a mount under another tenant mounts fresh. A tenant view with no resolved tenant saves, restores and mints nothing. The tenant context key is render-only, so a restored self.tenant is no longer a serialized string. Views without TenantMixin are unchanged. State and tokens that tenant views saved before the upgrade are not found once (one fresh mount).
  • V004 no longer false-fires on framework-invoked lifecycle hooks (#1684). The V004 system check ("public method looks like an event handler but is missing @event_handler") flagged user overrides of hooks the framework calls directly (self.X() / getattr / hasattr) rather than through the user-event router — these must NOT carry @event_handler, but their names match the event-handler-like regex and were absent from the V004 lifecycle-skip set in checks/components.py. Canonical symptom: handle_presence_leave (bit djust-org/djust-start#5). Added the 8 framework-invoked hooks (handle_presence_join/handle_presence_leave/handle_cursor_move/handle_tick/handle_async_result/handle_component_event/handle_info/on_wizard_complete) to the skip set. The fix originally landed on the 1.1 branch (#1685) against the pre-#1822-split checks.py; it was never ported to main's split checks/ (so the false-positive was live through 1.0.8) — this lands it on main. New regression TestV004LifecycleMethods::test_v004_ignores_framework_invoked_hooks_1684 (gate-off verified, #1468).

All releases · Atom feed