@verdaccio/auth 6.0.0-6-next.26 → 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/build/utils.js CHANGED
@@ -158,14 +158,20 @@ function verifyJWTPayload(token, secret) {
158
158
  function isAuthHeaderValid(authorization) {
159
159
  return authorization.split(' ').length === 2;
160
160
  }
161
+ /**
162
+ * Return a default configuration for authentication if none is provided.
163
+ * @param logger {Logger}
164
+ * @returns object of default implementations.
165
+ */
166
+
161
167
 
162
168
  function getDefaultPlugins(logger) {
163
169
  return {
164
- authenticate(user, password, cb) {
170
+ authenticate(_user, _password, cb) {
165
171
  cb(_core.errorUtils.getForbidden(_core.API_ERROR.BAD_USERNAME_PASSWORD));
166
172
  },
167
173
 
168
- adduser(user, password, cb) {
174
+ adduser(_user, _password, cb) {
169
175
  return cb(_core.errorUtils.getConflict(_core.API_ERROR.BAD_USERNAME_PASSWORD));
170
176
  },
171
177
 
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":["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","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","pkg","callback","trace","remote","groups","groupAccess","hasPermission","some","group","pkgName","getUnauthorized","isUnpublishMissing","hasGroups","undefined","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} from '@verdaccio/core';\nimport {\n AuthPackageAllow,\n Callback,\n Config,\n IPluginAuth,\n RemoteUser,\n Security,\n} from '@verdaccio/types';\n\nimport { AESPayload, TokenEncryption } from './auth';\nimport { verifyPayload } from './jwt-token';\nimport { aesDecrypt } from './legacy-token';\nimport { parseBasicPayload } from './token';\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\nexport function getDefaultPlugins(logger: any): IPluginAuth<Config> {\n return {\n authenticate(user: string, password: string, cb: Callback): void {\n cb(errorUtils.getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));\n },\n\n adduser(user: string, password: string, cb: Callback): 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): 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): 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","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","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 { AuthPackageAllow, Config, Logger, RemoteUser, Security } from '@verdaccio/types';\n\nimport { AESPayload, TokenEncryption } from './auth';\nimport { verifyPayload } from './jwt-token';\nimport { aesDecrypt } from './legacy-token';\nimport { parseBasicPayload } from './token';\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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"}
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@verdaccio/auth",
3
- "version": "6.0.0-6-next.26",
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,19 +30,19 @@
30
30
  },
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
- "@verdaccio/core": "6.0.0-6-next.47",
34
- "@verdaccio/config": "6.0.0-6-next.47",
35
- "@verdaccio/loaders": "6.0.0-6-next.16",
36
- "@verdaccio/logger": "6.0.0-6-next.15",
37
- "@verdaccio/utils": "6.0.0-6-next.15",
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.17"
42
+ "verdaccio-htpasswd": "11.0.0-6-next.19"
43
43
  },
44
44
  "devDependencies": {
45
- "@verdaccio/types": "11.0.0-6-next.16"
45
+ "@verdaccio/types": "11.0.0-6-next.17"
46
46
  },
47
47
  "funding": {
48
48
  "type": "opencollective",
package/src/auth.ts CHANGED
@@ -1,7 +1,7 @@
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
- import { HTPasswd, HTPasswdConfig } from 'verdaccio-htpasswd';
4
+ import { HTPasswd } from 'verdaccio-htpasswd';
5
5
 
6
6
  import { createAnonymousRemoteUser, createRemoteUser } from '@verdaccio/config';
7
7
  import {
@@ -11,18 +11,17 @@ import {
11
11
  TOKEN_BEARER,
12
12
  VerdaccioError,
13
13
  errorUtils,
14
+ pluginUtils,
14
15
  } from '@verdaccio/core';
15
- import { loadPlugin } from '@verdaccio/loaders';
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,84 +51,84 @@ 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 interface IAuth extends IBasicAuth<Config>, IAuthMiddleware, TokenEncryption {
78
- config: Config;
79
- logger: Logger;
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
- }
59
+ export type $RequestExtend = Request & { remote_user?: any; log: Logger };
60
+ export type $ResponseExtend = Response & { cookies?: any };
61
+ export type $NextFunctionVer = NextFunction & any;
86
62
 
87
- class Auth implements IAuth {
63
+ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
88
64
  public config: Config;
89
- public logger: Logger;
90
65
  public secret: string;
91
- public plugins: IPluginAuth<Config>[];
66
+ public plugins: pluginUtils.Auth<Config>[];
92
67
 
93
68
  public constructor(config: Config) {
94
69
  this.config = config;
95
- this.logger = LoggerApi.logger.child({ sub: 'auth' });
96
70
  this.secret = config.secret;
71
+ this.plugins = [];
97
72
  if (!this.secret) {
98
73
  throw new TypeError('secret it is required value on initialize the auth class');
99
74
  }
75
+ }
76
+
77
+ public async init() {
78
+ let plugins = (await this.loadPlugin()) as pluginUtils.Auth<unknown>[];
79
+ debug('auth plugins found %s', plugins.length);
80
+ if (!plugins || plugins.length === 0) {
81
+ plugins = this.loadDefaultPlugin();
82
+ }
83
+ this.plugins = plugins;
100
84
 
101
- this.plugins =
102
- _.isNil(config?.auth) === false ? this._loadPlugin(config) : this.loadDefaultPlugin(config);
103
85
  this._applyDefaultPlugins();
104
86
  }
105
87
 
106
- private loadDefaultPlugin(config: Config) {
107
- const plugingConf: HTPasswdConfig = { ...config, file: './htpasswd' };
108
- const pluginOptions: PluginOptions<{}> = {
109
- config,
110
- logger: this.logger,
88
+ private loadDefaultPlugin() {
89
+ debug('load default auth plugin');
90
+ const pluginOptions: pluginUtils.PluginOptions = {
91
+ config: this.config,
92
+ logger,
111
93
  };
112
94
  let authPlugin;
113
95
  try {
114
- authPlugin = new HTPasswd(plugingConf, pluginOptions as any as PluginOptions<HTPasswdConfig>);
96
+ authPlugin = new HTPasswd(
97
+ { file: './htpasswd' },
98
+ pluginOptions as any as pluginUtils.PluginOptions
99
+ );
115
100
  } catch (error: any) {
116
101
  debug('error on loading auth htpasswd plugin stack: %o', error);
102
+ logger.info({}, 'no auth plugin has been found');
117
103
  return [];
118
104
  }
119
105
 
120
106
  return [authPlugin];
121
107
  }
122
108
 
123
- private _loadPlugin(config: Config): IPluginAuth<Config>[] {
124
- const pluginOptions = {
125
- config,
126
- logger: this.logger,
127
- };
128
-
129
- return loadPlugin<IPluginAuth<Config>>(
130
- config,
131
- config.auth,
132
- pluginOptions,
133
- (plugin: IPluginAuth<Config>): boolean => {
109
+ private async loadPlugin() {
110
+ return asyncLoadPlugin<pluginUtils.Auth<unknown>>(
111
+ this.config.auth,
112
+ {
113
+ config: this.config,
114
+ logger,
115
+ },
116
+ (plugin): boolean => {
134
117
  const { authenticate, allow_access, allow_publish } = plugin;
135
118
 
136
- // @ts-ignore
137
- return authenticate || allow_access || allow_publish;
138
- }
119
+ return (
120
+ typeof authenticate !== 'undefined' ||
121
+ typeof allow_access !== 'undefined' ||
122
+ typeof allow_publish !== 'undefined'
123
+ );
124
+ },
125
+ this.config?.serverSettings?.pluginPrefix
139
126
  );
140
127
  }
141
128
 
142
129
  private _applyDefaultPlugins(): void {
143
130
  // TODO: rename to applyFallbackPluginMethods
144
- this.plugins.push(getDefaultPlugins(this.logger));
131
+ this.plugins.push(getDefaultPlugins(logger));
145
132
  }
146
133
 
147
134
  public changePassword(
@@ -164,7 +151,7 @@ class Auth implements IAuth {
164
151
  debug('updating password for %o', username);
165
152
  plugin.changePassword!(username, password, newPassword, (err, profile): void => {
166
153
  if (err) {
167
- this.logger.error(
154
+ logger.error(
168
155
  { username, err },
169
156
  `An error has been produced
170
157
  updating the password for @{username}. Error: @{err.message}`
@@ -185,17 +172,21 @@ class Auth implements IAuth {
185
172
  return Promise.resolve();
186
173
  }
187
174
 
188
- public authenticate(username: string, password: string, cb: Callback): void {
175
+ public authenticate(
176
+ username: string,
177
+ password: string,
178
+ cb: (error: VerdaccioError | null, user?: RemoteUser) => void
179
+ ): void {
189
180
  const plugins = this.plugins.slice(0);
190
181
  (function next(): void {
191
- const plugin = plugins.shift() as IPluginAuth<Config>;
182
+ const plugin = plugins.shift() as pluginUtils.Auth<Config>;
192
183
 
193
184
  if (isFunction(plugin.authenticate) === false) {
194
185
  return next();
195
186
  }
196
187
 
197
188
  debug('authenticating %o', username);
198
- plugin.authenticate(username, password, function (err, groups): void {
189
+ plugin.authenticate(username, password, function (err: VerdaccioError | null, groups): void {
199
190
  if (err) {
200
191
  debug('authenticating for user %o failed. Error: %o', username, err?.message);
201
192
  return cb(err);
@@ -226,37 +217,42 @@ class Auth implements IAuth {
226
217
  })();
227
218
  }
228
219
 
229
- public add_user(user: string, password: string, cb: Callback): void {
220
+ public add_user(
221
+ user: string,
222
+ password: string,
223
+ cb: (error: VerdaccioError | null, user?: RemoteUser) => void
224
+ ): void {
230
225
  const self = this;
231
226
  const plugins = this.plugins.slice(0);
232
227
  debug('add user %o', user);
233
228
 
234
229
  (function next(): void {
235
- const plugin = plugins.shift() as IPluginAuth<Config>;
236
- let method = 'adduser';
237
- if (isFunction(plugin[method]) === false) {
238
- method = 'add_user';
239
- self.logger.warn(
240
- 'the plugin method add_user in the auth plugin is deprecated and will' +
241
- ' be removed in next major release, notify to the plugin author'
242
- );
243
- }
244
-
245
- if (isFunction(plugin[method]) === false) {
230
+ const plugin = plugins.shift() as pluginUtils.Auth<Config>;
231
+ if (typeof plugin.adduser !== 'function') {
246
232
  next();
247
233
  } else {
248
- // p.add_user() execution
249
- plugin[method](user, password, function (err, ok): void {
250
- if (err) {
251
- debug('the user %o could not being added. Error: %o', user, err?.message);
252
- return cb(err);
253
- }
254
- if (ok) {
255
- debug('the user %o has been added', user);
256
- return self.authenticate(user, password, cb);
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();
257
254
  }
258
- next();
259
- });
255
+ );
260
256
  }
261
257
  })();
262
258
  }
@@ -265,27 +261,27 @@ class Auth implements IAuth {
265
261
  * Allow user to access a package.
266
262
  */
267
263
  public allow_access(
268
- { packageName, packageVersion }: AuthPluginPackage,
264
+ { packageName, packageVersion }: pluginUtils.AuthPluginPackage,
269
265
  user: RemoteUser,
270
- callback: Callback
266
+ callback: pluginUtils.AccessCallback
271
267
  ): void {
272
268
  const plugins = this.plugins.slice(0);
273
- const pkgAllowAcces: AllowAccess = { name: packageName, version: packageVersion };
269
+ const pkgAllowAccess: AllowAccess = { name: packageName, version: packageVersion };
274
270
  const pkg = Object.assign(
275
271
  {},
276
- pkgAllowAcces,
272
+ pkgAllowAccess,
277
273
  getMatchedPackagesSpec(packageName, this.config.packages)
278
274
  ) as AllowAccess & PackageAccess;
279
275
  debug('allow access for %o', packageName);
280
276
 
281
277
  (function next(): void {
282
- const plugin: IPluginAuth<Config> = plugins.shift() as IPluginAuth<Config>;
278
+ const plugin: pluginUtils.Auth<unknown> = plugins.shift() as pluginUtils.Auth<unknown>;
283
279
 
284
280
  if (_.isNil(plugin) || isFunction(plugin.allow_access) === false) {
285
281
  return next();
286
282
  }
287
283
 
288
- plugin.allow_access!(user, pkg, function (err, ok: boolean): void {
284
+ plugin.allow_access!(user, pkg, function (err: VerdaccioError | null, ok?: boolean): void {
289
285
  if (err) {
290
286
  debug('forbidden access for %o. Error: %o', packageName, err?.message);
291
287
  return callback(err);
@@ -302,7 +298,7 @@ class Auth implements IAuth {
302
298
  }
303
299
 
304
300
  public allow_unpublish(
305
- { packageName, packageVersion }: AuthPluginPackage,
301
+ { packageName, packageVersion }: pluginUtils.AuthPluginPackage,
306
302
  user: RemoteUser,
307
303
  callback: Callback
308
304
  ): void {
@@ -347,7 +343,7 @@ class Auth implements IAuth {
347
343
  * Allow user to publish a package.
348
344
  */
349
345
  public allow_publish(
350
- { packageName, packageVersion }: AuthPluginPackage,
346
+ { packageName, packageVersion }: pluginUtils.AuthPluginPackage,
351
347
  user: RemoteUser,
352
348
  callback: Callback
353
349
  ): void {
@@ -355,42 +351,35 @@ class Auth implements IAuth {
355
351
  const pkg = Object.assign(
356
352
  { name: packageName, version: packageVersion },
357
353
  getMatchedPackagesSpec(packageName, this.config.packages)
358
- );
354
+ ) as any;
359
355
  debug('allow publish for %o init | plugins: %o', packageName, plugins.length);
360
356
 
361
357
  (function next(): void {
362
358
  const plugin = plugins.shift();
363
359
 
364
- if (isFunction(plugin?.allow_publish) === false) {
360
+ if (typeof plugin?.allow_publish !== 'function') {
365
361
  debug('allow publish for %o plugin does not implement allow_publish', packageName);
366
362
  return next();
367
363
  }
368
364
 
369
- // @ts-ignore
370
- plugin.allow_publish(
371
- user,
372
- // @ts-ignore
373
- pkg,
374
- // @ts-ignore
375
- (err: VerdaccioError, ok: boolean): void => {
376
- if (_.isNil(err) === false && _.isError(err)) {
377
- debug('forbidden publish for %o', packageName);
378
- return callback(err);
379
- }
380
-
381
- if (ok) {
382
- debug('allowed publish for %o', packageName);
383
- return callback(null, ok);
384
- }
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
+ }
385
370
 
386
- debug('allow publish skip validation for %o', packageName);
387
- next(); // cb(null, false) causes next plugin to roll
371
+ if (ok) {
372
+ debug('allowed publish for %o', packageName);
373
+ return callback(null, ok);
388
374
  }
389
- );
375
+
376
+ debug('allow publish skip validation for %o', packageName);
377
+ next(); // cb(null, false) causes next plugin to roll
378
+ });
390
379
  })();
391
380
  }
392
381
 
393
- public apiJWTmiddleware(): Function {
382
+ public apiJWTmiddleware(): RequestHandler {
394
383
  debug('jwt middleware');
395
384
  const plugins = this.plugins.slice(0);
396
385
  const helpers = { createAnonymousRemoteUser, createRemoteUser };
@@ -400,10 +389,11 @@ class Auth implements IAuth {
400
389
  }
401
390
  }
402
391
 
403
- return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction): void => {
392
+ // @ts-ignore
393
+ return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction) => {
404
394
  req.pause();
405
395
 
406
- const next = function (err: VerdaccioError | void): void {
396
+ const next = function (err?: VerdaccioError): any {
407
397
  req.resume();
408
398
  // uncomment this to reject users with bad auth headers
409
399
  // return _next.apply(null, arguments)
@@ -412,6 +402,7 @@ class Auth implements IAuth {
412
402
  if (err) {
413
403
  req.remote_user.error = err.message;
414
404
  }
405
+
415
406
  return _next();
416
407
  };
417
408
 
@@ -462,7 +453,7 @@ class Auth implements IAuth {
462
453
  const credentials = convertPayloadToBase64(token).toString();
463
454
  const { user, password } = parseBasicPayload(credentials) as AESPayload;
464
455
  debug('authenticating %o', user);
465
- this.authenticate(user, password, (err, user): void => {
456
+ this.authenticate(user, password, (err: VerdaccioError | null, user): void => {
466
457
  if (!err) {
467
458
  debug('generating a remote user');
468
459
  req.remote_user = user;
@@ -522,14 +513,15 @@ class Auth implements IAuth {
522
513
  }
523
514
  }
524
515
 
525
- private _isRemoteUserValid(remote_user: RemoteUser): boolean {
526
- return _.isUndefined(remote_user) === false && _.isUndefined(remote_user.name) === false;
516
+ private _isRemoteUserValid(remote_user?: RemoteUser): boolean {
517
+ return _.isUndefined(remote_user) === false && _.isUndefined(remote_user?.name) === false;
527
518
  }
528
519
 
529
520
  /**
530
521
  * JWT middleware for WebUI
531
522
  */
532
- public webUIJWTmiddleware(): Function {
523
+ public webUIJWTmiddleware(): RequestHandler {
524
+ // @ts-ignore
533
525
  return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction): void => {
534
526
  if (this._isRemoteUserValid(req.remote_user)) {
535
527
  return _next();
@@ -560,7 +552,7 @@ class Auth implements IAuth {
560
552
  return next();
561
553
  }
562
554
 
563
- let credentials;
555
+ let credentials: RemoteUser | undefined;
564
556
  try {
565
557
  credentials = verifyJWTPayload(token, this.config.secret);
566
558
  } catch (err: any) {
@@ -568,9 +560,8 @@ class Auth implements IAuth {
568
560
  }
569
561
 
570
562
  if (this._isRemoteUserValid(credentials)) {
571
- const { name, groups } = credentials;
572
- // $FlowFixMe
573
- req.remote_user = createRemoteUser(name, groups);
563
+ const { name, groups } = credentials as RemoteUser;
564
+ req.remote_user = createRemoteUser(name as string, groups);
574
565
  } else {
575
566
  req.remote_user = createAnonymousRemoteUser();
576
567
  }
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { Auth, IAuth, TokenEncryption, IBasicAuth } from './auth';
1
+ export { Auth, TokenEncryption } from './auth';
2
2
  export * from './utils';
3
3
  export * from './legacy-token';
4
4
  export * from './jwt-token';
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
- export function getDefaultPlugins(logger: any): IPluginAuth<Config> {
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(user: string, password: string, cb: Callback): void {
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(user: string, password: string, cb: Callback): void {
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