diff --git a/nvm.sh b/nvm.sh index 0c48cb94..cc18543d 100755 --- a/nvm.sh +++ b/nvm.sh @@ -2388,7 +2388,14 @@ nvm_get_mirror() { esac - if ! nvm_echo "${NVM_MIRROR}" | command awk '{ if ($0 !~ /^https?:\/\/[a-zA-Z0-9.\/_-]+$/) exit 1 }'; then + # Allow RFC 3986 `unreserved` (A-Za-z0-9-._~) plus the authority and path + # punctuation a mirror URL legitimately needs: `:` for a port, `@` for + # userinfo, `[`/`]` for an IPv6 literal host, `%` for percent-encoding. + # `sub-delims` (!$&'()*+,;=) and the query/fragment delimiters (?#) stay out: + # nvm appends a path to this value, so a query string could never work anyway, + # and several of those characters are shell metacharacters. + # Note: in a bracket expression `]` must come first and `-` last to be literal. + if ! nvm_echo "${NVM_MIRROR}" | command awk '{ if ($0 !~ /^https?:\/\/[]a-zA-Z0-9._~:\/@%[-]+$/) exit 1 }'; then nvm_err '$NVM_NODEJS_ORG_MIRROR and $NVM_IOJS_ORG_MIRROR may only contain a URL' return 2 fi diff --git a/test/fast/Unit tests/nvm_get_mirror b/test/fast/Unit tests/nvm_get_mirror index 0c16ff4d..fd2ea940 100755 --- a/test/fast/Unit tests/nvm_get_mirror +++ b/test/fast/Unit tests/nvm_get_mirror @@ -52,3 +52,26 @@ testMirrors 'not a url' testMirrors 'ftp://wrong-scheme' testMirrors 'http://' testMirrors 'javascript:alert(1)' + +# a query string can never work, since nvm appends a path to the mirror +testMirrors 'https://nodejs.org/dist?token=abc' +testMirrors 'https://nodejs.org/dist#frag' + +testAcceptedMirrors() { + NVM_NODEJS_ORG_MIRROR="${1-}" + [ "$(nvm_get_mirror node std)" = "${1-}" ] || die "NVM_NODEJS_ORG_MIRROR should accept ${1-}" + unset NVM_NODEJS_ORG_MIRROR + + NVM_IOJS_ORG_MIRROR="${1-}" + [ "$(nvm_get_mirror iojs std)" = "${1-}" ] || die "NVM_IOJS_ORG_MIRROR should accept ${1-}" + unset NVM_IOJS_ORG_MIRROR +} + +# a private mirror on a non-default port is a URL, and must not be rejected +testAcceptedMirrors 'https://mirror.internal:8443/dist' +testAcceptedMirrors 'http://localhost:8080/dist' +# an IPv6 literal host, userinfo, percent-encoding, and `~` are all legal too +testAcceptedMirrors 'http://[::1]:8080/dist' +testAcceptedMirrors 'https://user:pw@nexus.corp.example.com/repository/nodejs-dist' +testAcceptedMirrors 'https://mirror.internal/a%20b/dist' +testAcceptedMirrors 'https://mirror.internal/~dist'