index.js 3.8 KB

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