diff --git a/backend/src/entities/connection/connection.controller.ts b/backend/src/entities/connection/connection.controller.ts index 9e91d312e..d646cbeb7 100644 --- a/backend/src/entities/connection/connection.controller.ts +++ b/backend/src/entities/connection/connection.controller.ts @@ -83,6 +83,7 @@ import { import { TokenValidationResult } from './use-cases/validate-connection-token.use.case.js'; import { isTestConnectionUtil } from './utils/is-test-connection-util.js'; import { SkipThrottle } from '@nestjs/throttler'; +import { isRedisConnectionUrl } from '@rocketadmin/shared-code/dist/src/data-access-layer/shared/create-data-access-object.js'; @UseInterceptors(SentryInterceptor) @Controller() @@ -243,7 +244,11 @@ export class ConnectionController { @UserId() userId: string, @MasterPassword() masterPwd: string, ): Promise { - if (!createConnectionDto.password && !isConnectionTypeAgent(createConnectionDto.type)) { + if ( + !createConnectionDto.password && + !isConnectionTypeAgent(createConnectionDto.type) && + !isRedisConnectionUrl(createConnectionDto.host) + ) { throw new BadRequestException(Messages.PASSWORD_MISSING); } if (createConnectionDto.masterEncryption && !masterPwd) { @@ -709,6 +714,10 @@ export class ConnectionController { return errors; } + if (isRedisConnectionUrl(connectionData.host)) { + return errors; + } + if (!connectionData.username && connectionData.type !== ConnectionTypesEnum.redis) errors.push(Messages.USERNAME_MISSING); diff --git a/backend/src/entities/connection/use-cases/test-connection.use.case.ts b/backend/src/entities/connection/use-cases/test-connection.use.case.ts index 3d085ab69..0f9f67e42 100644 --- a/backend/src/entities/connection/use-cases/test-connection.use.case.ts +++ b/backend/src/entities/connection/use-cases/test-connection.use.case.ts @@ -3,7 +3,10 @@ import { getRepository } from 'typeorm'; import AbstractUseCase from '../../../common/abstract-use.case.js'; import { IGlobalDatabaseContext } from '../../../common/application/global-database-context.interface.js'; import { BaseType } from '../../../common/data-injection.tokens.js'; -import { getDataAccessObject } from '@rocketadmin/shared-code/dist/src/data-access-layer/shared/create-data-access-object.js'; +import { + getDataAccessObject, + isRedisConnectionUrl, +} from '@rocketadmin/shared-code/dist/src/data-access-layer/shared/create-data-access-object.js'; import { Messages } from '../../../exceptions/text/messages.js'; import { processExceptionMessage } from '../../../exceptions/utils/process-exception-message.js'; import { isConnectionTypeAgent, slackPostMessage } from '../../../helpers/index.js'; @@ -96,7 +99,8 @@ export class TestConnectionUseCase if ( !connectionData.password && (connectionData.host !== toUpdate.host || connectionData.port !== toUpdate.port) && - !isConnectionTypeAgent(connectionData.type) + !isConnectionTypeAgent(connectionData.type) && + !isRedisConnectionUrl(connectionData.host) ) { return { result: false, @@ -125,7 +129,7 @@ export class TestConnectionUseCase }; } } else { - if (!connectionData.password) { + if (!connectionData.password && !isConnectionTypeAgent(connectionData.type) && !isRedisConnectionUrl(connectionData.host)) { return { result: false, message: Messages.PASSWORD_MISSING, diff --git a/shared-code/src/data-access-layer/data-access-objects/data-access-object-redis.ts b/shared-code/src/data-access-layer/data-access-objects/data-access-object-redis.ts index eb96ed159..8c81ea056 100644 --- a/shared-code/src/data-access-layer/data-access-objects/data-access-object-redis.ts +++ b/shared-code/src/data-access-layer/data-access-objects/data-access-object-redis.ts @@ -22,6 +22,7 @@ import { ValidateTableSettingsDS } from '../shared/data-structures/validate-tabl import { FilterCriteriaEnum } from '../shared/enums/filter-criteria.enum.js'; import { IDataAccessObject } from '../shared/interfaces/data-access-object.interface.js'; import { BasicDataAccessObject } from './basic-data-access-object.js'; +import { isRedisConnectionUrl } from '../shared/create-data-access-object.js'; export class DataAccessObjectRedis extends BasicDataAccessObject implements IDataAccessObject { constructor(connection: ConnectionParams) { @@ -857,6 +858,7 @@ export class DataAccessObjectRedis extends BasicDataAccessObject implements IDat try { if (!client) { const shouldUseTLS = this.connection.ssl !== false; + const isConnectionUrl = isRedisConnectionUrl(this.connection.host); const socketConfig: any = { host: this.connection.host, @@ -880,9 +882,10 @@ export class DataAccessObjectRedis extends BasicDataAccessObject implements IDat } client = createClient({ - socket: socketConfig, - password: this.connection.password || undefined, - username: this.connection.username || undefined, + socket: isConnectionUrl ? undefined : socketConfig, + url: isConnectionUrl ? this.connection.host : undefined, + password: isConnectionUrl ? undefined : this.connection.password ? this.connection.password : undefined, + username: isConnectionUrl ? undefined : this.connection.username ? this.connection.username : undefined, database: database, }); diff --git a/shared-code/src/data-access-layer/shared/create-data-access-object.ts b/shared-code/src/data-access-layer/shared/create-data-access-object.ts index 10b96e9f4..f98145764 100644 --- a/shared-code/src/data-access-layer/shared/create-data-access-object.ts +++ b/shared-code/src/data-access-layer/shared/create-data-access-object.ts @@ -96,7 +96,7 @@ function buildConnectionParams(connectionParams: IUnknownConnectionParams): Conn const sqlAndMongoRequiredKeys = ['type', 'host', 'port', 'username', 'password', 'database']; const elasticAndDynamoAndRedisRequiredKeys = ['host', 'username', 'password']; - const redisRequiredKeys = ['host', 'port', 'password']; + const redisRequiredKeys = !isRedisConnectionUrl(connectionParams.host) ? ['host', 'port', 'password'] : ['host']; switch (connectionParams.type) { case ConnectionTypesEnum.postgres: @@ -155,3 +155,8 @@ function buildConnectionParams(connectionParams: IUnknownConnectionParams): Conn }; return connection; } + +export function isRedisConnectionUrl(host: string): boolean { + const redisUrlPattern = /^rediss?:\/\/.+/i; + return redisUrlPattern.test(host); +}