@verdaccio/auth 6.0.0-6-next.29 → 6.0.0-6-next.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # @verdaccio/auth
2
2
 
3
+ ## 6.0.0-6-next.31
4
+
5
+ ### Patch Changes
6
+
7
+ - @verdaccio/core@6.0.0-6-next.52
8
+ - @verdaccio/config@6.0.0-6-next.52
9
+ - @verdaccio/loaders@6.0.0-6-next.21
10
+ - @verdaccio/logger@6.0.0-6-next.20
11
+ - verdaccio-htpasswd@11.0.0-6-next.22
12
+ - @verdaccio/utils@6.0.0-6-next.20
13
+
14
+ ## 6.0.0-6-next.30
15
+
16
+ ### Minor Changes
17
+
18
+ - 4b29d715: chore: move improvements from v5 to v6
19
+
20
+ Migrate improvements form v5 to v6:
21
+
22
+ - https://github.com/verdaccio/verdaccio/pull/3158
23
+ - https://github.com/verdaccio/verdaccio/pull/3151
24
+ - https://github.com/verdaccio/verdaccio/pull/2271
25
+ - https://github.com/verdaccio/verdaccio/pull/2787
26
+ - https://github.com/verdaccio/verdaccio/pull/2791
27
+ - https://github.com/verdaccio/verdaccio/pull/2205
28
+
29
+ ### Patch Changes
30
+
31
+ - Updated dependencies [4b29d715]
32
+ - @verdaccio/config@6.0.0-6-next.51
33
+ - @verdaccio/core@6.0.0-6-next.51
34
+ - @verdaccio/loaders@6.0.0-6-next.20
35
+ - verdaccio-htpasswd@11.0.0-6-next.21
36
+ - @verdaccio/logger@6.0.0-6-next.19
37
+ - @verdaccio/utils@6.0.0-6-next.19
38
+
3
39
  ## 6.0.0-6-next.29
4
40
 
5
41
  ### Patch Changes
package/build/auth.d.ts CHANGED
@@ -13,14 +13,14 @@ export interface IAuthMiddleware {
13
13
  apiJWTmiddleware(): $NextFunctionVer;
14
14
  webUIJWTmiddleware(): $NextFunctionVer;
15
15
  }
16
- export declare type $RequestExtend = Request & {
16
+ export type $RequestExtend = Request & {
17
17
  remote_user?: any;
18
18
  log: Logger;
19
19
  };
20
- export declare type $ResponseExtend = Response & {
20
+ export type $ResponseExtend = Response & {
21
21
  cookies?: any;
22
22
  };
23
- export declare type $NextFunctionVer = NextFunction & any;
23
+ export type $NextFunctionVer = NextFunction & any;
24
24
  declare class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
25
25
  config: Config;
26
26
  secret: string;
package/build/auth.js CHANGED
@@ -4,59 +4,38 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.Auth = void 0;
7
-
8
7
  var _debug = _interopRequireDefault(require("debug"));
9
-
10
8
  var _lodash = _interopRequireDefault(require("lodash"));
11
-
12
9
  var _verdaccioHtpasswd = require("verdaccio-htpasswd");
13
-
14
10
  var _config = require("@verdaccio/config");
15
-
16
11
  var _core = require("@verdaccio/core");
17
-
18
12
  var _loaders = require("@verdaccio/loaders");
19
-
20
13
  var _logger = require("@verdaccio/logger");
21
-
22
14
  var _utils = require("@verdaccio/utils");
23
-
24
15
  var _jwtToken = require("./jwt-token");
25
-
26
16
  var _legacyToken = require("./legacy-token");
27
-
28
17
  var _token = require("./token");
29
-
30
18
  var _utils2 = require("./utils");
31
-
32
19
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
33
-
34
20
  const debug = (0, _debug.default)('verdaccio:auth');
35
-
36
21
  class Auth {
37
22
  constructor(config) {
38
23
  this.config = config;
39
24
  this.secret = config.secret;
40
25
  this.plugins = [];
41
-
42
26
  if (!this.secret) {
43
27
  throw new TypeError('secret it is required value on initialize the auth class');
44
28
  }
45
29
  }
46
-
47
30
  async init() {
48
31
  let plugins = await this.loadPlugin();
49
32
  debug('auth plugins found %s', plugins.length);
50
-
51
33
  if (!plugins || plugins.length === 0) {
52
34
  plugins = this.loadDefaultPlugin();
53
35
  }
54
-
55
36
  this.plugins = plugins;
56
-
57
37
  this._applyDefaultPlugins();
58
38
  }
59
-
60
39
  loadDefaultPlugin() {
61
40
  debug('load default auth plugin');
62
41
  const pluginOptions = {
@@ -64,25 +43,19 @@ class Auth {
64
43
  logger: _logger.logger
65
44
  };
66
45
  let authPlugin;
67
-
68
46
  try {
69
47
  authPlugin = new _verdaccioHtpasswd.HTPasswd({
70
48
  file: './htpasswd'
71
49
  }, pluginOptions);
72
50
  } catch (error) {
73
51
  debug('error on loading auth htpasswd plugin stack: %o', error);
74
-
75
52
  _logger.logger.info({}, 'no auth plugin has been found');
76
-
77
53
  return [];
78
54
  }
79
-
80
55
  return [authPlugin];
81
56
  }
82
-
83
57
  async loadPlugin() {
84
58
  var _this$config, _this$config$serverSe;
85
-
86
59
  return (0, _loaders.asyncLoadPlugin)(this.config.auth, {
87
60
  config: this.config,
88
61
  logger: _logger.logger
@@ -95,19 +68,15 @@ class Auth {
95
68
  return typeof authenticate !== 'undefined' || typeof allow_access !== 'undefined' || typeof allow_publish !== 'undefined';
96
69
  }, (_this$config = this.config) === null || _this$config === void 0 ? void 0 : (_this$config$serverSe = _this$config.serverSettings) === null || _this$config$serverSe === void 0 ? void 0 : _this$config$serverSe.pluginPrefix);
97
70
  }
98
-
99
71
  _applyDefaultPlugins() {
100
72
  // TODO: rename to applyFallbackPluginMethods
101
73
  this.plugins.push((0, _utils2.getDefaultPlugins)(_logger.logger));
102
74
  }
103
-
104
75
  changePassword(username, password, newPassword, cb) {
105
76
  const validPlugins = _lodash.default.filter(this.plugins, plugin => (0, _utils.isFunction)(plugin.changePassword));
106
-
107
77
  if (_lodash.default.isEmpty(validPlugins)) {
108
78
  return cb(_core.errorUtils.getInternalError(_core.SUPPORT_ERRORS.PLUGIN_MISSING_INTERFACE));
109
79
  }
110
-
111
80
  for (const plugin of validPlugins) {
112
81
  if ((0, _utils.isNil)(plugin) || (0, _utils.isFunction)(plugin.changePassword) === false) {
113
82
  debug('auth plugin does not implement changePassword, trying next one');
@@ -121,76 +90,62 @@ class Auth {
121
90
  err
122
91
  }, `An error has been produced
123
92
  updating the password for @{username}. Error: @{err.message}`);
124
-
125
93
  return cb(err);
126
94
  }
127
-
128
95
  debug('updated password for %o was successful', username);
129
96
  return cb(null, profile);
130
97
  });
131
98
  }
132
99
  }
133
100
  }
134
-
135
101
  async invalidateToken(token) {
136
102
  // eslint-disable-next-line no-console
137
103
  console.log('invalidate token pending to implement', token);
138
104
  return Promise.resolve();
139
105
  }
140
-
141
106
  authenticate(username, password, cb) {
142
107
  const plugins = this.plugins.slice(0);
143
-
144
108
  (function next() {
145
109
  const plugin = plugins.shift();
146
-
147
110
  if ((0, _utils.isFunction)(plugin.authenticate) === false) {
148
111
  return next();
149
112
  }
150
-
151
113
  debug('authenticating %o', username);
152
114
  plugin.authenticate(username, password, function (err, groups) {
153
115
  if (err) {
154
116
  debug('authenticating for user %o failed. Error: %o', username, err === null || err === void 0 ? void 0 : err.message);
155
117
  return cb(err);
156
- } // Expect: SKIP if groups is falsey and not an array
118
+ }
119
+
120
+ // Expect: SKIP if groups is falsey and not an array
157
121
  // with at least one item (truthy length)
158
122
  // Expect: CONTINUE otherwise (will error if groups is not
159
123
  // an array, but this is current behavior)
160
124
  // Caveat: STRING (if valid) will pass successfully
161
125
  // bug give unexpected results
162
126
  // Info: Cannot use `== false to check falsey values`
163
-
164
-
165
127
  if (!!groups && groups.length !== 0) {
166
128
  // TODO: create a better understanding of expectations
167
129
  if (_lodash.default.isString(groups)) {
168
130
  throw new TypeError('plugin group error: invalid type for function');
169
131
  }
170
-
171
132
  const isGroupValid = _lodash.default.isArray(groups);
172
-
173
133
  if (!isGroupValid) {
174
134
  throw new TypeError(_core.API_ERROR.BAD_FORMAT_USER_GROUP);
175
135
  }
176
-
177
136
  debug('authentication for user %o was successfully. Groups: %o', username, groups);
178
137
  return cb(err, (0, _config.createRemoteUser)(username, groups));
179
138
  }
180
-
181
139
  next();
182
140
  });
183
141
  })();
184
142
  }
185
-
186
143
  add_user(user, password, cb) {
187
144
  const self = this;
188
145
  const plugins = this.plugins.slice(0);
189
146
  debug('add user %o', user);
190
-
191
147
  (function next() {
192
148
  const plugin = plugins.shift();
193
-
194
149
  if (typeof plugin.adduser !== 'function') {
195
150
  next();
196
151
  } else {
@@ -198,28 +153,24 @@ class Auth {
198
153
  if (typeof plugin.adduser === 'undefined' && typeof plugin.add_user === 'function') {
199
154
  throw _core.errorUtils.getInternalError('add_user method not longer supported, rename to adduser');
200
155
  }
201
-
202
156
  plugin.adduser(user, password, function (err, ok) {
203
157
  if (err) {
204
158
  debug('the user %o could not being added. Error: %o', user, err === null || err === void 0 ? void 0 : err.message);
205
159
  return cb(err);
206
160
  }
207
-
208
161
  if (ok) {
209
162
  debug('the user %o has been added', user);
210
163
  return self.authenticate(user, password, cb);
211
164
  }
212
-
213
165
  next();
214
166
  });
215
167
  }
216
168
  })();
217
169
  }
170
+
218
171
  /**
219
172
  * Allow user to access a package.
220
173
  */
221
-
222
-
223
174
  allow_access({
224
175
  packageName,
225
176
  packageVersion
@@ -231,25 +182,20 @@ class Auth {
231
182
  };
232
183
  const pkg = Object.assign({}, pkgAllowAccess, (0, _utils.getMatchedPackagesSpec)(packageName, this.config.packages));
233
184
  debug('allow access for %o', packageName);
234
-
235
185
  (function next() {
236
186
  const plugin = plugins.shift();
237
-
238
187
  if (_lodash.default.isNil(plugin) || (0, _utils.isFunction)(plugin.allow_access) === false) {
239
188
  return next();
240
189
  }
241
-
242
190
  plugin.allow_access(user, pkg, function (err, ok) {
243
191
  if (err) {
244
192
  debug('forbidden access for %o. Error: %o', packageName, err === null || err === void 0 ? void 0 : err.message);
245
193
  return callback(err);
246
194
  }
247
-
248
195
  if (ok) {
249
196
  debug('allowed access for %o', packageName);
250
197
  return callback(null, ok);
251
198
  }
252
-
253
199
  next(); // cb(null, false) causes next plugin to roll
254
200
  });
255
201
  })();
@@ -264,7 +210,6 @@ class Auth {
264
210
  version: packageVersion
265
211
  }, (0, _utils.getMatchedPackagesSpec)(packageName, this.config.packages));
266
212
  debug('allow unpublish for %o', packageName);
267
-
268
213
  for (const plugin of this.plugins) {
269
214
  if (_lodash.default.isNil(plugin) || (0, _utils.isFunction)(plugin.allow_unpublish) === false) {
270
215
  debug('allow unpublish for %o plugin does not implement allow_unpublish', packageName);
@@ -276,14 +221,12 @@ class Auth {
276
221
  debug('forbidden publish for %o, it will fallback on unpublish permissions', packageName);
277
222
  return callback(err);
278
223
  }
279
-
280
224
  if (_lodash.default.isNil(ok) === true) {
281
- debug('bypass unpublish for %o, publish will handle the access', packageName); // @ts-ignore
225
+ debug('bypass unpublish for %o, publish will handle the access', packageName);
226
+ // @ts-ignore
282
227
  // eslint-disable-next-line
283
-
284
228
  return this.allow_publish(...arguments);
285
229
  }
286
-
287
230
  if (ok) {
288
231
  debug('allowed unpublish for %o', packageName);
289
232
  return callback(null, ok);
@@ -292,11 +235,10 @@ class Auth {
292
235
  }
293
236
  }
294
237
  }
238
+
295
239
  /**
296
240
  * Allow user to publish a package.
297
241
  */
298
-
299
-
300
242
  allow_publish({
301
243
  packageName,
302
244
  packageVersion
@@ -307,26 +249,21 @@ class Auth {
307
249
  version: packageVersion
308
250
  }, (0, _utils.getMatchedPackagesSpec)(packageName, this.config.packages));
309
251
  debug('allow publish for %o init | plugins: %o', packageName, plugins.length);
310
-
311
252
  (function next() {
312
253
  const plugin = plugins.shift();
313
-
314
254
  if (typeof (plugin === null || plugin === void 0 ? void 0 : plugin.allow_publish) !== 'function') {
315
255
  debug('allow publish for %o plugin does not implement allow_publish', packageName);
316
256
  return next();
317
257
  }
318
-
319
258
  plugin.allow_publish(user, pkg, (err, ok) => {
320
259
  if (_lodash.default.isNil(err) === false && _lodash.default.isError(err)) {
321
260
  debug('forbidden publish for %o', packageName);
322
261
  return callback(err);
323
262
  }
324
-
325
263
  if (ok) {
326
264
  debug('allowed publish for %o', packageName);
327
265
  return callback(null, ok);
328
266
  }
329
-
330
267
  debug('allow publish skip validation for %o', packageName);
331
268
  next(); // cb(null, false) causes next plugin to roll
332
269
  });
@@ -340,80 +277,68 @@ class Auth {
340
277
  createAnonymousRemoteUser: _config.createAnonymousRemoteUser,
341
278
  createRemoteUser: _config.createRemoteUser
342
279
  };
343
-
344
280
  for (const plugin of plugins) {
345
281
  if (plugin.apiJWTmiddleware) {
346
282
  return plugin.apiJWTmiddleware(helpers);
347
283
  }
348
- } // @ts-ignore
349
-
284
+ }
350
285
 
286
+ // @ts-ignore
351
287
  return (req, res, _next) => {
352
288
  req.pause();
353
-
354
289
  const next = function (err) {
355
- req.resume(); // uncomment this to reject users with bad auth headers
290
+ req.resume();
291
+ // uncomment this to reject users with bad auth headers
356
292
  // return _next.apply(null, arguments)
357
293
  // swallow error, user remains unauthorized
358
294
  // set remoteUserError to indicate that user was attempting authentication
359
-
360
295
  if (err) {
361
296
  req.remote_user.error = err.message;
362
297
  }
363
-
364
298
  return _next();
365
299
  };
366
-
367
300
  if (this._isRemoteUserValid(req.remote_user)) {
368
301
  debug('jwt has a valid authentication header');
369
302
  return next();
370
- } // in case auth header does not exist we return anonymous function
371
-
303
+ }
372
304
 
305
+ // in case auth header does not exist we return anonymous function
373
306
  const remoteUser = (0, _config.createAnonymousRemoteUser)();
374
307
  req.remote_user = remoteUser;
375
308
  res.locals.remote_user = remoteUser;
376
309
  const {
377
310
  authorization
378
311
  } = req.headers;
379
-
380
312
  if (_lodash.default.isNil(authorization)) {
381
313
  debug('jwt, authentication header is missing');
382
314
  return next();
383
315
  }
384
-
385
316
  if (!(0, _utils2.isAuthHeaderValid)(authorization)) {
386
317
  debug('api middleware authentication heather is invalid');
387
318
  return next(_core.errorUtils.getBadRequest(_core.API_ERROR.BAD_AUTH_HEADER));
388
319
  }
389
-
390
320
  const {
391
321
  secret,
392
322
  security
393
323
  } = this.config;
394
-
395
324
  if ((0, _utils2.isAESLegacy)(security)) {
396
325
  debug('api middleware using legacy auth token');
397
-
398
326
  this._handleAESMiddleware(req, security, secret, authorization, next);
399
327
  } else {
400
328
  debug('api middleware using JWT auth token');
401
-
402
329
  this._handleJWTAPIMiddleware(req, security, secret, authorization, next);
403
330
  }
404
331
  };
405
332
  }
406
-
407
333
  _handleJWTAPIMiddleware(req, security, secret, authorization, next) {
408
334
  debug('handle JWT api middleware');
409
335
  const {
410
336
  scheme,
411
337
  token
412
338
  } = (0, _utils2.parseAuthTokenHeader)(authorization);
413
-
414
339
  if (scheme.toUpperCase() === _core.TOKEN_BASIC.toUpperCase()) {
415
- debug('handle basic token'); // this should happen when client tries to login with an existing user
416
-
340
+ debug('handle basic token');
341
+ // this should happen when client tries to login with an existing user
417
342
  const credentials = (0, _utils2.convertPayloadToBase64)(token).toString();
418
343
  const {
419
344
  user,
@@ -434,7 +359,6 @@ class Auth {
434
359
  } else {
435
360
  debug('handle jwt token');
436
361
  const credentials = (0, _utils2.getMiddlewareCredentials)(security, secret, authorization);
437
-
438
362
  if (credentials) {
439
363
  // if the signature is valid we rely on it
440
364
  req.remote_user = credentials;
@@ -447,14 +371,12 @@ class Auth {
447
371
  }
448
372
  }
449
373
  }
450
-
451
374
  _handleAESMiddleware(req, security, secret, authorization, next) {
452
375
  debug('handle legacy api middleware');
453
376
  debug('api middleware secret %o', typeof secret === 'string');
454
377
  debug('api middleware authorization %o', typeof authorization === 'string');
455
378
  const credentials = (0, _utils2.getMiddlewareCredentials)(security, secret, authorization);
456
379
  debug('api middleware credentials %o', credentials === null || credentials === void 0 ? void 0 : credentials.name);
457
-
458
380
  if (credentials) {
459
381
  const {
460
382
  user,
@@ -478,60 +400,47 @@ class Auth {
478
400
  return next(_core.errorUtils.getBadRequest(_core.API_ERROR.BAD_AUTH_HEADER));
479
401
  }
480
402
  }
481
-
482
403
  _isRemoteUserValid(remote_user) {
483
404
  return _lodash.default.isUndefined(remote_user) === false && _lodash.default.isUndefined(remote_user === null || remote_user === void 0 ? void 0 : remote_user.name) === false;
484
405
  }
406
+
485
407
  /**
486
408
  * JWT middleware for WebUI
487
409
  */
488
-
489
-
490
410
  webUIJWTmiddleware() {
491
411
  // @ts-ignore
492
412
  return (req, res, _next) => {
493
413
  if (this._isRemoteUserValid(req.remote_user)) {
494
414
  return _next();
495
415
  }
496
-
497
416
  req.pause();
498
-
499
417
  const next = err => {
500
418
  req.resume();
501
-
502
419
  if (err) {
503
420
  // req.remote_user.error = err.message;
504
421
  res.status(err.statusCode).send(err.message);
505
422
  }
506
-
507
423
  return _next();
508
424
  };
509
-
510
425
  const {
511
426
  authorization
512
427
  } = req.headers;
513
-
514
428
  if (_lodash.default.isNil(authorization)) {
515
429
  return next();
516
430
  }
517
-
518
431
  if (!(0, _utils2.isAuthHeaderValid)(authorization)) {
519
432
  return next(_core.errorUtils.getBadRequest(_core.API_ERROR.BAD_AUTH_HEADER));
520
433
  }
521
-
522
434
  const token = (authorization || '').replace(`${_core.TOKEN_BEARER} `, '');
523
-
524
435
  if (!token) {
525
436
  return next();
526
437
  }
527
-
528
438
  let credentials;
529
-
530
439
  try {
531
440
  credentials = (0, _utils2.verifyJWTPayload)(token, this.config.secret);
532
- } catch (err) {// FIXME: intended behaviour, do we want it?
441
+ } catch (err) {
442
+ // FIXME: intended behaviour, do we want it?
533
443
  }
534
-
535
444
  if (this._isRemoteUserValid(credentials)) {
536
445
  const {
537
446
  name,
@@ -541,11 +450,9 @@ class Auth {
541
450
  } else {
542
451
  req.remote_user = (0, _config.createAnonymousRemoteUser)();
543
452
  }
544
-
545
453
  next();
546
454
  };
547
455
  }
548
-
549
456
  async jwtEncrypt(user, signOptions) {
550
457
  const {
551
458
  real_groups,
@@ -554,7 +461,7 @@ class Auth {
554
461
  } = user;
555
462
  debug('jwt encrypt %o', name);
556
463
  const realGroupsValidated = _lodash.default.isNil(real_groups) ? [] : real_groups;
557
- const groupedGroups = _lodash.default.isNil(groups) ? real_groups : groups.concat(realGroupsValidated);
464
+ const groupedGroups = _lodash.default.isNil(groups) ? real_groups : Array.from(new Set([...groups.concat(realGroupsValidated)]));
558
465
  const payload = {
559
466
  real_groups: realGroupsValidated,
560
467
  name,
@@ -563,16 +470,13 @@ class Auth {
563
470
  const token = await (0, _jwtToken.signPayload)(payload, this.secret, signOptions);
564
471
  return token;
565
472
  }
473
+
566
474
  /**
567
475
  * Encrypt a string.
568
476
  */
569
-
570
-
571
477
  aesEncrypt(value) {
572
478
  return (0, _legacyToken.aesEncrypt)(value, this.secret);
573
479
  }
574
-
575
480
  }
576
-
577
481
  exports.Auth = Auth;
578
482
  //# sourceMappingURL=auth.js.map