diff --git a/apps/meteor/app/assets/server/assets.ts b/apps/meteor/app/assets/server/assets.ts index c6df82fcc7938..34c274564085b 100644 --- a/apps/meteor/app/assets/server/assets.ts +++ b/apps/meteor/app/assets/server/assets.ts @@ -396,8 +396,6 @@ void (async () => { } })(); -settings.watchByRegex(/^Assets_/, (key, value) => RocketChatAssets.processAsset(key, value)); - Meteor.startup(() => { setTimeout(() => { process.emit('message', { diff --git a/apps/meteor/app/cors/server/cors.ts b/apps/meteor/app/cors/server/cors.ts index effbb712681b1..a9d50ee429740 100644 --- a/apps/meteor/app/cors/server/cors.ts +++ b/apps/meteor/app/cors/server/cors.ts @@ -16,8 +16,6 @@ type NextFunction = (err?: any) => void; const logger = new Logger('CORS'); -let templatePromise: Promise | void; - declare module 'meteor/webapp' { // eslint-disable-next-line @typescript-eslint/no-namespace namespace WebApp { @@ -25,12 +23,10 @@ declare module 'meteor/webapp' { } } -settings.watch( - 'Enable_CSP', - Meteor.bindEnvironment(async (enabled) => { - templatePromise = WebAppInternals.setInlineScriptsAllowed(!enabled); - }), -); +let templatePromise: Promise | void; +export async function setInlineScriptsAllowed(allowed: boolean): Promise { + templatePromise = WebAppInternals.setInlineScriptsAllowed(allowed); +} WebApp.rawConnectHandlers.use(async (_req: http.IncomingMessage, res: http.ServerResponse, next: NextFunction) => { if (templatePromise) { @@ -109,9 +105,9 @@ declare module 'meteor/webapp' { } let cachingVersion = ''; -settings.watch('Troubleshoot_Force_Caching_Version', (value) => { - cachingVersion = String(value).trim(); -}); +export function setCachingVersion(value: string): void { + cachingVersion = value.trim(); +} // @ts-expect-error - accessing internal property of webapp WebAppInternals.staticFilesMiddleware = function ( diff --git a/apps/meteor/app/federation/server/startup/index.ts b/apps/meteor/app/federation/server/startup/index.ts index 17714a5c69c93..5d9191525d1b9 100644 --- a/apps/meteor/app/federation/server/startup/index.ts +++ b/apps/meteor/app/federation/server/startup/index.ts @@ -1,3 +1,2 @@ import './generateKeys'; -import './settings'; import './registerCallbacks'; diff --git a/apps/meteor/app/federation/server/startup/settings.ts b/apps/meteor/app/federation/server/startup/settings.ts deleted file mode 100644 index 4c3ae76501641..0000000000000 --- a/apps/meteor/app/federation/server/startup/settings.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { FederationKeys } from '@rocket.chat/models'; - -import { settings } from '../../../settings/server'; -import { STATUS_ENABLED, STATUS_REGISTERING, STATUS_ERROR_REGISTERING, STATUS_DISABLED } from '../constants'; -import { updateStatus, updateEnabled, isRegisteringOrEnabled } from '../functions/helpers'; -import { enableCallbacks, disableCallbacks } from '../lib/callbacks'; -import { registerWithHub } from '../lib/dns'; -import { getFederationDiscoveryMethod } from '../lib/getFederationDiscoveryMethod'; -import { getFederationDomain } from '../lib/getFederationDomain'; -import { setupLogger } from '../lib/logger'; - -const updateSettings = async function (): Promise { - // Get the key pair - - if (getFederationDiscoveryMethod() === 'hub' && !(await isRegisteringOrEnabled())) { - // Register with hub - try { - await updateStatus(STATUS_REGISTERING); - - await registerWithHub(getFederationDomain(), settings.get('Site_Url'), await FederationKeys.getPublicKeyString()); - - await updateStatus(STATUS_ENABLED); - } catch (err) { - // Disable federation - await updateEnabled(false); - - await updateStatus(STATUS_ERROR_REGISTERING); - } - return; - } - await updateStatus(STATUS_ENABLED); -}; - -// Add settings listeners -settings.watch('FEDERATION_Enabled', async function enableOrDisable(value) { - setupLogger.info(`Federation is ${value ? 'enabled' : 'disabled'}`); - - if (value) { - await updateSettings(); - - enableCallbacks(); - } else { - await updateStatus(STATUS_DISABLED); - - disableCallbacks(); - } -}); - -settings.watchMultiple(['FEDERATION_Discovery_Method', 'FEDERATION_Domain'], updateSettings); diff --git a/apps/meteor/app/irc/server/index.ts b/apps/meteor/app/irc/server/index.ts index aec5eb1f83fce..b4078b8571d50 100644 --- a/apps/meteor/app/irc/server/index.ts +++ b/apps/meteor/app/irc/server/index.ts @@ -1,2 +1 @@ -import './irc'; import './methods/resetIrcConnection'; diff --git a/apps/meteor/app/lib/server/lib/index.ts b/apps/meteor/app/lib/server/lib/index.ts index fd5c14c56d95c..9a5ee594a5a1e 100644 --- a/apps/meteor/app/lib/server/lib/index.ts +++ b/apps/meteor/app/lib/server/lib/index.ts @@ -9,7 +9,6 @@ import './notifyUsersOnMessage'; import './meteorFixes'; export { sendNotification } from './sendNotificationsOnMessage'; -export { hostname } from '../startup/settingsOnLoadSiteUrl'; export { passwordPolicy } from './passwordPolicy'; export { validateEmailDomain } from './validateEmailDomain'; export { RateLimiterClass as RateLimiter } from './RateLimiter'; diff --git a/apps/meteor/app/lib/server/startup/index.ts b/apps/meteor/app/lib/server/startup/index.ts index deadb8a44c06a..94084edafb398 100644 --- a/apps/meteor/app/lib/server/startup/index.ts +++ b/apps/meteor/app/lib/server/startup/index.ts @@ -1,5 +1,2 @@ import './rateLimiter'; import './robots'; -import './settingsOnLoadCdnPrefix'; -import './settingsOnLoadDirectReply'; -import './settingsOnLoadSMTP'; diff --git a/apps/meteor/app/lib/server/startup/settingsOnLoadCdnPrefix.js b/apps/meteor/app/lib/server/startup/settingsOnLoadCdnPrefix.js deleted file mode 100644 index 9dc8ef164b866..0000000000000 --- a/apps/meteor/app/lib/server/startup/settingsOnLoadCdnPrefix.js +++ /dev/null @@ -1,35 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { WebAppInternals } from 'meteor/webapp'; - -import { settings } from '../../../settings/server'; - -function testWebAppInternals(fn) { - typeof WebAppInternals !== 'undefined' && fn(WebAppInternals); -} -settings.change('CDN_PREFIX', (value) => { - const useForAll = settings.get('CDN_PREFIX_ALL'); - if (value && typeof value.valueOf() === 'string' && value.trim() && useForAll) { - return testWebAppInternals((WebAppInternals) => WebAppInternals.setBundledJsCssPrefix(value)); - } -}); - -settings.change('CDN_JSCSS_PREFIX', (value) => { - const useForAll = settings.get('CDN_PREFIX_ALL'); - if (value && typeof value.valueOf() === 'string' && value.trim() && !useForAll) { - return testWebAppInternals((WebAppInternals) => WebAppInternals.setBundledJsCssPrefix(value)); - } -}); - -Meteor.startup(() => { - const cdnValue = settings.get('CDN_PREFIX'); - const useForAll = settings.get('CDN_PREFIX_ALL'); - const cdnJsCss = settings.get('CDN_JSCSS_PREFIX'); - if (cdnValue && typeof cdnValue.valueOf() === 'string' && cdnValue.trim()) { - if (useForAll) { - return testWebAppInternals((WebAppInternals) => WebAppInternals.setBundledJsCssPrefix(cdnValue)); - } - if (cdnJsCss && typeof cdnJsCss.valueOf() === 'string' && cdnJsCss.trim()) { - return testWebAppInternals((WebAppInternals) => WebAppInternals.setBundledJsCssPrefix(cdnJsCss)); - } - } -}); diff --git a/apps/meteor/app/lib/server/startup/settingsOnLoadDirectReply.ts b/apps/meteor/app/lib/server/startup/settingsOnLoadDirectReply.ts deleted file mode 100644 index 67776c7f3d918..0000000000000 --- a/apps/meteor/app/lib/server/startup/settingsOnLoadDirectReply.ts +++ /dev/null @@ -1,43 +0,0 @@ -import _ from 'underscore'; - -import { logger } from '../../../../server/features/EmailInbox/logger'; -import { settings } from '../../../settings/server'; -import { DirectReplyIMAPInterceptor, POP3Helper } from '../lib/interceptDirectReplyEmails.js'; - -let client: DirectReplyIMAPInterceptor | POP3Helper | undefined; -const startEmailInterceptor = _.debounce(async () => { - logger.info('Email Interceptor...'); - const protocol = settings.get('Direct_Reply_Protocol'); - - const isEnabled = - settings.get('Direct_Reply_Enable') && - protocol && - settings.get('Direct_Reply_Host') && - settings.get('Direct_Reply_Port') && - settings.get('Direct_Reply_Username') && - settings.get('Direct_Reply_Password'); - - if (client) { - await client.stop(); - } - - if (!isEnabled) { - logger.info('Email Interceptor Stopped...'); - return; - } - logger.info('Starting Email Interceptor...'); - - if (protocol === 'IMAP') { - client = new DirectReplyIMAPInterceptor(); - await client.start(); - } - - if (protocol === 'POP') { - client = new POP3Helper(settings.get('Direct_Reply_Frequency')); - client.start(); - } -}, 1000); - -settings.watchByRegex(/^Direct_Reply_.+/, startEmailInterceptor); - -void startEmailInterceptor(); diff --git a/apps/meteor/app/lib/server/startup/settingsOnLoadSMTP.ts b/apps/meteor/app/lib/server/startup/settingsOnLoadSMTP.ts deleted file mode 100644 index e015fd578d87a..0000000000000 --- a/apps/meteor/app/lib/server/startup/settingsOnLoadSMTP.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { SystemLogger } from '../../../../server/lib/logger/system'; -import { settings } from '../../../settings/server'; - -settings.watchMultiple(['SMTP_Host', 'SMTP_Port', 'SMTP_Username', 'SMTP_Password', 'SMTP_Protocol', 'SMTP_Pool', 'SMTP_IgnoreTLS'], () => { - SystemLogger.info('Updating process.env.MAIL_URL'); - - if (!settings.get('SMTP_Host')) { - delete process.env.MAIL_URL; - return; - } - - process.env.MAIL_URL = `${settings.get('SMTP_Protocol')}://`; - - if (settings.get('SMTP_Username') && settings.get('SMTP_Password')) { - process.env.MAIL_URL += `${encodeURIComponent(settings.get('SMTP_Username'))}:${encodeURIComponent(settings.get('SMTP_Password'))}@`; - } - - process.env.MAIL_URL += encodeURIComponent(settings.get('SMTP_Host')); - - if (settings.get('SMTP_Port')) { - process.env.MAIL_URL += `:${parseInt(settings.get('SMTP_Port'))}`; - } - - process.env.MAIL_URL += `?pool=${settings.get('SMTP_Pool')}`; - - if (settings.get('SMTP_Protocol') === 'smtp' && settings.get('SMTP_IgnoreTLS')) { - process.env.MAIL_URL += '&secure=false&ignoreTLS=true'; - } -}); diff --git a/apps/meteor/app/lib/server/startup/settingsOnLoadSiteUrl.ts b/apps/meteor/app/lib/server/startup/settingsOnLoadSiteUrl.ts deleted file mode 100644 index 231e41cd4a104..0000000000000 --- a/apps/meteor/app/lib/server/startup/settingsOnLoadSiteUrl.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { WebAppInternals } from 'meteor/webapp'; - -import { settings } from '../../../settings/server'; - -export let hostname: string; - -settings.watch( - 'Site_Url', - // Needed as WebAppInternals.generateBoilerplate needs to be called in a fiber - Meteor.bindEnvironment((value) => { - if (value == null || value.trim() === '') { - return; - } - let host = value.replace(/\/$/, ''); - // let prefix = ''; - const match = value.match(/([^\/]+\/{2}[^\/]+)(\/.+)/); - if (match != null) { - host = match[1]; - // prefix = match[2].replace(/\/$/, ''); - } - (global as any).__meteor_runtime_config__.ROOT_URL = value; - - if (Meteor.absoluteUrl.defaultOptions?.rootUrl) { - Meteor.absoluteUrl.defaultOptions.rootUrl = value; - } - - hostname = host.replace(/^https?:\/\//, ''); - process.env.MOBILE_ROOT_URL = host; - process.env.MOBILE_DDP_URL = host; - if (typeof WebAppInternals !== 'undefined' && WebAppInternals.generateBoilerplate) { - return WebAppInternals.generateBoilerplate(); - } - }), -); diff --git a/apps/meteor/server/configuration/cas.ts b/apps/meteor/server/configuration/cas.ts index 300320dda3fa7..85d4bf88e1872 100644 --- a/apps/meteor/server/configuration/cas.ts +++ b/apps/meteor/server/configuration/cas.ts @@ -3,12 +3,12 @@ import debounce from 'lodash.debounce'; import { RoutePolicy } from 'meteor/routepolicy'; import { WebApp } from 'meteor/webapp'; -import { settings } from '../../app/settings/server/cached'; +import type { ICachedSettings } from '../../app/settings/server/CachedSettings'; import { loginHandlerCAS } from '../lib/cas/loginHandler'; import { middlewareCAS } from '../lib/cas/middleware'; import { updateCasServices } from '../lib/cas/updateCasService'; -export async function configureCAS() { +export async function configureCAS(settings: ICachedSettings) { const _updateCasServices = debounce(updateCasServices, 2000); settings.watchByRegex(/^CAS_.+/, async () => { diff --git a/apps/meteor/server/configuration/configureAssets.ts b/apps/meteor/server/configuration/configureAssets.ts new file mode 100644 index 0000000000000..c64dd4b5edaaf --- /dev/null +++ b/apps/meteor/server/configuration/configureAssets.ts @@ -0,0 +1,6 @@ +import { RocketChatAssets } from '../../app/assets/server'; +import type { ICachedSettings } from '../../app/settings/server/CachedSettings'; + +export async function configureAssets(settings: ICachedSettings): Promise { + settings.watchByRegex(/^Assets_/, (key, value) => RocketChatAssets.processAsset(key, value)); +} diff --git a/apps/meteor/server/configuration/configureBoilerplate.ts b/apps/meteor/server/configuration/configureBoilerplate.ts new file mode 100644 index 0000000000000..dbc5bd5e2ba8c --- /dev/null +++ b/apps/meteor/server/configuration/configureBoilerplate.ts @@ -0,0 +1,35 @@ +import { Meteor } from 'meteor/meteor'; +import { WebAppInternals } from 'meteor/webapp'; + +import type { ICachedSettings } from '../../app/settings/server/CachedSettings'; + +export function configureBoilerplate(settings: ICachedSettings): void { + settings.watch( + 'Site_Url', + // Needed as WebAppInternals.generateBoilerplate needs to be called in a fiber + Meteor.bindEnvironment((value) => { + if (value == null || value.trim() === '') { + return; + } + let host = value.replace(/\/$/, ''); + // let prefix = ''; + const match = value.match(/([^\/]+\/{2}[^\/]+)(\/.+)/); + if (match != null) { + host = match[1]; + // prefix = match[2].replace(/\/$/, ''); + } + (global as any).__meteor_runtime_config__.ROOT_URL = value; + + if (Meteor.absoluteUrl.defaultOptions?.rootUrl) { + Meteor.absoluteUrl.defaultOptions.rootUrl = value; + } + + // hostname = host.replace(/^https?:\/\//, ''); + process.env.MOBILE_ROOT_URL = host; + process.env.MOBILE_DDP_URL = host; + if (typeof WebAppInternals !== 'undefined' && WebAppInternals.generateBoilerplate) { + return WebAppInternals.generateBoilerplate(); + } + }), + ); +} diff --git a/apps/meteor/server/configuration/configureCDN.ts b/apps/meteor/server/configuration/configureCDN.ts new file mode 100644 index 0000000000000..b6d1aed4ae73a --- /dev/null +++ b/apps/meteor/server/configuration/configureCDN.ts @@ -0,0 +1,32 @@ +import { WebAppInternals } from 'meteor/webapp'; + +import type { ICachedSettings } from '../../app/settings/server/CachedSettings'; + +export async function configureCDN(settings: ICachedSettings): Promise { + settings.change('CDN_PREFIX', (value) => { + const useForAll = settings.get('CDN_PREFIX_ALL'); + if (value && useForAll) { + WebAppInternals.setBundledJsCssPrefix(value); + } + }); + + settings.change('CDN_JSCSS_PREFIX', (value) => { + const useForAll = settings.get('CDN_PREFIX_ALL'); + if (value && typeof value === 'string' && value.trim() && !useForAll) { + WebAppInternals.setBundledJsCssPrefix(value); + } + }); + + const cdnValue = settings.get('CDN_PREFIX'); + const useForAll = settings.get('CDN_PREFIX_ALL'); + const cdnJsCss = settings.get('CDN_JSCSS_PREFIX'); + if (cdnValue && typeof cdnValue === 'string' && cdnValue.trim()) { + if (useForAll) { + WebAppInternals.setBundledJsCssPrefix(cdnValue); + return; + } + if (cdnJsCss && typeof cdnJsCss === 'string' && cdnJsCss.trim()) { + WebAppInternals.setBundledJsCssPrefix(cdnJsCss); + } + } +} diff --git a/apps/meteor/server/configuration/configureCORS.ts b/apps/meteor/server/configuration/configureCORS.ts new file mode 100644 index 0000000000000..360d7536468c7 --- /dev/null +++ b/apps/meteor/server/configuration/configureCORS.ts @@ -0,0 +1,11 @@ +import { setCachingVersion, setInlineScriptsAllowed } from '../../app/cors/server/cors'; +import type { ICachedSettings } from '../../app/settings/server/CachedSettings'; + +export async function configureCORS(settings: ICachedSettings): Promise { + settings.watch('Enable_CSP', async (enabled) => { + await setInlineScriptsAllowed(!enabled); + }); + settings.watch('Troubleshoot_Force_Caching_Version', (value) => { + setCachingVersion(value); + }); +} diff --git a/apps/meteor/server/configuration/configureDirectReply.ts b/apps/meteor/server/configuration/configureDirectReply.ts new file mode 100644 index 0000000000000..e7266d10df7eb --- /dev/null +++ b/apps/meteor/server/configuration/configureDirectReply.ts @@ -0,0 +1,45 @@ +import _ from 'underscore'; + +import { DirectReplyIMAPInterceptor, POP3Helper } from '../../app/lib/server/lib/interceptDirectReplyEmails.js'; +import type { ICachedSettings } from '../../app/settings/server/CachedSettings'; +import { logger } from '../features/EmailInbox/logger'; + +export async function configureDirectReply(settings: ICachedSettings): Promise { + let client: DirectReplyIMAPInterceptor | POP3Helper | undefined; + const startEmailInterceptor = _.debounce(async () => { + logger.info('Email Interceptor...'); + const protocol = settings.get('Direct_Reply_Protocol'); + + const isEnabled = + settings.get('Direct_Reply_Enable') && + protocol && + settings.get('Direct_Reply_Host') && + settings.get('Direct_Reply_Port') && + settings.get('Direct_Reply_Username') && + settings.get('Direct_Reply_Password'); + + if (client) { + await client.stop(); + } + + if (!isEnabled) { + logger.info('Email Interceptor Stopped...'); + return; + } + logger.info('Starting Email Interceptor...'); + + if (protocol === 'IMAP') { + client = new DirectReplyIMAPInterceptor(); + await client.start(); + } + + if (protocol === 'POP') { + client = new POP3Helper(settings.get('Direct_Reply_Frequency')); + client.start(); + } + }, 1000); + + settings.watchByRegex(/^Direct_Reply_.+/, startEmailInterceptor); + + void startEmailInterceptor(); +} diff --git a/apps/meteor/app/irc/server/irc.js b/apps/meteor/server/configuration/configureIRC.ts similarity index 61% rename from apps/meteor/app/irc/server/irc.js rename to apps/meteor/server/configuration/configureIRC.ts index 7012e28291343..5cafe42c28760 100644 --- a/apps/meteor/app/irc/server/irc.js +++ b/apps/meteor/server/configuration/configureIRC.ts @@ -1,9 +1,13 @@ import { Meteor } from 'meteor/meteor'; -import Bridge from './irc-bridge'; -import { settings } from '../../settings/server'; +import Bridge from '../../app/irc/server/irc-bridge'; +import type { ICachedSettings } from '../../app/settings/server/CachedSettings'; + +export async function configureIRC(settings: ICachedSettings): Promise { + if (!settings.get('IRC_Enabled')) { + return; + } -if (!!settings.get('IRC_Enabled') === true) { // Normalize the config values const config = { server: { @@ -20,8 +24,5 @@ if (!!settings.get('IRC_Enabled') === true) { }; Meteor.ircBridge = new Bridge(config); - - Meteor.startup(async () => { - await Meteor.ircBridge.init(); - }); + await Meteor.ircBridge.init(); } diff --git a/apps/meteor/server/configuration/configureLogLevel.ts b/apps/meteor/server/configuration/configureLogLevel.ts new file mode 100644 index 0000000000000..b20ea0f07d647 --- /dev/null +++ b/apps/meteor/server/configuration/configureLogLevel.ts @@ -0,0 +1,23 @@ +import { setQueueLimit, logLevel, type LogLevelSetting } from '@rocket.chat/logger'; +import { Settings } from '@rocket.chat/models'; + +import type { ICachedSettings } from '../../app/settings/server/CachedSettings'; + +export async function configureLogLevel(settings: ICachedSettings) { + const LogLevel = await Settings.getValueById('Log_Level'); + if (LogLevel) { + logLevel.emit('changed', LogLevel as LogLevelSetting); + } + + settings.watch('Log_Level', (value) => { + if (value != null) { + logLevel.emit('changed', String(value) as LogLevelSetting); + } + }); + + settings.watch('Log_View_Limit', (value) => { + if (typeof value === 'number') { + setQueueLimit(value); + } + }); +} diff --git a/apps/meteor/server/configuration/configureSMTP.ts b/apps/meteor/server/configuration/configureSMTP.ts new file mode 100644 index 0000000000000..11833eb432545 --- /dev/null +++ b/apps/meteor/server/configuration/configureSMTP.ts @@ -0,0 +1,34 @@ +import type { ICachedSettings } from '../../app/settings/server/CachedSettings'; +import { SystemLogger } from '../lib/logger/system'; + +export function configureSMTP(settings: ICachedSettings): void { + settings.watchMultiple( + ['SMTP_Host', 'SMTP_Port', 'SMTP_Username', 'SMTP_Password', 'SMTP_Protocol', 'SMTP_Pool', 'SMTP_IgnoreTLS'], + () => { + SystemLogger.info('Updating process.env.MAIL_URL'); + + if (!settings.get('SMTP_Host')) { + delete process.env.MAIL_URL; + return; + } + + process.env.MAIL_URL = `${settings.get('SMTP_Protocol')}://`; + + if (settings.get('SMTP_Username') && settings.get('SMTP_Password')) { + process.env.MAIL_URL += `${encodeURIComponent(settings.get('SMTP_Username'))}:${encodeURIComponent(settings.get('SMTP_Password'))}@`; + } + + process.env.MAIL_URL += encodeURIComponent(settings.get('SMTP_Host')); + + if (settings.get('SMTP_Port')) { + process.env.MAIL_URL += `:${parseInt(settings.get('SMTP_Port'))}`; + } + + process.env.MAIL_URL += `?pool=${settings.get('SMTP_Pool')}`; + + if (settings.get('SMTP_Protocol') === 'smtp' && settings.get('SMTP_IgnoreTLS')) { + process.env.MAIL_URL += '&secure=false&ignoreTLS=true'; + } + }, + ); +} diff --git a/apps/meteor/server/configuration/federation.ts b/apps/meteor/server/configuration/federation.ts new file mode 100644 index 0000000000000..616b266d04195 --- /dev/null +++ b/apps/meteor/server/configuration/federation.ts @@ -0,0 +1,51 @@ +import { FederationKeys } from '@rocket.chat/models'; + +import { STATUS_ENABLED, STATUS_REGISTERING, STATUS_ERROR_REGISTERING, STATUS_DISABLED } from '../../app/federation/server/constants'; +import { updateStatus, updateEnabled, isRegisteringOrEnabled } from '../../app/federation/server/functions/helpers'; +import { enableCallbacks, disableCallbacks } from '../../app/federation/server/lib/callbacks'; +import { registerWithHub } from '../../app/federation/server/lib/dns'; +import { getFederationDiscoveryMethod } from '../../app/federation/server/lib/getFederationDiscoveryMethod'; +import { getFederationDomain } from '../../app/federation/server/lib/getFederationDomain'; +import { setupLogger } from '../../app/federation/server/lib/logger'; +import type { ICachedSettings } from '../../app/settings/server/CachedSettings'; + +export function configureFederation(settings: ICachedSettings): void { + const updateSettings = async function (): Promise { + // Get the key pair + + if (getFederationDiscoveryMethod() === 'hub' && !(await isRegisteringOrEnabled())) { + // Register with hub + try { + await updateStatus(STATUS_REGISTERING); + + await registerWithHub(getFederationDomain(), settings.get('Site_Url'), await FederationKeys.getPublicKeyString()); + + await updateStatus(STATUS_ENABLED); + } catch (err) { + // Disable federation + await updateEnabled(false); + + await updateStatus(STATUS_ERROR_REGISTERING); + } + return; + } + await updateStatus(STATUS_ENABLED); + }; + + // Add settings listeners + settings.watch('FEDERATION_Enabled', async function enableOrDisable(value) { + setupLogger.info(`Federation is ${value ? 'enabled' : 'disabled'}`); + + if (value) { + await updateSettings(); + + enableCallbacks(); + } else { + await updateStatus(STATUS_DISABLED); + + disableCallbacks(); + } + }); + + settings.watchMultiple(['FEDERATION_Discovery_Method', 'FEDERATION_Domain'], updateSettings); +} diff --git a/apps/meteor/server/configuration/index.ts b/apps/meteor/server/configuration/index.ts index e81d1a64eda19..4e7ce6de4e925 100644 --- a/apps/meteor/server/configuration/index.ts +++ b/apps/meteor/server/configuration/index.ts @@ -1,11 +1,34 @@ import { configureAccounts } from './accounts_meld'; import { configureCAS } from './cas'; +import { configureAssets } from './configureAssets'; +import { configureBoilerplate } from './configureBoilerplate'; +import { configureCDN } from './configureCDN'; +import { configureCORS } from './configureCORS'; +import { configureDirectReply } from './configureDirectReply'; +import { configureIRC } from './configureIRC'; +import { configureLogLevel } from './configureLogLevel'; +import { configureSMTP } from './configureSMTP'; +import { configureFederation } from './federation'; import { configureLDAP } from './ldap'; import { configureOAuth } from './oauth'; +import { configurePushNotifications } from './pushNotification'; +import type { ICachedSettings } from '../../app/settings/server/CachedSettings'; -export async function configureLoginServices() { - await configureAccounts(); - await configureCAS(); - await configureLDAP(); - await configureOAuth(); +export async function configureServer(settings: ICachedSettings) { + await Promise.all([ + configureLogLevel(settings), + configureAccounts(), + configureCAS(settings), + configureLDAP(settings), + configureOAuth(settings), + configureAssets(settings), + configureCORS(settings), + configureCDN(settings), + configurePushNotifications(settings), + configureBoilerplate(settings), + configureDirectReply(settings), + configureSMTP(settings), + configureFederation(settings), + configureIRC(settings), + ]); } diff --git a/apps/meteor/server/configuration/ldap.ts b/apps/meteor/server/configuration/ldap.ts index f7d8ee9c64c42..f88600b224067 100644 --- a/apps/meteor/server/configuration/ldap.ts +++ b/apps/meteor/server/configuration/ldap.ts @@ -1,10 +1,10 @@ import { LDAP } from '@rocket.chat/core-services'; import { Accounts } from 'meteor/accounts-base'; -import { settings } from '../../app/settings/server'; +import type { ICachedSettings } from '../../app/settings/server/CachedSettings'; import { callbacks } from '../../lib/callbacks'; -export async function configureLDAP() { +export async function configureLDAP(settings: ICachedSettings): Promise { // Register ldap login handler Accounts.registerLoginHandler('ldap', async (loginRequest: Record) => { if (!loginRequest.ldap || !loginRequest.ldapOptions) { diff --git a/apps/meteor/server/configuration/oauth.ts b/apps/meteor/server/configuration/oauth.ts index d79705171a7cf..d384d8dc13835 100644 --- a/apps/meteor/server/configuration/oauth.ts +++ b/apps/meteor/server/configuration/oauth.ts @@ -1,11 +1,11 @@ import debounce from 'lodash.debounce'; -import { settings } from '../../app/settings/server/cached'; +import type { ICachedSettings } from '../../app/settings/server/CachedSettings'; import { initCustomOAuthServices } from '../lib/oauth/initCustomOAuthServices'; import { removeOAuthService } from '../lib/oauth/removeOAuthService'; import { updateOAuthServices } from '../lib/oauth/updateOAuthServices'; -export async function configureOAuth() { +export async function configureOAuth(settings: ICachedSettings): Promise { const _updateOAuthServices = debounce(updateOAuthServices, 2000); settings.watchByRegex(/^Accounts_OAuth_.+/, () => { return _updateOAuthServices(); diff --git a/apps/meteor/server/configuration/pushNotification.ts b/apps/meteor/server/configuration/pushNotification.ts new file mode 100644 index 0000000000000..2bf870de4a223 --- /dev/null +++ b/apps/meteor/server/configuration/pushNotification.ts @@ -0,0 +1,71 @@ +import { getWorkspaceAccessToken } from '../../app/cloud/server'; +import { Push } from '../../app/push/server'; +import type { ICachedSettings } from '../../app/settings/server/CachedSettings'; + +export async function configurePushNotifications(settings: ICachedSettings): Promise { + settings.watch('Push_enable', async (enabled) => { + if (!enabled) { + return; + } + const gateways = + settings.get('Push_enable_gateway') && settings.get('Register_Server') && settings.get('Cloud_Service_Agree_PrivacyTerms') + ? settings.get('Push_gateway').split('\n') + : undefined; + + let apn: + | { + passphrase: string; + key: string; + cert: string; + gateway?: string; + } + | undefined; + let gcm: + | { + apiKey: string; + projectNumber: string; + } + | undefined; + + if (!gateways) { + gcm = { + apiKey: settings.get('Push_gcm_api_key'), + projectNumber: settings.get('Push_gcm_project_number'), + }; + + apn = { + passphrase: settings.get('Push_apn_passphrase'), + key: settings.get('Push_apn_key'), + cert: settings.get('Push_apn_cert'), + }; + + if (settings.get('Push_production') !== true) { + apn = { + passphrase: settings.get('Push_apn_dev_passphrase'), + key: settings.get('Push_apn_dev_key'), + cert: settings.get('Push_apn_dev_cert'), + gateway: 'gateway.sandbox.push.apple.com', + }; + } + + if (!apn.key || apn.key.trim() === '' || !apn.cert || apn.cert.trim() === '') { + apn = undefined; + } + + if (!gcm.apiKey || gcm.apiKey.trim() === '' || !gcm.projectNumber || gcm.projectNumber.trim() === '') { + gcm = undefined; + } + } + + Push.configure({ + apn, + gcm, + production: settings.get('Push_production'), + gateways, + uniqueId: settings.get('uniqueID'), + async getAuthorization() { + return `Bearer ${await getWorkspaceAccessToken()}`; + }, + }); + }); +} diff --git a/apps/meteor/server/configureLogLevel.ts b/apps/meteor/server/configureLogLevel.ts deleted file mode 100644 index 7320eea97ded4..0000000000000 --- a/apps/meteor/server/configureLogLevel.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { LogLevelSetting } from '@rocket.chat/logger'; -import { logLevel } from '@rocket.chat/logger'; -import { Settings } from '@rocket.chat/models'; - -export const configureLogLevel = async (): Promise => { - const LogLevel = await Settings.getValueById('Log_Level'); - if (LogLevel) { - logLevel.emit('changed', LogLevel as LogLevelSetting); - } -}; diff --git a/apps/meteor/server/lib/logger/startup.ts b/apps/meteor/server/lib/logger/startup.ts deleted file mode 100644 index 942bed95a9fb8..0000000000000 --- a/apps/meteor/server/lib/logger/startup.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { setQueueLimit, logLevel, type LogLevelSetting } from '@rocket.chat/logger'; - -import { settings } from '../../../app/settings/server'; - -settings.watch('Log_Level', (value) => { - if (value != null) { - logLevel.emit('changed', String(value) as LogLevelSetting); - } -}); - -settings.watch('Log_View_Limit', (value) => { - if (typeof value === 'number') { - setQueueLimit(value); - } -}); diff --git a/apps/meteor/server/lib/pushConfig.ts b/apps/meteor/server/lib/pushConfig.ts index 14f8c6b38ef32..62cd6a4bbc68c 100644 --- a/apps/meteor/server/lib/pushConfig.ts +++ b/apps/meteor/server/lib/pushConfig.ts @@ -5,7 +5,6 @@ import { Meteor } from 'meteor/meteor'; import { i18n } from './i18n'; import { hasPermissionAsync } from '../../app/authorization/server/functions/hasPermission'; -import { getWorkspaceAccessToken } from '../../app/cloud/server'; import { RateLimiter } from '../../app/lib/server/lib'; import { Push } from '../../app/push/server'; import { settings } from '../../app/settings/server'; @@ -70,69 +69,3 @@ Meteor.methods({ RateLimiter.limitMethod('push_test', 1, 1000, { userId: () => true, }); - -settings.watch('Push_enable', async (enabled) => { - if (!enabled) { - return; - } - const gateways = - settings.get('Push_enable_gateway') && settings.get('Register_Server') && settings.get('Cloud_Service_Agree_PrivacyTerms') - ? settings.get('Push_gateway').split('\n') - : undefined; - - let apn: - | { - passphrase: string; - key: string; - cert: string; - gateway?: string; - } - | undefined; - let gcm: - | { - apiKey: string; - projectNumber: string; - } - | undefined; - - if (!gateways) { - gcm = { - apiKey: settings.get('Push_gcm_api_key'), - projectNumber: settings.get('Push_gcm_project_number'), - }; - - apn = { - passphrase: settings.get('Push_apn_passphrase'), - key: settings.get('Push_apn_key'), - cert: settings.get('Push_apn_cert'), - }; - - if (settings.get('Push_production') !== true) { - apn = { - passphrase: settings.get('Push_apn_dev_passphrase'), - key: settings.get('Push_apn_dev_key'), - cert: settings.get('Push_apn_dev_cert'), - gateway: 'gateway.sandbox.push.apple.com', - }; - } - - if (!apn.key || apn.key.trim() === '' || !apn.cert || apn.cert.trim() === '') { - apn = undefined; - } - - if (!gcm.apiKey || gcm.apiKey.trim() === '' || !gcm.projectNumber || gcm.projectNumber.trim() === '') { - gcm = undefined; - } - } - - Push.configure({ - apn, - gcm, - production: settings.get('Push_production'), - gateways, - uniqueId: settings.get('uniqueID'), - async getAuthorization() { - return `Bearer ${await getWorkspaceAccessToken()}`; - }, - }); -}); diff --git a/apps/meteor/server/main.ts b/apps/meteor/server/main.ts index 0a3b164033b94..e2bfcda554737 100644 --- a/apps/meteor/server/main.ts +++ b/apps/meteor/server/main.ts @@ -1,16 +1,16 @@ import './tracing'; import './models'; + /** * ./settings uses top level await, in theory the settings creation * and the startup should be done in parallel */ import './settings'; -import '../app/settings/server'; -import { configureLoginServices } from './configuration'; -import { configureLogLevel } from './configureLogLevel'; +import { configureServer } from './configuration'; import { registerServices } from './services/startup'; import { startup } from './startup'; +import { settings } from '../app/settings/server'; import { startLicense } from '../ee/app/license/server/startup'; import { registerEEBroker } from '../ee/server'; import { startFederationService } from '../ee/server/startup/services'; @@ -20,13 +20,12 @@ import '../app/lib/server/startup'; import './importPackages'; import './methods'; import './publications'; -import './lib/logger/startup'; import '../lib/oauthRedirectUriServer'; import './lib/pushConfig'; import './features/EmailInbox/index'; -await Promise.all([configureLogLevel(), registerServices(), registerEEBroker(), startup()]); +await Promise.all([configureServer(settings), registerServices(), registerEEBroker(), startup()]); await startLicense(); -await Promise.all([configureLoginServices(), startFederationService()]); +await Promise.all([startFederationService()]);