Skip to content

[Bug]: Home dashboard always fails to load on explicitly approved plain HTTP servers #441

Description

@PrabuDzak

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 (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.

Reproduction steps

  1. Add a server by a plain HTTP address (for example http://cloud.lan:8080) and accept the plain HTTP consent dialog from feat(auth): allow explicitly approved HTTP servers #397.
  2. Complete login and open the Home workspace.
  3. 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.
Image Image

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

  • I removed credentials and private account data from this report.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions