Skip to content

Commit 56d6cfd

Browse files
committed
fix: encode url before opening
will filter out a small subset of non-URL-safe characters that still parse properly with `new URL` PR-URL: #3804 Credit: @isaacs Close: #3804 Reviewed-by: @wraithgar
1 parent 69ab10b commit 56d6cfd

File tree

2 files changed

+15
-9
lines changed

2 files changed

+15
-9
lines changed

lib/utils/open-url.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const { URL } = require('url')
44

55
// attempt to open URL in web-browser, print address otherwise:
66
const open = async (npm, url, errMsg) => {
7+
url = encodeURI(url)
78
const browser = npm.config.get('browser')
89

910
function printAlternateMsg () {

test/lib/utils/open-url.js

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,10 @@ t.test('returns error for non-https and non-file url', async (t) => {
4747
openerOpts = null
4848
OUTPUT.length = 0
4949
})
50-
t.rejects(openUrl(npm, 'ftp://www.npmjs.com', 'npm home'), /Invalid URL/, 'got the correct error')
50+
await t.rejects(openUrl(npm, 'ftp://www.npmjs.com', 'npm home'), /Invalid URL/, 'got the correct error')
5151
t.equal(openerUrl, null, 'did not open')
5252
t.same(openerOpts, null, 'did not open')
5353
t.same(OUTPUT, [], 'printed no output')
54-
t.end()
5554
})
5655

5756
t.test('returns error for non-parseable url', async (t) => {
@@ -60,11 +59,22 @@ t.test('returns error for non-parseable url', async (t) => {
6059
openerOpts = null
6160
OUTPUT.length = 0
6261
})
63-
t.rejects(openUrl(npm, 'git+ssh://user@host:repo.git', 'npm home'), /Invalid URL/, 'got the correct error')
62+
await t.rejects(openUrl(npm, 'git+ssh://user@host:repo.git', 'npm home'), /Invalid URL/, 'got the correct error')
6463
t.equal(openerUrl, null, 'did not open')
6564
t.same(openerOpts, null, 'did not open')
6665
t.same(OUTPUT, [], 'printed no output')
67-
t.end()
66+
})
67+
68+
t.test('encodes non-URL-safe characters in url provided', async (t) => {
69+
t.teardown(() => {
70+
openerUrl = null
71+
openerOpts = null
72+
OUTPUT.length = 0
73+
})
74+
await openUrl(npm, 'https://www.npmjs.com/|cat', 'npm home')
75+
t.equal(openerUrl, 'https://www.npmjs.com/%7Ccat', 'opened the encoded url')
76+
t.same(openerOpts, { command: null }, 'passed command as null (the default)')
77+
t.same(OUTPUT, [], 'printed no output')
6878
})
6979

7080
t.test('opens a url with the given browser', async (t) => {
@@ -79,7 +89,6 @@ t.test('opens a url with the given browser', async (t) => {
7989
t.equal(openerUrl, 'https://www.npmjs.com', 'opened the given url')
8090
t.same(openerOpts, { command: 'chrome' }, 'passed the given browser as command')
8191
t.same(OUTPUT, [], 'printed no output')
82-
t.end()
8392
})
8493

8594
t.test('prints where to go when browser is disabled', async (t) => {
@@ -96,7 +105,6 @@ t.test('prints where to go when browser is disabled', async (t) => {
96105
t.equal(OUTPUT.length, 1, 'got one logged message')
97106
t.equal(OUTPUT[0].length, 1, 'logged message had one value')
98107
t.matchSnapshot(OUTPUT[0][0], 'printed expected message')
99-
t.end()
100108
})
101109

102110
t.test('prints where to go when browser is disabled and json is enabled', async (t) => {
@@ -115,7 +123,6 @@ t.test('prints where to go when browser is disabled and json is enabled', async
115123
t.equal(OUTPUT.length, 1, 'got one logged message')
116124
t.equal(OUTPUT[0].length, 1, 'logged message had one value')
117125
t.matchSnapshot(OUTPUT[0][0], 'printed expected message')
118-
t.end()
119126
})
120127

121128
t.test('prints where to go when given browser does not exist', async (t) => {
@@ -133,7 +140,6 @@ t.test('prints where to go when given browser does not exist', async (t) => {
133140
t.equal(OUTPUT.length, 1, 'got one logged message')
134141
t.equal(OUTPUT[0].length, 1, 'logged message had one value')
135142
t.matchSnapshot(OUTPUT[0][0], 'printed expected message')
136-
t.end()
137143
})
138144

139145
t.test('handles unknown opener error', async (t) => {
@@ -146,5 +152,4 @@ t.test('handles unknown opener error', async (t) => {
146152
npm.config.set('browser', true)
147153
})
148154
t.rejects(openUrl(npm, 'https://www.npmjs.com', 'npm home'), 'failed', 'got the correct error')
149-
t.end()
150155
})

0 commit comments

Comments
 (0)