From 579e22a45e525cf10b4474daf9ad3fdd933932dd Mon Sep 17 00:00:00 2001 From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:16:18 +0100 Subject: [PATCH] fix: use ACL username and decode credentials in Redis URL parsing (#2434) * fix: use ACL username and decode credentials in Redis URL parsing * fix: pass family and TLS options to the collab app module --- .../collaboration/collaboration.gateway.ts | 1 + .../collaboration/server/collab-app.module.ts | 15 +++++++++++-- apps/server/src/common/helpers/utils.ts | 21 +++++++++++++++++-- .../src/integrations/queue/queue.module.ts | 1 + .../redis/redis-config.service.ts | 1 + .../integrations/throttle/throttle.module.ts | 1 + 6 files changed, 36 insertions(+), 4 deletions(-) diff --git a/apps/server/src/collaboration/collaboration.gateway.ts b/apps/server/src/collaboration/collaboration.gateway.ts index 05536664e..254b8d430 100644 --- a/apps/server/src/collaboration/collaboration.gateway.ts +++ b/apps/server/src/collaboration/collaboration.gateway.ts @@ -63,6 +63,7 @@ export class CollaborationGateway { redis: new RedisClient({ host: this.redisConfig.host, port: this.redisConfig.port, + username: this.redisConfig.username, password: this.redisConfig.password, db: this.redisConfig.db, family: this.redisConfig.family, diff --git a/apps/server/src/collaboration/server/collab-app.module.ts b/apps/server/src/collaboration/server/collab-app.module.ts index 85738d1cb..da48bfb94 100644 --- a/apps/server/src/collaboration/server/collab-app.module.ts +++ b/apps/server/src/collaboration/server/collab-app.module.ts @@ -14,7 +14,8 @@ import { RedisModule } from '@nestjs-labs/nestjs-ioredis'; import { RedisConfigService } from '../../integrations/redis/redis-config.service'; import { CaslModule } from '../../core/casl/casl.module'; import { CacheModule } from '@nestjs/cache-manager'; -import KeyvRedis from '@keyv/redis'; +import KeyvRedis, { defaultReconnectStrategy } from '@keyv/redis'; +import { parseRedisUrl } from '../../common/helpers'; @Module({ imports: [ @@ -33,10 +34,20 @@ import KeyvRedis from '@keyv/redis'; isGlobal: true, useFactory: async (environmentService: EnvironmentService) => { const redisUrl = environmentService.getRedisUrl(); + const { family, tls } = parseRedisUrl(redisUrl); return { ttl: 5 * 1000, - stores: [new KeyvRedis(redisUrl)], + stores: [ + new KeyvRedis({ + url: redisUrl, + socket: { + family, + reconnectStrategy: defaultReconnectStrategy, + ...tls, + }, + }), + ], }; }, inject: [EnvironmentService], diff --git a/apps/server/src/common/helpers/utils.ts b/apps/server/src/common/helpers/utils.ts index 100d55d92..aebe05385 100644 --- a/apps/server/src/common/helpers/utils.ts +++ b/apps/server/src/common/helpers/utils.ts @@ -28,6 +28,7 @@ export type RedisConfig = { host: string; port: number; db: number; + username?: string; password?: string; family?: number; tls?: { rejectUnauthorized?: boolean }; @@ -36,7 +37,15 @@ export type RedisConfig = { export function parseRedisUrl(redisUrl: string): RedisConfig { // format - redis[s]://[[username][:password]@][host][:port][/db-number][?family=4|6][&rejectUnauthorized=false] const url = new URL(redisUrl); - const { hostname, port, password, pathname, protocol, searchParams } = url; + const { + hostname, + port, + username, + password, + pathname, + protocol, + searchParams, + } = url; const portInt = port ? parseInt(port, 10) : 6379; let db: number = 0; @@ -62,7 +71,15 @@ export function parseRedisUrl(redisUrl: string): RedisConfig { : {} : undefined; - return { host: hostname, port: portInt, password: password || undefined, db, family, tls }; + return { + host: hostname, + port: portInt, + username: username ? decodeURIComponent(username) : undefined, + password: password ? decodeURIComponent(password) : undefined, + db, + family, + tls, + }; } export function createRetryStrategy() { diff --git a/apps/server/src/integrations/queue/queue.module.ts b/apps/server/src/integrations/queue/queue.module.ts index fcb317dbf..0c2c3c908 100644 --- a/apps/server/src/integrations/queue/queue.module.ts +++ b/apps/server/src/integrations/queue/queue.module.ts @@ -15,6 +15,7 @@ import { GeneralQueueProcessor } from './processors/general-queue.processor'; connection: { host: redisConfig.host, port: redisConfig.port, + username: redisConfig.username, password: redisConfig.password, db: redisConfig.db, family: redisConfig.family, diff --git a/apps/server/src/integrations/redis/redis-config.service.ts b/apps/server/src/integrations/redis/redis-config.service.ts index 7f3e90174..c613e0389 100644 --- a/apps/server/src/integrations/redis/redis-config.service.ts +++ b/apps/server/src/integrations/redis/redis-config.service.ts @@ -16,6 +16,7 @@ export class RedisConfigService implements RedisOptionsFactory { config: { host: redisConfig.host, port: redisConfig.port, + username: redisConfig.username, password: redisConfig.password, db: redisConfig.db, family: redisConfig.family, diff --git a/apps/server/src/integrations/throttle/throttle.module.ts b/apps/server/src/integrations/throttle/throttle.module.ts index e22eddc75..4c9537526 100644 --- a/apps/server/src/integrations/throttle/throttle.module.ts +++ b/apps/server/src/integrations/throttle/throttle.module.ts @@ -33,6 +33,7 @@ import Redis from 'ioredis'; new Redis({ host: redisConfig.host, port: redisConfig.port, + username: redisConfig.username, password: redisConfig.password, db: redisConfig.db, family: redisConfig.family,