diff --git a/lib/connection-parameters.js b/lib/connection-parameters.js index c1c535e98..da0e998d9 100644 --- a/lib/connection-parameters.js +++ b/lib/connection-parameters.js @@ -65,10 +65,15 @@ var ConnectionParameters = function(config) { this.fallback_application_name = val('fallback_application_name', config, false); }; +// Convert arg to a string, surround in single quotes, and escape single quotes and backslashes +var quoteParamValue = function(value) { + return "'" + ('' + value).replace(/\\/g, "\\\\").replace(/'/g, "\\'") + "'"; +}; + var add = function(params, config, paramName) { var value = config[paramName]; if(value) { - params.push(paramName+"='"+value+"'"); + params.push(paramName + "=" + quoteParamValue(value)); } }; @@ -87,23 +92,23 @@ ConnectionParameters.prototype.getLibpqConnectionString = function(cb) { add(params, ssl, 'sslcert'); if(this.database) { - params.push("dbname='" + this.database + "'"); + params.push("dbname=" + quoteParamValue(this.database)); } if(this.replication) { - params.push("replication='" + this.replication + "'"); + params.push("replication=" + quoteParamValue(this.replication)); } if(this.host) { - params.push("host=" + this.host); + params.push("host=" + quoteParamValue(this.host)); } if(this.isDomainSocket) { return cb(null, params.join(' ')); } if(this.client_encoding) { - params.push("client_encoding='" + this.client_encoding + "'"); + params.push("client_encoding=" + quoteParamValue(this.client_encoding)); } dns.lookup(this.host, function(err, address) { if(err) return cb(err, null); - params.push("hostaddr=" + address); + params.push("hostaddr=" + quoteParamValue(address)); return cb(null, params.join(' ')); }); }; diff --git a/test/unit/connection-parameters/creation-tests.js b/test/unit/connection-parameters/creation-tests.js index 33ee7eeeb..85c2bd037 100644 --- a/test/unit/connection-parameters/creation-tests.js +++ b/test/unit/connection-parameters/creation-tests.js @@ -126,7 +126,7 @@ test('libpq connection string building', function() { checkForPart(parts, "user='brian'"); checkForPart(parts, "password='xyz'"); checkForPart(parts, "port='888'"); - checkForPart(parts, "hostaddr=127.0.0.1"); + checkForPart(parts, "hostaddr='127.0.0.1'"); checkForPart(parts, "dbname='bam'"); })); }); @@ -143,7 +143,7 @@ test('libpq connection string building', function() { assert.isNull(err); var parts = constring.split(" "); checkForPart(parts, "user='brian'"); - checkForPart(parts, "hostaddr=127.0.0.1"); + checkForPart(parts, "hostaddr='127.0.0.1'"); })); }); @@ -173,7 +173,23 @@ test('libpq connection string building', function() { assert.isNull(err); var parts = constring.split(" "); checkForPart(parts, "user='brian'"); - checkForPart(parts, "host=/tmp/"); + checkForPart(parts, "host='/tmp/'"); + })); + }); + + test('config contains quotes and backslashes', function() { + var config = { + user: 'not\\brian', + password: 'bad\'chars', + port: 5432, + host: '/tmp/' + }; + var subject = new ConnectionParameters(config); + subject.getLibpqConnectionString(assert.calls(function(err, constring) { + assert.isNull(err); + var parts = constring.split(" "); + checkForPart(parts, "user='not\\\\brian'"); + checkForPart(parts, "password='bad\\'chars'"); })); });