1var fs = require('fs') 2var path = require('path') 3var mocha = require('mocha') 4var assert = require('assert') 5var requireUncached = require('require-uncached') 6 7var npmRcPath = path.join(__dirname, '..', '.npmrc') 8var afterEach = mocha.afterEach 9var describe = mocha.describe 10var it = mocha.it 11 12var base64 = require('../base64') 13var decodeBase64 = base64.decodeBase64 14var encodeBase64 = base64.encodeBase64 15 16/* eslint max-nested-callbacks: ["error", 4] */ 17 18describe('auth-token', function () { 19 afterEach(function (done) { 20 fs.unlink(npmRcPath, function () { 21 done() 22 }) 23 }) 24 25 it('should read global if no local is found', function () { 26 var getAuthToken = requireUncached('../index') 27 getAuthToken() 28 }) 29 30 it('should return undefined if no auth token is given for registry', function (done) { 31 fs.writeFile(npmRcPath, 'registry=http://registry.npmjs.eu/', function (err) { 32 var getAuthToken = requireUncached('../index') 33 assert(!err, err) 34 assert(!getAuthToken()) 35 done() 36 }) 37 }) 38 39 describe('legacy auth token', function () { 40 it('should return auth token if it is defined in the legacy way via the `_auth` key', function (done) { 41 var content = [ 42 '_auth=foobar', 43 'registry=http://registry.foobar.eu/' 44 ].join('\n') 45 46 fs.writeFile(npmRcPath, content, function (err) { 47 var getAuthToken = requireUncached('../index') 48 assert(!err, err) 49 assert.deepEqual(getAuthToken(), {token: 'foobar', type: 'Basic'}) 50 done() 51 }) 52 }) 53 54 it('should return legacy auth token defined by reference to an environment variable (with curly braces)', function (done) { 55 var environmentVariable = '__REGISTRY_AUTH_TOKEN_NPM_TOKEN__' 56 var content = [ 57 '_auth=${' + environmentVariable + '}', 58 'registry=http://registry.foobar.eu/' 59 ].join('\n') 60 61 process.env[environmentVariable] = 'foobar' 62 63 fs.writeFile(npmRcPath, content, function (err) { 64 var getAuthToken = requireUncached('../index') 65 assert(!err, err) 66 assert.deepEqual(getAuthToken(), {token: 'foobar', type: 'Basic'}) 67 delete process.env[environmentVariable] 68 done() 69 }) 70 }) 71 72 it('should return legacy auth token defined by reference to an environment variable (without curly braces)', function (done) { 73 var environmentVariable = '__REGISTRY_AUTH_TOKEN_NPM_TOKEN__' 74 var content = [ 75 '_auth=$' + environmentVariable, 76 'registry=http://registry.foobar.eu/' 77 ].join('\n') 78 79 process.env[environmentVariable] = 'foobar' 80 81 fs.writeFile(npmRcPath, content, function (err) { 82 var getAuthToken = requireUncached('../index') 83 assert(!err, err) 84 assert.deepEqual(getAuthToken(), {token: 'foobar', type: 'Basic'}) 85 delete process.env[environmentVariable] 86 done() 87 }) 88 }) 89 }) 90 91 describe('bearer token', function () { 92 it('should return auth token if registry is defined', function (done) { 93 var content = [ 94 'registry=http://registry.foobar.eu/', 95 '//registry.foobar.eu/:_authToken=foobar', '' 96 ].join('\n') 97 98 fs.writeFile(npmRcPath, content, function (err) { 99 var getAuthToken = requireUncached('../index') 100 assert(!err, err) 101 assert.deepEqual(getAuthToken(), {token: 'foobar', type: 'Bearer'}) 102 done() 103 }) 104 }) 105 106 it('should use npmrc passed in', function (done) { 107 var content = [ 108 'registry=http://registry.foobar.eu/', 109 '//registry.foobar.eu/:_authToken=foobar', '' 110 ].join('\n') 111 112 fs.writeFile(npmRcPath, content, function (err) { 113 var getAuthToken = requireUncached('../index') 114 assert(!err, err) 115 const npmrc = { 116 'registry': 'http://registry.foobar.eu/', 117 '//registry.foobar.eu/:_authToken': 'qar' 118 } 119 assert.deepEqual(getAuthToken({npmrc: npmrc}), {token: 'qar', type: 'Bearer'}) 120 done() 121 }) 122 }) 123 124 it('should return auth token if registry url has port specified', function (done) { 125 var content = [ 126 'registry=http://localhost:8770/', 127 // before the patch this token was selected. 128 '//localhost/:_authToken=ohno', 129 '//localhost:8770/:_authToken=beepboop', '' 130 ].join('\n') 131 132 fs.writeFile(npmRcPath, content, function (err) { 133 var getAuthToken = requireUncached('../index') 134 assert(!err, err) 135 assert.deepEqual(getAuthToken(), {token: 'beepboop', type: 'Bearer'}) 136 done() 137 }) 138 }) 139 140 it('should return auth token defined by reference to an environment variable (with curly braces)', function (done) { 141 var environmentVariable = '__REGISTRY_AUTH_TOKEN_NPM_TOKEN__' 142 var content = [ 143 'registry=http://registry.foobar.cc/', 144 '//registry.foobar.cc/:_authToken=${' + environmentVariable + '}', '' 145 ].join('\n') 146 process.env[environmentVariable] = 'foobar' 147 148 fs.writeFile(npmRcPath, content, function (err) { 149 var getAuthToken = requireUncached('../index') 150 assert(!err, err) 151 assert.deepEqual(getAuthToken(), {token: 'foobar', type: 'Bearer'}) 152 delete process.env[environmentVariable] 153 done() 154 }) 155 }) 156 157 it('should return auth token defined by reference to an environment variable (without curly braces)', function (done) { 158 var environmentVariable = '__REGISTRY_AUTH_TOKEN_NPM_TOKEN__' 159 var content = [ 160 'registry=http://registry.foobar.cc/', 161 '//registry.foobar.cc/:_authToken=$' + environmentVariable, '' 162 ].join('\n') 163 process.env[environmentVariable] = 'foobar' 164 165 fs.writeFile(npmRcPath, content, function (err) { 166 var getAuthToken = requireUncached('../index') 167 assert(!err, err) 168 assert.deepEqual(getAuthToken(), {token: 'foobar', type: 'Bearer'}) 169 delete process.env[environmentVariable] 170 done() 171 }) 172 }) 173 174 it('should try with and without a slash at the end of registry url', function (done) { 175 var content = [ 176 'registry=http://registry.foobar.eu', 177 '//registry.foobar.eu:_authToken=barbaz', '' 178 ].join('\n') 179 180 fs.writeFile(npmRcPath, content, function (err) { 181 var getAuthToken = requireUncached('../index') 182 assert(!err, err) 183 assert.deepEqual(getAuthToken(), {token: 'barbaz', type: 'Bearer'}) 184 done() 185 }) 186 }) 187 188 it('should fetch for the registry given (if defined)', function (done) { 189 var content = [ 190 '//registry.foobar.eu:_authToken=barbaz', 191 '//registry.blah.foo:_authToken=whatev', 192 '//registry.last.thing:_authToken=yep', '' 193 ].join('\n') 194 195 fs.writeFile(npmRcPath, content, function (err) { 196 var getAuthToken = requireUncached('../index') 197 assert(!err, err) 198 assert.deepEqual(getAuthToken('//registry.blah.foo'), {token: 'whatev', type: 'Bearer'}) 199 done() 200 }) 201 }) 202 203 it('recursively finds registries for deep url if option is set', function (done, undef) { 204 var opts = {recursive: true} 205 var content = [ 206 '//registry.blah.com/foo:_authToken=whatev', 207 '//registry.blah.org/foo/bar:_authToken=recurseExactlyOneLevel', 208 '//registry.blah.edu/foo/bar/baz:_authToken=recurseNoLevel', 209 '//registry.blah.eu:_authToken=yep', '' 210 ].join('\n') 211 212 fs.writeFile(npmRcPath, content, function (err) { 213 var getAuthToken = requireUncached('../index') 214 assert(!err, err) 215 assert.deepEqual(getAuthToken('https://registry.blah.edu/foo/bar/baz', opts), {token: 'recurseNoLevel', type: 'Bearer'}) 216 assert.deepEqual(getAuthToken('https://registry.blah.org/foo/bar/baz', opts), {token: 'recurseExactlyOneLevel', type: 'Bearer'}) 217 assert.deepEqual(getAuthToken('https://registry.blah.com/foo/bar/baz', opts), {token: 'whatev', type: 'Bearer'}) 218 assert.deepEqual(getAuthToken('http://registry.blah.eu/what/ever', opts), {token: 'yep', type: 'Bearer'}) 219 assert.deepEqual(getAuthToken('http://registry.blah.eu//what/ever', opts), undefined, 'does not hang') 220 assert.equal(getAuthToken('//some.registry', opts), undef) 221 done() 222 }) 223 }) 224 225 it('should try both with and without trailing slash', function (done) { 226 fs.writeFile(npmRcPath, '//registry.blah.com:_authToken=whatev', function (err) { 227 var getAuthToken = requireUncached('../index') 228 assert(!err, err) 229 assert.deepEqual(getAuthToken('https://registry.blah.com'), {token: 'whatev', type: 'Bearer'}) 230 done() 231 }) 232 }) 233 234 it('should prefer bearer token over basic token', function (done) { 235 var content = [ 236 'registry=http://registry.foobar.eu/', 237 'registry=http://registry.foobar.eu/', 238 '//registry.foobar.eu/:_authToken=bearerToken', 239 '//registry.foobar.eu/:_password=' + encodeBase64('foobar'), 240 '//registry.foobar.eu/:username=foobar', '' 241 ].join('\n') 242 243 fs.writeFile(npmRcPath, content, function (err) { 244 var getAuthToken = requireUncached('../index') 245 assert(!err, err) 246 assert.deepEqual(getAuthToken('//registry.foobar.eu'), {token: 'bearerToken', type: 'Bearer'}) 247 done() 248 }) 249 }) 250 251 it('"nerf darts" registry urls', function (done, undef) { 252 fs.writeFile(npmRcPath, '//contoso.pkgs.visualstudio.com/_packaging/MyFeed/npm/:_authToken=heider', function (err) { 253 var getAuthToken = requireUncached('../index') 254 assert(!err, err) 255 assert.deepEqual( 256 getAuthToken('https://contoso.pkgs.visualstudio.com/_packaging/MyFeed/npm/registry'), 257 {token: 'heider', type: 'Bearer'} 258 ) 259 done() 260 }) 261 }) 262 }) 263 264 describe('basic token', function () { 265 it('should return undefined if password or username are missing', function (done, undef) { 266 var content = [ 267 'registry=http://registry.foobar.eu/', 268 '//registry.foobar.eu/:_password=' + encodeBase64('foobar'), 269 '//registry.foobar.com/:username=foobar', '' 270 ].join('\n') 271 272 fs.writeFile(npmRcPath, content, function (err) { 273 var getAuthToken = requireUncached('../index') 274 assert(!err, err) 275 assert.equal(getAuthToken('//registry.foobar.eu'), undef) 276 assert.equal(getAuthToken('//registry.foobar.com'), undef) 277 done() 278 }) 279 }) 280 281 it('should return basic token if username and password are defined', function (done) { 282 var content = [ 283 'registry=http://registry.foobar.eu/', 284 '//registry.foobar.eu/:_password=' + encodeBase64('foobar'), 285 '//registry.foobar.eu/:username=foobar', '' 286 ].join('\n') 287 288 fs.writeFile(npmRcPath, content, function (err) { 289 var getAuthToken = requireUncached('../index') 290 assert(!err, err) 291 var token = getAuthToken() 292 assert.deepEqual(token, { 293 token: 'Zm9vYmFyOmZvb2Jhcg==', 294 type: 'Basic', 295 username: 'foobar', 296 password: 'foobar' 297 }) 298 assert.equal(decodeBase64(token.token), 'foobar:foobar') 299 done() 300 }) 301 }) 302 303 it('should return basic token if registry url has port specified', function (done) { 304 var content = [ 305 'registry=http://localhost:8770/', 306 // before the patch this token was selected. 307 '//localhost/:_authToken=ohno', 308 '//localhost:8770/:_password=' + encodeBase64('foobar'), 309 '//localhost:8770/:username=foobar', '' 310 ].join('\n') 311 312 fs.writeFile(npmRcPath, content, function (err) { 313 var getAuthToken = requireUncached('../index') 314 assert(!err, err) 315 var token = getAuthToken() 316 assert.deepEqual(token, { 317 token: 'Zm9vYmFyOmZvb2Jhcg==', 318 type: 'Basic', 319 username: 'foobar', 320 password: 'foobar' 321 }) 322 assert.equal(decodeBase64(token.token), 'foobar:foobar') 323 done() 324 }) 325 }) 326 327 it('should return password defined by reference to an environment variable (with curly braces)', function (done) { 328 var environmentVariable = '__REGISTRY_PASSWORD__' 329 var content = [ 330 'registry=http://registry.foobar.cc/', 331 '//registry.foobar.cc/:username=username', 332 '//registry.foobar.cc/:_password=${' + environmentVariable + '}', '' 333 ].join('\n') 334 process.env[environmentVariable] = encodeBase64('password') 335 336 fs.writeFile(npmRcPath, content, function (err) { 337 var getAuthToken = requireUncached('../index') 338 assert(!err, err) 339 var token = getAuthToken() 340 assert.deepEqual(token, { 341 type: 'Basic', 342 username: 'username', 343 password: 'password', 344 token: 'dXNlcm5hbWU6cGFzc3dvcmQ=' 345 }) 346 assert.equal(decodeBase64(token.token), 'username:password') 347 delete process.env[environmentVariable] 348 done() 349 }) 350 }) 351 352 it('should return password defined by reference to an environment variable (without curly braces)', function (done) { 353 var environmentVariable = '__REGISTRY_PASSWORD__' 354 var content = [ 355 'registry=http://registry.foobar.cc/', 356 '//registry.foobar.cc/:username=username', 357 '//registry.foobar.cc/:_password=$' + environmentVariable, '' 358 ].join('\n') 359 process.env[environmentVariable] = encodeBase64('password') 360 361 fs.writeFile(npmRcPath, content, function (err) { 362 var getAuthToken = requireUncached('../index') 363 assert(!err, err) 364 var token = getAuthToken() 365 assert.deepEqual(token, { 366 type: 'Basic', 367 username: 'username', 368 password: 'password', 369 token: 'dXNlcm5hbWU6cGFzc3dvcmQ=' 370 }) 371 assert.equal(decodeBase64(token.token), 'username:password') 372 delete process.env[environmentVariable] 373 done() 374 }) 375 }) 376 377 it('should try with and without a slash at the end of registry url', function (done) { 378 var content = [ 379 'registry=http://registry.foobar.eu', 380 '//registry.foobar.eu:_password=' + encodeBase64('barbay'), 381 '//registry.foobar.eu:username=barbaz', '' 382 ].join('\n') 383 384 fs.writeFile(npmRcPath, content, function (err) { 385 var getAuthToken = requireUncached('../index') 386 assert(!err, err) 387 var token = getAuthToken() 388 assert.deepEqual(token, { 389 token: 'YmFyYmF6OmJhcmJheQ==', 390 type: 'Basic', 391 password: 'barbay', 392 username: 'barbaz' 393 }) 394 assert.equal(decodeBase64(token.token), 'barbaz:barbay') 395 done() 396 }) 397 }) 398 399 it('should fetch for the registry given (if defined)', function (done) { 400 var content = [ 401 '//registry.foobar.eu:_authToken=barbaz', 402 '//registry.blah.foo:_password=' + encodeBase64('barbay'), 403 '//registry.blah.foo:username=barbaz', 404 '//registry.last.thing:_authToken=yep', '' 405 ].join('\n') 406 407 fs.writeFile(npmRcPath, content, function (err) { 408 var getAuthToken = requireUncached('../index') 409 assert(!err, err) 410 var token = getAuthToken('//registry.blah.foo') 411 assert.deepEqual(token, { 412 token: 'YmFyYmF6OmJhcmJheQ==', 413 type: 'Basic', 414 password: 'barbay', 415 username: 'barbaz' 416 }) 417 assert.equal(decodeBase64(token.token), 'barbaz:barbay') 418 done() 419 }) 420 }) 421 422 it('recursively finds registries for deep url if option is set', function (done, undef) { 423 var opts = {recursive: true} 424 var content = [ 425 '//registry.blah.com/foo:_password=' + encodeBase64('barbay'), 426 '//registry.blah.com/foo:username=barbaz', 427 '//registry.blah.eu:username=barbaz', 428 '//registry.blah.eu:_password=' + encodeBase64('foobaz'), '' 429 ].join('\n') 430 431 fs.writeFile(npmRcPath, content, function (err) { 432 var getAuthToken = requireUncached('../index') 433 assert(!err, err) 434 var token = getAuthToken('https://registry.blah.com/foo/bar/baz', opts) 435 assert.deepEqual(token, { 436 token: 'YmFyYmF6OmJhcmJheQ==', 437 type: 'Basic', 438 password: 'barbay', 439 username: 'barbaz' 440 }) 441 assert.equal(decodeBase64(token.token), 'barbaz:barbay') 442 token = getAuthToken('https://registry.blah.eu/foo/bar/baz', opts) 443 assert.deepEqual(token, { 444 token: 'YmFyYmF6OmZvb2Jheg==', 445 type: 'Basic', 446 password: 'foobaz', 447 username: 'barbaz' 448 }) 449 assert.equal(decodeBase64(token.token), 'barbaz:foobaz') 450 assert.equal(getAuthToken('//some.registry', opts), undef) 451 done() 452 }) 453 }) 454 }) 455}) 456