-
Notifications
You must be signed in to change notification settings - Fork 13k
chore(federation): bring back domain setting #37033
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
ggazzo
merged 6 commits into
chore/federation-backup
from
chore/federation-domain-config
Sep 23, 2025
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
871cdeb
chore(federation): bring back domain setting
rodrigok e3b4782
revie
debdutdeb 2ac5d59
Improve domain handling
rodrigok 7a862ae
Update apps/meteor/ee/server/startup/federation.ts
debdutdeb 46422b1
deafult to ''
debdutdeb b2cefcf
Fix lint
rodrigok File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,13 +10,45 @@ import { registerFederationRoutes } from '../api/federation'; | |
|
|
||
| const logger = new Logger('Federation'); | ||
|
|
||
| // TODO: should validate if the domain is resolving to us or not correctly | ||
| // should use homeserver.getFinalSomethingSomething and validate final Host header to have siteUrl | ||
| // this is a minimum sanity check to avoid full urls instead of the expected domain part | ||
| function validateDomain(domain: string): boolean { | ||
| const value = domain.trim(); | ||
|
|
||
| if (!value) { | ||
| logger.error('The Federation domain is not set'); | ||
| return false; | ||
| } | ||
|
|
||
| if (value.toLowerCase() !== value) { | ||
| logger.error(`The Federation domain "${value}" cannot have uppercase letters`); | ||
| return false; | ||
| } | ||
|
|
||
| try { | ||
| const valid = new URL(`https://${value}`).hostname === value; | ||
|
|
||
| if (!valid) { | ||
| throw new Error(); | ||
| } | ||
| } catch { | ||
| logger.error(`The configured Federation domain "${value}" is not valid`); | ||
| return false; | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| export const startFederationService = async (): Promise<void> => { | ||
| let federationMatrixService: FederationMatrix | undefined; | ||
|
|
||
|
Comment on lines
44
to
45
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prevent broadcast-listener leaks across restarts; remove on stop and register once. Each stop/start cycle adds another listener; they’re never removed. This can duplicate events and waste memory. Apply these diffs: @@
export const startFederationService = async (): Promise<void> => {
let federationMatrixService: FederationMatrix | undefined;
+ let broadcastHandler: ((name: string, eventName: string, args: any[]) => void) | undefined;
@@
- StreamerCentral.on('broadcast', (name, eventName, args) => {
- if (!federationMatrixService) {
- return;
- }
- if (name === 'notify-room' && eventName.endsWith('user-activity')) {
- const [rid] = eventName.split('/');
- const [user, activity] = args;
- void federationMatrixService.notifyUserTyping(rid, user, activity.includes('user-typing'));
- }
- });
+ broadcastHandler = (name, eventName, args) => {
+ if (!federationMatrixService) {
+ return;
+ }
+ if (name === 'notify-room' && eventName.endsWith('user-activity')) {
+ const [rid] = eventName.split('/');
+ const [user, activity] = args;
+ void federationMatrixService.notifyUserTyping(rid, user, activity.includes('user-typing'));
+ }
+ };
+ // @ts-expect-error: EventEmitter-like API
+ StreamerCentral.on?.('broadcast', broadcastHandler);
@@
const stopService = async (): Promise<void> => {
if (!federationMatrixService) {
logger.debug('Federation-matrix service not registered... skipping');
return;
}
logger.debug('Stopping federation-matrix service');
// TODO: Unregister routes
// await unregisterFederationRoutes(federationMatrixService);
+ if (broadcastHandler) {
+ // @ts-expect-error: removeListener/off exist on StreamerCentral emitter
+ StreamerCentral.removeListener?.('broadcast', broadcastHandler);
+ // @ts-expect-error
+ StreamerCentral.off?.('broadcast', broadcastHandler);
+ broadcastHandler = undefined;
+ }
+
await api.destroyService(federationMatrixService);
federationMatrixService = undefined;
};Also applies to: 63-74, 82-95 🤖 Prompt for AI Agents |
||
| const shouldStartService = (): boolean => { | ||
| const hasLicense = License.hasModule('federation'); | ||
| const isEnabled = settings.get('Federation_Service_Enabled') === true; | ||
| return hasLicense && isEnabled; | ||
| const domain = settings.get<string>('Federation_Service_Domain'); | ||
| const hasDomain = validateDomain(domain); | ||
| return hasLicense && isEnabled && hasDomain; | ||
| }; | ||
|
|
||
| const startService = async (): Promise<void> => { | ||
|
|
@@ -88,4 +120,16 @@ export const startFederationService = async (): Promise<void> => { | |
| await stopService(); | ||
| } | ||
| }); | ||
|
|
||
| settings.watch<string>('Federation_Service_Domain', async (domain) => { | ||
| logger.debug('Federation_Service_Domain setting changed:', domain); | ||
| if (shouldStartService()) { | ||
| if (domain.toLowerCase() !== federationMatrixService?.getServerName().toLowerCase()) { | ||
| await stopService(); | ||
| } | ||
| await startService(); | ||
| } else { | ||
| await stopService(); | ||
| } | ||
| }); | ||
| }; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
🧩 Analysis chain
Verify the domain validation requirements against the latest Matrix specification.
The
validateDomainfunction implements several validation rules (trimming, non-empty check, lowercase requirement, URL hostname validation), but it's unclear if these requirements align with the latest Matrix homeserver domain specifications.Based on the search results, Matrix homeserver domains should match what you've configured in your Matrix configuration file, but the specific validation requirements for domain format aren't clearly documented. Please search for the latest Matrix specification requirements for homeserver domain validation:
🌐 Web query:
💡 Result:
Key sources that specify Matrix homeserver domain-name validation and requirements:
Matrix specification — Server name grammar & rules (server_name = hostname [ ":" port ], hostname may be IPv4/IPv6 literal or DNS name; recommendations on length/case; based on RFC 1123). [1][2]
Matrix Server-Server (federation) / discovery rules — how homeserver names are resolved: use /.well-known/matrix/server, then _matrix._tcp SRV, then connect to hostname:8448; certificate and Host header expectations for IP literals vs DNS names. [3]
Matrix historical/r0.1.2 federation text describing certificate/Host header handling and resolution order (useful for precise validation behaviour). [4]
Related discussion: SVCB/HTTPS records are not currently supported for homeserver discovery (implementation/issue thread). [5]
References
If you want, I can extract the exact server_name grammar and the TLS/Host-header rules into a short spec excerpt.
Citations:
Align validateDomain with Matrix server_name grammar
Current checks (rejecting uppercase; strict
new URL(...).hostname === value) will reject valid Matrix server_name forms (IDNs, optional ports, IPv6 literals). Actions:URLequality check with validation that follows Matrix server_name = hostname [ ":" port ] — allow DNS names, IPv4, bracketed IPv6 literals, and optional port; support IDNs by converting to ASCII (punycode) before validation or use a robust host-parser library.🤖 Prompt for AI Agents