diff --git a/lib/commands/help.js b/lib/commands/help.js index 0de047615711a..2986f917f9e0f 100644 --- a/lib/commands/help.js +++ b/lib/commands/help.js @@ -120,7 +120,7 @@ class Help extends BaseCommand { break case 'browser': - await openUrl(this.npm, this.htmlMan(man), 'help available at the following URL') + await openUrl(this.npm, this.htmlMan(man), 'help available at the following URL', true) return default: diff --git a/lib/utils/open-url.js b/lib/utils/open-url.js index ddbbddccf3be4..eed2449dcce51 100644 --- a/lib/utils/open-url.js +++ b/lib/utils/open-url.js @@ -3,7 +3,7 @@ const opener = require('opener') const { URL } = require('url') // attempt to open URL in web-browser, print address otherwise: -const open = async (npm, url, errMsg) => { +const open = async (npm, url, errMsg, isFile) => { url = encodeURI(url) const browser = npm.config.get('browser') @@ -24,12 +24,16 @@ const open = async (npm, url, errMsg) => { return } - try { - if (!/^https?:$/.test(new URL(url).protocol)) { - throw new Error() + // We pass this in as true from the help command so we know we don't have to + // check the protocol + if (!isFile) { + try { + if (!/^https?:$/.test(new URL(url).protocol)) { + throw new Error() + } + } catch (_) { + throw new Error('Invalid URL: ' + url) } - } catch (_) { - throw new Error('Invalid URL: ' + url) } const command = browser === true ? null : browser diff --git a/test/lib/utils/open-url.js b/test/lib/utils/open-url.js index cc63af12943a1..1bf47d8bbaedc 100644 --- a/test/lib/utils/open-url.js +++ b/test/lib/utils/open-url.js @@ -73,6 +73,18 @@ t.test('returns error for file url', async t => { t.same(OUTPUT, [], 'printed no output') }) +t.test('file url allowed if explicitly asked for', async t => { + t.teardown(() => { + openerUrl = null + openerOpts = null + OUTPUT.length = 0 + }) + await openUrl(npm, 'file:///man/page/npm-install', 'npm home', true) + t.equal(openerUrl, 'file:///man/page/npm-install', 'opened the given url') + t.same(openerOpts, { command: null }, 'passed command as null (the default)') + t.same(OUTPUT, [], 'printed no output') +}) + t.test('returns error for non-parseable url', async t => { t.teardown(() => { openerUrl = null