From 9be7ee88afd2bb04e4d5a1a8da9a389ac13f8c40 Mon Sep 17 00:00:00 2001 From: Luigi Pinca Date: Sat, 8 Jan 2022 21:10:56 +0100 Subject: [PATCH] [fix] Correctly handle userinfo containing the at sign --- index.js | 37 ++++++++++++++++++++++------ test/test.js | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index 702308b..b819461 100644 --- a/index.js +++ b/index.js @@ -304,7 +304,11 @@ function Url(address, location, parser) { if (parse !== parse) { url[key] = address; } else if ('string' === typeof parse) { - if (~(index = address.indexOf(parse))) { + index = parse === '@' + ? address.lastIndexOf(parse) + : address.indexOf(parse); + + if (~index) { if ('number' === typeof instruction[2]) { url[key] = address.slice(0, index); address = address.slice(index + instruction[2]); @@ -370,10 +374,21 @@ function Url(address, location, parser) { // Parse down the `auth` for the username and password. // url.username = url.password = ''; + if (url.auth) { - instruction = url.auth.split(':'); - url.username = instruction[0]; - url.password = instruction[1] || ''; + index = url.auth.indexOf(':'); + + if (~index) { + url.username = url.auth.slice(0, index); + url.username = encodeURIComponent(decodeURIComponent(url.username)); + + url.password = url.auth.slice(index + 1); + url.password = encodeURIComponent(decodeURIComponent(url.password)) + } else { + url.username = encodeURIComponent(decodeURIComponent(url.auth)); + } + + url.auth = url.password ? url.username +':'+ url.password : url.username; } url.origin = url.protocol !== 'file:' && isSpecial(url.protocol) && url.host @@ -465,9 +480,17 @@ function set(part, value, fn) { break; case 'auth': - var splits = value.split(':'); - url.username = splits[0]; - url.password = splits.length === 2 ? splits[1] : ''; + var index = value.indexOf(':'); + + if (~index) { + url.username = value.slice(0, index); + url.username = encodeURIComponent(decodeURIComponent(url.username)); + + url.password = value.slice(index + 1); + url.password = encodeURIComponent(decodeURIComponent(url.password)); + } else { + url.username = encodeURIComponent(decodeURIComponent(value)); + } } for (var i = 0; i < rules.length; i++) { diff --git a/test/test.js b/test/test.js index 8130081..18f16ef 100644 --- a/test/test.js +++ b/test/test.js @@ -689,6 +689,54 @@ describe('url-parse', function () { assume(parsed.hostname).equals('www.example.com'); assume(parsed.href).equals(url); }); + + it('handles @ in username', function () { + var url = 'http://user@@www.example.com/' + , parsed = parse(url); + + assume(parsed.protocol).equals('http:'); + assume(parsed.auth).equals('user%40'); + assume(parsed.username).equals('user%40'); + assume(parsed.password).equals(''); + assume(parsed.hostname).equals('www.example.com'); + assume(parsed.pathname).equals('/'); + assume(parsed.href).equals('http://user%40@www.example.com/'); + + url = 'http://user%40@www.example.com/'; + parsed = parse(url); + + assume(parsed.protocol).equals('http:'); + assume(parsed.auth).equals('user%40'); + assume(parsed.username).equals('user%40'); + assume(parsed.password).equals(''); + assume(parsed.hostname).equals('www.example.com'); + assume(parsed.pathname).equals('/'); + assume(parsed.href).equals('http://user%40@www.example.com/'); + }); + + it('handles @ in password', function () { + var url = 'http://user@:pas:s@@www.example.com/' + , parsed = parse(url); + + assume(parsed.protocol).equals('http:'); + assume(parsed.auth).equals('user%40:pas%3As%40'); + assume(parsed.username).equals('user%40'); + assume(parsed.password).equals('pas%3As%40'); + assume(parsed.hostname).equals('www.example.com'); + assume(parsed.pathname).equals('/'); + assume(parsed.href).equals('http://user%40:pas%3As%40@www.example.com/'); + + url = 'http://user%40:pas%3As%40@www.example.com/' + parsed = parse(url); + + assume(parsed.protocol).equals('http:'); + assume(parsed.auth).equals('user%40:pas%3As%40'); + assume(parsed.username).equals('user%40'); + assume(parsed.password).equals('pas%3As%40'); + assume(parsed.hostname).equals('www.example.com'); + assume(parsed.pathname).equals('/'); + assume(parsed.href).equals('http://user%40:pas%3As%40@www.example.com/'); + }); }); it('accepts multiple ???', function () { @@ -1124,6 +1172,26 @@ describe('url-parse', function () { assume(data.username).equals(''); assume(data.password).equals('quux'); assume(data.href).equals('https://:quux@example.com/'); + + assume(data.set('auth', 'user@:pass@')).equals(data); + assume(data.username).equals('user%40'); + assume(data.password).equals('pass%40'); + assume(data.href).equals('https://user%40:pass%40@example.com/'); + + assume(data.set('auth', 'user%40:pass%40')).equals(data); + assume(data.username).equals('user%40'); + assume(data.password).equals('pass%40'); + assume(data.href).equals('https://user%40:pass%40@example.com/'); + + assume(data.set('auth', 'user:pass:word')).equals(data); + assume(data.username).equals('user'); + assume(data.password).equals('pass%3Aword'); + assume(data.href).equals('https://user:pass%3Aword@example.com/'); + + assume(data.set('auth', 'user:pass%3Aword')).equals(data); + assume(data.username).equals('user'); + assume(data.password).equals('pass%3Aword'); + assume(data.href).equals('https://user:pass%3Aword@example.com/'); }); it('updates other values', function () {