Skip to content

Feat/session restore#113

Closed
JanZachmann wants to merge 6 commits intoomnect:mainfrom
JanZachmann:feat/session-restore
Closed

Feat/session restore#113
JanZachmann wants to merge 6 commits intoomnect:mainfrom
JanZachmann:feat/session-restore

Conversation

@JanZachmann
Copy link
Contributor

No description provided.

- Add scanning, connecting, disconnecting, and saved-network management
  through the wifi-commissioning-service (unix domain socket)
- E2E coverage: auth flow, WiFi operations, form interaction edge cases

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
…frastructure

- **Model & Synchronization:** Moved  and  from the persistent  state to ephemeral . This ensures that these one-time notification flags do not persist across device reboots or accidental state synchronization cycles, preventing redundant modal popups.
- **Core Logic:** Implemented  in the Crux Core to decouple the initial application hydration from subsequent polling cycles. This allows for a deterministic startup sequence where the UI can react to the device state immediately after WASM initialization.
- **Test Infrastructure:**
    - Refactored  and  to utilize  for modal suppression, replacing the fragile  injection pattern.
    - Introduced  and  in the harness to reduce boilerplate and improve reliability of complex network redirection tests.
    - Standardized healthcheck mocking across all E2E tests to ensure consistent behavior during version-mismatch and rollback scenarios.
- **Backend & Utilities:** Added  to handle cases where the backend returns valid JSON alongside non-2xx status codes (e.g., 503 during version mismatch).

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
After login, a page refresh caused the JWT (held only in WASM memory)
to be lost, forcing re-login. The server-side session cookie already
survived page refresh; this change uses it.

During WASM init, `initializeCore()` now calls `GET /token/refresh`
(credentials: include) before sending Initialize. A content-type guard
(`text/plain`) ensures the Vite SPA HTML fallback is never mistaken for
a valid token. On success, the returned JWT is sent to Core via the new
`AuthEvent::RestoreSession(String)` event which sets `is_authenticated`
and stores the token without triggering a re-login form.

Bumps version to 1.2.1.

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Before, the /set-password route guard unconditionally triggered a
Keycloak login regardless of whether a password was already set or
the user was already authenticated. This caused spurious OIDC
round-trips in all but the initial setup scenario.

The guard now short-circuits in priority order:
1. Already authenticated (session restore) → redirect to /
2. Password already set → redirect to /login
3. Otherwise, proceed with portal-auth (Keycloak) flow

Add e2e tests for the three previously uncovered scenarios (password
set with/without Keycloak, already authenticated). Also make two
existing tests explicitly mock require-set-password=true so they
exercise the intended code path rather than the catch fallback.

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Unknown routes now redirect to / via a catchall entry; the existing
requiresAuth guard then sends unauthenticated users to /login.

Three e2e tests added covering:
- protected route accessed without authentication → /login
- invalid route accessed without authentication → /login
- invalid route accessed as authenticated user → /

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Two bugs prevented session restore on F5:

1. session_token() returned the JWT without a Content-Type header.
   actix-web's HttpResponseBuilder::body() does not set it automatically
   for String values. The frontend guard checks for 'text/plain' and
   silently skipped restore when the header was absent.

2. Key::generate() was called on every run_server() invocation, so any
   backend restart (including network-config-triggered restarts) generated
   a new signing key, invalidating all existing session cookies.

Fix 1: add .content_type("text/plain; charset=utf-8") to session_token().
Fix 2: introduce SessionKeyService that loads the key from
       PathConfig.session_key_path (/data/session.key) on startup, or
       generates and persists a new one when the file is absent.

Also tighten the e2e mocks: mockLoginSuccess now plants the session
cookie and mockTokenRefresh validates its presence, catching regressions
in the cookie roundtrip that the previous mocks ignored.

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
@JanZachmann JanZachmann closed this Mar 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant