• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1var url = require('url')
2var base64 = require('./base64')
3
4var decodeBase64 = base64.decodeBase64
5var encodeBase64 = base64.encodeBase64
6
7var tokenKey = ':_authToken'
8var userKey = ':username'
9var passwordKey = ':_password'
10
11module.exports = function () {
12  var checkUrl
13  var options
14  if (arguments.length >= 2) {
15    checkUrl = arguments[0]
16    options = arguments[1]
17  } else if (typeof arguments[0] === 'string') {
18    checkUrl = arguments[0]
19  } else {
20    options = arguments[0]
21  }
22  options = options || {}
23  options.npmrc = options.npmrc || require('rc')('npm', {registry: 'https://registry.npmjs.org/'})
24  checkUrl = checkUrl || options.npmrc.registry
25  return getRegistryAuthInfo(checkUrl, options) || getLegacyAuthInfo(options.npmrc)
26}
27
28function getRegistryAuthInfo (checkUrl, options) {
29  var parsed = url.parse(checkUrl, false, true)
30  var pathname
31
32  while (pathname !== '/' && parsed.pathname !== pathname) {
33    pathname = parsed.pathname || '/'
34
35    var regUrl = '//' + parsed.host + pathname.replace(/\/$/, '')
36    var authInfo = getAuthInfoForUrl(regUrl, options.npmrc)
37    if (authInfo) {
38      return authInfo
39    }
40
41    // break if not recursive
42    if (!options.recursive) {
43      return /\/$/.test(checkUrl)
44        ? undefined
45        : getRegistryAuthInfo(url.resolve(checkUrl, '.'), options)
46    }
47
48    parsed.pathname = url.resolve(normalizePath(pathname), '..') || '/'
49  }
50
51  return undefined
52}
53
54function getLegacyAuthInfo (npmrc) {
55  if (!npmrc._auth) {
56    return undefined
57  }
58
59  var token = replaceEnvironmentVariable(npmrc._auth)
60
61  return {token: token, type: 'Basic'}
62}
63
64function normalizePath (path) {
65  return path[path.length - 1] === '/' ? path : path + '/'
66}
67
68function getAuthInfoForUrl (regUrl, npmrc) {
69  // try to get bearer token
70  var bearerAuth = getBearerToken(npmrc[regUrl + tokenKey] || npmrc[regUrl + '/' + tokenKey])
71  if (bearerAuth) {
72    return bearerAuth
73  }
74
75  // try to get basic token
76  var username = npmrc[regUrl + userKey] || npmrc[regUrl + '/' + userKey]
77  var password = npmrc[regUrl + passwordKey] || npmrc[regUrl + '/' + passwordKey]
78  var basicAuth = getTokenForUsernameAndPassword(username, password)
79  if (basicAuth) {
80    return basicAuth
81  }
82
83  return undefined
84}
85
86function replaceEnvironmentVariable (token) {
87  return token.replace(/^\$\{?([^}]*)\}?$/, function (fullMatch, envVar) {
88    return process.env[envVar]
89  })
90}
91
92function getBearerToken (tok) {
93  if (!tok) {
94    return undefined
95  }
96
97  // check if bearer token is set as environment variable
98  var token = replaceEnvironmentVariable(tok)
99
100  return {token: token, type: 'Bearer'}
101}
102
103function getTokenForUsernameAndPassword (username, password) {
104  if (!username || !password) {
105    return undefined
106  }
107
108  // passwords are base64 encoded, so we need to decode it
109  // See https://github.com/npm/npm/blob/v3.10.6/lib/config/set-credentials-by-uri.js#L26
110  var pass = decodeBase64(replaceEnvironmentVariable(password))
111
112  // a basic auth token is base64 encoded 'username:password'
113  // See https://github.com/npm/npm/blob/v3.10.6/lib/config/get-credentials-by-uri.js#L70
114  var token = encodeBase64(username + ':' + pass)
115
116  // we found a basicToken token so let's exit the loop
117  return {
118    token: token,
119    type: 'Basic',
120    password: pass,
121    username: username
122  }
123}
124