Skip to content

Commit cfea150

Browse files
author
Alex Wilson
committed
Allow passwords to be provided using a function
1 parent 3f32f7d commit cfea150

File tree

9 files changed

+143
-17
lines changed

9 files changed

+143
-17
lines changed

lib/client.js

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,27 @@ Client.prototype.connect = function(callback) {
6363

6464
function checkPgPass(cb) {
6565
return function(msg) {
66-
if (null !== self.password) {
66+
if (self.password !== undefined && self.password !== null) {
6767
cb(msg);
68-
} else {
69-
pgPass(self.connectionParameters, function(pass){
70-
if (undefined !== pass) {
71-
self.connectionParameters.password = self.password = pass;
72-
}
73-
cb(msg);
74-
});
68+
return;
7569
}
70+
self.connectionParameters.getPassword(function (err, pw) {
71+
if (err) {
72+
self.emit('error', err);
73+
return;
74+
}
75+
self.password = pw;
76+
if (null !== self.password) {
77+
cb(msg);
78+
} else {
79+
pgPass(self.connectionParameters, function(pass){
80+
if (undefined !== pass) {
81+
self.password = pass;
82+
}
83+
cb(msg);
84+
});
85+
}
86+
});
7687
};
7788
}
7889

lib/connection-parameters.js

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
var url = require('url');
22
var dns = require('dns');
3+
var EventEmitter = require('events').EventEmitter;
34

45
var defaults = require(__dirname + '/defaults');
56

@@ -39,13 +40,31 @@ var ConnectionParameters = function(config) {
3940
this.database = val('database', config);
4041
this.port = parseInt(val('port', config), 10);
4142
this.host = val('host', config);
42-
this.password = val('password', config);
4343
this.binary = val('binary', config);
4444
this.ssl = config.ssl || useSsl();
4545
this.client_encoding = val("client_encoding", config);
4646
//a domain socket begins with '/'
4747
this.isDomainSocket = (!(this.host||'').indexOf('/'));
4848

49+
if (typeof(config.password) === 'function') {
50+
this.pwEmitter = new EventEmitter();
51+
var self = this;
52+
config.password(this, function (err, pw) {
53+
if (!err)
54+
self.password = pw;
55+
else if (err instanceof Error)
56+
self.password = err;
57+
else
58+
self.password = new Error('Password generator function failed: ' + err);
59+
60+
var pwEmitter = self.pwEmitter;
61+
delete (self.pwEmitter);
62+
pwEmitter.emit('done', err);
63+
});
64+
} else {
65+
this.password = val('password', config);
66+
}
67+
4968
this.application_name = val('application_name', config, 'PGAPPNAME');
5069
this.fallback_application_name = val('fallback_application_name', config, false);
5170
};
@@ -57,7 +76,37 @@ var add = function(params, config, paramName) {
5776
}
5877
};
5978

79+
ConnectionParameters.prototype.getPassword = function(cb) {
80+
if (this.pwEmitter) {
81+
var self = this;
82+
this.pwEmitter.on('done', function (err) {
83+
cb(err, self.password);
84+
});
85+
return;
86+
}
87+
if (this.password instanceof Error) {
88+
cb(this.password);
89+
} else {
90+
cb(null, this.password);
91+
}
92+
};
93+
6094
ConnectionParameters.prototype.getLibpqConnectionString = function(cb) {
95+
if (this.pwEmitter) {
96+
var self = this;
97+
this.pwEmitter.on('done', function (err) {
98+
if (err) {
99+
cb(err);
100+
return;
101+
}
102+
self.getLibpqConnectionString(cb);
103+
});
104+
return;
105+
}
106+
if (this.password instanceof Error) {
107+
cb(this.password);
108+
return;
109+
}
61110
var params = [];
62111
add(params, this, 'user');
63112
add(params, this, 'password');

lib/connection.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ Connection.prototype.cancel = function(processID, secretKey) {
173173
Connection.prototype.password = function(password) {
174174
//0x70 = 'p'
175175
this._send(0x70, this.writer.addCString(password));
176+
this.emit('sentPassword');
176177
};
177178

178179
Connection.prototype._send = function(code, more) {

test/unit/client/cleartext-password-tests.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ test('cleartext password authentication', function(){
1010
var client = createClient();
1111
client.password = "!";
1212
client.connection.stream.packets = [];
13+
var sent = false;
14+
client.connection.on('sentPassword', function() {
15+
sent = true;
16+
});
1317
client.connection.emit('authenticationCleartextPassword');
18+
assert.ok(sent);
1419
test('responds with password', function() {
1520
var packets = client.connection.stream.packets;
1621
assert.lengthIs(packets, 1);

test/unit/client/configuration-tests.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,37 @@ test('client settings', function() {
3030
assert.equal(client.password, password);
3131
});
3232

33+
test('password function', function() {
34+
var user = 'brian';
35+
var database = 'pgjstest';
36+
var password = function(params, cb) {
37+
cb(null, 'boom');
38+
};
39+
var client = createClient({
40+
user: user,
41+
database: database,
42+
port: 321,
43+
password: password
44+
});
45+
46+
assert.equal(client.user, user);
47+
assert.equal(client.database, database);
48+
assert.equal(client.port, 321);
49+
var sent = false;
50+
client.connection.on('sentPassword', function() {
51+
sent = true;
52+
});
53+
client.connection.emit('authenticationCleartextPassword');
54+
assert.ok(sent);
55+
assert.equal(client.password, 'boom');
56+
});
57+
3358
});
3459

3560
test('initializing from a config string', function() {
3661

3762
test('uses the correct values from the config string', function() {
38-
var client = new Client("postgres://brian:pass@host1:333/databasename")
63+
var client = new Client("postgres://brian:pass@host1:333/databasename");
3964
assert.equal(client.user, 'brian');
4065
assert.equal(client.password, "pass");
4166
assert.equal(client.host, "host1");

test/unit/client/md5-password-tests.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,15 @@ test('md5 authentication', function() {
44
var client = createClient();
55
client.password = "!";
66
var salt = Buffer([1, 2, 3, 4]);
7+
8+
var sent = false;
9+
client.connection.on('sentPassword', function() {
10+
sent = true;
11+
});
12+
client.connection.stream.packets = [];
713
client.connection.emit('authenticationMD5Password', {salt: salt});
814

15+
assert.ok(sent);
916
test('responds', function() {
1017
assert.lengthIs(client.connection.stream.packets, 1);
1118
test('should have correct encrypted data', function() {
@@ -17,5 +24,4 @@ test('md5 authentication', function() {
1724
.addCString(password).join(true,'p'));
1825
});
1926
});
20-
2127
});

test/unit/client/test-helper.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
var helper = require(__dirname+'/../test-helper');
22
var Connection = require(__dirname + '/../../../lib/connection');
3-
var makeClient = function() {
3+
var makeClient = function(config) {
44
var connection = new Connection({stream: "no"});
55
connection.startup = function() {};
66
connection.connect = function() {};
77
connection.query = function(text) {
88
this.queries.push(text);
99
};
1010
connection.queries = [];
11-
var client = new Client({connection: connection});
11+
config = config || {};
12+
if (typeof(config) === 'object')
13+
config.connection = connection;
14+
var client = new Client(config);
15+
client.connection = connection;
1216
client.connect();
1317
client.connection.emit('connect');
1418
return client;

test/unit/connection-parameters/creation-tests.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,27 @@ test('ConnectionParameters initializing from config', function() {
4747
assert.ok(subject.isDomainSocket === false);
4848
});
4949

50+
test('ConnectionParameters initializing from config with password function', function() {
51+
var config = {
52+
user: 'brian',
53+
database: 'home',
54+
port: 7777,
55+
password: function (params, cb) {
56+
cb(null, 'pizza');
57+
},
58+
binary: true,
59+
encoding: 'utf8',
60+
host: 'yo',
61+
ssl: {
62+
asdf: 'blah'
63+
}
64+
};
65+
var subject = new ConnectionParameters(config);
66+
config.password = 'pizza';
67+
compare(subject, config, 'config');
68+
assert.ok(subject.isDomainSocket === false);
69+
});
70+
5071
test('escape spaces if present', function() {
5172
subject = new ConnectionParameters('postgres://localhost/post gres');
5273
assert.equal(subject.database, 'post gres');

test/unit/test-helper.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,17 @@ p.write = function(packet) {
1717

1818
p.writable = true;
1919

20-
createClient = function() {
20+
createClient = function(config) {
2121
var stream = new MemoryStream();
2222
stream.readyState = "open";
23-
var client = new Client({
24-
connection: new Connection({stream: stream})
25-
});
23+
var connection = new Connection({stream: stream});
24+
config = config || {};
25+
if (typeof(config) === 'object')
26+
config.connection = connection;
27+
var client = new Client(config);
28+
client.connection = connection;
2629
client.connect();
30+
client.connection.emit('connect');
2731
return client;
2832
};
2933

0 commit comments

Comments
 (0)