@verdaccio/auth 6.0.0-6-next.27 → 6.0.0-6-next.28
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 +11 -0
- package/build/auth.d.ts +16 -33
- package/build/auth.js +29 -34
- package/build/auth.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.js +1 -15
- package/build/index.js.map +1 -1
- package/build/utils.d.ts +10 -5
- package/build/utils.js +8 -2
- package/build/utils.js.map +1 -1
- package/package.json +8 -8
- package/src/auth.ts +97 -113
- package/src/index.ts +1 -1
- package/src/utils.ts +12 -13
- package/test/auth-utils.spec.ts +2 -3
- package/test/auth.spec.ts +10 -11
- package/tsconfig.build.json +3 -3
- package/tsconfig.json +6 -6
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@verdaccio/auth",
|
|
3
|
-
"version": "6.0.0-6-next.
|
|
3
|
+
"version": "6.0.0-6-next.28",
|
|
4
4
|
"description": "logger",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
|
-
"types": "build/index.d.ts",
|
|
6
|
+
"types": "./build/index.d.ts",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Juan Picado",
|
|
9
9
|
"email": "juanpicado19@gmail.com"
|
|
@@ -30,16 +30,16 @@
|
|
|
30
30
|
},
|
|
31
31
|
"license": "MIT",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@verdaccio/core": "6.0.0-6-next.
|
|
34
|
-
"@verdaccio/config": "6.0.0-6-next.
|
|
35
|
-
"@verdaccio/loaders": "6.0.0-6-next.
|
|
36
|
-
"@verdaccio/logger": "6.0.0-6-next.
|
|
37
|
-
"@verdaccio/utils": "6.0.0-6-next.
|
|
33
|
+
"@verdaccio/core": "6.0.0-6-next.49",
|
|
34
|
+
"@verdaccio/config": "6.0.0-6-next.49",
|
|
35
|
+
"@verdaccio/loaders": "6.0.0-6-next.18",
|
|
36
|
+
"@verdaccio/logger": "6.0.0-6-next.17",
|
|
37
|
+
"@verdaccio/utils": "6.0.0-6-next.17",
|
|
38
38
|
"debug": "4.3.4",
|
|
39
39
|
"express": "4.18.1",
|
|
40
40
|
"jsonwebtoken": "8.5.1",
|
|
41
41
|
"lodash": "4.17.21",
|
|
42
|
-
"verdaccio-htpasswd": "11.0.0-6-next.
|
|
42
|
+
"verdaccio-htpasswd": "11.0.0-6-next.19"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@verdaccio/types": "11.0.0-6-next.17"
|
package/src/auth.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import buildDebug from 'debug';
|
|
2
|
-
import { NextFunction, Request, Response } from 'express';
|
|
2
|
+
import { NextFunction, Request, RequestHandler, Response } from 'express';
|
|
3
3
|
import _ from 'lodash';
|
|
4
4
|
import { HTPasswd } from 'verdaccio-htpasswd';
|
|
5
5
|
|
|
@@ -11,18 +11,17 @@ import {
|
|
|
11
11
|
TOKEN_BEARER,
|
|
12
12
|
VerdaccioError,
|
|
13
13
|
errorUtils,
|
|
14
|
+
pluginUtils,
|
|
14
15
|
} from '@verdaccio/core';
|
|
15
16
|
import { asyncLoadPlugin } from '@verdaccio/loaders';
|
|
17
|
+
import { logger } from '@verdaccio/logger';
|
|
16
18
|
import {
|
|
17
19
|
AllowAccess,
|
|
18
|
-
AuthPluginPackage,
|
|
19
20
|
Callback,
|
|
20
21
|
Config,
|
|
21
|
-
IPluginAuth,
|
|
22
22
|
JWTSignOptions,
|
|
23
23
|
Logger,
|
|
24
24
|
PackageAccess,
|
|
25
|
-
PluginOptions,
|
|
26
25
|
RemoteUser,
|
|
27
26
|
Security,
|
|
28
27
|
} from '@verdaccio/types';
|
|
@@ -41,20 +40,8 @@ import {
|
|
|
41
40
|
verifyJWTPayload,
|
|
42
41
|
} from './utils';
|
|
43
42
|
|
|
44
|
-
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
45
|
-
const LoggerApi = require('@verdaccio/logger');
|
|
46
|
-
|
|
47
43
|
const debug = buildDebug('verdaccio:auth');
|
|
48
44
|
|
|
49
|
-
export interface IBasicAuth<T> {
|
|
50
|
-
config: T & Config;
|
|
51
|
-
authenticate(user: string, password: string, cb: Callback): void;
|
|
52
|
-
invalidateToken?(token: string): Promise<void>;
|
|
53
|
-
changePassword(user: string, password: string, newPassword: string, cb: Callback): void;
|
|
54
|
-
allow_access(pkg: AuthPluginPackage, user: RemoteUser, callback: Callback): void;
|
|
55
|
-
add_user(user: string, password: string, cb: Callback): any;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
45
|
export interface TokenEncryption {
|
|
59
46
|
jwtEncrypt(user: RemoteUser, signOptions: JWTSignOptions): Promise<string>;
|
|
60
47
|
aesEncrypt(buf: string): string | void;
|
|
@@ -64,36 +51,22 @@ export interface AESPayload {
|
|
|
64
51
|
user: string;
|
|
65
52
|
password: string;
|
|
66
53
|
}
|
|
67
|
-
|
|
68
|
-
export type $RequestExtend = Request & { remote_user?: any; log: Logger };
|
|
69
|
-
export type $ResponseExtend = Response & { cookies?: any };
|
|
70
|
-
export type $NextFunctionVer = NextFunction & any;
|
|
71
|
-
|
|
72
54
|
export interface IAuthMiddleware {
|
|
73
55
|
apiJWTmiddleware(): $NextFunctionVer;
|
|
74
56
|
webUIJWTmiddleware(): $NextFunctionVer;
|
|
75
57
|
}
|
|
76
58
|
|
|
77
|
-
export
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
secret: string;
|
|
81
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
82
|
-
plugins: any[];
|
|
83
|
-
allow_unpublish(pkg: AuthPluginPackage, user: RemoteUser, callback: Callback): void;
|
|
84
|
-
invalidateToken(token: string): Promise<void>;
|
|
85
|
-
init(): Promise<void>;
|
|
86
|
-
}
|
|
59
|
+
export type $RequestExtend = Request & { remote_user?: any; log: Logger };
|
|
60
|
+
export type $ResponseExtend = Response & { cookies?: any };
|
|
61
|
+
export type $NextFunctionVer = NextFunction & any;
|
|
87
62
|
|
|
88
|
-
class Auth implements
|
|
63
|
+
class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
|
|
89
64
|
public config: Config;
|
|
90
|
-
public logger: Logger;
|
|
91
65
|
public secret: string;
|
|
92
|
-
public plugins:
|
|
66
|
+
public plugins: pluginUtils.Auth<Config>[];
|
|
93
67
|
|
|
94
68
|
public constructor(config: Config) {
|
|
95
69
|
this.config = config;
|
|
96
|
-
this.logger = LoggerApi.logger.child({ sub: 'auth' });
|
|
97
70
|
this.secret = config.secret;
|
|
98
71
|
this.plugins = [];
|
|
99
72
|
if (!this.secret) {
|
|
@@ -102,7 +75,7 @@ class Auth implements IAuth {
|
|
|
102
75
|
}
|
|
103
76
|
|
|
104
77
|
public async init() {
|
|
105
|
-
let plugins = await this.loadPlugin();
|
|
78
|
+
let plugins = (await this.loadPlugin()) as pluginUtils.Auth<unknown>[];
|
|
106
79
|
debug('auth plugins found %s', plugins.length);
|
|
107
80
|
if (!plugins || plugins.length === 0) {
|
|
108
81
|
plugins = this.loadDefaultPlugin();
|
|
@@ -114,33 +87,40 @@ class Auth implements IAuth {
|
|
|
114
87
|
|
|
115
88
|
private loadDefaultPlugin() {
|
|
116
89
|
debug('load default auth plugin');
|
|
117
|
-
const pluginOptions: PluginOptions = {
|
|
90
|
+
const pluginOptions: pluginUtils.PluginOptions = {
|
|
118
91
|
config: this.config,
|
|
119
|
-
logger
|
|
92
|
+
logger,
|
|
120
93
|
};
|
|
121
94
|
let authPlugin;
|
|
122
95
|
try {
|
|
123
|
-
authPlugin = new HTPasswd(
|
|
96
|
+
authPlugin = new HTPasswd(
|
|
97
|
+
{ file: './htpasswd' },
|
|
98
|
+
pluginOptions as any as pluginUtils.PluginOptions
|
|
99
|
+
);
|
|
124
100
|
} catch (error: any) {
|
|
125
101
|
debug('error on loading auth htpasswd plugin stack: %o', error);
|
|
102
|
+
logger.info({}, 'no auth plugin has been found');
|
|
126
103
|
return [];
|
|
127
104
|
}
|
|
128
105
|
|
|
129
106
|
return [authPlugin];
|
|
130
107
|
}
|
|
131
108
|
|
|
132
|
-
private async loadPlugin()
|
|
133
|
-
return asyncLoadPlugin<
|
|
109
|
+
private async loadPlugin() {
|
|
110
|
+
return asyncLoadPlugin<pluginUtils.Auth<unknown>>(
|
|
134
111
|
this.config.auth,
|
|
135
112
|
{
|
|
136
113
|
config: this.config,
|
|
137
|
-
logger
|
|
114
|
+
logger,
|
|
138
115
|
},
|
|
139
|
-
(plugin
|
|
116
|
+
(plugin): boolean => {
|
|
140
117
|
const { authenticate, allow_access, allow_publish } = plugin;
|
|
141
118
|
|
|
142
|
-
|
|
143
|
-
|
|
119
|
+
return (
|
|
120
|
+
typeof authenticate !== 'undefined' ||
|
|
121
|
+
typeof allow_access !== 'undefined' ||
|
|
122
|
+
typeof allow_publish !== 'undefined'
|
|
123
|
+
);
|
|
144
124
|
},
|
|
145
125
|
this.config?.serverSettings?.pluginPrefix
|
|
146
126
|
);
|
|
@@ -148,7 +128,7 @@ class Auth implements IAuth {
|
|
|
148
128
|
|
|
149
129
|
private _applyDefaultPlugins(): void {
|
|
150
130
|
// TODO: rename to applyFallbackPluginMethods
|
|
151
|
-
this.plugins.push(getDefaultPlugins(
|
|
131
|
+
this.plugins.push(getDefaultPlugins(logger));
|
|
152
132
|
}
|
|
153
133
|
|
|
154
134
|
public changePassword(
|
|
@@ -171,7 +151,7 @@ class Auth implements IAuth {
|
|
|
171
151
|
debug('updating password for %o', username);
|
|
172
152
|
plugin.changePassword!(username, password, newPassword, (err, profile): void => {
|
|
173
153
|
if (err) {
|
|
174
|
-
|
|
154
|
+
logger.error(
|
|
175
155
|
{ username, err },
|
|
176
156
|
`An error has been produced
|
|
177
157
|
updating the password for @{username}. Error: @{err.message}`
|
|
@@ -192,17 +172,21 @@ class Auth implements IAuth {
|
|
|
192
172
|
return Promise.resolve();
|
|
193
173
|
}
|
|
194
174
|
|
|
195
|
-
public authenticate(
|
|
175
|
+
public authenticate(
|
|
176
|
+
username: string,
|
|
177
|
+
password: string,
|
|
178
|
+
cb: (error: VerdaccioError | null, user?: RemoteUser) => void
|
|
179
|
+
): void {
|
|
196
180
|
const plugins = this.plugins.slice(0);
|
|
197
181
|
(function next(): void {
|
|
198
|
-
const plugin = plugins.shift() as
|
|
182
|
+
const plugin = plugins.shift() as pluginUtils.Auth<Config>;
|
|
199
183
|
|
|
200
184
|
if (isFunction(plugin.authenticate) === false) {
|
|
201
185
|
return next();
|
|
202
186
|
}
|
|
203
187
|
|
|
204
188
|
debug('authenticating %o', username);
|
|
205
|
-
plugin.authenticate(username, password, function (err, groups): void {
|
|
189
|
+
plugin.authenticate(username, password, function (err: VerdaccioError | null, groups): void {
|
|
206
190
|
if (err) {
|
|
207
191
|
debug('authenticating for user %o failed. Error: %o', username, err?.message);
|
|
208
192
|
return cb(err);
|
|
@@ -233,37 +217,42 @@ class Auth implements IAuth {
|
|
|
233
217
|
})();
|
|
234
218
|
}
|
|
235
219
|
|
|
236
|
-
public add_user(
|
|
220
|
+
public add_user(
|
|
221
|
+
user: string,
|
|
222
|
+
password: string,
|
|
223
|
+
cb: (error: VerdaccioError | null, user?: RemoteUser) => void
|
|
224
|
+
): void {
|
|
237
225
|
const self = this;
|
|
238
226
|
const plugins = this.plugins.slice(0);
|
|
239
227
|
debug('add user %o', user);
|
|
240
228
|
|
|
241
229
|
(function next(): void {
|
|
242
|
-
const plugin = plugins.shift() as
|
|
243
|
-
|
|
244
|
-
if (isFunction(plugin[method]) === false) {
|
|
245
|
-
method = 'add_user';
|
|
246
|
-
self.logger.warn(
|
|
247
|
-
'the plugin method add_user in the auth plugin is deprecated and will' +
|
|
248
|
-
' be removed in next major release, notify to the plugin author'
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
if (isFunction(plugin[method]) === false) {
|
|
230
|
+
const plugin = plugins.shift() as pluginUtils.Auth<Config>;
|
|
231
|
+
if (typeof plugin.adduser !== 'function') {
|
|
253
232
|
next();
|
|
254
233
|
} else {
|
|
255
|
-
//
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
234
|
+
// @ts-expect-error future major (7.x) should remove this section
|
|
235
|
+
if (typeof plugin.adduser === 'undefined' && typeof plugin.add_user === 'function') {
|
|
236
|
+
throw errorUtils.getInternalError(
|
|
237
|
+
'add_user method not longer supported, rename to adduser'
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
plugin.adduser(
|
|
242
|
+
user,
|
|
243
|
+
password,
|
|
244
|
+
function (err: VerdaccioError | null, ok?: boolean | string): void {
|
|
245
|
+
if (err) {
|
|
246
|
+
debug('the user %o could not being added. Error: %o', user, err?.message);
|
|
247
|
+
return cb(err);
|
|
248
|
+
}
|
|
249
|
+
if (ok) {
|
|
250
|
+
debug('the user %o has been added', user);
|
|
251
|
+
return self.authenticate(user, password, cb);
|
|
252
|
+
}
|
|
253
|
+
next();
|
|
264
254
|
}
|
|
265
|
-
|
|
266
|
-
});
|
|
255
|
+
);
|
|
267
256
|
}
|
|
268
257
|
})();
|
|
269
258
|
}
|
|
@@ -272,27 +261,27 @@ class Auth implements IAuth {
|
|
|
272
261
|
* Allow user to access a package.
|
|
273
262
|
*/
|
|
274
263
|
public allow_access(
|
|
275
|
-
{ packageName, packageVersion }: AuthPluginPackage,
|
|
264
|
+
{ packageName, packageVersion }: pluginUtils.AuthPluginPackage,
|
|
276
265
|
user: RemoteUser,
|
|
277
|
-
callback:
|
|
266
|
+
callback: pluginUtils.AccessCallback
|
|
278
267
|
): void {
|
|
279
268
|
const plugins = this.plugins.slice(0);
|
|
280
|
-
const
|
|
269
|
+
const pkgAllowAccess: AllowAccess = { name: packageName, version: packageVersion };
|
|
281
270
|
const pkg = Object.assign(
|
|
282
271
|
{},
|
|
283
|
-
|
|
272
|
+
pkgAllowAccess,
|
|
284
273
|
getMatchedPackagesSpec(packageName, this.config.packages)
|
|
285
274
|
) as AllowAccess & PackageAccess;
|
|
286
275
|
debug('allow access for %o', packageName);
|
|
287
276
|
|
|
288
277
|
(function next(): void {
|
|
289
|
-
const plugin:
|
|
278
|
+
const plugin: pluginUtils.Auth<unknown> = plugins.shift() as pluginUtils.Auth<unknown>;
|
|
290
279
|
|
|
291
280
|
if (_.isNil(plugin) || isFunction(plugin.allow_access) === false) {
|
|
292
281
|
return next();
|
|
293
282
|
}
|
|
294
283
|
|
|
295
|
-
plugin.allow_access!(user, pkg, function (err, ok
|
|
284
|
+
plugin.allow_access!(user, pkg, function (err: VerdaccioError | null, ok?: boolean): void {
|
|
296
285
|
if (err) {
|
|
297
286
|
debug('forbidden access for %o. Error: %o', packageName, err?.message);
|
|
298
287
|
return callback(err);
|
|
@@ -309,7 +298,7 @@ class Auth implements IAuth {
|
|
|
309
298
|
}
|
|
310
299
|
|
|
311
300
|
public allow_unpublish(
|
|
312
|
-
{ packageName, packageVersion }: AuthPluginPackage,
|
|
301
|
+
{ packageName, packageVersion }: pluginUtils.AuthPluginPackage,
|
|
313
302
|
user: RemoteUser,
|
|
314
303
|
callback: Callback
|
|
315
304
|
): void {
|
|
@@ -354,7 +343,7 @@ class Auth implements IAuth {
|
|
|
354
343
|
* Allow user to publish a package.
|
|
355
344
|
*/
|
|
356
345
|
public allow_publish(
|
|
357
|
-
{ packageName, packageVersion }: AuthPluginPackage,
|
|
346
|
+
{ packageName, packageVersion }: pluginUtils.AuthPluginPackage,
|
|
358
347
|
user: RemoteUser,
|
|
359
348
|
callback: Callback
|
|
360
349
|
): void {
|
|
@@ -362,42 +351,35 @@ class Auth implements IAuth {
|
|
|
362
351
|
const pkg = Object.assign(
|
|
363
352
|
{ name: packageName, version: packageVersion },
|
|
364
353
|
getMatchedPackagesSpec(packageName, this.config.packages)
|
|
365
|
-
);
|
|
354
|
+
) as any;
|
|
366
355
|
debug('allow publish for %o init | plugins: %o', packageName, plugins.length);
|
|
367
356
|
|
|
368
357
|
(function next(): void {
|
|
369
358
|
const plugin = plugins.shift();
|
|
370
359
|
|
|
371
|
-
if (
|
|
360
|
+
if (typeof plugin?.allow_publish !== 'function') {
|
|
372
361
|
debug('allow publish for %o plugin does not implement allow_publish', packageName);
|
|
373
362
|
return next();
|
|
374
363
|
}
|
|
375
364
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
// @ts-ignore
|
|
382
|
-
(err: VerdaccioError, ok: boolean): void => {
|
|
383
|
-
if (_.isNil(err) === false && _.isError(err)) {
|
|
384
|
-
debug('forbidden publish for %o', packageName);
|
|
385
|
-
return callback(err);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
if (ok) {
|
|
389
|
-
debug('allowed publish for %o', packageName);
|
|
390
|
-
return callback(null, ok);
|
|
391
|
-
}
|
|
365
|
+
plugin.allow_publish(user, pkg, (err: VerdaccioError | null, ok?: boolean): void => {
|
|
366
|
+
if (_.isNil(err) === false && _.isError(err)) {
|
|
367
|
+
debug('forbidden publish for %o', packageName);
|
|
368
|
+
return callback(err);
|
|
369
|
+
}
|
|
392
370
|
|
|
393
|
-
|
|
394
|
-
|
|
371
|
+
if (ok) {
|
|
372
|
+
debug('allowed publish for %o', packageName);
|
|
373
|
+
return callback(null, ok);
|
|
395
374
|
}
|
|
396
|
-
|
|
375
|
+
|
|
376
|
+
debug('allow publish skip validation for %o', packageName);
|
|
377
|
+
next(); // cb(null, false) causes next plugin to roll
|
|
378
|
+
});
|
|
397
379
|
})();
|
|
398
380
|
}
|
|
399
381
|
|
|
400
|
-
public apiJWTmiddleware():
|
|
382
|
+
public apiJWTmiddleware(): RequestHandler {
|
|
401
383
|
debug('jwt middleware');
|
|
402
384
|
const plugins = this.plugins.slice(0);
|
|
403
385
|
const helpers = { createAnonymousRemoteUser, createRemoteUser };
|
|
@@ -407,10 +389,11 @@ class Auth implements IAuth {
|
|
|
407
389
|
}
|
|
408
390
|
}
|
|
409
391
|
|
|
410
|
-
|
|
392
|
+
// @ts-ignore
|
|
393
|
+
return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction) => {
|
|
411
394
|
req.pause();
|
|
412
395
|
|
|
413
|
-
const next = function (err
|
|
396
|
+
const next = function (err?: VerdaccioError): any {
|
|
414
397
|
req.resume();
|
|
415
398
|
// uncomment this to reject users with bad auth headers
|
|
416
399
|
// return _next.apply(null, arguments)
|
|
@@ -419,6 +402,7 @@ class Auth implements IAuth {
|
|
|
419
402
|
if (err) {
|
|
420
403
|
req.remote_user.error = err.message;
|
|
421
404
|
}
|
|
405
|
+
|
|
422
406
|
return _next();
|
|
423
407
|
};
|
|
424
408
|
|
|
@@ -469,7 +453,7 @@ class Auth implements IAuth {
|
|
|
469
453
|
const credentials = convertPayloadToBase64(token).toString();
|
|
470
454
|
const { user, password } = parseBasicPayload(credentials) as AESPayload;
|
|
471
455
|
debug('authenticating %o', user);
|
|
472
|
-
this.authenticate(user, password, (err, user): void => {
|
|
456
|
+
this.authenticate(user, password, (err: VerdaccioError | null, user): void => {
|
|
473
457
|
if (!err) {
|
|
474
458
|
debug('generating a remote user');
|
|
475
459
|
req.remote_user = user;
|
|
@@ -529,14 +513,15 @@ class Auth implements IAuth {
|
|
|
529
513
|
}
|
|
530
514
|
}
|
|
531
515
|
|
|
532
|
-
private _isRemoteUserValid(remote_user
|
|
533
|
-
return _.isUndefined(remote_user) === false && _.isUndefined(remote_user
|
|
516
|
+
private _isRemoteUserValid(remote_user?: RemoteUser): boolean {
|
|
517
|
+
return _.isUndefined(remote_user) === false && _.isUndefined(remote_user?.name) === false;
|
|
534
518
|
}
|
|
535
519
|
|
|
536
520
|
/**
|
|
537
521
|
* JWT middleware for WebUI
|
|
538
522
|
*/
|
|
539
|
-
public webUIJWTmiddleware():
|
|
523
|
+
public webUIJWTmiddleware(): RequestHandler {
|
|
524
|
+
// @ts-ignore
|
|
540
525
|
return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction): void => {
|
|
541
526
|
if (this._isRemoteUserValid(req.remote_user)) {
|
|
542
527
|
return _next();
|
|
@@ -567,7 +552,7 @@ class Auth implements IAuth {
|
|
|
567
552
|
return next();
|
|
568
553
|
}
|
|
569
554
|
|
|
570
|
-
let credentials;
|
|
555
|
+
let credentials: RemoteUser | undefined;
|
|
571
556
|
try {
|
|
572
557
|
credentials = verifyJWTPayload(token, this.config.secret);
|
|
573
558
|
} catch (err: any) {
|
|
@@ -575,9 +560,8 @@ class Auth implements IAuth {
|
|
|
575
560
|
}
|
|
576
561
|
|
|
577
562
|
if (this._isRemoteUserValid(credentials)) {
|
|
578
|
-
const { name, groups } = credentials;
|
|
579
|
-
|
|
580
|
-
req.remote_user = createRemoteUser(name, groups);
|
|
563
|
+
const { name, groups } = credentials as RemoteUser;
|
|
564
|
+
req.remote_user = createRemoteUser(name as string, groups);
|
|
581
565
|
} else {
|
|
582
566
|
req.remote_user = createAnonymousRemoteUser();
|
|
583
567
|
}
|
package/src/index.ts
CHANGED
package/src/utils.ts
CHANGED
|
@@ -9,15 +9,9 @@ import {
|
|
|
9
9
|
TOKEN_BEARER,
|
|
10
10
|
VerdaccioError,
|
|
11
11
|
errorUtils,
|
|
12
|
+
pluginUtils,
|
|
12
13
|
} from '@verdaccio/core';
|
|
13
|
-
import {
|
|
14
|
-
AuthPackageAllow,
|
|
15
|
-
Callback,
|
|
16
|
-
Config,
|
|
17
|
-
IPluginAuth,
|
|
18
|
-
RemoteUser,
|
|
19
|
-
Security,
|
|
20
|
-
} from '@verdaccio/types';
|
|
14
|
+
import { AuthPackageAllow, Config, Logger, RemoteUser, Security } from '@verdaccio/types';
|
|
21
15
|
|
|
22
16
|
import { AESPayload, TokenEncryption } from './auth';
|
|
23
17
|
import { verifyPayload } from './jwt-token';
|
|
@@ -161,13 +155,18 @@ export function isAuthHeaderValid(authorization: string): boolean {
|
|
|
161
155
|
return authorization.split(' ').length === 2;
|
|
162
156
|
}
|
|
163
157
|
|
|
164
|
-
|
|
158
|
+
/**
|
|
159
|
+
* Return a default configuration for authentication if none is provided.
|
|
160
|
+
* @param logger {Logger}
|
|
161
|
+
* @returns object of default implementations.
|
|
162
|
+
*/
|
|
163
|
+
export function getDefaultPlugins(logger: Logger): pluginUtils.Auth<Config> {
|
|
165
164
|
return {
|
|
166
|
-
authenticate(
|
|
165
|
+
authenticate(_user: string, _password: string, cb: pluginUtils.AuthCallback): void {
|
|
167
166
|
cb(errorUtils.getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));
|
|
168
167
|
},
|
|
169
168
|
|
|
170
|
-
adduser(
|
|
169
|
+
adduser(_user: string, _password: string, cb: pluginUtils.AuthUserCallback): void {
|
|
171
170
|
return cb(errorUtils.getConflict(API_ERROR.BAD_USERNAME_PASSWORD));
|
|
172
171
|
},
|
|
173
172
|
|
|
@@ -182,7 +181,7 @@ export function getDefaultPlugins(logger: any): IPluginAuth<Config> {
|
|
|
182
181
|
|
|
183
182
|
export type ActionsAllowed = 'publish' | 'unpublish' | 'access';
|
|
184
183
|
|
|
185
|
-
export function allow_action(action: ActionsAllowed, logger): AllowAction {
|
|
184
|
+
export function allow_action(action: ActionsAllowed, logger: Logger): AllowAction {
|
|
186
185
|
return function allowActionCallback(
|
|
187
186
|
user: RemoteUser,
|
|
188
187
|
pkg: AuthPackageAllow,
|
|
@@ -217,7 +216,7 @@ export function allow_action(action: ActionsAllowed, logger): AllowAction {
|
|
|
217
216
|
/**
|
|
218
217
|
*
|
|
219
218
|
*/
|
|
220
|
-
export function handleSpecialUnpublish(logger): any {
|
|
219
|
+
export function handleSpecialUnpublish(logger: Logger): any {
|
|
221
220
|
return function (user: RemoteUser, pkg: AuthPackageAllow, callback: AllowActionCallback): void {
|
|
222
221
|
const action = 'unpublish';
|
|
223
222
|
// verify whether the unpublish prop has been defined
|
package/test/auth-utils.spec.ts
CHANGED
|
@@ -24,7 +24,6 @@ import type { AllowActionCallbackResponse } from '@verdaccio/utils';
|
|
|
24
24
|
import {
|
|
25
25
|
ActionsAllowed,
|
|
26
26
|
Auth,
|
|
27
|
-
IAuth,
|
|
28
27
|
aesDecrypt,
|
|
29
28
|
allow_action,
|
|
30
29
|
getApiToken,
|
|
@@ -70,7 +69,7 @@ describe('Auth utilities', () => {
|
|
|
70
69
|
methodNotBeenCalled: string
|
|
71
70
|
): Promise<string> {
|
|
72
71
|
const config: Config = getConfig(configFileName, secret);
|
|
73
|
-
const auth:
|
|
72
|
+
const auth: Auth = new Auth(config);
|
|
74
73
|
await auth.init();
|
|
75
74
|
// @ts-ignore
|
|
76
75
|
const spy = jest.spyOn(auth, methodToSpy);
|
|
@@ -409,7 +408,7 @@ describe('Auth utilities', () => {
|
|
|
409
408
|
test.concurrent('should return empty credential corrupted payload', async () => {
|
|
410
409
|
const secret = 'b2df428b9929d3ace7c598bbf4e496b2';
|
|
411
410
|
const config: Config = getConfig('security-legacy', secret);
|
|
412
|
-
const auth:
|
|
411
|
+
const auth: Auth = new Auth(config);
|
|
413
412
|
await auth.init();
|
|
414
413
|
const token = auth.aesEncrypt(null);
|
|
415
414
|
const security: Security = config.security;
|
package/test/auth.spec.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
|
|
3
|
-
import { IAuth } from '@verdaccio/auth';
|
|
4
3
|
import { Config as AppConfig, ROLES, getDefaultConfig } from '@verdaccio/config';
|
|
5
4
|
import { errorUtils } from '@verdaccio/core';
|
|
6
5
|
import { setup } from '@verdaccio/logger';
|
|
@@ -9,14 +8,14 @@ import { Config } from '@verdaccio/types';
|
|
|
9
8
|
import { Auth } from '../src';
|
|
10
9
|
import { authPluginFailureConf, authPluginPassThrougConf, authProfileConf } from './helper/plugin';
|
|
11
10
|
|
|
12
|
-
setup(
|
|
11
|
+
setup({});
|
|
13
12
|
|
|
14
13
|
describe('AuthTest', () => {
|
|
15
14
|
test('should init correctly', async () => {
|
|
16
15
|
const config: Config = new AppConfig({ ...authProfileConf });
|
|
17
16
|
config.checkSecretKey('12345');
|
|
18
17
|
|
|
19
|
-
const auth:
|
|
18
|
+
const auth: Auth = new Auth(config);
|
|
20
19
|
await auth.init();
|
|
21
20
|
expect(auth).toBeDefined();
|
|
22
21
|
});
|
|
@@ -25,7 +24,7 @@ describe('AuthTest', () => {
|
|
|
25
24
|
const config: Config = new AppConfig({ ...authProfileConf, auth: undefined });
|
|
26
25
|
config.checkSecretKey('12345');
|
|
27
26
|
|
|
28
|
-
const auth:
|
|
27
|
+
const auth: Auth = new Auth(config);
|
|
29
28
|
await auth.init();
|
|
30
29
|
expect(auth).toBeDefined();
|
|
31
30
|
});
|
|
@@ -35,7 +34,7 @@ describe('AuthTest', () => {
|
|
|
35
34
|
test('should be a success login', async () => {
|
|
36
35
|
const config: Config = new AppConfig({ ...authProfileConf });
|
|
37
36
|
config.checkSecretKey('12345');
|
|
38
|
-
const auth:
|
|
37
|
+
const auth: Auth = new Auth(config);
|
|
39
38
|
await auth.init();
|
|
40
39
|
expect(auth).toBeDefined();
|
|
41
40
|
|
|
@@ -62,7 +61,7 @@ describe('AuthTest', () => {
|
|
|
62
61
|
test('should be a fail on login', async () => {
|
|
63
62
|
const config: Config = new AppConfig(authPluginFailureConf);
|
|
64
63
|
config.checkSecretKey('12345');
|
|
65
|
-
const auth:
|
|
64
|
+
const auth: Auth = new Auth(config);
|
|
66
65
|
await auth.init();
|
|
67
66
|
expect(auth).toBeDefined();
|
|
68
67
|
|
|
@@ -81,7 +80,7 @@ describe('AuthTest', () => {
|
|
|
81
80
|
test('should skip falsy values', async () => {
|
|
82
81
|
const config: Config = new AppConfig({ ...authPluginPassThrougConf });
|
|
83
82
|
config.checkSecretKey('12345');
|
|
84
|
-
const auth:
|
|
83
|
+
const auth: Auth = new Auth(config);
|
|
85
84
|
await auth.init();
|
|
86
85
|
expect(auth).toBeDefined();
|
|
87
86
|
|
|
@@ -101,7 +100,7 @@ describe('AuthTest', () => {
|
|
|
101
100
|
test('should error truthy non-array', async () => {
|
|
102
101
|
const config: Config = new AppConfig({ ...authPluginPassThrougConf });
|
|
103
102
|
config.checkSecretKey('12345');
|
|
104
|
-
const auth:
|
|
103
|
+
const auth: Auth = new Auth(config);
|
|
105
104
|
await auth.init();
|
|
106
105
|
expect(auth).toBeDefined();
|
|
107
106
|
|
|
@@ -119,7 +118,7 @@ describe('AuthTest', () => {
|
|
|
119
118
|
test('should skip empty array', async () => {
|
|
120
119
|
const config: Config = new AppConfig({ ...authPluginPassThrougConf });
|
|
121
120
|
config.checkSecretKey('12345');
|
|
122
|
-
const auth:
|
|
121
|
+
const auth: Auth = new Auth(config);
|
|
123
122
|
await auth.init();
|
|
124
123
|
expect(auth).toBeDefined();
|
|
125
124
|
|
|
@@ -136,7 +135,7 @@ describe('AuthTest', () => {
|
|
|
136
135
|
test('should accept valid array', async () => {
|
|
137
136
|
const config: Config = new AppConfig({ ...authPluginPassThrougConf });
|
|
138
137
|
config.checkSecretKey('12345');
|
|
139
|
-
const auth:
|
|
138
|
+
const auth: Auth = new Auth(config);
|
|
140
139
|
await auth.init();
|
|
141
140
|
expect(auth).toBeDefined();
|
|
142
141
|
|
|
@@ -165,7 +164,7 @@ describe('AuthTest', () => {
|
|
|
165
164
|
},
|
|
166
165
|
});
|
|
167
166
|
config.checkSecretKey('12345');
|
|
168
|
-
const auth:
|
|
167
|
+
const auth: Auth = new Auth(config);
|
|
169
168
|
await auth.init();
|
|
170
169
|
|
|
171
170
|
return new Promise((resolve) => {
|
package/tsconfig.build.json
CHANGED