From 3776fa52203a125fd32d671612b0dd2b303970e8 Mon Sep 17 00:00:00 2001 From: Masafumi Koba Date: Thu, 21 Mar 2019 14:20:22 +0900 Subject: [PATCH] fix(git-host): disallow URI-encoded slash (%2F) in `path` PR-URL: https://github.com/npm/hosted-git-info/pull/44 Credit: @ybiquitous Close: #44 Reviewed-by: @isaacs --- git-host.js | 9 ++++++++- test/bitbucket.js | 5 +++++ test/gist.js | 4 ++++ test/github.js | 5 +++++ test/gitlab.js | 5 +++++ test/https-with-inline-auth.js | 3 +++ 6 files changed, 30 insertions(+), 1 deletion(-) diff --git a/git-host.js b/git-host.js index dd9036e..60fec3c 100644 --- a/git-host.js +++ b/git-host.js @@ -38,7 +38,14 @@ GitHost.prototype._fill = function (template, opts) { var rawPath = vars.path var rawProject = vars.project Object.keys(vars).forEach(function (key) { - vars[key] = encodeURIComponent(vars[key]) + var value = vars[key] + if (key === 'path' && typeof value === 'string') { + vars[key] = value.split('/').map(function (pathComponent) { + return encodeURIComponent(pathComponent) + }).join('/') + } else { + vars[key] = encodeURIComponent(value) + } }) vars['auth@'] = rawAuth ? rawAuth + '@' : '' vars['#fragment'] = rawFragment ? '#' + this.hashformat(rawFragment) : '' diff --git a/test/bitbucket.js b/test/bitbucket.js index 8f08a5e..fe6297f 100644 --- a/test/bitbucket.js +++ b/test/bitbucket.js @@ -10,13 +10,18 @@ test('fromUrl(bitbucket url)', function (t) { if (!hostinfo) return t.is(hostinfo.https(), 'git+https://bitbucket.org/111/222.git' + hash, label + ' -> https') t.is(hostinfo.browse(), 'https://bitbucket.org/111/222' + (branch ? '/src/' + branch : ''), label + ' -> browse') + t.is(hostinfo.browse(''), 'https://bitbucket.org/111/222/src/' + (branch || 'master') + '/', label + ' -> browse(path)') t.is(hostinfo.browse('C'), 'https://bitbucket.org/111/222/src/' + (branch || 'master') + '/C', label + ' -> browse(path)') + t.is(hostinfo.browse('C/D'), 'https://bitbucket.org/111/222/src/' + (branch || 'master') + '/C/D', label + ' -> browse(path)') t.is(hostinfo.browse('C', 'A'), 'https://bitbucket.org/111/222/src/' + (branch || 'master') + '/C#a', label + ' -> browse(path, fragment)') + t.is(hostinfo.browse('C/D', 'A'), 'https://bitbucket.org/111/222/src/' + (branch || 'master') + '/C/D#a', label + ' -> browse(path, fragment)') t.is(hostinfo.docs(), 'https://bitbucket.org/111/222' + (branch ? '/src/' + branch : '') + '#readme', label + ' -> docs') t.is(hostinfo.ssh(), 'git@bitbucket.org:111/222.git' + hash, label + ' -> ssh') t.is(hostinfo.sshurl(), 'git+ssh://git@bitbucket.org/111/222.git' + hash, label + ' -> sshurl') t.is(hostinfo.shortcut(), 'bitbucket:111/222' + hash, label + ' -> shortcut') + t.is(hostinfo.file(''), 'https://bitbucket.org/111/222/raw/' + (branch || 'master') + '/', label + ' -> file') t.is(hostinfo.file('C'), 'https://bitbucket.org/111/222/raw/' + (branch || 'master') + '/C', label + ' -> file') + t.is(hostinfo.file('C/D'), 'https://bitbucket.org/111/222/raw/' + (branch || 'master') + '/C/D', label + ' -> file') t.is(hostinfo.tarball(), 'https://bitbucket.org/111/222/get/' + (branch || 'master') + '.tar.gz', label + ' -> tarball') } diff --git a/test/gist.js b/test/gist.js index edfda02..a40cf26 100644 --- a/test/gist.js +++ b/test/gist.js @@ -13,14 +13,18 @@ test('fromUrl(gist url)', function (t) { t.is(hostinfo.git(), 'git://gist.github.com/' + proj + '.git' + hash, label + ' -> git') t.is(hostinfo.browse(), 'https://gist.github.com/' + proj + (branch ? '/' + branch : ''), label + ' -> browse') t.is(hostinfo.browse('C'), 'https://gist.github.com/' + proj + (branch ? '/' + branch : '') + '#file-c', label + ' -> browse(path)') + t.is(hostinfo.browse('C/D'), 'https://gist.github.com/' + proj + (branch ? '/' + branch : '') + '#file-cd', label + ' -> browse(path)') t.is(hostinfo.browse('C', 'A'), 'https://gist.github.com/' + proj + (branch ? '/' + branch : '') + '#file-c', label + ' -> browse(path, fragment)') + t.is(hostinfo.browse('C/D', 'A'), 'https://gist.github.com/' + proj + (branch ? '/' + branch : '') + '#file-cd', label + ' -> browse(path)') t.is(hostinfo.bugs(), 'https://gist.github.com/' + proj, label + ' -> bugs') t.is(hostinfo.docs(), 'https://gist.github.com/' + proj + (branch ? '/' + branch : ''), label + ' -> docs') t.is(hostinfo.ssh(), 'git@gist.github.com:/' + proj + '.git' + hash, label + ' -> ssh') t.is(hostinfo.sshurl(), 'git+ssh://git@gist.github.com/' + proj + '.git' + hash, label + ' -> sshurl') t.is(hostinfo.shortcut(), 'gist:' + proj + hash, label + ' -> shortcut') if (hostinfo.user) { + t.is(hostinfo.file(''), 'https://gist.githubusercontent.com/111/' + proj + '/raw/' + (branch ? branch + '/' : ''), label + ' -> file') t.is(hostinfo.file('C'), 'https://gist.githubusercontent.com/111/' + proj + '/raw/' + (branch ? branch + '/' : '') + 'C', label + ' -> file') + t.is(hostinfo.file('C/D'), 'https://gist.githubusercontent.com/111/' + proj + '/raw/' + (branch ? branch + '/' : '') + 'C/D', label + ' -> file') t.is(hostinfo.tarball(), 'https://gist.github.com/111/' + proj + '/archive/' + (branch || 'master') + '.tar.gz', label + ' -> tarball') } } diff --git a/test/github.js b/test/github.js index 8a4b6cc..755f1fe 100644 --- a/test/github.js +++ b/test/github.js @@ -13,8 +13,11 @@ test('fromUrl(github url)', function (t) { t.is(hostinfo.https(), 'git+https://github.com/111/222.git' + hash, label + ' -> https') t.is(hostinfo.git(), 'git://github.com/111/222.git' + hash, label + ' -> git') t.is(hostinfo.browse(), 'https://github.com/111/222' + treebranch, label + ' -> browse') + t.is(hostinfo.browse(''), 'https://github.com/111/222/tree/' + (branch || 'master') + '/', label + ' -> browse("")') t.is(hostinfo.browse('C'), 'https://github.com/111/222/tree/' + (branch || 'master') + '/C', label + ' -> browse(path)') + t.is(hostinfo.browse('C/D'), 'https://github.com/111/222/tree/' + (branch || 'master') + '/C/D', label + ' -> browse(path)') t.is(hostinfo.browse('C', 'A'), 'https://github.com/111/222/tree/' + (branch || 'master') + '/C#a', label + ' -> browse(path, fragment)') + t.is(hostinfo.browse('C/D', 'A'), 'https://github.com/111/222/tree/' + (branch || 'master') + '/C/D#a', label + ' -> browse(path, fragment)') t.is(hostinfo.bugs(), 'https://github.com/111/222/issues', label + ' -> bugs') t.is(hostinfo.docs(), 'https://github.com/111/222' + treebranch + '#readme', label + ' -> docs') t.is(hostinfo.ssh(), 'git@github.com:111/222.git' + hash, label + ' -> ssh') @@ -24,7 +27,9 @@ test('fromUrl(github url)', function (t) { t.is(hostinfo.hash(), hash, ' -> hash') t.is(hostinfo.path({ noCommittish: true }), '111/222', ' -> path (no committish)') t.is(hostinfo.shortcut(), 'github:111/222' + hash, label + ' -> shortcut') + t.is(hostinfo.file(''), 'https://raw.githubusercontent.com/111/222/' + (branch || 'master') + '/', label + ' -> file') t.is(hostinfo.file('C'), 'https://raw.githubusercontent.com/111/222/' + (branch || 'master') + '/C', label + ' -> file') + t.is(hostinfo.file('C/D'), 'https://raw.githubusercontent.com/111/222/' + (branch || 'master') + '/C/D', label + ' -> file') t.is(hostinfo.tarball(), 'https://codeload.github.com/111/222/tar.gz/' + (branch || 'master'), label + ' -> tarball') } diff --git a/test/gitlab.js b/test/gitlab.js index 289d934..36e6307 100644 --- a/test/gitlab.js +++ b/test/gitlab.js @@ -10,13 +10,18 @@ test('fromUrl(gitlab url)', function (t) { if (!hostinfo) return t.is(hostinfo.https(), 'git+https://gitlab.com/111/222.git' + hash, label + ' -> https') t.is(hostinfo.browse(), 'https://gitlab.com/111/222' + (branch ? '/tree/' + branch : ''), label + ' -> browse') + t.is(hostinfo.browse(''), 'https://gitlab.com/111/222/tree/' + (branch || 'master') + '/', label + ' -> browse(path)') t.is(hostinfo.browse('C'), 'https://gitlab.com/111/222/tree/' + (branch || 'master') + '/C', label + ' -> browse(path)') + t.is(hostinfo.browse('C/D'), 'https://gitlab.com/111/222/tree/' + (branch || 'master') + '/C/D', label + ' -> browse(path)') t.is(hostinfo.browse('C', 'A'), 'https://gitlab.com/111/222/tree/' + (branch || 'master') + '/C#a', label + ' -> browse(path, fragment)') + t.is(hostinfo.browse('C/D', 'A'), 'https://gitlab.com/111/222/tree/' + (branch || 'master') + '/C/D#a', label + ' -> browse(path, fragment)') t.is(hostinfo.docs(), 'https://gitlab.com/111/222' + (branch ? '/tree/' + branch : '') + '#readme', label + ' -> docs') t.is(hostinfo.ssh(), 'git@gitlab.com:111/222.git' + hash, label + ' -> ssh') t.is(hostinfo.sshurl(), 'git+ssh://git@gitlab.com/111/222.git' + hash, label + ' -> sshurl') t.is(hostinfo.shortcut(), 'gitlab:111/222' + hash, label + ' -> shortcut') + t.is(hostinfo.file(''), 'https://gitlab.com/111/222/raw/' + (branch || 'master') + '/', label + ' -> file') t.is(hostinfo.file('C'), 'https://gitlab.com/111/222/raw/' + (branch || 'master') + '/C', label + ' -> file') + t.is(hostinfo.file('C/D'), 'https://gitlab.com/111/222/raw/' + (branch || 'master') + '/C/D', label + ' -> file') t.is(hostinfo.tarball(), 'https://gitlab.com/111/222/repository/archive.tar.gz?ref=' + (branch || 'master'), label + ' -> tarball') } diff --git a/test/https-with-inline-auth.js b/test/https-with-inline-auth.js index dde0638..b14cb29 100644 --- a/test/https-with-inline-auth.js +++ b/test/https-with-inline-auth.js @@ -12,13 +12,16 @@ test('HTTPS GitHub URL with embedded auth -- generally not a good idea', functio t.is(hostinfo.git(), 'git://user:pass@github.com/111/222.git' + hash, label + ' -> git') t.is(hostinfo.browse(), 'https://github.com/111/222' + (branch ? '/tree/' + branch : ''), label + ' -> browse') t.is(hostinfo.browse('C'), 'https://github.com/111/222/tree/' + (branch || 'master') + '/C', label + ' -> browse(path)') + t.is(hostinfo.browse('C/D'), 'https://github.com/111/222/tree/' + (branch || 'master') + '/C/D', label + ' -> browse(path)') t.is(hostinfo.browse('C', 'A'), 'https://github.com/111/222/tree/' + (branch || 'master') + '/C#a', label + ' -> browse(path, fragment)') + t.is(hostinfo.browse('C/D', 'A'), 'https://github.com/111/222/tree/' + (branch || 'master') + '/C/D#a', label + ' -> browse(path, fragment)') t.is(hostinfo.bugs(), 'https://github.com/111/222/issues', label + ' -> bugs') t.is(hostinfo.docs(), 'https://github.com/111/222' + (branch ? '/tree/' + branch : '') + '#readme', label + ' -> docs') t.is(hostinfo.ssh(), 'git@github.com:111/222.git' + hash, label + ' -> ssh') t.is(hostinfo.sshurl(), 'git+ssh://git@github.com/111/222.git' + hash, label + ' -> sshurl') t.is(hostinfo.shortcut(), 'github:111/222' + hash, label + ' -> shortcut') t.is(hostinfo.file('C'), 'https://user:pass@raw.githubusercontent.com/111/222/' + (branch || 'master') + '/C', label + ' -> file') + t.is(hostinfo.file('C/D'), 'https://user:pass@raw.githubusercontent.com/111/222/' + (branch || 'master') + '/C/D', label + ' -> file') } // insecure protocols