@verdaccio/auth 7.0.0-next.3 → 7.0.0-next.5
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 +30 -0
- package/build/auth.d.ts +7 -26
- package/build/auth.js +43 -31
- package/build/auth.js.map +1 -1
- package/build/index.d.ts +1 -0
- package/build/index.js +12 -0
- package/build/index.js.map +1 -1
- package/build/signature-legacy.d.ts +5 -0
- package/build/signature-legacy.js +60 -0
- package/build/signature-legacy.js.map +1 -0
- package/build/signature.d.ts +4 -0
- package/build/signature.js +60 -0
- package/build/signature.js.map +1 -0
- package/build/types.d.ts +34 -0
- package/build/types.js +13 -0
- package/build/types.js.map +1 -0
- package/build/utils.d.ts +5 -15
- package/build/utils.js +19 -9
- package/build/utils.js.map +1 -1
- package/package.json +12 -10
- package/src/auth.ts +66 -59
- package/src/index.ts +1 -0
- package/src/signature-legacy.ts +66 -0
- package/src/signature.ts +66 -0
- package/src/types.ts +46 -0
- package/src/utils.ts +37 -31
- package/test/auth.spec.ts +561 -40
- package/test/helper/plugin.ts +8 -0
- package/test/partials/plugin/verdaccio-access-ok/access.js +9 -0
- package/test/partials/plugin/verdaccio-access-ok/package.json +5 -0
- package/test/partials/plugin/verdaccio-adduser/adduser.js +25 -0
- package/test/partials/plugin/verdaccio-adduser/package.json +5 -0
- package/test/partials/plugin/verdaccio-adduser-legacy/adduser.js +25 -0
- package/test/partials/plugin/verdaccio-adduser-legacy/package.json +5 -0
- package/test/partials/plugin/verdaccio-change-password/change.js +32 -0
- package/test/partials/plugin/verdaccio-change-password/package.json +5 -0
- package/test/partials/plugin/verdaccio-fail/fail.js +3 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signature.js","names":["_debug","_interopRequireDefault","require","_lodash","_core","_signature","_utils","obj","__esModule","default","debug","buildDebug","parseAESCredentials","authorizationHeader","secret","scheme","token","parseAuthTokenHeader","toUpperCase","TOKEN_BASIC","credentials","convertPayloadToBase64","toString","TOKEN_BEARER","aesDecrypt","getMiddlewareCredentials","security","secretKey","isAESLegacy","parsedCredentials","parseBasicPayload","_","isString","verifyJWTPayload"],"sources":["../src/signature.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport _ from 'lodash';\n\nimport { TOKEN_BASIC, TOKEN_BEARER } from '@verdaccio/core';\nimport { aesDecrypt, parseBasicPayload } from '@verdaccio/signature';\nimport { Security } from '@verdaccio/types';\n\nimport { AuthMiddlewarePayload } from './types';\nimport {\n convertPayloadToBase64,\n isAESLegacy,\n parseAuthTokenHeader,\n verifyJWTPayload,\n} from './utils';\n\nconst debug = buildDebug('verdaccio:auth:utils');\n\nexport function parseAESCredentials(authorizationHeader: string, secret: string) {\n debug('parseAESCredentials');\n const { scheme, token } = parseAuthTokenHeader(authorizationHeader);\n\n // basic is deprecated and should not be enforced\n // basic is currently being used for functional test\n if (scheme.toUpperCase() === TOKEN_BASIC.toUpperCase()) {\n debug('legacy header basic');\n const credentials = convertPayloadToBase64(token).toString();\n\n return credentials;\n } else if (scheme.toUpperCase() === TOKEN_BEARER.toUpperCase()) {\n debug('legacy header bearer');\n const credentials = aesDecrypt(token, secret);\n\n return credentials;\n }\n}\n\nexport function getMiddlewareCredentials(\n security: Security,\n secretKey: string,\n authorizationHeader: string\n): AuthMiddlewarePayload {\n debug('getMiddlewareCredentials');\n // comment out for debugging purposes\n if (isAESLegacy(security)) {\n debug('is legacy');\n const credentials = parseAESCredentials(authorizationHeader, secretKey);\n if (!credentials) {\n debug('parse legacy credentials failed');\n return;\n }\n\n const parsedCredentials = parseBasicPayload(credentials);\n if (!parsedCredentials) {\n debug('parse legacy basic payload credentials failed');\n return;\n }\n\n return parsedCredentials;\n }\n const { scheme, token } = parseAuthTokenHeader(authorizationHeader);\n\n debug('is jwt');\n if (_.isString(token) && scheme.toUpperCase() === TOKEN_BEARER.toUpperCase()) {\n return verifyJWTPayload(token, secretKey);\n }\n}\n"],"mappings":";;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,OAAA,GAAAF,sBAAA,CAAAC,OAAA;AAEA,IAAAE,KAAA,GAAAF,OAAA;AACA,IAAAG,UAAA,GAAAH,OAAA;AAIA,IAAAI,MAAA,GAAAJ,OAAA;AAKiB,SAAAD,uBAAAM,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,KAAAE,OAAA,EAAAF,GAAA;AAEjB,MAAMG,KAAK,GAAG,IAAAC,cAAU,EAAC,sBAAsB,CAAC;AAEzC,SAASC,mBAAmBA,CAACC,mBAA2B,EAAEC,MAAc,EAAE;EAC/EJ,KAAK,CAAC,qBAAqB,CAAC;EAC5B,MAAM;IAAEK,MAAM;IAAEC;EAAM,CAAC,GAAG,IAAAC,2BAAoB,EAACJ,mBAAmB,CAAC;;EAEnE;EACA;EACA,IAAIE,MAAM,CAACG,WAAW,CAAC,CAAC,KAAKC,iBAAW,CAACD,WAAW,CAAC,CAAC,EAAE;IACtDR,KAAK,CAAC,qBAAqB,CAAC;IAC5B,MAAMU,WAAW,GAAG,IAAAC,6BAAsB,EAACL,KAAK,CAAC,CAACM,QAAQ,CAAC,CAAC;IAE5D,OAAOF,WAAW;EACpB,CAAC,MAAM,IAAIL,MAAM,CAACG,WAAW,CAAC,CAAC,KAAKK,kBAAY,CAACL,WAAW,CAAC,CAAC,EAAE;IAC9DR,KAAK,CAAC,sBAAsB,CAAC;IAC7B,MAAMU,WAAW,GAAG,IAAAI,qBAAU,EAACR,KAAK,EAAEF,MAAM,CAAC;IAE7C,OAAOM,WAAW;EACpB;AACF;AAEO,SAASK,wBAAwBA,CACtCC,QAAkB,EAClBC,SAAiB,EACjBd,mBAA2B,EACJ;EACvBH,KAAK,CAAC,0BAA0B,CAAC;EACjC;EACA,IAAI,IAAAkB,kBAAW,EAACF,QAAQ,CAAC,EAAE;IACzBhB,KAAK,CAAC,WAAW,CAAC;IAClB,MAAMU,WAAW,GAAGR,mBAAmB,CAACC,mBAAmB,EAAEc,SAAS,CAAC;IACvE,IAAI,CAACP,WAAW,EAAE;MAChBV,KAAK,CAAC,iCAAiC,CAAC;MACxC;IACF;IAEA,MAAMmB,iBAAiB,GAAG,IAAAC,4BAAiB,EAACV,WAAW,CAAC;IACxD,IAAI,CAACS,iBAAiB,EAAE;MACtBnB,KAAK,CAAC,+CAA+C,CAAC;MACtD;IACF;IAEA,OAAOmB,iBAAiB;EAC1B;EACA,MAAM;IAAEd,MAAM;IAAEC;EAAM,CAAC,GAAG,IAAAC,2BAAoB,EAACJ,mBAAmB,CAAC;EAEnEH,KAAK,CAAC,QAAQ,CAAC;EACf,IAAIqB,eAAC,CAACC,QAAQ,CAAChB,KAAK,CAAC,IAAID,MAAM,CAACG,WAAW,CAAC,CAAC,KAAKK,kBAAY,CAACL,WAAW,CAAC,CAAC,EAAE;IAC5E,OAAO,IAAAe,uBAAgB,EAACjB,KAAK,EAAEW,SAAS,CAAC;EAC3C;AACF"}
|
package/build/types.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { NextFunction, Request, Response } from 'express';
|
|
2
|
+
import { VerdaccioError } from '@verdaccio/core';
|
|
3
|
+
import { AuthPackageAllow, JWTSignOptions, Logger, RemoteUser } from '@verdaccio/types';
|
|
4
|
+
export interface AESPayload {
|
|
5
|
+
user: string;
|
|
6
|
+
password: string;
|
|
7
|
+
}
|
|
8
|
+
export type BasicPayload = AESPayload | void;
|
|
9
|
+
export type AuthMiddlewarePayload = RemoteUser | BasicPayload;
|
|
10
|
+
export interface AuthTokenHeader {
|
|
11
|
+
scheme: string;
|
|
12
|
+
token: string;
|
|
13
|
+
}
|
|
14
|
+
export type AllowActionCallbackResponse = boolean | undefined;
|
|
15
|
+
export type AllowActionCallback = (error: VerdaccioError | null, allowed?: AllowActionCallbackResponse) => void;
|
|
16
|
+
export type AllowAction = (user: RemoteUser, pkg: AuthPackageAllow, callback: AllowActionCallback) => void;
|
|
17
|
+
export interface TokenEncryption {
|
|
18
|
+
jwtEncrypt(user: RemoteUser, signOptions: JWTSignOptions): Promise<string>;
|
|
19
|
+
aesEncrypt(buf: string): string | void;
|
|
20
|
+
}
|
|
21
|
+
export type ActionsAllowed = 'publish' | 'unpublish' | 'access';
|
|
22
|
+
export interface IAuthMiddleware {
|
|
23
|
+
apiJWTmiddleware(): $NextFunctionVer;
|
|
24
|
+
webUIJWTmiddleware(): $NextFunctionVer;
|
|
25
|
+
}
|
|
26
|
+
export type $RequestExtend = Request & {
|
|
27
|
+
remote_user?: any;
|
|
28
|
+
log: Logger;
|
|
29
|
+
};
|
|
30
|
+
export type $ResponseExtend = Response & {
|
|
31
|
+
cookies?: any;
|
|
32
|
+
};
|
|
33
|
+
export type $NextFunctionVer = NextFunction & any;
|
|
34
|
+
export { NextFunction };
|
package/build/types.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "NextFunction", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _express.NextFunction;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
var _express = require("express");
|
|
13
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","names":["_express","require"],"sources":["../src/types.ts"],"sourcesContent":["import { NextFunction, Request, Response } from 'express';\n\nimport { VerdaccioError } from '@verdaccio/core';\nimport { AuthPackageAllow, JWTSignOptions, Logger, RemoteUser } from '@verdaccio/types';\n\nexport interface AESPayload {\n user: string;\n password: string;\n}\n\nexport type BasicPayload = AESPayload | void;\nexport type AuthMiddlewarePayload = RemoteUser | BasicPayload;\n\nexport interface AuthTokenHeader {\n scheme: string;\n token: string;\n}\nexport type AllowActionCallbackResponse = boolean | undefined;\nexport type AllowActionCallback = (\n error: VerdaccioError | null,\n allowed?: AllowActionCallbackResponse\n) => void;\n\nexport type AllowAction = (\n user: RemoteUser,\n pkg: AuthPackageAllow,\n callback: AllowActionCallback\n) => void;\n\nexport interface TokenEncryption {\n jwtEncrypt(user: RemoteUser, signOptions: JWTSignOptions): Promise<string>;\n aesEncrypt(buf: string): string | void;\n}\n\nexport type ActionsAllowed = 'publish' | 'unpublish' | 'access';\n\n// remove\nexport interface IAuthMiddleware {\n apiJWTmiddleware(): $NextFunctionVer;\n webUIJWTmiddleware(): $NextFunctionVer;\n}\n\nexport type $RequestExtend = Request & { remote_user?: any; log: Logger };\nexport type $ResponseExtend = Response & { cookies?: any };\nexport type $NextFunctionVer = NextFunction & any;\nexport { NextFunction };\n"],"mappings":";;;;;;;;;;;AAAA,IAAAA,QAAA,GAAAC,OAAA"}
|
package/build/utils.d.ts
CHANGED
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
export type BasicPayload = AESPayload | void;
|
|
6
|
-
export type AuthMiddlewarePayload = RemoteUser | BasicPayload;
|
|
7
|
-
export interface AuthTokenHeader {
|
|
8
|
-
scheme: string;
|
|
9
|
-
token: string;
|
|
10
|
-
}
|
|
11
|
-
export type AllowActionCallbackResponse = boolean | undefined;
|
|
12
|
-
export type AllowActionCallback = (error: VerdaccioError | null, allowed?: AllowActionCallbackResponse) => void;
|
|
13
|
-
export type AllowAction = (user: RemoteUser, pkg: AuthPackageAllow, callback: AllowActionCallback) => void;
|
|
2
|
+
import { pluginUtils } from '@verdaccio/core';
|
|
3
|
+
import { Config, Logger, RemoteUser, Security } from '@verdaccio/types';
|
|
4
|
+
import { ActionsAllowed, AllowAction, AuthMiddlewarePayload, AuthTokenHeader, TokenEncryption } from './types';
|
|
14
5
|
/**
|
|
15
6
|
* Split authentication header eg: Bearer [secret_token]
|
|
16
7
|
* @param authorizationHeader auth token
|
|
17
8
|
*/
|
|
18
9
|
export declare function parseAuthTokenHeader(authorizationHeader: string): AuthTokenHeader;
|
|
19
|
-
export declare function parseAESCredentials(authorizationHeader: string, secret: string): string | void;
|
|
20
|
-
export declare function getMiddlewareCredentials(security: Security, secretKey: string, authorizationHeader: string): AuthMiddlewarePayload;
|
|
10
|
+
export declare function parseAESCredentials(authorizationHeader: string, secret: string, enhanced: boolean): string | void;
|
|
11
|
+
export declare function getMiddlewareCredentials(security: Security, secretKey: string, authorizationHeader: string, enhanced?: boolean): AuthMiddlewarePayload;
|
|
21
12
|
export declare function isAESLegacy(security: Security): boolean;
|
|
22
13
|
export declare function getApiToken(auth: TokenEncryption, config: Config, remoteUser: RemoteUser, aesPassword: string): Promise<string | void>;
|
|
23
14
|
export declare const expireReasons: string[];
|
|
@@ -29,7 +20,6 @@ export declare function isAuthHeaderValid(authorization: string): boolean;
|
|
|
29
20
|
* @returns object of default implementations.
|
|
30
21
|
*/
|
|
31
22
|
export declare function getDefaultPlugins(logger: Logger): pluginUtils.Auth<Config>;
|
|
32
|
-
export type ActionsAllowed = 'publish' | 'unpublish' | 'access';
|
|
33
23
|
export declare function allow_action(action: ActionsAllowed, logger: Logger): AllowAction;
|
|
34
24
|
/**
|
|
35
25
|
*
|
package/build/utils.js
CHANGED
|
@@ -23,6 +23,7 @@ var _core = require("@verdaccio/core");
|
|
|
23
23
|
var _signature = require("@verdaccio/signature");
|
|
24
24
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
25
25
|
const debug = (0, _debug.default)('verdaccio:auth:utils');
|
|
26
|
+
|
|
26
27
|
/**
|
|
27
28
|
* Split authentication header eg: Bearer [secret_token]
|
|
28
29
|
* @param authorizationHeader auth token
|
|
@@ -35,7 +36,7 @@ function parseAuthTokenHeader(authorizationHeader) {
|
|
|
35
36
|
token
|
|
36
37
|
};
|
|
37
38
|
}
|
|
38
|
-
function parseAESCredentials(authorizationHeader, secret) {
|
|
39
|
+
function parseAESCredentials(authorizationHeader, secret, enhanced) {
|
|
39
40
|
debug('parseAESCredentials');
|
|
40
41
|
const {
|
|
41
42
|
scheme,
|
|
@@ -50,16 +51,19 @@ function parseAESCredentials(authorizationHeader, secret) {
|
|
|
50
51
|
return credentials;
|
|
51
52
|
} else if (scheme.toUpperCase() === _core.TOKEN_BEARER.toUpperCase()) {
|
|
52
53
|
debug('legacy header bearer');
|
|
53
|
-
|
|
54
|
+
debug('legacy header enhanced?', enhanced);
|
|
55
|
+
const credentials = enhanced ? (0, _signature.aesDecrypt)(token.toString(), secret) :
|
|
56
|
+
// FUTURE: once deprecated legacy is removed this logic won't be longer need it
|
|
57
|
+
(0, _signature.aesDecryptDeprecated)(convertPayloadToBase64(token), secret).toString('utf-8');
|
|
54
58
|
return credentials;
|
|
55
59
|
}
|
|
56
60
|
}
|
|
57
|
-
function getMiddlewareCredentials(security, secretKey, authorizationHeader) {
|
|
61
|
+
function getMiddlewareCredentials(security, secretKey, authorizationHeader, enhanced = true) {
|
|
58
62
|
debug('getMiddlewareCredentials');
|
|
59
63
|
// comment out for debugging purposes
|
|
60
64
|
if (isAESLegacy(security)) {
|
|
61
65
|
debug('is legacy');
|
|
62
|
-
const credentials = parseAESCredentials(authorizationHeader, secretKey);
|
|
66
|
+
const credentials = parseAESCredentials(authorizationHeader, secretKey, enhanced);
|
|
63
67
|
if (!credentials) {
|
|
64
68
|
debug('parse legacy credentials failed');
|
|
65
69
|
return;
|
|
@@ -109,8 +113,7 @@ async function getApiToken(auth, config, remoteUser, aesPassword) {
|
|
|
109
113
|
resolve(auth.aesEncrypt(buildUser(remoteUser.name, aesPassword)));
|
|
110
114
|
});
|
|
111
115
|
}
|
|
112
|
-
const expireReasons = ['JsonWebTokenError', 'TokenExpiredError'];
|
|
113
|
-
exports.expireReasons = expireReasons;
|
|
116
|
+
const expireReasons = exports.expireReasons = ['JsonWebTokenError', 'TokenExpiredError'];
|
|
114
117
|
function verifyJWTPayload(token, secret) {
|
|
115
118
|
try {
|
|
116
119
|
const payload = (0, _signature.verifyPayload)(token, secret);
|
|
@@ -138,12 +141,13 @@ function isAuthHeaderValid(authorization) {
|
|
|
138
141
|
function getDefaultPlugins(logger) {
|
|
139
142
|
return {
|
|
140
143
|
authenticate(_user, _password, cb) {
|
|
144
|
+
debug('triggered default authenticate method');
|
|
141
145
|
cb(_core.errorUtils.getForbidden(_core.API_ERROR.BAD_USERNAME_PASSWORD));
|
|
142
146
|
},
|
|
143
147
|
adduser(_user, _password, cb) {
|
|
148
|
+
debug('triggered default adduser method');
|
|
144
149
|
return cb(_core.errorUtils.getConflict(_core.API_ERROR.BAD_USERNAME_PASSWORD));
|
|
145
150
|
},
|
|
146
|
-
// FIXME: allow_action and allow_publish should be in the @verdaccio/types
|
|
147
151
|
// @ts-ignore
|
|
148
152
|
allow_access: allow_action('access', logger),
|
|
149
153
|
// @ts-ignore
|
|
@@ -160,8 +164,13 @@ function allow_action(action, logger) {
|
|
|
160
164
|
name,
|
|
161
165
|
groups
|
|
162
166
|
} = user;
|
|
167
|
+
debug('allow_action "%s": groups %s', action, groups);
|
|
163
168
|
const groupAccess = pkg[action];
|
|
164
|
-
|
|
169
|
+
debug('allow_action "%s": groupAccess %s', action, groupAccess);
|
|
170
|
+
const hasPermission = groupAccess.some(group => {
|
|
171
|
+
return name === group || groups.includes(group);
|
|
172
|
+
});
|
|
173
|
+
debug('package "%s" has permission "%s"', name, hasPermission);
|
|
165
174
|
logger.trace({
|
|
166
175
|
pkgName: pkg.name,
|
|
167
176
|
hasPermission,
|
|
@@ -189,7 +198,8 @@ function handleSpecialUnpublish(logger) {
|
|
|
189
198
|
return function (user, pkg, callback) {
|
|
190
199
|
const action = 'unpublish';
|
|
191
200
|
// verify whether the unpublish prop has been defined
|
|
192
|
-
const isUnpublishMissing =
|
|
201
|
+
const isUnpublishMissing = !pkg[action];
|
|
202
|
+
debug('is unpublish method missing ? %s', isUnpublishMissing);
|
|
193
203
|
const hasGroups = isUnpublishMissing ? false : pkg[action].length > 0;
|
|
194
204
|
logger.trace({
|
|
195
205
|
user: user.name,
|
package/build/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":["_debug","_interopRequireDefault","require","_lodash","_config","_core","_signature","obj","__esModule","default","debug","buildDebug","parseAuthTokenHeader","authorizationHeader","parts","split","scheme","token","parseAESCredentials","secret","toUpperCase","TOKEN_BASIC","credentials","convertPayloadToBase64","toString","TOKEN_BEARER","aesDecrypt","getMiddlewareCredentials","security","secretKey","isAESLegacy","parsedCredentials","parseBasicPayload","_","isString","verifyJWTPayload","legacy","jwt","api","isNil","getApiToken","auth","config","remoteUser","aesPassword","Promise","resolve","aesEncrypt","buildUser","name","sign","jwtEncrypt","expireReasons","exports","payload","verifyPayload","error","includes","createAnonymousRemoteUser","errorUtils","getCode","HTTP_STATUS","UNAUTHORIZED","message","isAuthHeaderValid","authorization","length","getDefaultPlugins","logger","authenticate","_user","_password","cb","getForbidden","API_ERROR","BAD_USERNAME_PASSWORD","adduser","getConflict","allow_access","allow_action","allow_publish","allow_unpublish","handleSpecialUnpublish","action","allowActionCallback","user","pkg","callback","trace","remote","groups","groupAccess","hasPermission","some","group","pkgName","getUnauthorized","isUnpublishMissing","hasGroups","undefined","password","String","Buffer","from"],"sources":["../src/utils.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport _ from 'lodash';\n\nimport { createAnonymousRemoteUser } from '@verdaccio/config';\nimport {\n API_ERROR,\n HTTP_STATUS,\n TOKEN_BASIC,\n TOKEN_BEARER,\n VerdaccioError,\n errorUtils,\n pluginUtils,\n} from '@verdaccio/core';\nimport { aesDecrypt, parseBasicPayload, verifyPayload } from '@verdaccio/signature';\nimport { AuthPackageAllow, Config, Logger, RemoteUser, Security } from '@verdaccio/types';\n\nimport { AESPayload, TokenEncryption } from './auth';\n\nconst debug = buildDebug('verdaccio:auth:utils');\n\nexport type BasicPayload = AESPayload | void;\nexport type AuthMiddlewarePayload = RemoteUser | BasicPayload;\n\nexport interface AuthTokenHeader {\n scheme: string;\n token: string;\n}\nexport type AllowActionCallbackResponse = boolean | undefined;\nexport type AllowActionCallback = (\n error: VerdaccioError | null,\n allowed?: AllowActionCallbackResponse\n) => void;\n\nexport type AllowAction = (\n user: RemoteUser,\n pkg: AuthPackageAllow,\n callback: AllowActionCallback\n) => void;\n\n/**\n * Split authentication header eg: Bearer [secret_token]\n * @param authorizationHeader auth token\n */\nexport function parseAuthTokenHeader(authorizationHeader: string): AuthTokenHeader {\n const parts = authorizationHeader.split(' ');\n const [scheme, token] = parts;\n\n return { scheme, token };\n}\n\nexport function parseAESCredentials(authorizationHeader: string, secret: string) {\n debug('parseAESCredentials');\n const { scheme, token } = parseAuthTokenHeader(authorizationHeader);\n\n // basic is deprecated and should not be enforced\n // basic is currently being used for functional test\n if (scheme.toUpperCase() === TOKEN_BASIC.toUpperCase()) {\n debug('legacy header basic');\n const credentials = convertPayloadToBase64(token).toString();\n\n return credentials;\n } else if (scheme.toUpperCase() === TOKEN_BEARER.toUpperCase()) {\n debug('legacy header bearer');\n const credentials = aesDecrypt(token, secret);\n\n return credentials;\n }\n}\n\nexport function getMiddlewareCredentials(\n security: Security,\n secretKey: string,\n authorizationHeader: string\n): AuthMiddlewarePayload {\n debug('getMiddlewareCredentials');\n // comment out for debugging purposes\n if (isAESLegacy(security)) {\n debug('is legacy');\n const credentials = parseAESCredentials(authorizationHeader, secretKey);\n if (!credentials) {\n debug('parse legacy credentials failed');\n return;\n }\n\n const parsedCredentials = parseBasicPayload(credentials);\n if (!parsedCredentials) {\n debug('parse legacy basic payload credentials failed');\n return;\n }\n\n return parsedCredentials;\n }\n const { scheme, token } = parseAuthTokenHeader(authorizationHeader);\n\n debug('is jwt');\n if (_.isString(token) && scheme.toUpperCase() === TOKEN_BEARER.toUpperCase()) {\n return verifyJWTPayload(token, secretKey);\n }\n}\n\nexport function isAESLegacy(security: Security): boolean {\n const { legacy, jwt } = security.api;\n\n return _.isNil(legacy) === false && _.isNil(jwt) && legacy === true;\n}\n\nexport async function getApiToken(\n auth: TokenEncryption,\n config: Config,\n remoteUser: RemoteUser,\n aesPassword: string\n): Promise<string | void> {\n debug('get api token');\n const { security } = config;\n\n if (isAESLegacy(security)) {\n debug('security legacy enabled');\n // fallback all goes to AES encryption\n return await new Promise((resolve): void => {\n resolve(auth.aesEncrypt(buildUser(remoteUser.name as string, aesPassword)));\n });\n }\n const { jwt } = security.api;\n\n if (jwt?.sign) {\n return await auth.jwtEncrypt(remoteUser, jwt.sign);\n }\n return await new Promise((resolve): void => {\n resolve(auth.aesEncrypt(buildUser(remoteUser.name as string, aesPassword)));\n });\n}\n\nexport const expireReasons: string[] = ['JsonWebTokenError', 'TokenExpiredError'];\n\nexport function verifyJWTPayload(token: string, secret: string): RemoteUser {\n try {\n const payload: RemoteUser = verifyPayload(token, secret);\n\n return payload;\n } catch (error: any) {\n // #168 this check should be removed as soon AES encrypt is removed.\n if (expireReasons.includes(error.name)) {\n // it might be possible the jwt configuration is enabled and\n // old tokens fails still remains in usage, thus\n // we return an anonymous user to force log in.\n return createAnonymousRemoteUser();\n }\n throw errorUtils.getCode(HTTP_STATUS.UNAUTHORIZED, error.message);\n }\n}\n\nexport function isAuthHeaderValid(authorization: string): boolean {\n return authorization.split(' ').length === 2;\n}\n\n/**\n * Return a default configuration for authentication if none is provided.\n * @param logger {Logger}\n * @returns object of default implementations.\n */\nexport function getDefaultPlugins(logger: Logger): pluginUtils.Auth<Config> {\n return {\n authenticate(_user: string, _password: string, cb: pluginUtils.AuthCallback): void {\n cb(errorUtils.getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));\n },\n\n adduser(_user: string, _password: string, cb: pluginUtils.AuthUserCallback): void {\n return cb(errorUtils.getConflict(API_ERROR.BAD_USERNAME_PASSWORD));\n },\n\n // FIXME: allow_action and allow_publish should be in the @verdaccio/types\n // @ts-ignore\n allow_access: allow_action('access', logger),\n // @ts-ignore\n allow_publish: allow_action('publish', logger),\n allow_unpublish: handleSpecialUnpublish(logger),\n };\n}\n\nexport type ActionsAllowed = 'publish' | 'unpublish' | 'access';\n\nexport function allow_action(action: ActionsAllowed, logger: Logger): AllowAction {\n return function allowActionCallback(\n user: RemoteUser,\n pkg: AuthPackageAllow,\n callback: AllowActionCallback\n ): void {\n logger.trace({ remote: user.name }, `[auth/allow_action]: user: @{remote}`);\n const { name, groups } = user;\n const groupAccess = pkg[action] as string[];\n const hasPermission = groupAccess.some((group) => name === group || groups.includes(group));\n logger.trace(\n { pkgName: pkg.name, hasPermission, remote: user.name, groupAccess },\n `[auth/allow_action]: hasPermission? @{hasPermission} for user: @{remote}, package: @{pkgName}`\n );\n\n if (hasPermission) {\n logger.trace({ remote: user.name }, `auth/allow_action: access granted to: @{remote}`);\n return callback(null, true);\n }\n\n if (name) {\n callback(\n errorUtils.getForbidden(`user ${name} is not allowed to ${action} package ${pkg.name}`)\n );\n } else {\n callback(\n errorUtils.getUnauthorized(`authorization required to ${action} package ${pkg.name}`)\n );\n }\n };\n}\n\n/**\n *\n */\nexport function handleSpecialUnpublish(logger: Logger): any {\n return function (user: RemoteUser, pkg: AuthPackageAllow, callback: AllowActionCallback): void {\n const action = 'unpublish';\n // verify whether the unpublish prop has been defined\n const isUnpublishMissing: boolean = _.isNil(pkg[action]);\n const hasGroups: boolean = isUnpublishMissing ? false : (pkg[action] as string[]).length > 0;\n logger.trace(\n { user: user.name, name: pkg.name, hasGroups },\n `fallback unpublish for @{name} has groups: @{hasGroups} for @{user}`\n );\n\n if (isUnpublishMissing || hasGroups === false) {\n return callback(null, undefined);\n }\n\n logger.trace(\n { user: user.name, name: pkg.name, action, hasGroups },\n `allow_action for @{action} for @{name} has groups: @{hasGroups} for @{user}`\n );\n return allow_action(action, logger)(user, pkg, callback);\n };\n}\n\nexport function buildUser(name: string, password: string): string {\n return String(`${name}:${password}`);\n}\n\nexport function convertPayloadToBase64(payload: string): Buffer {\n return Buffer.from(payload, 'base64');\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.js","names":["_debug","_interopRequireDefault","require","_lodash","_config","_core","_signature","obj","__esModule","default","debug","buildDebug","parseAuthTokenHeader","authorizationHeader","parts","split","scheme","token","parseAESCredentials","secret","enhanced","toUpperCase","TOKEN_BASIC","credentials","convertPayloadToBase64","toString","TOKEN_BEARER","aesDecrypt","aesDecryptDeprecated","getMiddlewareCredentials","security","secretKey","isAESLegacy","parsedCredentials","parseBasicPayload","_","isString","verifyJWTPayload","legacy","jwt","api","isNil","getApiToken","auth","config","remoteUser","aesPassword","Promise","resolve","aesEncrypt","buildUser","name","sign","jwtEncrypt","expireReasons","exports","payload","verifyPayload","error","includes","createAnonymousRemoteUser","errorUtils","getCode","HTTP_STATUS","UNAUTHORIZED","message","isAuthHeaderValid","authorization","length","getDefaultPlugins","logger","authenticate","_user","_password","cb","getForbidden","API_ERROR","BAD_USERNAME_PASSWORD","adduser","getConflict","allow_access","allow_action","allow_publish","allow_unpublish","handleSpecialUnpublish","action","allowActionCallback","user","pkg","callback","trace","remote","groups","groupAccess","hasPermission","some","group","pkgName","getUnauthorized","isUnpublishMissing","hasGroups","undefined","password","String","Buffer","from"],"sources":["../src/utils.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport _ from 'lodash';\n\nimport { createAnonymousRemoteUser } from '@verdaccio/config';\nimport {\n API_ERROR,\n HTTP_STATUS,\n TOKEN_BASIC,\n TOKEN_BEARER,\n errorUtils,\n pluginUtils,\n} from '@verdaccio/core';\nimport {\n aesDecrypt,\n aesDecryptDeprecated,\n parseBasicPayload,\n verifyPayload,\n} from '@verdaccio/signature';\nimport { AuthPackageAllow, Config, Logger, RemoteUser, Security } from '@verdaccio/types';\n\nimport {\n ActionsAllowed,\n AllowAction,\n AllowActionCallback,\n AuthMiddlewarePayload,\n AuthTokenHeader,\n TokenEncryption,\n} from './types';\n\nconst debug = buildDebug('verdaccio:auth:utils');\n\n/**\n * Split authentication header eg: Bearer [secret_token]\n * @param authorizationHeader auth token\n */\nexport function parseAuthTokenHeader(authorizationHeader: string): AuthTokenHeader {\n const parts = authorizationHeader.split(' ');\n const [scheme, token] = parts;\n\n return { scheme, token };\n}\n\nexport function parseAESCredentials(\n authorizationHeader: string,\n secret: string,\n enhanced: boolean\n) {\n debug('parseAESCredentials');\n const { scheme, token } = parseAuthTokenHeader(authorizationHeader);\n\n // basic is deprecated and should not be enforced\n // basic is currently being used for functional test\n if (scheme.toUpperCase() === TOKEN_BASIC.toUpperCase()) {\n debug('legacy header basic');\n const credentials = convertPayloadToBase64(token).toString();\n\n return credentials;\n } else if (scheme.toUpperCase() === TOKEN_BEARER.toUpperCase()) {\n debug('legacy header bearer');\n debug('legacy header enhanced?', enhanced);\n const credentials = enhanced\n ? aesDecrypt(token.toString(), secret)\n : // FUTURE: once deprecated legacy is removed this logic won't be longer need it\n aesDecryptDeprecated(convertPayloadToBase64(token), secret).toString('utf-8');\n\n return credentials;\n }\n}\n\nexport function getMiddlewareCredentials(\n security: Security,\n secretKey: string,\n authorizationHeader: string,\n enhanced: boolean = true\n): AuthMiddlewarePayload {\n debug('getMiddlewareCredentials');\n // comment out for debugging purposes\n if (isAESLegacy(security)) {\n debug('is legacy');\n const credentials = parseAESCredentials(authorizationHeader, secretKey, enhanced);\n if (!credentials) {\n debug('parse legacy credentials failed');\n return;\n }\n\n const parsedCredentials = parseBasicPayload(credentials);\n if (!parsedCredentials) {\n debug('parse legacy basic payload credentials failed');\n return;\n }\n\n return parsedCredentials;\n }\n const { scheme, token } = parseAuthTokenHeader(authorizationHeader);\n\n debug('is jwt');\n if (_.isString(token) && scheme.toUpperCase() === TOKEN_BEARER.toUpperCase()) {\n return verifyJWTPayload(token, secretKey);\n }\n}\n\nexport function isAESLegacy(security: Security): boolean {\n const { legacy, jwt } = security.api;\n\n return _.isNil(legacy) === false && _.isNil(jwt) && legacy === true;\n}\n\nexport async function getApiToken(\n auth: TokenEncryption,\n config: Config,\n remoteUser: RemoteUser,\n aesPassword: string\n): Promise<string | void> {\n debug('get api token');\n const { security } = config;\n\n if (isAESLegacy(security)) {\n debug('security legacy enabled');\n // fallback all goes to AES encryption\n return await new Promise((resolve): void => {\n resolve(auth.aesEncrypt(buildUser(remoteUser.name as string, aesPassword)));\n });\n }\n const { jwt } = security.api;\n\n if (jwt?.sign) {\n return await auth.jwtEncrypt(remoteUser, jwt.sign);\n }\n return await new Promise((resolve): void => {\n resolve(auth.aesEncrypt(buildUser(remoteUser.name as string, aesPassword)));\n });\n}\n\nexport const expireReasons: string[] = ['JsonWebTokenError', 'TokenExpiredError'];\n\nexport function verifyJWTPayload(token: string, secret: string): RemoteUser {\n try {\n const payload: RemoteUser = verifyPayload(token, secret);\n\n return payload;\n } catch (error: any) {\n // #168 this check should be removed as soon AES encrypt is removed.\n if (expireReasons.includes(error.name)) {\n // it might be possible the jwt configuration is enabled and\n // old tokens fails still remains in usage, thus\n // we return an anonymous user to force log in.\n return createAnonymousRemoteUser();\n }\n throw errorUtils.getCode(HTTP_STATUS.UNAUTHORIZED, error.message);\n }\n}\n\nexport function isAuthHeaderValid(authorization: string): boolean {\n return authorization.split(' ').length === 2;\n}\n\n/**\n * Return a default configuration for authentication if none is provided.\n * @param logger {Logger}\n * @returns object of default implementations.\n */\nexport function getDefaultPlugins(logger: Logger): pluginUtils.Auth<Config> {\n return {\n authenticate(_user: string, _password: string, cb: pluginUtils.AuthCallback): void {\n debug('triggered default authenticate method');\n cb(errorUtils.getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));\n },\n\n adduser(_user: string, _password: string, cb: pluginUtils.AuthUserCallback): void {\n debug('triggered default adduser method');\n return cb(errorUtils.getConflict(API_ERROR.BAD_USERNAME_PASSWORD));\n },\n\n // @ts-ignore\n allow_access: allow_action('access', logger),\n // @ts-ignore\n allow_publish: allow_action('publish', logger),\n allow_unpublish: handleSpecialUnpublish(logger),\n };\n}\n\nexport function allow_action(action: ActionsAllowed, logger: Logger): AllowAction {\n return function allowActionCallback(\n user: RemoteUser,\n pkg: AuthPackageAllow,\n callback: AllowActionCallback\n ): void {\n logger.trace({ remote: user.name }, `[auth/allow_action]: user: @{remote}`);\n const { name, groups } = user;\n debug('allow_action \"%s\": groups %s', action, groups);\n const groupAccess = pkg[action] as string[];\n debug('allow_action \"%s\": groupAccess %s', action, groupAccess);\n const hasPermission = groupAccess.some((group) => {\n return name === group || groups.includes(group);\n });\n debug('package \"%s\" has permission \"%s\"', name, hasPermission);\n logger.trace(\n { pkgName: pkg.name, hasPermission, remote: user.name, groupAccess },\n `[auth/allow_action]: hasPermission? @{hasPermission} for user: @{remote}, package: @{pkgName}`\n );\n\n if (hasPermission) {\n logger.trace({ remote: user.name }, `auth/allow_action: access granted to: @{remote}`);\n return callback(null, true);\n }\n\n if (name) {\n callback(\n errorUtils.getForbidden(`user ${name} is not allowed to ${action} package ${pkg.name}`)\n );\n } else {\n callback(\n errorUtils.getUnauthorized(`authorization required to ${action} package ${pkg.name}`)\n );\n }\n };\n}\n\n/**\n *\n */\nexport function handleSpecialUnpublish(logger: Logger): any {\n return function (user: RemoteUser, pkg: AuthPackageAllow, callback: AllowActionCallback): void {\n const action = 'unpublish';\n // verify whether the unpublish prop has been defined\n const isUnpublishMissing: boolean = !pkg[action];\n debug('is unpublish method missing ? %s', isUnpublishMissing);\n const hasGroups: boolean = isUnpublishMissing ? false : (pkg[action] as string[]).length > 0;\n logger.trace(\n { user: user.name, name: pkg.name, hasGroups },\n `fallback unpublish for @{name} has groups: @{hasGroups} for @{user}`\n );\n\n if (isUnpublishMissing || hasGroups === false) {\n return callback(null, undefined);\n }\n\n logger.trace(\n { user: user.name, name: pkg.name, action, hasGroups },\n `allow_action for @{action} for @{name} has groups: @{hasGroups} for @{user}`\n );\n return allow_action(action, logger)(user, pkg, callback);\n };\n}\n\nexport function buildUser(name: string, password: string): string {\n return String(`${name}:${password}`);\n}\n\nexport function convertPayloadToBase64(payload: string): Buffer {\n return Buffer.from(payload, 'base64');\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@verdaccio/auth",
|
|
3
|
-
"version": "7.0.0-next.
|
|
3
|
+
"version": "7.0.0-next.5",
|
|
4
4
|
"description": "logger",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "./build/index.d.ts",
|
|
@@ -29,19 +29,21 @@
|
|
|
29
29
|
},
|
|
30
30
|
"license": "MIT",
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@verdaccio/core": "7.0.0-next.
|
|
33
|
-
"@verdaccio/config": "7.0.0-next.
|
|
34
|
-
"@verdaccio/loaders": "7.0.0-next.
|
|
35
|
-
"@verdaccio/logger": "7.0.0-next.
|
|
36
|
-
"@verdaccio/signature": "7.0.0-next.
|
|
37
|
-
"@verdaccio/utils": "7.0.0-next.
|
|
32
|
+
"@verdaccio/core": "7.0.0-next.5",
|
|
33
|
+
"@verdaccio/config": "7.0.0-next.5",
|
|
34
|
+
"@verdaccio/loaders": "7.0.0-next.5",
|
|
35
|
+
"@verdaccio/logger": "7.0.0-next.5",
|
|
36
|
+
"@verdaccio/signature": "7.0.0-next.3",
|
|
37
|
+
"@verdaccio/utils": "7.0.0-next.5",
|
|
38
38
|
"debug": "4.3.4",
|
|
39
|
-
"express": "4.18.2",
|
|
40
39
|
"lodash": "4.17.21",
|
|
41
|
-
"verdaccio-htpasswd": "12.0.0-next.
|
|
40
|
+
"verdaccio-htpasswd": "12.0.0-next.5"
|
|
42
41
|
},
|
|
43
42
|
"devDependencies": {
|
|
44
|
-
"
|
|
43
|
+
"express": "4.18.2",
|
|
44
|
+
"supertest": "6.3.3",
|
|
45
|
+
"@verdaccio/middleware": "7.0.0-next.5",
|
|
46
|
+
"@verdaccio/types": "12.0.0-next.2"
|
|
45
47
|
},
|
|
46
48
|
"funding": {
|
|
47
49
|
"type": "opencollective",
|
package/src/auth.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import buildDebug from 'debug';
|
|
2
|
-
import { NextFunction, Request, RequestHandler, Response } from 'express';
|
|
3
2
|
import _ from 'lodash';
|
|
4
3
|
import { HTPasswd } from 'verdaccio-htpasswd';
|
|
5
4
|
|
|
@@ -12,22 +11,36 @@ import {
|
|
|
12
11
|
VerdaccioError,
|
|
13
12
|
errorUtils,
|
|
14
13
|
pluginUtils,
|
|
14
|
+
warningUtils,
|
|
15
15
|
} from '@verdaccio/core';
|
|
16
|
+
import '@verdaccio/core';
|
|
16
17
|
import { asyncLoadPlugin } from '@verdaccio/loaders';
|
|
17
18
|
import { logger } from '@verdaccio/logger';
|
|
18
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
aesEncrypt,
|
|
21
|
+
aesEncryptDeprecated,
|
|
22
|
+
parseBasicPayload,
|
|
23
|
+
signPayload,
|
|
24
|
+
} from '@verdaccio/signature';
|
|
19
25
|
import {
|
|
20
26
|
AllowAccess,
|
|
21
27
|
Callback,
|
|
22
28
|
Config,
|
|
23
29
|
JWTSignOptions,
|
|
24
|
-
Logger,
|
|
25
30
|
PackageAccess,
|
|
26
31
|
RemoteUser,
|
|
27
32
|
Security,
|
|
28
33
|
} from '@verdaccio/types';
|
|
29
34
|
import { getMatchedPackagesSpec, isFunction, isNil } from '@verdaccio/utils';
|
|
30
35
|
|
|
36
|
+
import {
|
|
37
|
+
$RequestExtend,
|
|
38
|
+
$ResponseExtend,
|
|
39
|
+
AESPayload,
|
|
40
|
+
IAuthMiddleware,
|
|
41
|
+
NextFunction,
|
|
42
|
+
TokenEncryption,
|
|
43
|
+
} from './types';
|
|
31
44
|
import {
|
|
32
45
|
convertPayloadToBase64,
|
|
33
46
|
getDefaultPlugins,
|
|
@@ -40,25 +53,6 @@ import {
|
|
|
40
53
|
|
|
41
54
|
const debug = buildDebug('verdaccio:auth');
|
|
42
55
|
|
|
43
|
-
export interface TokenEncryption {
|
|
44
|
-
jwtEncrypt(user: RemoteUser, signOptions: JWTSignOptions): Promise<string>;
|
|
45
|
-
aesEncrypt(buf: string): string | void;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// remove
|
|
49
|
-
export interface AESPayload {
|
|
50
|
-
user: string;
|
|
51
|
-
password: string;
|
|
52
|
-
}
|
|
53
|
-
export interface IAuthMiddleware {
|
|
54
|
-
apiJWTmiddleware(): $NextFunctionVer;
|
|
55
|
-
webUIJWTmiddleware(): $NextFunctionVer;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export type $RequestExtend = Request & { remote_user?: any; log: Logger };
|
|
59
|
-
export type $ResponseExtend = Response & { cookies?: any };
|
|
60
|
-
export type $NextFunctionVer = NextFunction & any;
|
|
61
|
-
|
|
62
56
|
class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
|
|
63
57
|
public config: Config;
|
|
64
58
|
public secret: string;
|
|
@@ -75,6 +69,7 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
|
|
|
75
69
|
|
|
76
70
|
public async init() {
|
|
77
71
|
let plugins = (await this.loadPlugin()) as pluginUtils.Auth<unknown>[];
|
|
72
|
+
|
|
78
73
|
debug('auth plugins found %s', plugins.length);
|
|
79
74
|
if (!plugins || plugins.length === 0) {
|
|
80
75
|
plugins = this.loadDefaultPlugin();
|
|
@@ -226,29 +221,32 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
|
|
|
226
221
|
debug('add user %o', user);
|
|
227
222
|
|
|
228
223
|
(function next(): void {
|
|
224
|
+
let method = 'adduser';
|
|
229
225
|
const plugin = plugins.shift() as pluginUtils.Auth<Config>;
|
|
230
|
-
|
|
226
|
+
// @ts-expect-error future major (7.x) should remove this section
|
|
227
|
+
if (typeof plugin.adduser === 'undefined' && typeof plugin.add_user === 'function') {
|
|
228
|
+
method = 'add_user';
|
|
229
|
+
warningUtils.emit(warningUtils.Codes.VERWAR006);
|
|
230
|
+
}
|
|
231
|
+
// @ts-ignore
|
|
232
|
+
if (typeof plugin[method] !== 'function') {
|
|
231
233
|
next();
|
|
232
234
|
} else {
|
|
233
|
-
//
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
'add_user method not longer supported, rename to adduser'
|
|
237
|
-
);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
plugin.adduser(
|
|
235
|
+
// TODO: replace by adduser whenever add_user deprecation method has been removed
|
|
236
|
+
// @ts-ignore
|
|
237
|
+
plugin[method](
|
|
241
238
|
user,
|
|
242
239
|
password,
|
|
243
240
|
function (err: VerdaccioError | null, ok?: boolean | string): void {
|
|
244
241
|
if (err) {
|
|
245
|
-
debug('the user
|
|
242
|
+
debug('the user %o could not being added. Error: %o', user, err?.message);
|
|
246
243
|
return cb(err);
|
|
247
244
|
}
|
|
248
245
|
if (ok) {
|
|
249
246
|
debug('the user %o has been added', user);
|
|
250
247
|
return self.authenticate(user, password, cb);
|
|
251
248
|
}
|
|
249
|
+
debug('user could not be added, skip to next auth plugin');
|
|
252
250
|
next();
|
|
253
251
|
}
|
|
254
252
|
);
|
|
@@ -308,12 +306,11 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
|
|
|
308
306
|
debug('allow unpublish for %o', packageName);
|
|
309
307
|
|
|
310
308
|
for (const plugin of this.plugins) {
|
|
311
|
-
if (
|
|
309
|
+
if (typeof plugin?.allow_unpublish !== 'function') {
|
|
312
310
|
debug('allow unpublish for %o plugin does not implement allow_unpublish', packageName);
|
|
313
311
|
continue;
|
|
314
312
|
} else {
|
|
315
|
-
|
|
316
|
-
plugin.allow_unpublish!(user, pkg, (err, ok: boolean): void => {
|
|
313
|
+
plugin.allow_unpublish(user, pkg, (err, ok): void => {
|
|
317
314
|
if (err) {
|
|
318
315
|
debug(
|
|
319
316
|
'forbidden publish for %o, it will fallback on unpublish permissions',
|
|
@@ -324,9 +321,7 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
|
|
|
324
321
|
|
|
325
322
|
if (_.isNil(ok) === true) {
|
|
326
323
|
debug('bypass unpublish for %o, publish will handle the access', packageName);
|
|
327
|
-
|
|
328
|
-
// eslint-disable-next-line
|
|
329
|
-
return this.allow_publish(...arguments);
|
|
324
|
+
return this.allow_publish({ packageName, packageVersion }, user, callback);
|
|
330
325
|
}
|
|
331
326
|
|
|
332
327
|
if (ok) {
|
|
@@ -350,7 +345,7 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
|
|
|
350
345
|
const pkg = Object.assign(
|
|
351
346
|
{ name: packageName, version: packageVersion },
|
|
352
347
|
getMatchedPackagesSpec(packageName, this.config.packages)
|
|
353
|
-
)
|
|
348
|
+
);
|
|
354
349
|
debug('allow publish for %o init | plugins: %o', packageName, plugins.length);
|
|
355
350
|
|
|
356
351
|
(function next(): void {
|
|
@@ -378,7 +373,7 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
|
|
|
378
373
|
})();
|
|
379
374
|
}
|
|
380
375
|
|
|
381
|
-
public apiJWTmiddleware():
|
|
376
|
+
public apiJWTmiddleware(): any {
|
|
382
377
|
debug('jwt middleware');
|
|
383
378
|
const plugins = this.plugins.slice(0);
|
|
384
379
|
const helpers = { createAnonymousRemoteUser, createRemoteUser };
|
|
@@ -388,11 +383,9 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
|
|
|
388
383
|
}
|
|
389
384
|
}
|
|
390
385
|
|
|
391
|
-
// @ts-ignore
|
|
392
386
|
return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction) => {
|
|
393
387
|
req.pause();
|
|
394
|
-
|
|
395
|
-
const next = function (err?: VerdaccioError): any {
|
|
388
|
+
const next = function (err?: VerdaccioError): NextFunction {
|
|
396
389
|
req.resume();
|
|
397
390
|
// uncomment this to reject users with bad auth headers
|
|
398
391
|
// return _next.apply(null, arguments)
|
|
@@ -402,13 +395,14 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
|
|
|
402
395
|
req.remote_user.error = err.message;
|
|
403
396
|
}
|
|
404
397
|
|
|
405
|
-
return _next();
|
|
398
|
+
return _next() as unknown as NextFunction;
|
|
406
399
|
};
|
|
407
400
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
401
|
+
// FUTURE: disabled, not removed yet but seems unreacable code
|
|
402
|
+
// if (this._isRemoteUserValid(req.remote_user)) {
|
|
403
|
+
// debug('jwt has a valid authentication header');
|
|
404
|
+
// return next();
|
|
405
|
+
// }
|
|
412
406
|
|
|
413
407
|
// in case auth header does not exist we return anonymous function
|
|
414
408
|
const remoteUser = createAnonymousRemoteUser();
|
|
@@ -429,20 +423,20 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
|
|
|
429
423
|
|
|
430
424
|
if (isAESLegacy(security)) {
|
|
431
425
|
debug('api middleware using legacy auth token');
|
|
432
|
-
this.
|
|
426
|
+
this.handleAESMiddleware(req, security, secret, authorization, next);
|
|
433
427
|
} else {
|
|
434
428
|
debug('api middleware using JWT auth token');
|
|
435
|
-
this.
|
|
429
|
+
this.handleJWTAPIMiddleware(req, security, secret, authorization, next);
|
|
436
430
|
}
|
|
437
431
|
};
|
|
438
432
|
}
|
|
439
433
|
|
|
440
|
-
private
|
|
434
|
+
private handleJWTAPIMiddleware(
|
|
441
435
|
req: $RequestExtend,
|
|
442
436
|
security: Security,
|
|
443
437
|
secret: string,
|
|
444
438
|
authorization: string,
|
|
445
|
-
next:
|
|
439
|
+
next: any
|
|
446
440
|
): void {
|
|
447
441
|
debug('handle JWT api middleware');
|
|
448
442
|
const { scheme, token } = parseAuthTokenHeader(authorization);
|
|
@@ -479,7 +473,7 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
|
|
|
479
473
|
}
|
|
480
474
|
}
|
|
481
475
|
|
|
482
|
-
private
|
|
476
|
+
private handleAESMiddleware(
|
|
483
477
|
req: $RequestExtend,
|
|
484
478
|
security: Security,
|
|
485
479
|
secret: string,
|
|
@@ -489,7 +483,12 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
|
|
|
489
483
|
debug('handle legacy api middleware');
|
|
490
484
|
debug('api middleware secret %o', typeof secret === 'string');
|
|
491
485
|
debug('api middleware authorization %o', typeof authorization === 'string');
|
|
492
|
-
const credentials: any = getMiddlewareCredentials(
|
|
486
|
+
const credentials: any = getMiddlewareCredentials(
|
|
487
|
+
security,
|
|
488
|
+
secret,
|
|
489
|
+
authorization,
|
|
490
|
+
this.config?.getEnhancedLegacySignature()
|
|
491
|
+
);
|
|
493
492
|
debug('api middleware credentials %o', credentials?.name);
|
|
494
493
|
if (credentials) {
|
|
495
494
|
const { user, password } = credentials;
|
|
@@ -519,8 +518,7 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
|
|
|
519
518
|
/**
|
|
520
519
|
* JWT middleware for WebUI
|
|
521
520
|
*/
|
|
522
|
-
public webUIJWTmiddleware()
|
|
523
|
-
// @ts-ignore
|
|
521
|
+
public webUIJWTmiddleware() {
|
|
524
522
|
return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction): void => {
|
|
525
523
|
if (this._isRemoteUserValid(req.remote_user)) {
|
|
526
524
|
return _next();
|
|
@@ -530,7 +528,7 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
|
|
|
530
528
|
const next = (err: VerdaccioError | void): void => {
|
|
531
529
|
req.resume();
|
|
532
530
|
if (err) {
|
|
533
|
-
|
|
531
|
+
req.remote_user.error = err.message;
|
|
534
532
|
res.status(err.statusCode).send(err.message);
|
|
535
533
|
}
|
|
536
534
|
|
|
@@ -581,7 +579,6 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
|
|
|
581
579
|
name,
|
|
582
580
|
groups: groupedGroups,
|
|
583
581
|
};
|
|
584
|
-
|
|
585
582
|
const token: string = await signPayload(payload, this.secret, signOptions);
|
|
586
583
|
|
|
587
584
|
return token;
|
|
@@ -591,7 +588,17 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
|
|
|
591
588
|
* Encrypt a string.
|
|
592
589
|
*/
|
|
593
590
|
public aesEncrypt(value: string): string | void {
|
|
594
|
-
|
|
591
|
+
// enhancedLegacySignature enables modern aes192 algorithm signature
|
|
592
|
+
if (this.config?.getEnhancedLegacySignature()) {
|
|
593
|
+
debug('signing with enhaced aes legacy');
|
|
594
|
+
const token = aesEncrypt(value, this.secret);
|
|
595
|
+
return token;
|
|
596
|
+
} else {
|
|
597
|
+
debug('signing with enhaced aes deprecated legacy');
|
|
598
|
+
// deprecated aes (legacy) signature, only must be used for legacy version
|
|
599
|
+
const token = aesEncryptDeprecated(Buffer.from(value), this.secret).toString('base64');
|
|
600
|
+
return token;
|
|
601
|
+
}
|
|
595
602
|
}
|
|
596
603
|
}
|
|
597
604
|
|
package/src/index.ts
CHANGED