From f30be1af26361eee1a111441a4a4bf280883e27c Mon Sep 17 00:00:00 2001 From: Antoine Arlaud Date: Wed, 27 Mar 2024 17:51:15 +0100 Subject: [PATCH] feat: send clientconfig metadata to server --- lib/client/dispatcher/index.ts | 19 ----- lib/client/hooks/startup/processHooks.ts | 3 +- lib/client/index.ts | 2 + lib/client/socket.ts | 1 + lib/client/socketHandlers/openHandler.ts | 4 +- lib/client/types/client.ts | 15 ++++ lib/client/utils/configHelpers.ts | 48 ++++++++++++ lib/server/utils/socket.ts | 1 + test/functional/server-client.test.ts | 13 ++++ test/unit/configHelper.test.ts | 98 ++++++++++++++++++++++++ 10 files changed, 183 insertions(+), 21 deletions(-) create mode 100644 lib/client/utils/configHelpers.ts create mode 100644 test/unit/configHelper.test.ts diff --git a/lib/client/dispatcher/index.ts b/lib/client/dispatcher/index.ts index 474762c54..0786ef3fe 100644 --- a/lib/client/dispatcher/index.ts +++ b/lib/client/dispatcher/index.ts @@ -1,27 +1,8 @@ import { log as logger } from '../../logs/logger'; -import { Config } from '../types/config'; import { hashToken } from '../../common/utils/token'; import { HttpDispatcherServiceClient } from './client/api'; import { ServerId, getServerIdFromDispatcher } from './dispatcher-service'; -export function highAvailabilityModeEnabled(config: any): boolean { - // high availability mode is disabled per default - let highAvailabilityModeEnabled = false; - - const highAvailabilityModeEnabledValue = (config as Config) - .BROKER_HA_MODE_ENABLED; - - if (typeof highAvailabilityModeEnabledValue !== 'undefined') { - highAvailabilityModeEnabled = - highAvailabilityModeEnabledValue.toLowerCase() === 'true' || - highAvailabilityModeEnabledValue.toLowerCase() === 'yes'; - } - - logger.info({ enabled: highAvailabilityModeEnabled }, 'checking for HA mode'); - - return highAvailabilityModeEnabled; -} - export async function getServerId( config: any, brokerToken: string, diff --git a/lib/client/hooks/startup/processHooks.ts b/lib/client/hooks/startup/processHooks.ts index adaaff277..1d258f2e8 100644 --- a/lib/client/hooks/startup/processHooks.ts +++ b/lib/client/hooks/startup/processHooks.ts @@ -1,10 +1,11 @@ -import { getServerId, highAvailabilityModeEnabled } from '../../dispatcher'; +import { getServerId } from '../../dispatcher'; import { log as logger } from '../../../logs/logger'; import { executePreflightChecks, preflightChecksEnabled } from '../../checks'; import { commitSigningEnabled, commitSigningFilterRules } from '../../scm'; import { HookResults } from '../../types/client'; import { CheckResult } from '../../checks/types'; import { ClientOpts } from '../../../common/types/options'; +import { highAvailabilityModeEnabled } from '../../utils/configHelpers'; export const processStartUpHooks = async ( clientOpts: ClientOpts, diff --git a/lib/client/index.ts b/lib/client/index.ts index e9646b485..b4ce2b723 100644 --- a/lib/client/index.ts +++ b/lib/client/index.ts @@ -17,6 +17,7 @@ import { isWebsocketConnOpen } from './utils/socketHelpers'; import { loadAllFilters } from '../common/filter/filtersAsync'; import { ClientOpts, LoadedClientOpts } from '../common/types/options'; import { websocketConnectionSelectorMiddleware } from './routesHandler/websocketConnectionMiddlewares'; +import { getClientConfigMetadata } from './utils/configHelpers'; process.on('uncaughtException', (error) => { if (error.message == 'read ECONNRESET') { @@ -59,6 +60,7 @@ export const main = async (clientOpts: ClientOpts) => { filters: clientOpts.filters, preflightChecks: hookResults.preflightCheckResults, version, + clientConfig: getClientConfigMetadata(clientOpts.config), }; let websocketConnections: WebSocketConnection[] = []; diff --git a/lib/client/socket.ts b/lib/client/socket.ts index 30b54c98d..79deb22a1 100644 --- a/lib/client/socket.ts +++ b/lib/client/socket.ts @@ -98,6 +98,7 @@ export const createWebSocket = ( websocket.serverId = serverId || ''; websocket.friendlyName = identifyingMetadata.friendlyName || ''; } + websocket.clientConfig = identifyingMetadata.clientConfig; logger.info( { diff --git a/lib/client/socketHandlers/openHandler.ts b/lib/client/socketHandlers/openHandler.ts index cfb0f0c86..6c00e8f91 100644 --- a/lib/client/socketHandlers/openHandler.ts +++ b/lib/client/socketHandlers/openHandler.ts @@ -16,6 +16,8 @@ export const openHandler = ( : '****', preflightChecks: identifyingMetadata.preflightChecks, version: identifyingMetadata.version, + clientConfig: identifyingMetadata.clientConfig, + filters: identifyingMetadata.filters ?? {}, }; if (clientOps.config.universalBrokerEnabled) { metadata['supportedIntegrationType'] = @@ -36,7 +38,7 @@ export const openHandler = ( token: clientOps.config.universalBrokerEnabled ? identifyingMetadata.identifier : clientOps.config.brokerToken, - metadata: identifyingMetadata, + metadata: metadata, }; io.send('identify', clientData); }; diff --git a/lib/client/types/client.ts b/lib/client/types/client.ts index 6ac2d2fb4..9f074fe9b 100644 --- a/lib/client/types/client.ts +++ b/lib/client/types/client.ts @@ -5,6 +5,19 @@ export interface HookResults { preflightCheckResults?: CheckResult[]; } +export interface ConfigMetadata { + haMode: boolean; + debugMode: boolean; + bodyLogMode: boolean; + credPooling: boolean; + privateCa: boolean; + tlsReject: boolean; + proxy: boolean; + customAccept: boolean; + insecureDownstream: boolean; + universalBroker: boolean; +} + export interface IdentifyingMetadata { capabilities: string[]; clientId: string; @@ -17,6 +30,7 @@ export interface IdentifyingMetadata { socketVersion?: number; socketType?: string; friendlyName?: string; + clientConfig: ConfigMetadata; } export interface ConnectionMetadata { @@ -40,6 +54,7 @@ export interface WebSocketConnection { socketVersion?: any; socketType?: string; identifier?: string; + clientConfig?: any; friendlyName?: string; supportedIntegrationType: string; serverId: string; diff --git a/lib/client/utils/configHelpers.ts b/lib/client/utils/configHelpers.ts new file mode 100644 index 000000000..fe3985267 --- /dev/null +++ b/lib/client/utils/configHelpers.ts @@ -0,0 +1,48 @@ +import { ConfigMetadata } from '../types/client'; +import { Config } from '../types/config'; +import { log as logger } from '../../logs/logger'; + +export const getClientConfigMetadata = ( + clientConfig: Record, +): ConfigMetadata => { + const configMetadata: ConfigMetadata = { + haMode: highAvailabilityModeEnabled(clientConfig), + debugMode: clientConfig.logLevel === 'debug' ? true : false, + bodyLogMode: clientConfig.logEnableBody ? true : false, + credPooling: isCredPoolingUsed(clientConfig), + privateCa: clientConfig.nodeExtraCaCert ? true : false, + tlsReject: + parseInt(clientConfig.nodeTlsRejectUnauthorized) === 0 ? true : false, + proxy: clientConfig.httpProxy || clientConfig.httpsProxy ? true : false, + customAccept: clientConfig.accept ? true : false, + insecureDownstream: clientConfig.insecureDownstream ? true : false, + universalBroker: clientConfig.universalBrokerEnabled ? true : false, + }; + return configMetadata; +}; + +const isCredPoolingUsed = (config: Record): boolean => { + for (const key in config) { + if (config.hasOwnProperty(key) && key.includes('_POOL')) { + return true; // Found a key containing '_POOL' + } + } + return false; +}; + +export function highAvailabilityModeEnabled(config: any): boolean { + // high availability mode is disabled per default + let highAvailabilityModeEnabled = false; + const highAvailabilityModeEnabledValue = (config as Config) + .BROKER_HA_MODE_ENABLED; + + if (typeof highAvailabilityModeEnabledValue !== 'undefined') { + highAvailabilityModeEnabled = + highAvailabilityModeEnabledValue.toLowerCase() === 'true' || + highAvailabilityModeEnabledValue.toLowerCase() === 'yes'; + } + + logger.info({ enabled: highAvailabilityModeEnabled }, 'checking for HA mode'); + + return highAvailabilityModeEnabled; +} diff --git a/lib/server/utils/socket.ts b/lib/server/utils/socket.ts index be71abe87..fe6e6bd8c 100644 --- a/lib/server/utils/socket.ts +++ b/lib/server/utils/socket.ts @@ -4,5 +4,6 @@ export const metadataWithoutFilters = (metadataWithFilters) => { clientId: metadataWithFilters.clientId, preflightChecks: metadataWithFilters.preflightChecks, version: metadataWithFilters.version, + clientConfig: metadataWithFilters.clientConfig ?? {}, }; }; diff --git a/test/functional/server-client.test.ts b/test/functional/server-client.test.ts index 067d8afc3..f00b4f895 100644 --- a/test/functional/server-client.test.ts +++ b/test/functional/server-client.test.ts @@ -58,6 +58,19 @@ describe('proxy requests originating from behind the broker server', () => { filters: expect.any(Object), clientId: expect.any(String), version: version, + clientConfig: { + bodyLogMode: false, + credPooling: true, //client sets a PASSWORD_POOL + customAccept: true, + debugMode: false, + haMode: false, + insecureDownstream: false, + privateCa: false, + proxy: false, + tlsReject: false, + universalBroker: false, + }, + identifier: '****', }); }); diff --git a/test/unit/configHelper.test.ts b/test/unit/configHelper.test.ts new file mode 100644 index 000000000..fd7a7a18f --- /dev/null +++ b/test/unit/configHelper.test.ts @@ -0,0 +1,98 @@ +import { getClientConfigMetadata } from '../../lib/client/utils/configHelpers'; +import { getConfig, loadBrokerConfig } from '../../lib/common/config/config'; +import { LoadedClientOpts } from '../../lib/common/types/options'; + +describe('config', () => { + beforeAll(() => { + loadBrokerConfig(); + }); + afterEach(() => { + delete process.env.LOG_LEVEL; + delete process.env.LOG_ENABLE_BODY; + delete process.env.GITHUB_TOKEN_POOL; + delete process.env.INSECURE_DOWNSTREAM; + delete process.env.BROKER_HA_MODE_ENABLED; + delete process.env.HTTP_PROXY; + delete process.env.NODE_EXTRA_CA_CERT; + delete process.env.ACCEPT; + delete process.env.NODE_TLS_REJECT_UNAUTHORIZED; + delete process.env.UNIVERSAL_BROKER_ENABLED; + }); + + afterAll(() => { + delete process.env.LOG_LEVEL; + delete process.env.LOG_ENABLE_BODY; + delete process.env.GITHUB_TOKEN_POOL; + delete process.env.INSECURE_DOWNSTREAM; + delete process.env.BROKER_HA_MODE_ENABLED; + delete process.env.HTTP_PROXY; + delete process.env.NODE_EXTRA_CA_CERT; + delete process.env.ACCEPT; + delete process.env.NODE_TLS_REJECT_UNAUTHORIZED; + delete process.env.UNIVERSAL_BROKER_ENABLED; + }); + it('everything is false for empty config', () => { + loadBrokerConfig(); + const config = getConfig(); + expect(getClientConfigMetadata(config as LoadedClientOpts)).toEqual({ + bodyLogMode: false, + credPooling: false, + customAccept: false, + debugMode: false, + haMode: false, + privateCa: false, + proxy: false, + tlsReject: false, + insecureDownstream: false, + universalBroker: false, + }); + }); + + it('everything is true for everything enabled in config', () => { + process.env.LOG_LEVEL = 'debug'; + process.env.LOG_ENABLE_BODY = 'true'; + process.env.GITHUB_TOKEN_POOL = '123,456'; + process.env.INSECURE_DOWNSTREAM = 'true_but_truly_value_does_not_matter'; + process.env.BROKER_HA_MODE_ENABLED = 'true'; + process.env.HTTP_PROXY = 'http://myproxy'; + process.env.NODE_EXTRA_CA_CERT = 'my/path'; + process.env.ACCEPT = 'my/path'; + process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; + process.env.UNIVERSAL_BROKER_ENABLED = 'true'; + loadBrokerConfig(); + const config = getConfig(); + expect(getClientConfigMetadata(config as LoadedClientOpts)).toEqual({ + bodyLogMode: true, + credPooling: true, + customAccept: true, + debugMode: true, + haMode: true, + privateCa: true, + proxy: true, + tlsReject: true, + insecureDownstream: true, + universalBroker: true, + }); + }); + + it('everything is false for everything disabled in config', () => { + process.env.LOG_LEVEL = 'info'; + process.env.GITHUB_TOKEN = '456'; + process.env.BROKER_HA_MODE_ENABLED = 'false'; + process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1'; + loadBrokerConfig(); + const config = getConfig(); + expect(getClientConfigMetadata(config as LoadedClientOpts)).toEqual({ + bodyLogMode: false, + credPooling: false, + customAccept: false, + debugMode: false, + haMode: false, + privateCa: false, + proxy: false, + tlsReject: false, + insecureDownstream: false, + universalBroker: false, + }); + }); +});