Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/thirty-turtles-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"nostream": patch
---

Fix Redis cache connection config to skip AUTH when `REDIS_PASSWORD` is unset
54 changes: 47 additions & 7 deletions src/cache/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,49 @@ import { createLogger } from '../factories/logger-factory'

const logger = createLogger('cache-client')

export const getCacheConfig = (): RedisClientOptions => ({
url: process.env.REDIS_URI
? process.env.REDIS_URI
: `redis://${process.env.REDIS_USER}:${process.env.REDIS_PASSWORD}@${process.env.REDIS_HOST}:${process.env.REDIS_PORT}`,
password: process.env.REDIS_PASSWORD,
})
const redactRedisUrlCredentials = (url: string): string => {
try {
const parsedUrl = new URL(url)

if (!parsedUrl.username && !parsedUrl.password) {
return url
}

parsedUrl.username = parsedUrl.username ? '***' : ''
parsedUrl.password = parsedUrl.password ? '***' : ''

return parsedUrl.toString()
} catch {
return url
}
}

export const getCacheConfig = (): RedisClientOptions => {
if (process.env.REDIS_URI) {
return {
url: process.env.REDIS_URI,
...(process.env.REDIS_PASSWORD ? { password: process.env.REDIS_PASSWORD } : {}),
}
}

const hasPassword = Boolean(process.env.REDIS_PASSWORD)
const host = process.env.REDIS_HOST
const port = process.env.REDIS_PORT

if (hasPassword) {
const username = process.env.REDIS_USER ?? 'default'

Comment thread
Justxd22 marked this conversation as resolved.
return {
url: `redis://${host}:${port}`,
username,
password: process.env.REDIS_PASSWORD,
}
Comment thread
Justxd22 marked this conversation as resolved.
}

return {
url: `redis://${host}:${port}`,
}
}

let instance: CacheClient | undefined = undefined

Expand All @@ -18,7 +55,10 @@ export const getCacheClient = (): CacheClient => {
const config = getCacheConfig()
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { password: _, ...loggableConfig } = config
logger('config: %o', loggableConfig)
logger('config: %o', {
...loggableConfig,
...(loggableConfig.url ? { url: redactRedisUrlCredentials(loggableConfig.url) } : {}),
})
instance = createClient(config)
}

Expand Down
72 changes: 72 additions & 0 deletions test/unit/cache/client.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { expect } from 'chai'

import { getCacheConfig } from '../../../src/cache/client'

describe('getCacheConfig', () => {
const originalEnv = process.env

beforeEach(() => {
process.env = { ...originalEnv }
delete process.env.REDIS_URI
delete process.env.REDIS_USER
delete process.env.REDIS_PASSWORD
delete process.env.REDIS_HOST
delete process.env.REDIS_PORT
})

afterEach(() => {
process.env = originalEnv
})

it('builds unauthenticated redis url when REDIS_URI and REDIS_PASSWORD are unset', () => {
process.env.REDIS_HOST = 'localhost'
process.env.REDIS_PORT = '6379'

const config = getCacheConfig()

expect(config).to.deep.equal({
url: 'redis://localhost:6379',
})
})

it('builds authenticated redis config when REDIS_PASSWORD is set', () => {
process.env.REDIS_HOST = 'localhost'
process.env.REDIS_PORT = '6379'
process.env.REDIS_USER = 'default'
process.env.REDIS_PASSWORD = 'secret'

const config = getCacheConfig()

expect(config).to.deep.equal({
url: 'redis://localhost:6379',
username: 'default',
password: 'secret',
})
})

it('defaults REDIS_USER to default when REDIS_PASSWORD is set and REDIS_USER is unset', () => {
process.env.REDIS_HOST = 'localhost'
process.env.REDIS_PORT = '6379'
process.env.REDIS_PASSWORD = 'secret'

const config = getCacheConfig()

expect(config).to.deep.equal({
url: 'redis://localhost:6379',
username: 'default',
password: 'secret',
})
})

it('prefers REDIS_URI over host/port settings', () => {
process.env.REDIS_URI = 'redis://cache.internal:6380'
process.env.REDIS_PASSWORD = 'secret'

const config = getCacheConfig()

expect(config).to.deep.equal({
url: 'redis://cache.internal:6380',
password: 'secret',
})
})
})
Loading