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