You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
After logging in to a server that was explicitly approved over plain HTTP, the Home dashboard fails on every load with "The dashboard could not be loaded. Try again." Pressing Try again never succeeds. Expected: the dashboard loads for a plain HTTP account the same way it does for an HTTPS one.
PR #397 (aa990a1) added plain HTTP support at the login and transport level: the explicit consent flow, transport acceptance, and the Android cross-scheme redirect and network security handling. It did not cover response-level link validation on the dashboard.
Root cause: the dashboard widget and item parsers validate every absolute link with an https-only rule (isSafeDashboardLink in ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/DashboardStatus.kt). Nextcloud builds widget, icon, and item links from its own configured protocol, so a plain HTTP server returns http:// links. A required link fails validation, parsing throws, and the whole dashboard load is rejected. The account was already approved for plain HTTP at login, so rejecting its own origin's links only breaks the workspace without protecting anything.
Every other surface already handles this correctly. Activity links, unified search, share links, the native link router, dynamic app descriptors, and incoming Android links all accept http:// when it matches the account origin. Office editing is blocked on plain HTTP by design with an explicit message. The dashboard is the only screen that fails generically.
Proposed fix: derive a link policy from the account's server URL and thread it through the dashboard parsers.
https:// links are always accepted. Relative links keep the existing rules.
Only when the account origin itself is plain HTTP, additionally accept http:// links to that exact origin. All other plain HTTP links stay rejected, so the relaxation is scoped to what the user already consented to at login.
TLS-only remains the default policy. Optional icon links that fail the policy are dropped rather than failing the load.
This mirrors the same-account rule in nextcloudLinkDestination (NextcloudLinkRouting.kt) and the accountOriginSecure threading in the Office document workflow.
Platform
Linux
Nextcloud Native version or commit
nightly-20260829-1318-run1457-3c60206f
Nextcloud server and affected app versions
Any server reachable over plain HTTP with the Dashboard app enabled. The server version does not matter because the failure is client-side parsing.
The dashboard errors immediately with "The dashboard could not be loaded. Try again." It never succeeds on first load or refresh, because the widget response contains http://cloud.lan:8080/... links that fail https-only validation.
What happened?
After logging in to a server that was explicitly approved over plain HTTP, the Home dashboard fails on every load with "The dashboard could not be loaded. Try again." Pressing Try again never succeeds. Expected: the dashboard loads for a plain HTTP account the same way it does for an HTTPS one.
PR #397 (aa990a1) added plain HTTP support at the login and transport level: the explicit consent flow, transport acceptance, and the Android cross-scheme redirect and network security handling. It did not cover response-level link validation on the dashboard.
Root cause: the dashboard widget and item parsers validate every absolute link with an https-only rule (
isSafeDashboardLinkinui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/DashboardStatus.kt). Nextcloud builds widget, icon, and item links from its own configured protocol, so a plain HTTP server returnshttp://links. A required link fails validation, parsing throws, and the whole dashboard load is rejected. The account was already approved for plain HTTP at login, so rejecting its own origin's links only breaks the workspace without protecting anything.Every other surface already handles this correctly. Activity links, unified search, share links, the native link router, dynamic app descriptors, and incoming Android links all accept
http://when it matches the account origin. Office editing is blocked on plain HTTP by design with an explicit message. The dashboard is the only screen that fails generically.Proposed fix: derive a link policy from the account's server URL and thread it through the dashboard parsers.
https://links are always accepted. Relative links keep the existing rules.http://links to that exact origin. All other plain HTTP links stay rejected, so the relaxation is scoped to what the user already consented to at login.This mirrors the same-account rule in
nextcloudLinkDestination(NextcloudLinkRouting.kt) and theaccountOriginSecurethreading in the Office document workflow.Platform
Linux
Nextcloud Native version or commit
nightly-20260829-1318-run1457-3c60206f
Nextcloud server and affected app versions
Any server reachable over plain HTTP with the Dashboard app enabled. The server version does not matter because the failure is client-side parsing.
Reproduction steps
http://cloud.lan:8080) and accept the plain HTTP consent dialog from feat(auth): allow explicitly approved HTTP servers #397.http://cloud.lan:8080/...links that fail https-only validation.Redacted logs or screenshots
{"sequence":2,"occurredAt":"2026-08-30T14:48:05Z","severity":"Info","component":"Authentication","operation":"login.challenge","outcome":"started","fields":[{"name":"login_origin_matches_entered","value":"true"},{"name":"poll_origin_matches_entered","value":"true"},{"name":"poll_fallback_available","value":"false"},{"name":"transport_security","value":"plaintext"}]} {"sequence":4,"occurredAt":"2026-08-30T14:48:48Z","severity":"Info","component":"Authentication","operation":"login.poll","outcome":"approved","fields":[{"name":"result_origin_matches_entered","value":"true"},{"name":"poll_fallback_used","value":"false"}]} {"sequence":7,"occurredAt":"2026-08-30T14:49:04Z","severity":"Error","component":"App","operation":"dashboard.load","outcome":"failed","code":"DASHBOARD_WIDGETS_FAILED","accountScope":"<account:redacted>","fields":[{"name":"stage","value":"widgets"},{"name":"cached_available","value":"false"},{"name":"route_variant","value":"ocs_v2_dashboard_widgets_v1"},{"name":"response_classification","value":"malformed_response"},{"name":"http_status_family","value":"2xx"}]} {"sequence":44,"occurredAt":"2026-08-30T15:03:44Z","severity":"Error","component":"App","operation":"dashboard.load","outcome":"failed","code":"DASHBOARD_WIDGETS_FAILED","accountScope":"<account:redacted>","fields":[{"name":"stage","value":"widgets"},{"name":"cached_available","value":"false"},{"name":"route_variant","value":"ocs_v2_dashboard_widgets_v1"},{"name":"response_classification","value":"malformed_response"},{"name":"http_status_family","value":"2xx"}]}Privacy check