index.js 3.2 KB

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