diff --git a/index.js b/index.js index 2ccb1d6..b94f6f1 100644 --- a/index.js +++ b/index.js @@ -47,7 +47,7 @@ function fromUrl (giturl, opts) { var gitHostInfo = gitHosts[gitHostName] var auth = null if (parsed.auth && authProtocols[parsed.protocol]) { - auth = decodeURIComponent(parsed.auth) + auth = parsed.auth } var committish = parsed.hash ? decodeURIComponent(parsed.hash.substr(1)) : null var user = null @@ -106,7 +106,15 @@ function fixupUnqualifiedGist (giturl) { function parseGitUrl (giturl) { var matched = giturl.match(/^([^@]+)@([^:/]+):[/]?((?:[^/]+[/])?[^/]+?)(?:[.]git)?(#.*)?$/) - if (!matched) return url.parse(giturl) + if (!matched) { + var legacy = url.parse(giturl) + if (legacy.auth) { + var whatwg = new url.URL(giturl) + legacy.auth = whatwg.username || '' + if (whatwg.password) legacy.auth += ':' + whatwg.password + } + return legacy + } return { protocol: 'git+ssh:', slashes: true, diff --git a/test/auth.js b/test/auth.js new file mode 100644 index 0000000..0e5c752 --- /dev/null +++ b/test/auth.js @@ -0,0 +1,18 @@ +var HostedGitInfo = require('../') + +var tap = require('tap') +var url = require('url') + +// Auth credentials with special characters (colon and/or at-sign) should remain correctly escaped +var parsedInfo = HostedGitInfo.fromUrl('https://user%3An%40me:p%40ss%3Aword@github.com/npm/hosted-git-info.git') +tap.equal(parsedInfo.auth, 'user%3An%40me:p%40ss%3Aword') + +// Node.js' built-in `url` module should be able to parse the resulting url +var parsedUrl = new url.URL(parsedInfo.toString()) +tap.equal(parsedUrl.username, 'user%3An%40me') +tap.equal(parsedUrl.password, 'p%40ss%3Aword') +tap.equal(parsedUrl.hostname, 'github.com') + +// For full backwards-compatibility; support auth where only username or only password is provided +tap.equal(HostedGitInfo.fromUrl('https://user%3An%40me@github.com/npm/hosted-git-info.git').auth, 'user%3An%40me') +tap.equal(HostedGitInfo.fromUrl('https://:p%40ss%3Aword@github.com/npm/hosted-git-info.git').auth, ':p%40ss%3Aword')