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

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.
@@ -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.27",
3
+ "version": "6.0.0-6-next.29",
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.48",
34
- "@verdaccio/config": "6.0.0-6-next.48",
35
- "@verdaccio/loaders": "6.0.0-6-next.17",
36
- "@verdaccio/logger": "6.0.0-6-next.16",
37
- "@verdaccio/utils": "6.0.0-6-next.16",
33
+ "@verdaccio/core": "6.0.0-6-next.50",
34
+ "@verdaccio/config": "6.0.0-6-next.50",
35
+ "@verdaccio/loaders": "6.0.0-6-next.19",
36
+ "@verdaccio/logger": "6.0.0-6-next.18",
37
+ "@verdaccio/utils": "6.0.0-6-next.18",
38
38
  "debug": "4.3.4",
39
- "express": "4.18.1",
39
+ "express": "4.18.2",
40
40
  "jsonwebtoken": "8.5.1",
41
41
  "lodash": "4.17.21",
42
- "verdaccio-htpasswd": "11.0.0-6-next.18"
42
+ "verdaccio-htpasswd": "11.0.0-6-next.20"
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 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
- 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 IAuth {
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: IPluginAuth<Config>[];
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: this.logger,
92
+ logger,
120
93
  };
121
94
  let authPlugin;
122
95
  try {
123
- authPlugin = new HTPasswd({ file: './htpasswd' }, pluginOptions as any as PluginOptions);
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(): Promise<IPluginAuth<Config>[]> {
133
- return asyncLoadPlugin<IPluginAuth<Config>>(
109
+ private async loadPlugin() {
110
+ return asyncLoadPlugin<pluginUtils.Auth<unknown>>(
134
111
  this.config.auth,
135
112
  {
136
113
  config: this.config,
137
- logger: this.logger,
114
+ logger,
138
115
  },
139
- (plugin: IPluginAuth<Config>): boolean => {
116
+ (plugin): boolean => {
140
117
  const { authenticate, allow_access, allow_publish } = plugin;
141
118
 
142
- // @ts-ignore
143
- return authenticate || allow_access || allow_publish;
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(this.logger));
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
- this.logger.error(
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(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 {
196
180
  const plugins = this.plugins.slice(0);
197
181
  (function next(): void {
198
- const plugin = plugins.shift() as IPluginAuth<Config>;
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(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 {
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 IPluginAuth<Config>;
243
- let method = 'adduser';
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
- // p.add_user() execution
256
- plugin[method](user, password, function (err, ok): void {
257
- if (err) {
258
- debug('the user %o could not being added. Error: %o', user, err?.message);
259
- return cb(err);
260
- }
261
- if (ok) {
262
- debug('the user %o has been added', user);
263
- 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();
264
254
  }
265
- next();
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: Callback
266
+ callback: pluginUtils.AccessCallback
278
267
  ): void {
279
268
  const plugins = this.plugins.slice(0);
280
- const pkgAllowAcces: AllowAccess = { name: packageName, version: packageVersion };
269
+ const pkgAllowAccess: AllowAccess = { name: packageName, version: packageVersion };
281
270
  const pkg = Object.assign(
282
271
  {},
283
- pkgAllowAcces,
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: IPluginAuth<Config> = plugins.shift() as IPluginAuth<Config>;
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: boolean): void {
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 (isFunction(plugin?.allow_publish) === false) {
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
- // @ts-ignore
377
- plugin.allow_publish(
378
- user,
379
- // @ts-ignore
380
- pkg,
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
- debug('allow publish skip validation for %o', packageName);
394
- next(); // cb(null, false) causes next plugin to roll
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(): Function {
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
- return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction): void => {
392
+ // @ts-ignore
393
+ return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction) => {
411
394
  req.pause();
412
395
 
413
- const next = function (err: VerdaccioError | void): void {
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: RemoteUser): boolean {
533
- 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;
534
518
  }
535
519
 
536
520
  /**
537
521
  * JWT middleware for WebUI
538
522
  */
539
- public webUIJWTmiddleware(): Function {
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
- // $FlowFixMe
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
@@ -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
@@ -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: IAuth = new Auth(config);
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: IAuth = new Auth(config);
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;