Skip to content

Commit da8915c

Browse files
committed
allow user & database to be provided dynamically
1 parent f58cd4f commit da8915c

File tree

8 files changed

+74
-58
lines changed

8 files changed

+74
-58
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -994,9 +994,9 @@ const sql = postgres('postgres://username:password@host:port/database', {
994994

995995
Note that `max_lifetime = 60 * (30 + Math.random() * 30)` by default. This resolves to an interval between 30 and 60 minutes to optimize for the benefits of prepared statements **and** working nicely with Linux's OOM killer.
996996

997-
### Dynamic passwords
997+
### Dynamic credentials
998998

999-
When clients need to use alternative authentication schemes such as access tokens or connections to databases with rotating passwords, provide either a synchronous or asynchronous function that will resolve the dynamic password value at connection time.
999+
When clients need to use alternative authentication schemes such as access tokens or connections to databases with rotating usernames, database names or passwords, provide either a synchronous or asynchronous function that will resolve the dynamic value at connection time.
10001000

10011001
```js
10021002
const sql = postgres(url, {

cf/src/connection.js

+14-12
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,8 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
5555
const {
5656
ssl,
5757
max,
58-
user,
5958
host,
6059
port,
61-
database,
6260
parsers,
6361
transform,
6462
onnotice,
@@ -73,6 +71,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
7371
const sent = Queue()
7472
, id = uid++
7573
, backend = { pid: null, secret: null }
74+
, User = Resolve(options.user)
75+
, Database = Resolve(options.database)
76+
, Pass = Resolve(options.pass)
7677
, idleTimer = timer(end, options.idle_timeout)
7778
, lifeTimer = timer(end, options.max_lifetime)
7879
, connectTimer = timer(connectTimedOut, options.connect_timeout)
@@ -355,7 +356,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
355356
setTimeout(connect, closedDate ? closedDate + delay - performance.now() : 0)
356357
}
357358

358-
function connected() {
359+
async function connected() {
359360
try {
360361
statements = {}
361362
needsTypes = options.fetch_types
@@ -364,7 +365,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
364365
lifeTimer.start()
365366
socket.on('data', data)
366367
keep_alive && socket.setKeepAlive && socket.setKeepAlive(true, 1000 * keep_alive)
367-
const s = StartupMessage()
368+
const s = await StartupMessage()
368369
write(s)
369370
} catch (err) {
370371
error(err)
@@ -667,10 +668,11 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
667668
}
668669

669670
async function AuthenticationMD5Password(x) {
671+
const [pass, user] = await Promise.all([Pass(), User()])
670672
const payload = 'md5' + (
671-
await md5(
673+
md5(
672674
Buffer.concat([
673-
Buffer.from(await md5((await Pass()) + user)),
675+
Buffer.from(md5(pass + user)),
674676
x.subarray(9)
675677
])
676678
)
@@ -722,11 +724,10 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
722724
socket.destroy()
723725
}
724726

725-
function Pass() {
726-
return Promise.resolve(typeof options.pass === 'function'
727-
? options.pass()
728-
: options.pass
729-
)
727+
function Resolve(opt) {
728+
return async () => typeof opt === 'function'
729+
? opt.apply(options, [options])
730+
: opt
730731
}
731732

732733
function NoData() {
@@ -969,7 +970,8 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
969970
])
970971
}
971972

972-
function StartupMessage() {
973+
async function StartupMessage() {
974+
const [user, database] = await Promise.all([User(), Database()])
973975
return cancelMessage || b().inc(4).i16(3).z(2).str(
974976
Object.entries(Object.assign({
975977
user,

cjs/src/connection.js

+14-12
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,8 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
5353
const {
5454
ssl,
5555
max,
56-
user,
5756
host,
5857
port,
59-
database,
6058
parsers,
6159
transform,
6260
onnotice,
@@ -71,6 +69,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
7169
const sent = Queue()
7270
, id = uid++
7371
, backend = { pid: null, secret: null }
72+
, User = Resolve(options.user)
73+
, Database = Resolve(options.database)
74+
, Pass = Resolve(options.pass)
7475
, idleTimer = timer(end, options.idle_timeout)
7576
, lifeTimer = timer(end, options.max_lifetime)
7677
, connectTimer = timer(connectTimedOut, options.connect_timeout)
@@ -353,7 +354,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
353354
setTimeout(connect, closedDate ? closedDate + delay - performance.now() : 0)
354355
}
355356

356-
function connected() {
357+
async function connected() {
357358
try {
358359
statements = {}
359360
needsTypes = options.fetch_types
@@ -362,7 +363,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
362363
lifeTimer.start()
363364
socket.on('data', data)
364365
keep_alive && socket.setKeepAlive && socket.setKeepAlive(true, 1000 * keep_alive)
365-
const s = StartupMessage()
366+
const s = await StartupMessage()
366367
write(s)
367368
} catch (err) {
368369
error(err)
@@ -665,10 +666,11 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
665666
}
666667

667668
async function AuthenticationMD5Password(x) {
669+
const [pass, user] = await Promise.all([Pass(), User()])
668670
const payload = 'md5' + (
669-
await md5(
671+
md5(
670672
Buffer.concat([
671-
Buffer.from(await md5((await Pass()) + user)),
673+
Buffer.from(md5(pass + user)),
672674
x.subarray(9)
673675
])
674676
)
@@ -720,11 +722,10 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
720722
socket.destroy()
721723
}
722724

723-
function Pass() {
724-
return Promise.resolve(typeof options.pass === 'function'
725-
? options.pass()
726-
: options.pass
727-
)
725+
function Resolve(opt) {
726+
return async () => typeof opt === 'function'
727+
? opt.apply(options, [options])
728+
: opt
728729
}
729730

730731
function NoData() {
@@ -967,7 +968,8 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
967968
])
968969
}
969970

970-
function StartupMessage() {
971+
async function StartupMessage() {
972+
const [user, database] = await Promise.all([User(), Database()])
971973
return cancelMessage || b().inc(4).i16(3).z(2).str(
972974
Object.entries(Object.assign({
973975
user,

deno/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -990,9 +990,9 @@ const sql = postgres('postgres://username:password@host:port/database', {
990990

991991
Note that `max_lifetime = 60 * (30 + Math.random() * 30)` by default. This resolves to an interval between 30 and 60 minutes to optimize for the benefits of prepared statements **and** working nicely with Linux's OOM killer.
992992

993-
### Dynamic passwords
993+
### Dynamic credentials
994994

995-
When clients need to use alternative authentication schemes such as access tokens or connections to databases with rotating passwords, provide either a synchronous or asynchronous function that will resolve the dynamic password value at connection time.
995+
When clients need to use alternative authentication schemes such as access tokens or connections to databases with rotating usernames, database names or passwords, provide either a synchronous or asynchronous function that will resolve the dynamic value at connection time.
996996

997997
```js
998998
const sql = postgres(url, {

deno/src/connection.js

+14-12
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,8 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
5656
const {
5757
ssl,
5858
max,
59-
user,
6059
host,
6160
port,
62-
database,
6361
parsers,
6462
transform,
6563
onnotice,
@@ -74,6 +72,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
7472
const sent = Queue()
7573
, id = uid++
7674
, backend = { pid: null, secret: null }
75+
, User = Resolve(options.user)
76+
, Database = Resolve(options.database)
77+
, Pass = Resolve(options.pass)
7778
, idleTimer = timer(end, options.idle_timeout)
7879
, lifeTimer = timer(end, options.max_lifetime)
7980
, connectTimer = timer(connectTimedOut, options.connect_timeout)
@@ -356,7 +357,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
356357
setTimeout(connect, closedDate ? closedDate + delay - performance.now() : 0)
357358
}
358359

359-
function connected() {
360+
async function connected() {
360361
try {
361362
statements = {}
362363
needsTypes = options.fetch_types
@@ -365,7 +366,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
365366
lifeTimer.start()
366367
socket.on('data', data)
367368
keep_alive && socket.setKeepAlive && socket.setKeepAlive(true)
368-
const s = StartupMessage()
369+
const s = await StartupMessage()
369370
write(s)
370371
} catch (err) {
371372
error(err)
@@ -668,10 +669,11 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
668669
}
669670

670671
async function AuthenticationMD5Password(x) {
672+
const [pass, user] = await Promise.all([Pass(), User()])
671673
const payload = 'md5' + (
672-
await md5(
674+
md5(
673675
Buffer.concat([
674-
Buffer.from(await md5((await Pass()) + user)),
676+
Buffer.from(md5(pass + user)),
675677
x.subarray(9)
676678
])
677679
)
@@ -723,11 +725,10 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
723725
socket.destroy()
724726
}
725727

726-
function Pass() {
727-
return Promise.resolve(typeof options.pass === 'function'
728-
? options.pass()
729-
: options.pass
730-
)
728+
function Resolve(opt) {
729+
return async () => typeof opt === 'function'
730+
? opt.apply(options, [options])
731+
: opt
731732
}
732733

733734
function NoData() {
@@ -970,7 +971,8 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
970971
])
971972
}
972973

973-
function StartupMessage() {
974+
async function StartupMessage() {
975+
const [user, database] = await Promise.all([User(), Database()])
974976
return cancelMessage || b().inc(4).i16(3).z(2).str(
975977
Object.entries(Object.assign({
976978
user,

deno/types/index.d.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ interface BaseOptions<T extends Record<string, postgres.PostgresType>> {
3636
* Name of database to connect to
3737
* @default process.env['PGDATABASE'] || options.user
3838
*/
39-
database: string;
39+
database: Resolver<T, string>;
4040
/**
4141
* Username of database user
4242
* @default process.env['PGUSERNAME'] || process.env['PGUSER'] || require('os').userInfo().username
4343
*/
44-
user: string;
44+
user: Resolver<T, string>;
4545
/**
4646
* How to deal with ssl (can be a tls.connect option object)
4747
* @default false
@@ -127,6 +127,10 @@ interface BaseOptions<T extends Record<string, postgres.PostgresType>> {
127127
}
128128

129129

130+
type Resolver<T extends Record<string, postgres.PostgresType>, U> =
131+
| U
132+
| ((this: postgres.Options<T>, options: postgres.Options<T>) => U)
133+
130134
declare const PRIVATE: unique symbol;
131135

132136
declare class NotAPromise {
@@ -358,7 +362,7 @@ declare namespace postgres {
358362
* Password of database user
359363
* @default process.env['PGPASSWORD']
360364
*/
361-
password?: string | (() => string | Promise<string>) | undefined;
365+
password?: Resolver<T, string> | undefined;
362366
/** Name of database to connect to (an alias for `database`) */
363367
db?: Options<T>['database'] | undefined;
364368
/** Username of database user (an alias for `user`) */

src/connection.js

+14-12
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,8 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
5353
const {
5454
ssl,
5555
max,
56-
user,
5756
host,
5857
port,
59-
database,
6058
parsers,
6159
transform,
6260
onnotice,
@@ -71,6 +69,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
7169
const sent = Queue()
7270
, id = uid++
7371
, backend = { pid: null, secret: null }
72+
, User = Resolve(options.user)
73+
, Database = Resolve(options.database)
74+
, Pass = Resolve(options.pass)
7475
, idleTimer = timer(end, options.idle_timeout)
7576
, lifeTimer = timer(end, options.max_lifetime)
7677
, connectTimer = timer(connectTimedOut, options.connect_timeout)
@@ -353,7 +354,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
353354
setTimeout(connect, closedDate ? closedDate + delay - performance.now() : 0)
354355
}
355356

356-
function connected() {
357+
async function connected() {
357358
try {
358359
statements = {}
359360
needsTypes = options.fetch_types
@@ -362,7 +363,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
362363
lifeTimer.start()
363364
socket.on('data', data)
364365
keep_alive && socket.setKeepAlive && socket.setKeepAlive(true, 1000 * keep_alive)
365-
const s = StartupMessage()
366+
const s = await StartupMessage()
366367
write(s)
367368
} catch (err) {
368369
error(err)
@@ -665,10 +666,11 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
665666
}
666667

667668
async function AuthenticationMD5Password(x) {
669+
const [pass, user] = await Promise.all([Pass(), User()])
668670
const payload = 'md5' + (
669-
await md5(
671+
md5(
670672
Buffer.concat([
671-
Buffer.from(await md5((await Pass()) + user)),
673+
Buffer.from(md5(pass + user)),
672674
x.subarray(9)
673675
])
674676
)
@@ -720,11 +722,10 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
720722
socket.destroy()
721723
}
722724

723-
function Pass() {
724-
return Promise.resolve(typeof options.pass === 'function'
725-
? options.pass()
726-
: options.pass
727-
)
725+
function Resolve(opt) {
726+
return async () => typeof opt === 'function'
727+
? opt.apply(options, [options])
728+
: opt
728729
}
729730

730731
function NoData() {
@@ -967,7 +968,8 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
967968
])
968969
}
969970

970-
function StartupMessage() {
971+
async function StartupMessage() {
972+
const [user, database] = await Promise.all([User(), Database()])
971973
return cancelMessage || b().inc(4).i16(3).z(2).str(
972974
Object.entries(Object.assign({
973975
user,

0 commit comments

Comments
 (0)