From 4bda23e0b149fabbcdc32aa4b1c4a84fe702b4d1 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 21 Nov 2023 10:06:16 +0000 Subject: [PATCH 1/6] Use WHATWG URL parsing, if available, instead of url.parse --- lib/ConnectionConfig.js | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/ConnectionConfig.js b/lib/ConnectionConfig.js index 06f4399c5..4286aef74 100644 --- a/lib/ConnectionConfig.js +++ b/lib/ConnectionConfig.js @@ -177,7 +177,7 @@ ConnectionConfig.parseFlagList = function parseFlagList(flagList) { }; ConnectionConfig.parseUrl = function(url) { - url = urlParse(url, true); + url = (typeof URL == 'function' && typeof URL.prototype == 'object' ? new URL(url) : urlParse(url, true)); var options = { host : url.hostname, @@ -185,13 +185,28 @@ ConnectionConfig.parseUrl = function(url) { database : url.pathname.substr(1) }; - if (url.auth) { + if (typeof url.username == 'string') { + options.user = url.username; + options.password = url.password; + } else if (url.auth) { var auth = url.auth.split(':'); options.user = auth.shift(); options.password = auth.join(':'); } - if (url.query) { + if (url.searchParams) { + for (var key in url.searchParams) { + var value = url.searchParams[key]; + + try { + // Try to parse this as a JSON expression first + options[key] = JSON.parse(value); + } catch (err) { + // Otherwise assume it is a plain string + options[key] = value; + } + } + } else if (url.query) { for (var key in url.query) { var value = url.query[key]; From e909c098127655a0881219cd520cd172e2d0f3f9 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 21 Nov 2023 13:30:47 +0000 Subject: [PATCH 2/6] Fix connection config parsing --- lib/ConnectionConfig.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/ConnectionConfig.js b/lib/ConnectionConfig.js index 4286aef74..cfab9237e 100644 --- a/lib/ConnectionConfig.js +++ b/lib/ConnectionConfig.js @@ -195,9 +195,7 @@ ConnectionConfig.parseUrl = function(url) { } if (url.searchParams) { - for (var key in url.searchParams) { - var value = url.searchParams[key]; - + url.searchParams.forEach(function (value, key) { try { // Try to parse this as a JSON expression first options[key] = JSON.parse(value); @@ -205,7 +203,7 @@ ConnectionConfig.parseUrl = function(url) { // Otherwise assume it is a plain string options[key] = value; } - } + }); } else if (url.query) { for (var key in url.query) { var value = url.query[key]; From 2e2a156223a165bbb22d667e4383b83ce3cca7aa Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 21 Nov 2023 13:31:30 +0000 Subject: [PATCH 3/6] test: fix password encoding test when using WHATWG URL --- test/unit/test-ConnectionConfig.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/unit/test-ConnectionConfig.js b/test/unit/test-ConnectionConfig.js index 67e573468..d941f4051 100644 --- a/test/unit/test-ConnectionConfig.js +++ b/test/unit/test-ConnectionConfig.js @@ -3,6 +3,7 @@ var Crypto = require('crypto'); var test = require('utest'); var assert = require('assert'); var ConnectionConfig = common.ConnectionConfig; +var usesWhatwgUrl = (typeof URL == 'function' && typeof URL.prototype == 'object'); test('ConnectionConfig#Constructor', { 'takes user,pw,host,port,db from url string': function() { @@ -23,7 +24,7 @@ test('ConnectionConfig#Constructor', { assert.equal(config.host, 'myhost'); assert.equal(config.port, 3333); assert.equal(config.user, 'myuser'); - assert.equal(config.password, 'my:pass'); + assert.equal(config.password, usesWhatwgUrl ? 'my%3Apass' : 'my:pass'); assert.equal(config.database, 'mydb'); }, From 70b1be8c0a265685e51beccf302b40f22f4f6392 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 21 Nov 2023 14:09:36 +0000 Subject: [PATCH 4/6] Fix connection config password node being decoded if necessary --- lib/ConnectionConfig.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/ConnectionConfig.js b/lib/ConnectionConfig.js index cfab9237e..0e7a44804 100644 --- a/lib/ConnectionConfig.js +++ b/lib/ConnectionConfig.js @@ -187,7 +187,11 @@ ConnectionConfig.parseUrl = function(url) { if (typeof url.username == 'string') { options.user = url.username; - options.password = url.password; + try { + options.password = decodeURIComponent(url.password); + } catch (e) { + options.password = url.password; + } } else if (url.auth) { var auth = url.auth.split(':'); options.user = auth.shift(); From d1b2511ec9dbb11ef3c687306ea67997d1bf14b9 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 21 Nov 2023 14:09:54 +0000 Subject: [PATCH 5/6] test: rolls back previous change, not needed anymore --- test/unit/test-ConnectionConfig.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/unit/test-ConnectionConfig.js b/test/unit/test-ConnectionConfig.js index d941f4051..67e573468 100644 --- a/test/unit/test-ConnectionConfig.js +++ b/test/unit/test-ConnectionConfig.js @@ -3,7 +3,6 @@ var Crypto = require('crypto'); var test = require('utest'); var assert = require('assert'); var ConnectionConfig = common.ConnectionConfig; -var usesWhatwgUrl = (typeof URL == 'function' && typeof URL.prototype == 'object'); test('ConnectionConfig#Constructor', { 'takes user,pw,host,port,db from url string': function() { @@ -24,7 +23,7 @@ test('ConnectionConfig#Constructor', { assert.equal(config.host, 'myhost'); assert.equal(config.port, 3333); assert.equal(config.user, 'myuser'); - assert.equal(config.password, usesWhatwgUrl ? 'my%3Apass' : 'my:pass'); + assert.equal(config.password, 'my:pass'); assert.equal(config.database, 'mydb'); }, From 6725ac8be611cd2840bb0bc362c651368c261619 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 21 Nov 2023 16:12:42 +0000 Subject: [PATCH 6/6] Implement a permissive decodeURIComponent --- lib/ConnectionConfig.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/ConnectionConfig.js b/lib/ConnectionConfig.js index 0e7a44804..a6f8fa78b 100644 --- a/lib/ConnectionConfig.js +++ b/lib/ConnectionConfig.js @@ -187,11 +187,7 @@ ConnectionConfig.parseUrl = function(url) { if (typeof url.username == 'string') { options.user = url.username; - try { - options.password = decodeURIComponent(url.password); - } catch (e) { - options.password = url.password; - } + options.password = decodeUriComponent(url.password); } else if (url.auth) { var auth = url.auth.split(':'); options.user = auth.shift(); @@ -224,3 +220,13 @@ ConnectionConfig.parseUrl = function(url) { return options; }; + +function decodeUriComponent(str) { + return str.replace(/\%([a-f0-9]{2})/ig, function (_, hex) { + try { + return String.fromCharCode(parseInt(hex, 16)); + } catch (e) { + return _; + } + }); +}