mirror of
https://github.com/docmost/docmost.git
synced 2026-08-24 09:22:16 +10:00
fix: handle empty password, missing port, and TLS in Redis URL parsing (#2021)
* fix: handle empty password, missing port, and TLS in Redis URL parsing --------- Co-authored-by: Philipinho <16838612+Philipinho@users.noreply.github.com>
This commit is contained in:
co-authored by
Philipinho
parent
8913d20aa0
commit
8c2c49ea6d
@@ -22,7 +22,8 @@ import { TelemetryModule } from './integrations/telemetry/telemetry.module';
|
|||||||
import { RedisModule } from '@nestjs-labs/nestjs-ioredis';
|
import { RedisModule } from '@nestjs-labs/nestjs-ioredis';
|
||||||
import { RedisConfigService } from './integrations/redis/redis-config.service';
|
import { RedisConfigService } from './integrations/redis/redis-config.service';
|
||||||
import { CacheModule } from '@nestjs/cache-manager';
|
import { CacheModule } from '@nestjs/cache-manager';
|
||||||
import KeyvRedis from '@keyv/redis';
|
import KeyvRedis, { defaultReconnectStrategy } from '@keyv/redis';
|
||||||
|
import { parseRedisUrl } from './common/helpers';
|
||||||
import { LoggerModule } from './common/logger/logger.module';
|
import { LoggerModule } from './common/logger/logger.module';
|
||||||
import { ClsModule } from 'nestjs-cls';
|
import { ClsModule } from 'nestjs-cls';
|
||||||
import { NoopAuditModule } from './integrations/audit/audit.module';
|
import { NoopAuditModule } from './integrations/audit/audit.module';
|
||||||
@@ -62,10 +63,20 @@ try {
|
|||||||
isGlobal: true,
|
isGlobal: true,
|
||||||
useFactory: async (environmentService: EnvironmentService) => {
|
useFactory: async (environmentService: EnvironmentService) => {
|
||||||
const redisUrl = environmentService.getRedisUrl();
|
const redisUrl = environmentService.getRedisUrl();
|
||||||
|
const { family, tls } = parseRedisUrl(redisUrl);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ttl: 5 * 1000,
|
ttl: 5 * 1000,
|
||||||
stores: [new KeyvRedis(redisUrl)],
|
stores: [
|
||||||
|
new KeyvRedis({
|
||||||
|
url: redisUrl,
|
||||||
|
socket: {
|
||||||
|
family,
|
||||||
|
reconnectStrategy: defaultReconnectStrategy,
|
||||||
|
...tls,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
inject: [EnvironmentService],
|
inject: [EnvironmentService],
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ export class CollaborationGateway {
|
|||||||
password: this.redisConfig.password,
|
password: this.redisConfig.password,
|
||||||
db: this.redisConfig.db,
|
db: this.redisConfig.db,
|
||||||
family: this.redisConfig.family,
|
family: this.redisConfig.family,
|
||||||
|
tls: this.redisConfig.tls,
|
||||||
retryStrategy: createRetryStrategy(),
|
retryStrategy: createRetryStrategy(),
|
||||||
}),
|
}),
|
||||||
serverId: `collab-${os?.hostname()}-${nanoid(10)}`,
|
serverId: `collab-${os?.hostname()}-${nanoid(10)}`,
|
||||||
|
|||||||
@@ -30,13 +30,14 @@ export type RedisConfig = {
|
|||||||
db: number;
|
db: number;
|
||||||
password?: string;
|
password?: string;
|
||||||
family?: number;
|
family?: number;
|
||||||
|
tls?: { rejectUnauthorized?: boolean };
|
||||||
};
|
};
|
||||||
|
|
||||||
export function parseRedisUrl(redisUrl: string): RedisConfig {
|
export function parseRedisUrl(redisUrl: string): RedisConfig {
|
||||||
// format - redis[s]://[[username][:password]@][host][:port][/db-number][?family=4|6]
|
// format - redis[s]://[[username][:password]@][host][:port][/db-number][?family=4|6][&rejectUnauthorized=false]
|
||||||
const url = new URL(redisUrl);
|
const url = new URL(redisUrl);
|
||||||
const { hostname, port, password, pathname, searchParams } = url;
|
const { hostname, port, password, pathname, protocol, searchParams } = url;
|
||||||
const portInt = parseInt(port, 10);
|
const portInt = port ? parseInt(port, 10) : 6379;
|
||||||
|
|
||||||
let db: number = 0;
|
let db: number = 0;
|
||||||
// extract db value if present
|
// extract db value if present
|
||||||
@@ -54,7 +55,14 @@ export function parseRedisUrl(redisUrl: string): RedisConfig {
|
|||||||
family = parseInt(familyParam, 10);
|
family = parseInt(familyParam, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { host: hostname, port: portInt, password, db, family };
|
const tls =
|
||||||
|
protocol === 'rediss:'
|
||||||
|
? searchParams.get('rejectUnauthorized') === 'false'
|
||||||
|
? { rejectUnauthorized: false }
|
||||||
|
: {}
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
return { host: hostname, port: portInt, password: password || undefined, db, family, tls };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createRetryStrategy() {
|
export function createRetryStrategy() {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
import { EnvironmentService } from '../environment/environment.service';
|
import { EnvironmentService } from '../environment/environment.service';
|
||||||
import { Redis } from 'ioredis';
|
import { Redis } from 'ioredis';
|
||||||
|
import { parseRedisUrl } from '../../common/helpers';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RedisHealthIndicator {
|
export class RedisHealthIndicator {
|
||||||
@@ -19,8 +20,10 @@ export class RedisHealthIndicator {
|
|||||||
const indicator = this.healthIndicatorService.check(key);
|
const indicator = this.healthIndicatorService.check(key);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const redis = new Redis(this.environmentService.getRedisUrl(), {
|
const redisUrl = this.environmentService.getRedisUrl();
|
||||||
|
const redis = new Redis(redisUrl, {
|
||||||
maxRetriesPerRequest: 15,
|
maxRetriesPerRequest: 15,
|
||||||
|
tls: parseRedisUrl(redisUrl).tls,
|
||||||
});
|
});
|
||||||
|
|
||||||
await redis.ping();
|
await redis.ping();
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { GeneralQueueProcessor } from './processors/general-queue.processor';
|
|||||||
password: redisConfig.password,
|
password: redisConfig.password,
|
||||||
db: redisConfig.db,
|
db: redisConfig.db,
|
||||||
family: redisConfig.family,
|
family: redisConfig.family,
|
||||||
|
tls: redisConfig.tls,
|
||||||
retryStrategy: createRetryStrategy(),
|
retryStrategy: createRetryStrategy(),
|
||||||
},
|
},
|
||||||
defaultJobOptions: {
|
defaultJobOptions: {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export class RedisConfigService implements RedisOptionsFactory {
|
|||||||
password: redisConfig.password,
|
password: redisConfig.password,
|
||||||
db: redisConfig.db,
|
db: redisConfig.db,
|
||||||
family: redisConfig.family,
|
family: redisConfig.family,
|
||||||
|
tls: redisConfig.tls,
|
||||||
retryStrategy: createRetryStrategy(),
|
retryStrategy: createRetryStrategy(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export class WsRedisIoAdapter extends IoAdapter {
|
|||||||
|
|
||||||
const options: RedisOptions = {
|
const options: RedisOptions = {
|
||||||
family: this.redisConfig.family,
|
family: this.redisConfig.family,
|
||||||
|
tls: this.redisConfig.tls,
|
||||||
retryStrategy: createRetryStrategy(),
|
retryStrategy: createRetryStrategy(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user