• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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