Rocket.Chat icon indicating copy to clipboard operation
Rocket.Chat copied to clipboard

feat(federation): add improved errors messaging

Open ricardogarim opened this issue 2 months ago • 3 comments

Proposed changes (including videos or screenshots)

As per FB-25, this PR implements a pre-federation validation shield that blocks outbound federation actions (invites, DMs, and room creation involving remote users) unless the destination domain is allowed, reachable, and the target user exists.

Works along with https://github.com/RocketChat/homeserver/pull/305.

This introduces a sequential validation layer composed of three checks that run before any federation transaction is executed.

1. Policy vetting check (allow list enforcement)

Validates whether the remote domain is authorized according to the organization's Federation Domain Allow List.

If the domain is not allowed, the server immediately returns:

  • HTTP 403 Forbidden
  • Error code: federation-policy-denied

Message returned: "Action Blocked. Communication with one of the domains in the list is restricted by your organization's security policy."

2. Domain existence check (DNS / reachability)

Ensures that the remote homeserver domain resolves and is reachable.

If DNS lookup fails or the server is unreachable, the server returns:

  • Error code: federation-connection-failed

Message: "Connection Failed. The server domain could not be reached or does not support federation."

3. User existence check (protocol lookup)

Queries the remote homeserver for the given user ID.

If the remote server responds with a 404 for the user, the server blocks the request with:

  • Error code: federation-user-not-found

Message: "Invitation blocked. The specified user couldn’t be found on their homeserver."

Issue(s)

Test cases

Test Category Scenario Pathways Tested Input Expected Result Error Code UI Feedback
General Rule Invite multiple users where one fails Room creation modal, DM modal, inside room Mixed users Entire operation fails Depends on failure type Error message displayed

POLICY VETTING (RC ALLOW LIST)

Test Category Scenario Pathways Tested Input Expected Result Error Code UI Feedback
Policy Vetting RC Allow List contains only hs1, inviting user from hs2 Room creation modal @admin:hs2 Fail federation-policy-denied Policy message
Policy Vetting Same case tested via DM creation DM creation modal @admin:hs2 Fail Same Same
Policy Vetting Same case tested via inside-room invite Inside room ("Continue adding?") @admin:hs2 Status POLICY_DENIED; failing on continue federation-policy-denied Tooltip and final error
Policy Vetting Same case tested via /invite Slash command /invite @admin:hs2 Fail federation-policy-denied Same policy message
Policy Vetting RC Allow List contains only hs1, inviting user from hs1 All entry points @admin:hs1 Success None None
Policy Vetting Empty allow list allows all domains All entry points Any domain Success None None

DOMAIN EXISTENCE

Test Category Scenario Pathways Tested Input Expected Result Error Code UI Feedback
Domain Check Non-existent domain Room creation modal @admin:hs3 Fail federation-connection-failed Connection failed message
Domain Check Same case via DM creation DM creation modal @admin:hs3 Fail Same Same
Domain Check Same case inside room Inside room @admin:hs3 Status CONNECTION_FAILED None (status-level) + failure on continue Tooltip: "Unable to verify user"
Domain Check Same case via /invite Slash command /invite @admin:hs3 Fail federation-connection-failed Same

USER EXISTENCE

Test Category Scenario Pathways Tested Input Expected Result Error Code UI Feedback
User Existence Non-existent user on valid domain Room creation modal @admin2:hs1 Fail federation-user-not-found User-not-found message
User Existence Same case via DM creation DM creation modal @admin2:hs1 Fail Same Same
User Existence Same case inside room Inside room @admin2:hs1 Status USER_NOT_FOUND, continue disabled None (status-level) Tooltip: "User is unverified"
User Existence Same case via /invite Slash command /invite @admin2:hs1 Fail federation-user-not-found Same

Summary by CodeRabbit

  • New Features

    • Enforced federation domain allowlist for username-based members and when adding users to rooms.
    • Validates federated users before direct room creation with clearer mapped error responses.
    • Exposed federation validation helpers and a federation validation error type for federation flows.
  • Chores

    • Added configurable federation validation timeouts for network and user checks.

✏️ Tip: You can customize this high-level summary in your review settings.

ricardogarim avatar Nov 24 '25 02:11 ricardogarim

Looks like this PR is ready to merge! 🎉 If you have any trouble, please check the PR guidelines

dionisio-bot[bot] avatar Nov 24 '25 02:11 dionisio-bot[bot]

⚠️ No Changeset found

Latest commit: decfe3d4d9f4d6de4c782e3b1906f03467a7236d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

changeset-bot[bot] avatar Nov 24 '25 02:11 changeset-bot[bot]

Walkthrough

Adds pre-federation domain allowlist and federated-user validation checks to room creation and invite hooks; exposes new federation-domain helpers and a FederationMatrix.validateFederatedUsers API; surfaces federation validation errors as Meteor errors and adds related configuration and dependency bumps.

Changes

Cohort / File(s) Summary
Room creation & hooks
apps/meteor/app/lib/server/functions/createRoom.ts, apps/meteor/ee/server/hooks/federation/index.ts
Enforce domain allowlist for username-based federated members, validate federated usernames via FederationMatrix.validateFederatedUsers, map FederationValidationError → Meteor.Error, and require access-federation permission where applicable.
Federation domain allowlist
ee/packages/federation-matrix/src/api/middlewares/isFederationDomainAllowed.ts
New helpers isFederationDomainAllowed(domains) and isFederationDomainAllowedForUsernames(usernames) that extract domains and evaluate against exact, wildcard, and suffix allowlist rules.
Federation core & API
ee/packages/federation-matrix/src/FederationMatrix.ts, ee/packages/federation-matrix/src/index.ts
Added validateFederatedUsers(usernames: string[]) to FederationMatrix; integrate domain allowlist checks in verification flows; export isFederationDomainAllowed* and FederationValidationError. Maps SDK error codes to validation results.
Config & timeouts
ee/packages/federation-matrix/src/setup.ts
Adds federation.validation config (networkCheckTimeoutMs, userCheckTimeoutMs) sourced from env vars (defaults 3000ms).
Service interface & deps
packages/core-services/src/types/IFederationMatrixService.ts, ee/packages/federation-matrix/package.json, packages/core-services/package.json
Added validateFederatedUsers to IFederationMatrixService; bumped @rocket.chat/federation-sdk from 0.3.50.3.6 in federation and core-services packages.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant CreateRoom as createRoom Handler
    participant FedAPI as isFederationDomainAllowedForUsernames
    participant FedMatrix as FederationMatrix.validateFederatedUsers
    participant SDK as federation-sdk

    Client->>CreateRoom: createRoom(members: usernames[])
    CreateRoom->>FedAPI: isFederationDomainAllowedForUsernames(usernames)
    alt Domain Allowed
        FedAPI-->>CreateRoom: true
        CreateRoom->>FedMatrix: validateFederatedUsers(usernames)
        FedMatrix->>SDK: validateOutboundUser(matrixId) for each federated user
        alt Validation Success
            SDK-->>FedMatrix: verified
            FedMatrix-->>CreateRoom: success
            CreateRoom-->>Client: room created
        else Validation Failure
            SDK-->>FedMatrix: error (unreachable/not found/policy)
            FedMatrix-->>CreateRoom: throw FederationValidationError
            CreateRoom-->>Client: Meteor.Error (federation-policy-denied / mapped error)
        end
    else Domain Blocked
        FedAPI-->>CreateRoom: false
        CreateRoom-->>Client: Meteor.Error (federation-policy-denied)
    end
sequenceDiagram
    participant Client
    participant Hook as beforeAddUserToRoom
    participant Perm as Permission Service
    participant FedAPI as isFederationDomainAllowedForUsernames
    participant Invite as invite flow

    Client->>Hook: add user to room (username)
    Hook->>Perm: check access-federation
    alt Permitted
        Perm-->>Hook: allowed
        Hook->>FedAPI: isFederationDomainAllowedForUsernames([username])
        alt Domain Allowed
            FedAPI-->>Hook: true
            Hook->>Invite: proceed to federated invite
            Invite-->>Client: success
        else Domain Denied
            FedAPI-->>Hook: false
            Hook-->>Client: Meteor.Error (federation-policy-denied)
        end
    else Not Permitted
        Perm-->>Hook: denied
        Hook-->>Client: permission error
    end

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • RocketChat/Rocket.Chat#37582 — touches createDirectMessage and federated flag handling which affects whether new validation gates trigger.
  • RocketChat/Rocket.Chat#37015 — modifies the same createRoom flow; likely overlaps with pre-creation federation checks.
  • RocketChat/Rocket.Chat#37377 — adjusts federation authorization hooks and permission usage overlapping beforeAddUserToRoom changes.

Suggested labels

stat: ready to merge

Suggested reviewers

  • ggazzo
  • sampaiodiego

Poem

🐇 I checked each domain and counted hops,
Small ears perked when validation stops.
Domains allowed, users found—hooray!
No ghost rooms left to lead astray.
A hopping cheer for safe DMs today! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the primary objective of adding validation error handling and improved messaging for federation operations, matching the core changes throughout the codebase.
Linked Issues check ✅ Passed All three validation checks from FB-25 are implemented: policy vetting via isFederationDomainAllowedForUsernames, network reachability checks, and user existence validation via validateFederatedUsers, with proper error mapping.
Out of Scope Changes check ✅ Passed All changes are within scope: domain policy enforcement, user validation, error handling, and configuration for federation checks; no UI/UX or unrelated changes detected.
✨ Finishing touches
  • [ ] 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • [ ] Create PR with unit tests
  • [ ] Post copyable unit tests in a comment
  • [ ] Commit unit tests in branch feat/fed-errors-messaging

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot] avatar Nov 24 '25 02:11 coderabbitai[bot]

📦 Docker Image Size Report

📈 Changes

Service Current Baseline Change Percent
sum of all images 1.1GiB 1.1GiB +11MiB
rocketchat 355MiB 345MiB +11MiB
omnichannel-transcript-service 132MiB 132MiB +203B
queue-worker-service 132MiB 132MiB -402B
ddp-streamer-service 126MiB 126MiB +375B
account-service 113MiB 113MiB +857B
authorization-service 111MiB 111MiB +9.2KiB
presence-service 111MiB 111MiB +8.2KiB

📊 Historical Trend

---
config:
  theme: "dark"
  xyChart:
    width: 900
    height: 400
---
xychart
  title "Image Size Evolution by Service (Last 30 Days + This PR)"
  x-axis ["11/15 22:28", "11/16 01:28", "11/17 23:50", "11/18 22:53", "11/19 23:02", "11/21 16:49", "11/24 17:34", "11/27 22:32", "11/28 19:05", "12/01 23:01", "12/02 21:57", "12/03 21:00", "12/04 18:17", "12/05 21:56", "12/08 20:15", "12/09 22:17", "12/10 23:26", "12/11 21:56", "12/12 22:45", "12/13 01:34", "12/15 22:31", "12/16 22:18", "12/17 21:04", "12/18 23:12", "12/19 23:27", "12/20 21:03", "12/22 18:54", "12/23 16:16", "12/23 19:43 (PR)"]
  y-axis "Size (GB)" 0 --> 0.5
  line "account-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
  line "authorization-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
  line "ddp-streamer-service" [0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12]
  line "omnichannel-transcript-service" [0.14, 0.14, 0.14, 0.14, 0.14, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13]
  line "presence-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
  line "queue-worker-service" [0.14, 0.14, 0.14, 0.14, 0.14, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13]
  line "rocketchat" [0.36, 0.36, 0.35, 0.35, 0.35, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.35]

Statistics (last 28 days):

  • 📊 Average: 1.5GiB
  • ⬇️ Minimum: 1.2GiB
  • ⬆️ Maximum: 1.6GiB
  • 🎯 Current PR: 1.1GiB
ℹ️ About this report

This report compares Docker image sizes from this build against the develop baseline.

  • Tag: pr-37581
  • Baseline: develop
  • Timestamp: 2025-12-23 19:43:00 UTC
  • Historical data points: 28

Updated: Tue, 23 Dec 2025 19:43:01 GMT

github-actions[bot] avatar Dec 19 '25 23:12 github-actions[bot]

Codecov Report

:white_check_mark: All modified and coverable lines are covered by tests. :white_check_mark: Project coverage is 70.64%. Comparing base (a8a84ab) to head (decfe3d).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #37581      +/-   ##
===========================================
- Coverage    70.66%   70.64%   -0.03%     
===========================================
  Files         3143     3143              
  Lines       108694   108694              
  Branches     19572    19557      -15     
===========================================
- Hits         76810    76783      -27     
- Misses       29887    29909      +22     
- Partials      1997     2002       +5     
Flag Coverage Δ
e2e 60.18% <ø> (-0.02%) :arrow_down:
e2e-api 47.39% <ø> (-0.08%) :arrow_down:
unit 71.76% <ø> (-0.04%) :arrow_down:

Flags with carried forward coverage won't be shown. Click here to find out more.

:rocket: New features to boost your workflow:
  • :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • :package: JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

codecov[bot] avatar Dec 23 '25 18:12 codecov[bot]