Skip to content

Commit d5cf830

Browse files
committed
fix: do not allow invalid gist urls
Gists are either name/hex{32}, or just /hex{32}. If someone omits the project, and just specifies a name, then that is an error and should be treated as such. Also, eliminate some dead code paths and bring the tests up to 100%.
1 parent e518222 commit d5cf830

7 files changed

+73
-59
lines changed

git-host-info.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ var gitHosts = module.exports = {
2828
gist: {
2929
'protocols': [ 'git', 'git+ssh', 'git+https', 'ssh', 'https' ],
3030
'domain': 'gist.github.com',
31-
'pathmatch': /^[/](?:([^/]+)[/])?([a-z0-9]+)(?:[.]git)?$/,
31+
'pathmatch': /^[/](?:([^/]+)[/])?([a-z0-9]{32,})(?:[.]git)?$/,
3232
'filetemplate': 'https://gist.githubusercontent.com/{user}/{project}/raw{/committish}/{path}',
3333
'bugstemplate': 'https://{domain}/{project}',
3434
'gittemplate': 'git://{domain}/{project}.git{#committish}',

git-host.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict'
22
var gitHosts = require('./git-host-info.js')
33
/* eslint-disable node/no-deprecated-api */
4+
/* istanbul ignore next */
45
var extend = Object.assign || require('util')._extend
56

67
var GitHost = module.exports = function (type, user, auth, project, committish, defaultRepresentation, opts) {
@@ -127,5 +128,6 @@ GitHost.prototype.getDefaultRepresentation = function () {
127128
}
128129

129130
GitHost.prototype.toString = function (opts) {
130-
return (this[this.default] || this.sshurl).call(this, opts)
131+
const method = this.default || /* istanbul ignore next */ 'sshurl'
132+
return this[method](opts)
131133
}

index.js

+12-10
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,14 @@ var LRU = require('lru-cache')
66
var cache = new LRU({max: 1000})
77

88
var protocolToRepresentationMap = {
9-
'git+ssh': 'sshurl',
10-
'git+https': 'https',
11-
'ssh': 'sshurl',
12-
'git': 'git'
9+
'git+ssh:': 'sshurl',
10+
'git+https:': 'https',
11+
'ssh:': 'sshurl',
12+
'git:': 'git'
1313
}
1414

1515
function protocolToRepresentation (protocol) {
16-
if (protocol.substr(-1) === ':') protocol = protocol.slice(0, -1)
17-
return protocolToRepresentationMap[protocol] || protocol
16+
return protocolToRepresentationMap[protocol] || protocol.slice(0, -1)
1817
}
1918

2019
var authProtocols = {
@@ -65,13 +64,17 @@ function fromUrl (giturl, opts) {
6564
var pathmatch = gitHostInfo.pathmatch
6665
var matched = parsed.path.match(pathmatch)
6766
if (!matched) return
68-
if (matched[1] != null) user = decodeURIComponent(matched[1].replace(/^:/, ''))
69-
if (matched[2] != null) project = decodeURIComponent(matched[2])
67+
if (matched[1] !== null && matched[1] !== undefined) {
68+
user = decodeURIComponent(matched[1].replace(/^:/, ''))
69+
}
70+
project = decodeURIComponent(matched[2])
7071
defaultRepresentation = protocolToRepresentation(parsed.protocol)
7172
}
7273
return new GitHost(gitHostName, user, auth, project, committish, defaultRepresentation, opts)
7374
} catch (ex) {
74-
if (!(ex instanceof URIError)) throw ex
75+
/* istanbul ignore else */
76+
if (ex instanceof URIError) {
77+
} else throw ex
7578
}
7679
}).filter(function (gitHostInfo) { return gitHostInfo })
7780
if (matches.length !== 1) return
@@ -101,7 +104,6 @@ function fixupUnqualifiedGist (giturl) {
101104
}
102105

103106
function parseGitUrl (giturl) {
104-
if (typeof giturl !== 'string') giturl = '' + giturl
105107
var matched = giturl.match(/^([^@]+)@([^:/]+):[/]?((?:[^/]+[/])?[^/]+?)(?:[.]git)?(#.*)?$/)
106108
if (!matched) return url.parse(giturl)
107109
return {

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"postrelease": "npm publish && git push --follow-tags",
2525
"pretest": "standard",
2626
"release": "standard-version -s",
27-
"test": "tap -J --nyc-arg=--all --coverage test"
27+
"test": "tap -J --100 test/*.js"
2828
},
2929
"dependencies": {
3030
"lru-cache": "^5.1.1"

test/gist.js

+24-23
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,43 @@ var HostedGit = require('../index')
33
var test = require('tap').test
44

55
test('fromUrl(gist url)', function (t) {
6+
var proj = new Array(33).join('2')
67
function verify (host, label, branch) {
78
var hostinfo = HostedGit.fromUrl(host)
89
var hash = branch ? '#' + branch : ''
910
t.ok(hostinfo, label)
1011
if (!hostinfo) return
11-
t.is(hostinfo.https(), 'git+https://gist.github.com/222.git' + hash, label + ' -> https')
12-
t.is(hostinfo.git(), 'git://gist.github.com/222.git' + hash, label + ' -> git')
13-
t.is(hostinfo.browse(), 'https://gist.github.com/222' + (branch ? '/' + branch : ''), label + ' -> browse')
14-
t.is(hostinfo.browse('C'), 'https://gist.github.com/222' + (branch ? '/' + branch : '') + '#file-c', label + ' -> browse(path)')
15-
t.is(hostinfo.browse('C', 'A'), 'https://gist.github.com/222' + (branch ? '/' + branch : '') + '#file-c', label + ' -> browse(path, fragment)')
16-
t.is(hostinfo.bugs(), 'https://gist.github.com/222', label + ' -> bugs')
17-
t.is(hostinfo.docs(), 'https://gist.github.com/222' + (branch ? '/' + branch : ''), label + ' -> docs')
18-
t.is(hostinfo.ssh(), 'git@gist.github.com:/222.git' + hash, label + ' -> ssh')
19-
t.is(hostinfo.sshurl(), 'git+ssh://git@gist.github.com/222.git' + hash, label + ' -> sshurl')
20-
t.is(hostinfo.shortcut(), 'gist:222' + hash, label + ' -> shortcut')
12+
t.is(hostinfo.https(), 'git+https://gist.github.com/' + proj + '.git' + hash, label + ' -> https')
13+
t.is(hostinfo.git(), 'git://gist.github.com/' + proj + '.git' + hash, label + ' -> git')
14+
t.is(hostinfo.browse(), 'https://gist.github.com/' + proj + (branch ? '/' + branch : ''), label + ' -> browse')
15+
t.is(hostinfo.browse('C'), 'https://gist.github.com/' + proj + (branch ? '/' + branch : '') + '#file-c', label + ' -> browse(path)')
16+
t.is(hostinfo.browse('C', 'A'), 'https://gist.github.com/' + proj + (branch ? '/' + branch : '') + '#file-c', label + ' -> browse(path, fragment)')
17+
t.is(hostinfo.bugs(), 'https://gist.github.com/' + proj, label + ' -> bugs')
18+
t.is(hostinfo.docs(), 'https://gist.github.com/' + proj + (branch ? '/' + branch : ''), label + ' -> docs')
19+
t.is(hostinfo.ssh(), 'git@gist.github.com:/' + proj + '.git' + hash, label + ' -> ssh')
20+
t.is(hostinfo.sshurl(), 'git+ssh://git@gist.github.com/' + proj + '.git' + hash, label + ' -> sshurl')
21+
t.is(hostinfo.shortcut(), 'gist:' + proj + hash, label + ' -> shortcut')
2122
if (hostinfo.user) {
22-
t.is(hostinfo.file('C'), 'https://gist.githubusercontent.com/111/222/raw/' + (branch ? branch + '/' : '') + 'C', label + ' -> file')
23-
t.is(hostinfo.tarball(), 'https://gist.github.com/111/222/archive/' + (branch || 'master') + '.tar.gz', label + ' -> tarball')
23+
t.is(hostinfo.file('C'), 'https://gist.githubusercontent.com/111/' + proj + '/raw/' + (branch ? branch + '/' : '') + 'C', label + ' -> file')
24+
t.is(hostinfo.tarball(), 'https://gist.github.com/111/' + proj + '/archive/' + (branch || 'master') + '.tar.gz', label + ' -> tarball')
2425
}
2526
}
2627

27-
verify('git@gist.github.com:222.git', 'git@')
28-
var hostinfo = HostedGit.fromUrl('git@gist.github.com:/ef860c7z5e0de3179341.git')
28+
verify('git@gist.github.com:' + proj + '.git', 'git@')
29+
var hostinfo = HostedGit.fromUrl('git@gist.github.com:/c2b12db30a49324325a3781302668408.git')
2930
if (t.ok(hostinfo, 'git@hex')) {
30-
t.is(hostinfo.https(), 'git+https://gist.github.com/ef860c7z5e0de3179341.git', 'git@hex -> https')
31+
t.is(hostinfo.https(), 'git+https://gist.github.com/c2b12db30a49324325a3781302668408.git', 'git@hex -> https')
3132
}
32-
verify('git@gist.github.com:/222.git', 'git@/')
33-
verify('git://gist.github.com/222', 'git')
34-
verify('git://gist.github.com/222.git', 'git.git')
35-
verify('git://gist.github.com/222#branch', 'git#branch', 'branch')
36-
verify('git://gist.github.com/222.git#branch', 'git.git#branch', 'branch')
33+
verify('git@gist.github.com:/' + proj + '.git', 'git@/')
34+
verify('git://gist.github.com/' + proj, 'git')
35+
verify('git://gist.github.com/' + proj + '.git', 'git.git')
36+
verify('git://gist.github.com/' + proj + '#branch', 'git#branch', 'branch')
37+
verify('git://gist.github.com/' + proj + '.git#branch', 'git.git#branch', 'branch')
3738

38-
require('./lib/standard-tests')(verify, 'gist.github.com', 'gist')
39+
require('./lib/standard-tests')(verify, 'gist.github.com', 'gist', proj)
3940

40-
verify(HostedGit.fromUrl('gist:111/222').toString(), 'round-tripped shortcut')
41-
verify('gist:222', 'shortened shortcut')
41+
verify(HostedGit.fromUrl('gist:111/' + proj).toString(), 'round-tripped shortcut')
42+
verify('gist:' + proj, 'shortened shortcut')
4243

4344
t.end()
4445
})

test/github.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,23 @@ test('fromUrl(github url)', function (t) {
66
function verify (host, label, branch) {
77
var hostinfo = HostedGit.fromUrl(host)
88
var hash = branch ? '#' + branch : ''
9+
var treebranch = branch ? '/tree/' + branch : ''
10+
t.equal(hostinfo._fill(), undefined)
911
t.ok(hostinfo, label)
1012
if (!hostinfo) return
1113
t.is(hostinfo.https(), 'git+https://github.com/111/222.git' + hash, label + ' -> https')
1214
t.is(hostinfo.git(), 'git://github.com/111/222.git' + hash, label + ' -> git')
13-
t.is(hostinfo.browse(), 'https://github.com/111/222' + (branch ? '/tree/' + branch : ''), label + ' -> browse')
15+
t.is(hostinfo.browse(), 'https://github.com/111/222' + treebranch, label + ' -> browse')
1416
t.is(hostinfo.browse('C'), 'https://github.com/111/222/tree/' + (branch || 'master') + '/C', label + ' -> browse(path)')
1517
t.is(hostinfo.browse('C', 'A'), 'https://github.com/111/222/tree/' + (branch || 'master') + '/C#a', label + ' -> browse(path, fragment)')
1618
t.is(hostinfo.bugs(), 'https://github.com/111/222/issues', label + ' -> bugs')
17-
t.is(hostinfo.docs(), 'https://github.com/111/222' + (branch ? '/tree/' + branch : '') + '#readme', label + ' -> docs')
19+
t.is(hostinfo.docs(), 'https://github.com/111/222' + treebranch + '#readme', label + ' -> docs')
1820
t.is(hostinfo.ssh(), 'git@github.com:111/222.git' + hash, label + ' -> ssh')
1921
t.is(hostinfo.sshurl(), 'git+ssh://git@github.com/111/222.git' + hash, label + ' -> sshurl')
22+
t.is(hostinfo.sshurl({ noGitPlus: true }), 'ssh://git@github.com/111/222.git' + hash, label + ' -> sshurl (no git plus)')
23+
t.is(hostinfo.path(), '111/222' + hash, ' -> path')
24+
t.is(hostinfo.hash(), hash, ' -> hash')
25+
t.is(hostinfo.path({ noCommittish: true }), '111/222', ' -> path (no committish)')
2026
t.is(hostinfo.shortcut(), 'github:111/222' + hash, label + ' -> shortcut')
2127
t.is(hostinfo.file('C'), 'https://raw.githubusercontent.com/111/222/' + (branch || 'master') + '/C', label + ' -> file')
2228
t.is(hostinfo.tarball(), 'https://codeload.github.com/111/222/tar.gz/' + (branch || 'master'), label + ' -> tarball')
@@ -41,5 +47,7 @@ test('fromUrl(github url)', function (t) {
4147

4248
require('./lib/standard-tests')(verify, 'www.github.com', 'github')
4349

50+
t.equal(HostedGit.fromUrl('git+ssh://github.com/foo.git'), undefined)
51+
4452
t.end()
4553
})

test/lib/standard-tests.js

+22-21
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
'use strict'
2-
module.exports = function (verify, domain, shortname) {
3-
verify('https://' + domain + '/111/222', 'https')
4-
verify('https://' + domain + '/111/222.git', 'https.git')
5-
verify('https://' + domain + '/111/222#branch', 'https#branch', 'branch')
6-
verify('https://' + domain + '/111/222.git#branch', 'https.git#branch', 'branch')
2+
module.exports = function (verify, domain, shortname, proj) {
3+
proj = proj || '222'
4+
verify('https://' + domain + '/111/' + proj, 'https')
5+
verify('https://' + domain + '/111/' + proj + '.git', 'https.git')
6+
verify('https://' + domain + '/111/' + proj + '#branch', 'https#branch', 'branch')
7+
verify('https://' + domain + '/111/' + proj + '.git#branch', 'https.git#branch', 'branch')
78

8-
verify('git+https://' + domain + '/111/222', 'git+https')
9-
verify('git+https://' + domain + '/111/222.git', 'git+https.git')
10-
verify('git+https://' + domain + '/111/222#branch', 'git+https#branch', 'branch')
11-
verify('git+https://' + domain + '/111/222.git#branch', 'git+https.git#branch', 'branch')
9+
verify('git+https://' + domain + '/111/' + proj, 'git+https')
10+
verify('git+https://' + domain + '/111/' + proj + '.git', 'git+https.git')
11+
verify('git+https://' + domain + '/111/' + proj + '#branch', 'git+https#branch', 'branch')
12+
verify('git+https://' + domain + '/111/' + proj + '.git#branch', 'git+https.git#branch', 'branch')
1213

13-
verify('git@' + domain + ':111/222', 'ssh')
14-
verify('git@' + domain + ':111/222.git', 'ssh.git')
15-
verify('git@' + domain + ':111/222#branch', 'ssh', 'branch')
16-
verify('git@' + domain + ':111/222.git#branch', 'ssh.git', 'branch')
14+
verify('git@' + domain + ':111/' + proj, 'ssh')
15+
verify('git@' + domain + ':111/' + proj + '.git', 'ssh.git')
16+
verify('git@' + domain + ':111/' + proj + '#branch', 'ssh', 'branch')
17+
verify('git@' + domain + ':111/' + proj + '.git#branch', 'ssh.git', 'branch')
1718

18-
verify('git+ssh://git@' + domain + '/111/222', 'ssh url')
19-
verify('git+ssh://git@' + domain + '/111/222.git', 'ssh url.git')
20-
verify('git+ssh://git@' + domain + '/111/222#branch', 'ssh url#branch', 'branch')
21-
verify('git+ssh://git@' + domain + '/111/222.git#branch', 'ssh url.git#branch', 'branch')
19+
verify('git+ssh://git@' + domain + '/111/' + proj, 'ssh url')
20+
verify('git+ssh://git@' + domain + '/111/' + proj + '.git', 'ssh url.git')
21+
verify('git+ssh://git@' + domain + '/111/' + proj + '#branch', 'ssh url#branch', 'branch')
22+
verify('git+ssh://git@' + domain + '/111/' + proj + '.git#branch', 'ssh url.git#branch', 'branch')
2223

23-
verify(shortname + ':111/222', 'shortcut')
24-
verify(shortname + ':111/222.git', 'shortcut.git')
25-
verify(shortname + ':111/222#branch', 'shortcut#branch', 'branch')
26-
verify(shortname + ':111/222.git#branch', 'shortcut.git#branch', 'branch')
24+
verify(shortname + ':111/' + proj, 'shortcut')
25+
verify(shortname + ':111/' + proj + '.git', 'shortcut.git')
26+
verify(shortname + ':111/' + proj + '#branch', 'shortcut#branch', 'branch')
27+
verify(shortname + ':111/' + proj + '.git#branch', 'shortcut.git#branch', 'branch')
2728
}

0 commit comments

Comments
 (0)