mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-24 16:01:42 +00:00
fix(frontend): keep connection parameter names case-sensitive
libpq does not fold them: `?SslMode=disable` is rejected as an invalid URI query parameter rather than read as `sslmode`, which a local server confirms. Folding made Windmill accept and honour a string Postgres itself refuses; naming the parameter instead tells the user why it cannot be stored. The last-value-wins rule for a repeated parameter is unchanged, and matches what the same server does. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -138,16 +138,13 @@ describe('unsupportedConnectionParam', () => {
|
||||
expect(parsePostgresConnectionString(disguised)?.sslmode).toBeUndefined()
|
||||
})
|
||||
|
||||
// libpq matches parameter names case-insensitively. Folding in one reader and not the other
|
||||
// is what lets a name through the allowlist and past the parser, so the string is saved as
|
||||
// whatever the default happens to be rather than what it asked for.
|
||||
it('reads a parameter whatever its case', () => {
|
||||
// libpq rejects `?SslMode=` as an invalid URI query parameter rather than folding it, so a
|
||||
// string carrying one does not connect anywhere. Naming it is the honest answer; honouring
|
||||
// it would save a resource from a URI Postgres itself refuses.
|
||||
it('refuses a parameter whose name is not the one libpq accepts', () => {
|
||||
const shouted = 'postgres://u:p@h/db?SslMode=verify-full'
|
||||
expect(unsupportedConnectionParam(shouted)).toBeUndefined()
|
||||
expect(parsePostgresConnectionString(shouted)?.sslmode).toBe('verify-full')
|
||||
expect(unsupportedConnectionParam('postgres://u:p@h/db?Connect_Timeout=1')).toBe(
|
||||
'connect_timeout'
|
||||
)
|
||||
expect(unsupportedConnectionParam(shouted)).toBe('SslMode')
|
||||
expect(parsePostgresConnectionString(shouted)?.sslmode).toBeUndefined()
|
||||
})
|
||||
|
||||
// libpq takes the last of a repeated parameter. Taking the first reads a weaker mode than
|
||||
|
||||
@@ -25,16 +25,17 @@ const CONNECTION_STRING =
|
||||
/postgres(?:ql)?:\/\/(?<user>[^:@]+)(?::(?<password>[^@]+))?@(?<host>\[[^\]]+\]|[^:\/?]+)(?::(?<port>\d+))?\/(?<dbname>[^\?]+)?/
|
||||
|
||||
/**
|
||||
* The query parameters, read the way libpq reads them: names are case-insensitive, and a name
|
||||
* The query parameters, read the way libpq reads them: names are case-sensitive — `SslMode` is
|
||||
* rejected outright as an invalid URI query parameter, not folded to `sslmode` — and a name
|
||||
* repeated takes its last value. One reader for both the parser and the allowlist below, or
|
||||
* they disagree about what a string says — a name only one of them folds is refused by neither
|
||||
* and honoured by neither.
|
||||
* they disagree about what a string says and a name is refused by neither and honoured by
|
||||
* neither.
|
||||
*/
|
||||
function paramsOf(connectionString: string): Map<string, string> {
|
||||
const query = connectionString.split('?').slice(1).join('?')
|
||||
const params = new Map<string, string>()
|
||||
if (!query) return params
|
||||
new URLSearchParams(query).forEach((value, name) => params.set(name.toLowerCase(), value))
|
||||
new URLSearchParams(query).forEach((value, name) => params.set(name, value))
|
||||
return params
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user