@verdaccio/auth 9.0.0-next-9.28 → 9.0.0-next-9.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.
- package/build/auth.d.ts +12 -0
- package/build/auth.js +55 -1
- package/build/auth.js.map +1 -1
- package/build/auth.mjs +56 -2
- package/build/auth.mjs.map +1 -1
- package/build/index.d.ts +1 -0
- package/build/index.js +7 -0
- package/build/index.mjs +3 -2
- package/build/tfa-store.d.ts +134 -0
- package/build/tfa-store.js +291 -0
- package/build/tfa-store.js.map +1 -0
- package/build/tfa-store.mjs +286 -0
- package/build/tfa-store.mjs.map +1 -0
- package/build/types.d.ts +1 -1
- package/build/utils.d.ts +11 -0
- package/build/utils.js +24 -8
- package/build/utils.js.map +1 -1
- package/build/utils.mjs +23 -9
- package/build/utils.mjs.map +1 -1
- package/package.json +10 -9
package/build/auth.d.ts
CHANGED
|
@@ -27,6 +27,18 @@ declare class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBas
|
|
|
27
27
|
*/
|
|
28
28
|
allow_access({ packageName, packageVersion }: pluginUtils.AuthPluginPackage, user: RemoteUser, callback: pluginUtils.AccessCallback): void;
|
|
29
29
|
allow_unpublish({ packageName, packageVersion }: pluginUtils.AuthPluginPackage, user: RemoteUser, callback: Callback): void;
|
|
30
|
+
/**
|
|
31
|
+
* Allow a user to submit a package version for review (`npm stage publish`).
|
|
32
|
+
*
|
|
33
|
+
* Deliberately a weaker capability than publishing: granting `stage` to a
|
|
34
|
+
* group that lacks `publish` is what turns staging into a real review gate,
|
|
35
|
+
* because those users can propose a release but not make one.
|
|
36
|
+
*
|
|
37
|
+
* When the packages configuration says nothing about `stage`, the built-in
|
|
38
|
+
* plugin answers `undefined` and this falls back to `allow_publish`, so
|
|
39
|
+
* existing configurations behave exactly as before.
|
|
40
|
+
*/
|
|
41
|
+
allow_stage({ packageName, packageVersion }: pluginUtils.AuthPluginPackage, user: RemoteUser, callback: Callback): void;
|
|
30
42
|
/**
|
|
31
43
|
* Allow user to publish a package.
|
|
32
44
|
*/
|
package/build/auth.js
CHANGED
|
@@ -232,6 +232,60 @@ var Auth = class {
|
|
|
232
232
|
return next();
|
|
233
233
|
}
|
|
234
234
|
/**
|
|
235
|
+
* Allow a user to submit a package version for review (`npm stage publish`).
|
|
236
|
+
*
|
|
237
|
+
* Deliberately a weaker capability than publishing: granting `stage` to a
|
|
238
|
+
* group that lacks `publish` is what turns staging into a real review gate,
|
|
239
|
+
* because those users can propose a release but not make one.
|
|
240
|
+
*
|
|
241
|
+
* When the packages configuration says nothing about `stage`, the built-in
|
|
242
|
+
* plugin answers `undefined` and this falls back to `allow_publish`, so
|
|
243
|
+
* existing configurations behave exactly as before.
|
|
244
|
+
*/
|
|
245
|
+
allow_stage({ packageName, packageVersion }, user, callback) {
|
|
246
|
+
const plugins = this.plugins.slice(0);
|
|
247
|
+
const pkg = Object.assign({
|
|
248
|
+
name: packageName,
|
|
249
|
+
version: packageVersion
|
|
250
|
+
}, _verdaccio_core.authUtils.getMatchedPackagesSpec(packageName, this.config.packages));
|
|
251
|
+
debug$1("check stage permissions for user %o to package %o", user.name, packageName);
|
|
252
|
+
const next = () => {
|
|
253
|
+
const plugin = plugins.shift();
|
|
254
|
+
if (typeof plugin?.allow_stage !== "function") {
|
|
255
|
+
debug$1("plugin does not implement allow_stage");
|
|
256
|
+
return next();
|
|
257
|
+
}
|
|
258
|
+
plugin.allow_stage(user, pkg, (err, ok) => {
|
|
259
|
+
if (err) {
|
|
260
|
+
debug$1("forbidden stage. Error: %o", err);
|
|
261
|
+
return callback(err);
|
|
262
|
+
}
|
|
263
|
+
if ((0, lodash_es.isNil)(ok) === true) {
|
|
264
|
+
debug$1("bypass stage for %o, publish will handle the access", packageName);
|
|
265
|
+
this.logger.trace({
|
|
266
|
+
user: user.name,
|
|
267
|
+
name: pkg.name
|
|
268
|
+
}, `bypass stage for @{name} by @{user}, publish will handle the access`);
|
|
269
|
+
return this.allow_publish({
|
|
270
|
+
packageName,
|
|
271
|
+
packageVersion
|
|
272
|
+
}, user, callback);
|
|
273
|
+
}
|
|
274
|
+
if (ok) {
|
|
275
|
+
debug$1("stage was granted");
|
|
276
|
+
this.logger.trace({
|
|
277
|
+
user: user.name,
|
|
278
|
+
name: pkg.name
|
|
279
|
+
}, `stage was granted for @{name} by @{user}`);
|
|
280
|
+
return callback(null, ok);
|
|
281
|
+
}
|
|
282
|
+
debug$1("stage was denied. Rolling to next plugin");
|
|
283
|
+
return next();
|
|
284
|
+
});
|
|
285
|
+
};
|
|
286
|
+
return next();
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
235
289
|
* Allow user to publish a package.
|
|
236
290
|
*/
|
|
237
291
|
allow_publish({ packageName, packageVersion }, user, callback) {
|
|
@@ -420,7 +474,7 @@ var Auth = class {
|
|
|
420
474
|
if (!this.isLegacyAuthCacheEnabled()) return;
|
|
421
475
|
const { scheme } = require_utils.parseAuthTokenHeader(authorization);
|
|
422
476
|
if (scheme.toUpperCase() !== _verdaccio_core.TOKEN_BEARER.toUpperCase()) return;
|
|
423
|
-
return (0, node_crypto.createHash)(
|
|
477
|
+
return (0, node_crypto.createHash)(require_utils.SHA256_ALGORITHM).update(authorization).digest("hex");
|
|
424
478
|
}
|
|
425
479
|
getLegacyAuthCacheEntry(cacheKey) {
|
|
426
480
|
if (!cacheKey) return;
|
package/build/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","names":[],"sources":["../src/auth.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { filter, isEmpty, isNil, isUndefined } from 'lodash-es';\nimport { createHash } from 'node:crypto';\nimport { HTPasswd } from 'verdaccio-htpasswd';\n\nimport { createAnonymousRemoteUser, createRemoteUser } from '@verdaccio/config';\nimport type { VerdaccioError, pluginUtils } from '@verdaccio/core';\nimport {\n API_ERROR,\n PLUGIN_CATEGORY,\n PLUGIN_PREFIX,\n SUPPORT_ERRORS,\n TOKEN_BEARER,\n authUtils,\n errorUtils,\n pluginUtils as pluginSanity,\n warningUtils,\n} from '@verdaccio/core';\nimport { asyncLoadPlugin } from '@verdaccio/loaders';\nimport { aesEncrypt, signPayload } from '@verdaccio/signature';\nimport type {\n AllowAccess,\n Callback,\n Config,\n JWTSignOptions,\n Logger,\n PackageAccess,\n RemoteUser,\n Security,\n} from '@verdaccio/types';\n\nimport type {\n $RequestExtend,\n $ResponseExtend,\n IAuthMiddleware,\n NextFunction,\n TokenEncryption,\n} from './types';\nimport {\n getDefaultPluginMethods,\n getMiddlewareCredentials,\n isAESLegacy,\n isAuthHeaderValid,\n parseAuthTokenHeader,\n verifyJWTPayload,\n} from './utils';\n\nconst debug = buildDebug('verdaccio:auth');\ntype LegacyAuthCacheEntry = {\n expiresAt: number;\n user: RemoteUser;\n};\n\ntype LegacyAuthCacheWaiter = (err: VerdaccioError | null, user?: RemoteUser) => void;\n\nfunction cloneRemoteUser(user: RemoteUser): RemoteUser {\n return {\n ...user,\n groups: user.groups ? [...user.groups] : user.groups,\n real_groups: user.real_groups ? [...user.real_groups] : user.real_groups,\n token: user.token ? { ...user.token } : user.token,\n };\n}\n\nclass Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {\n public config: Config;\n public secret: string;\n public logger: Logger;\n public plugins: pluginUtils.Auth<Config>[];\n public options: { legacyMergeConfigs: boolean };\n private legacyAuthCache: Map<string, LegacyAuthCacheEntry>;\n private legacyAuthCacheWaiters: Map<string, LegacyAuthCacheWaiter[]>;\n\n public constructor(config: Config, logger: Logger, options = { legacyMergeConfigs: false }) {\n this.config = config;\n this.secret = config.secret;\n this.logger = logger;\n this.plugins = [];\n this.options = options;\n this.legacyAuthCache = new Map();\n this.legacyAuthCacheWaiters = new Map();\n if (!this.secret) {\n throw new TypeError('secret it is required value on initialize the auth class');\n }\n }\n\n public async init() {\n let plugins = await this.loadPlugin();\n\n debug('auth plugins found %s', plugins.length);\n // Missing auth config or no loaded plugins -> load default htpasswd plugin\n // Empty auth config (null) -> just use fallback methods\n if (this.config.auth !== null && (!plugins || plugins.length === 0)) {\n plugins = this.loadDefaultPlugin();\n }\n this.plugins = plugins;\n\n this.applyFallbackPluginMethods();\n }\n\n private loadDefaultPlugin() {\n debug('load default auth plugin');\n let authPlugin;\n try {\n authPlugin = new HTPasswd(\n { file: './htpasswd' },\n {\n config: this.config,\n logger: this.logger,\n }\n );\n this.logger.info(\n { name: 'verdaccio-htpasswd', pluginCategory: PLUGIN_CATEGORY.AUTHENTICATION },\n 'plugin @{name} successfully loaded (@{pluginCategory})'\n );\n } catch (error: any) {\n debug('error on loading auth htpasswd plugin stack: %o', error);\n this.logger.info({}, 'no auth plugin has been found');\n return [];\n }\n\n return [authPlugin];\n }\n\n private async loadPlugin() {\n return asyncLoadPlugin<pluginUtils.Auth<Config>>(\n this.config.auth,\n {\n config: this.config,\n logger: this.logger,\n },\n pluginSanity.authSanityCheck,\n this.options.legacyMergeConfigs,\n this.config?.server?.pluginPrefix ?? PLUGIN_PREFIX,\n PLUGIN_CATEGORY.AUTHENTICATION\n );\n }\n\n private applyFallbackPluginMethods(): void {\n this.plugins.push(getDefaultPluginMethods(this.logger));\n }\n\n public changePassword(\n username: string,\n password: string,\n newPassword: string,\n cb: Callback\n ): void {\n const validPlugins = filter(\n this.plugins,\n (plugin) => typeof plugin.changePassword === 'function'\n );\n\n if (isEmpty(validPlugins)) {\n return cb(errorUtils.getInternalError(SUPPORT_ERRORS.PLUGIN_MISSING_INTERFACE));\n }\n\n for (const plugin of validPlugins) {\n if (isNil(plugin) || typeof plugin.changePassword !== 'function') {\n debug('auth plugin does not implement changePassword, trying next one');\n continue;\n } else {\n debug('updating password for %o', username);\n plugin.changePassword!(username, password, newPassword, (err, profile): void => {\n if (err) {\n this.logger.error(\n { username, err },\n `An error has been produced\n updating the password for @{username}. Error: @{err.message}`\n );\n return cb(err);\n }\n\n debug('updated password for %o was successful', username);\n return cb(null, profile);\n });\n }\n }\n }\n\n public async invalidateToken(token: string) {\n // eslint-disable-next-line no-console\n console.log('invalidate token pending to implement', token);\n return Promise.resolve();\n }\n\n public authenticate(\n username: string,\n password: string,\n cb: (error: VerdaccioError | null, user?: RemoteUser) => void\n ): void {\n const plugins = this.plugins.slice(0);\n (function next(): void {\n const plugin = plugins.shift();\n\n if (typeof plugin?.authenticate !== 'function') {\n return next();\n }\n\n debug('authenticating %o', username);\n plugin.authenticate(username, password, function (err: VerdaccioError | null, groups): void {\n if (err) {\n debug('authenticating for user %o failed. Error: %o', username, err?.message);\n return cb(err);\n }\n\n // Expect: SKIP if groups is falsey and not an array\n // with at least one item (truthy length)\n // Expect: CONTINUE otherwise (will error if groups is not\n // an array, but this is current behavior)\n // Caveat: STRING (if valid) will pass successfully\n // bug give unexpected results\n // Info: Cannot use `== false to check falsey values`\n if (!!groups && groups.length !== 0) {\n // TODO: create a better understanding of expectations\n if (typeof groups === 'string') {\n throw new TypeError('plugin group error: invalid type for function');\n }\n const isGroupValid: boolean = Array.isArray(groups);\n if (!isGroupValid) {\n throw new TypeError(API_ERROR.BAD_FORMAT_USER_GROUP);\n }\n\n debug('authentication for user %o was successfully. Groups: %o', username, groups);\n return cb(err, createRemoteUser(username, groups));\n }\n next();\n });\n })();\n }\n\n public add_user(\n user: string,\n password: string,\n cb: (error: VerdaccioError | null, user?: RemoteUser) => void\n ): void {\n const self = this;\n const plugins = this.plugins.slice(0);\n debug('add user %o', user);\n\n (function next(): void {\n let method = 'adduser';\n const plugin = plugins.shift();\n // @ts-expect-error future major (7.x) should remove this section\n if (typeof plugin.adduser === 'undefined' && typeof plugin.add_user === 'function') {\n method = 'add_user';\n warningUtils.emit(warningUtils.Codes.VERWAR006);\n }\n // @ts-ignore\n if (typeof plugin[method] !== 'function') {\n next();\n } else {\n // TODO: replace by adduser whenever add_user deprecation method has been removed\n // @ts-ignore\n plugin[method](\n user,\n password,\n function (err: VerdaccioError | null, ok?: boolean | string): void {\n if (err) {\n debug('the user %o could not be added. Error: %o', user, err?.message);\n return cb(err);\n }\n if (ok) {\n debug('the user %o has been added', user);\n return self.authenticate(user, password, cb);\n }\n debug('user could not be added, skip to next auth plugin');\n next();\n }\n );\n }\n })();\n }\n\n /**\n * Allow user to access a package.\n */\n public allow_access(\n { packageName, packageVersion }: pluginUtils.AuthPluginPackage,\n user: RemoteUser,\n callback: pluginUtils.AccessCallback\n ): void {\n const plugins = this.plugins.slice(0);\n const pkg = Object.assign(\n { name: packageName, version: packageVersion },\n authUtils.getMatchedPackagesSpec(packageName, this.config.packages)\n ) as AllowAccess & PackageAccess;\n\n debug('check access permissions for user %o to package %o', user.name, packageName);\n\n // Use const instead of function declaration so we can use this.logger\n const next = (): void => {\n const plugin = plugins.shift();\n\n if (typeof plugin?.allow_access !== 'function') {\n debug('plugin does not implement allow_access');\n return next();\n }\n\n plugin.allow_access(user, pkg, (err: VerdaccioError | null, ok?: boolean): void => {\n if (err) {\n debug('forbidden access. Error: %o', err);\n return callback(err);\n }\n\n if (ok) {\n debug('access was granted');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `access was granted for @{name} by @{user}`\n );\n return callback(null, ok);\n }\n\n // cb(null, false) causes next plugin to roll\n debug('access was denied. Rolling to next plugin');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `intermediate access denial for @{name} by @{user}, rolling to next plugin`\n );\n return next();\n });\n };\n\n return next();\n }\n\n public allow_unpublish(\n { packageName, packageVersion }: pluginUtils.AuthPluginPackage,\n user: RemoteUser,\n callback: Callback\n ): void {\n const plugins = this.plugins.slice(0);\n const pkg = Object.assign(\n { name: packageName, version: packageVersion },\n authUtils.getMatchedPackagesSpec(packageName, this.config.packages)\n );\n\n debug('check unpublish permissions for user %o to package %o', user.name, packageName);\n\n // Use const instead of function declaration so we can use this.logger\n const next = (): void => {\n const plugin = plugins.shift();\n\n if (typeof plugin?.allow_unpublish !== 'function') {\n debug('plugin does not implement allow_unpublish');\n return next();\n }\n\n plugin.allow_unpublish(user, pkg, (err: VerdaccioError | null, ok?: boolean): void => {\n if (err) {\n debug('forbidden unpublish. Error: %o', err);\n return callback(err);\n }\n\n // The following is different from the allow_access and allow_publish implementations:\n // If the packages config is missing an entry for \"unpublish\", the built-in default method\n // (or a plugin) will return undefined, which will trigger the allow_publish fallback.\n // (see utils.ts, handleSpecialUnpublish, callback(null, undefined))\n if (isNil(ok) === true) {\n debug('bypass unpublish for %o, publish will handle the access', packageName);\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `bypass unpublish for @{name} by @{user}, publish will handle the access`\n );\n return this.allow_publish({ packageName, packageVersion }, user, callback);\n }\n\n if (ok) {\n debug('unpublish was granted');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `unpublish was granted for @{name} by @{user}`\n );\n return callback(null, ok);\n }\n\n // cb(null, false) causes next plugin to roll\n debug('unpublish was denied. Rolling to next plugin');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `intermediate unpublish denial for @{name} by @{user}, rolling to next plugin`\n );\n return next();\n });\n };\n\n return next();\n }\n\n /**\n * Allow user to publish a package.\n */\n public allow_publish(\n { packageName, packageVersion }: pluginUtils.AuthPluginPackage,\n user: RemoteUser,\n callback: Callback\n ): void {\n const plugins = this.plugins.slice(0);\n const pkg = Object.assign(\n { name: packageName, version: packageVersion },\n authUtils.getMatchedPackagesSpec(packageName, this.config.packages)\n );\n\n debug('check publish permissions for user %o to package %o', user.name, packageName);\n\n // Use const instead of function declaration so we can use this.logger\n const next = (): void => {\n const plugin = plugins.shift();\n\n if (typeof plugin?.allow_publish !== 'function') {\n debug('plugin does not implement allow_publish');\n return next();\n }\n\n plugin.allow_publish(user, pkg, (err: VerdaccioError | null, ok?: boolean): void => {\n if (err) {\n debug('forbidden publish. Error: %o', err);\n return callback(err);\n }\n\n if (ok) {\n debug('publish was granted');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `publish was granted for @{name} by @{user}`\n );\n return callback(null, ok);\n }\n\n // cb(null, false) causes next plugin to roll\n debug('publish was denied. Rolling to next plugin');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `intermediate publish denial for @{name} by @{user}, rolling to next plugin`\n );\n return next();\n });\n };\n\n return next();\n }\n\n public apiJWTmiddleware(): any {\n debug('jwt middleware');\n const plugins = this.plugins.slice(0);\n const helpers = { createAnonymousRemoteUser, createRemoteUser };\n for (const plugin of plugins) {\n if (plugin.apiJWTmiddleware) {\n return plugin.apiJWTmiddleware(helpers);\n }\n }\n\n return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction) => {\n req.pause();\n const next = function (err?: VerdaccioError): NextFunction {\n req.resume();\n if (err) {\n return _next(err) as unknown as NextFunction;\n }\n\n return _next() as unknown as NextFunction;\n };\n\n // FUTURE: disabled, not removed yet but seems unreacable code\n // if (this._isRemoteUserValid(req.remote_user)) {\n // debug('jwt has a valid authentication header');\n // return next();\n // }\n\n // in case auth header does not exist we return anonymous function\n const remoteUser = createAnonymousRemoteUser();\n req.remote_user = remoteUser;\n res.locals.remote_user = remoteUser;\n\n const { authorization } = req.headers;\n if (isNil(authorization)) {\n debug('jwt, authentication header is missing');\n return next();\n }\n\n if (!isAuthHeaderValid(authorization)) {\n debug('api middleware authentication heather is invalid');\n return next(errorUtils.getBadRequest(API_ERROR.BAD_AUTH_HEADER));\n }\n const { secret, security } = this.config;\n\n if (isAESLegacy(security)) {\n debug('api middleware using legacy auth token');\n this.handleAESMiddleware(req, security, secret, authorization, next);\n } else {\n debug('api middleware using JWT auth token');\n this.handleJWTAPIMiddleware(req, security, secret, authorization, next);\n }\n };\n }\n\n private handleJWTAPIMiddleware(\n req: $RequestExtend,\n security: Security,\n secret: string,\n authorization: string,\n next: any\n ): void {\n debug('handle JWT api middleware');\n const credentials: any = getMiddlewareCredentials(security, secret, authorization);\n if (credentials) {\n // if the signature is valid we rely on it\n req.remote_user = credentials;\n debug('generating a remote user');\n next();\n } else {\n // with JWT throw 401\n debug('jwt invalid token');\n next(errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));\n }\n }\n\n private handleAESMiddleware(\n req: $RequestExtend,\n security: Security,\n secret: string,\n authorization: string,\n next: Function\n ): void {\n debug('handle legacy api middleware');\n debug('api middleware has a secret? %o', typeof secret === 'string');\n debug('api middleware authorization %o', typeof authorization === 'string');\n const credentials: any = getMiddlewareCredentials(security, secret, authorization);\n debug('api middleware credentials %o', credentials?.name);\n if (credentials) {\n const cacheKey = this.getLegacyAuthCacheKey(authorization);\n const cachedUser = this.getLegacyAuthCacheEntry(cacheKey);\n if (cachedUser) {\n req.remote_user = cachedUser;\n debug('generating cached remote user');\n return next();\n }\n\n const { user, password } = credentials;\n const applyAuthResult = (err: VerdaccioError | null, user?: RemoteUser): void => {\n if (!err && user) {\n req.remote_user = credentials.tokenKey\n ? { ...user, token: { key: credentials.tokenKey } }\n : user;\n debug('generating a remote user');\n next();\n } else {\n req.remote_user = createAnonymousRemoteUser();\n debug('generating anonymous user');\n next(err || errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));\n }\n };\n // concurrent requests for the same token wait for the in-flight one\n if (this.enqueueLegacyAuthCacheWaiter(cacheKey, applyAuthResult)) {\n return;\n }\n\n debug('authenticating %o', user);\n const onAuthComplete = (err: VerdaccioError | null, user?: RemoteUser): void => {\n // only the leader writes the cache; waiters just reuse its result\n if (!err && user) {\n this.setLegacyAuthCacheEntry(\n cacheKey,\n credentials.tokenKey ? { ...user, token: { key: credentials.tokenKey } } : user\n );\n }\n applyAuthResult(err, user);\n this.resolveLegacyAuthCacheWaiters(cacheKey, err, user);\n };\n try {\n this.authenticate(user, password, onAuthComplete);\n } catch (err: any) {\n onAuthComplete(errorUtils.getInternalError(err?.message));\n }\n } else {\n const remoteUser = this.getJWTRemoteUserFromBearer(authorization);\n if (remoteUser) {\n req.remote_user = remoteUser;\n debug('generating a remote user from jwt bearer');\n return next();\n }\n\n debug('legacy invalid header');\n return next(errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));\n }\n }\n\n private getJWTRemoteUserFromBearer(authorization: string): RemoteUser | void {\n const { scheme, token } = parseAuthTokenHeader(authorization);\n if (scheme.toUpperCase() !== TOKEN_BEARER.toUpperCase() || !token) {\n return;\n }\n\n let credentials: RemoteUser | undefined;\n try {\n credentials = verifyJWTPayload(token, this.config.secret, this.config.security);\n } catch {\n return;\n }\n\n if (this._isRemoteUserValid(credentials)) {\n const { name, groups } = credentials as RemoteUser;\n return createRemoteUser(name as string, groups);\n }\n }\n\n private enqueueLegacyAuthCacheWaiter(\n cacheKey: string | void,\n waiter: LegacyAuthCacheWaiter\n ): boolean {\n if (!cacheKey) {\n return false;\n }\n\n const waiters = this.legacyAuthCacheWaiters.get(cacheKey);\n if (!waiters) {\n this.legacyAuthCacheWaiters.set(cacheKey, []);\n return false;\n }\n\n waiters.push(waiter);\n return true;\n }\n\n private resolveLegacyAuthCacheWaiters(\n cacheKey: string | void,\n err: VerdaccioError | null,\n user?: RemoteUser\n ): void {\n if (!cacheKey) {\n return;\n }\n\n const waiters = this.legacyAuthCacheWaiters.get(cacheKey);\n this.legacyAuthCacheWaiters.delete(cacheKey);\n if (!waiters) {\n return;\n }\n\n for (const waiter of waiters) {\n waiter(err, user);\n }\n }\n\n private isLegacyAuthCacheEnabled(): boolean {\n // opt-in: disabled unless explicitly turned on via config\n return this.config.server?.legacyAuthCache?.enabled === true;\n }\n\n private getLegacyAuthCacheTtlMs(): number {\n const ttlMs = this.config.server?.legacyAuthCache?.ttlMs;\n return typeof ttlMs === 'number' && ttlMs > 0 ? ttlMs : 30 * 1000;\n }\n\n private getLegacyAuthCacheMaxEntries(): number {\n const maxEntries = this.config.server?.legacyAuthCache?.maxEntries;\n return typeof maxEntries === 'number' && maxEntries > 0 ? maxEntries : 1000;\n }\n\n private getLegacyAuthCacheKey(authorization: string): string | void {\n if (!this.isLegacyAuthCacheEnabled()) {\n return;\n }\n\n const { scheme } = parseAuthTokenHeader(authorization);\n if (scheme.toUpperCase() !== TOKEN_BEARER.toUpperCase()) {\n return;\n }\n\n return createHash('sha256').update(authorization).digest('hex');\n }\n\n private getLegacyAuthCacheEntry(cacheKey: string | void): RemoteUser | void {\n if (!cacheKey) {\n return;\n }\n\n const entry = this.legacyAuthCache.get(cacheKey);\n if (!entry) {\n return;\n }\n\n if (entry.expiresAt <= Date.now()) {\n this.legacyAuthCache.delete(cacheKey);\n return;\n }\n\n this.legacyAuthCache.delete(cacheKey);\n this.legacyAuthCache.set(cacheKey, entry);\n return cloneRemoteUser(entry.user);\n }\n\n private setLegacyAuthCacheEntry(cacheKey: string | void, user: RemoteUser): void {\n if (!cacheKey) {\n return;\n }\n\n this.legacyAuthCache.set(cacheKey, {\n expiresAt: Date.now() + this.getLegacyAuthCacheTtlMs(),\n user: cloneRemoteUser(user),\n });\n\n const maxEntries = this.getLegacyAuthCacheMaxEntries();\n while (this.legacyAuthCache.size > maxEntries) {\n const oldestKey = this.legacyAuthCache.keys().next().value;\n if (!oldestKey) {\n break;\n }\n this.legacyAuthCache.delete(oldestKey);\n }\n }\n\n private _isRemoteUserValid(remote_user?: RemoteUser): boolean {\n return isUndefined(remote_user) === false && isUndefined(remote_user?.name) === false;\n }\n\n /**\n * JWT middleware for WebUI\n */\n public webUIJWTmiddleware() {\n return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction): void => {\n if (this._isRemoteUserValid(req.remote_user)) {\n return _next();\n }\n\n req.pause();\n const next = (err: VerdaccioError | void): void => {\n req.resume();\n if (err) {\n req.remote_user.error = err.message;\n res.status(err.statusCode).send(err.message);\n }\n\n return _next();\n };\n\n const { authorization } = req.headers;\n if (isNil(authorization)) {\n req.remote_user = createAnonymousRemoteUser();\n return next();\n }\n\n if (!isAuthHeaderValid(authorization)) {\n return next(errorUtils.getBadRequest(API_ERROR.BAD_AUTH_HEADER));\n }\n\n const token = (authorization || '').replace(`${TOKEN_BEARER} `, '');\n if (!token) {\n return next();\n }\n\n let credentials: RemoteUser | undefined;\n try {\n credentials = verifyJWTPayload(token, this.config.secret, this.config.security);\n } catch {\n // FIXME: intended behaviour, do we want it?\n }\n\n if (this._isRemoteUserValid(credentials)) {\n const { name, groups } = credentials as RemoteUser;\n req.remote_user = createRemoteUser(name as string, groups);\n } else {\n req.remote_user = createAnonymousRemoteUser();\n }\n\n next();\n };\n }\n\n public async jwtEncrypt(user: RemoteUser, signOptions: JWTSignOptions): Promise<string> {\n const { real_groups, name, groups, token: tokenMetadata } = user;\n debug('jwt encrypt %o', name);\n const realGroupsValidated = isNil(real_groups) ? [] : real_groups;\n const groupedGroups = isNil(groups)\n ? real_groups\n : Array.from(new Set([...groups.concat(realGroupsValidated)]));\n const payload: RemoteUser = {\n real_groups: realGroupsValidated,\n name,\n groups: groupedGroups,\n };\n if (tokenMetadata?.key) {\n payload.token = { key: tokenMetadata.key };\n }\n const signedToken: string = await signPayload(\n payload,\n this.secret,\n signOptions as Parameters<typeof signPayload>[2]\n );\n\n return signedToken;\n }\n\n /**\n * Encrypt a string.\n */\n public aesEncrypt(value: string): string | void {\n debug('signing with aes encryption');\n const token = aesEncrypt(value, this.secret);\n return token;\n }\n}\n\nexport { Auth };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auth.js","names":[],"sources":["../src/auth.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { filter, isEmpty, isNil, isUndefined } from 'lodash-es';\nimport { createHash } from 'node:crypto';\nimport { HTPasswd } from 'verdaccio-htpasswd';\n\nimport { createAnonymousRemoteUser, createRemoteUser } from '@verdaccio/config';\nimport type { VerdaccioError, pluginUtils } from '@verdaccio/core';\nimport {\n API_ERROR,\n PLUGIN_CATEGORY,\n PLUGIN_PREFIX,\n SUPPORT_ERRORS,\n TOKEN_BEARER,\n authUtils,\n errorUtils,\n pluginUtils as pluginSanity,\n warningUtils,\n} from '@verdaccio/core';\nimport { asyncLoadPlugin } from '@verdaccio/loaders';\nimport { aesEncrypt, signPayload } from '@verdaccio/signature';\nimport type {\n AllowAccess,\n Callback,\n Config,\n JWTSignOptions,\n Logger,\n PackageAccess,\n RemoteUser,\n Security,\n} from '@verdaccio/types';\n\nimport type {\n $RequestExtend,\n $ResponseExtend,\n IAuthMiddleware,\n NextFunction,\n TokenEncryption,\n} from './types';\nimport {\n SHA256_ALGORITHM,\n getDefaultPluginMethods,\n getMiddlewareCredentials,\n isAESLegacy,\n isAuthHeaderValid,\n parseAuthTokenHeader,\n verifyJWTPayload,\n} from './utils';\n\nconst debug = buildDebug('verdaccio:auth');\ntype LegacyAuthCacheEntry = {\n expiresAt: number;\n user: RemoteUser;\n};\n\ntype LegacyAuthCacheWaiter = (err: VerdaccioError | null, user?: RemoteUser) => void;\n\nfunction cloneRemoteUser(user: RemoteUser): RemoteUser {\n return {\n ...user,\n groups: user.groups ? [...user.groups] : user.groups,\n real_groups: user.real_groups ? [...user.real_groups] : user.real_groups,\n token: user.token ? { ...user.token } : user.token,\n };\n}\n\nclass Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {\n public config: Config;\n public secret: string;\n public logger: Logger;\n public plugins: pluginUtils.Auth<Config>[];\n public options: { legacyMergeConfigs: boolean };\n private legacyAuthCache: Map<string, LegacyAuthCacheEntry>;\n private legacyAuthCacheWaiters: Map<string, LegacyAuthCacheWaiter[]>;\n\n public constructor(config: Config, logger: Logger, options = { legacyMergeConfigs: false }) {\n this.config = config;\n this.secret = config.secret;\n this.logger = logger;\n this.plugins = [];\n this.options = options;\n this.legacyAuthCache = new Map();\n this.legacyAuthCacheWaiters = new Map();\n if (!this.secret) {\n throw new TypeError('secret it is required value on initialize the auth class');\n }\n }\n\n public async init() {\n let plugins = await this.loadPlugin();\n\n debug('auth plugins found %s', plugins.length);\n // Missing auth config or no loaded plugins -> load default htpasswd plugin\n // Empty auth config (null) -> just use fallback methods\n if (this.config.auth !== null && (!plugins || plugins.length === 0)) {\n plugins = this.loadDefaultPlugin();\n }\n this.plugins = plugins;\n\n this.applyFallbackPluginMethods();\n }\n\n private loadDefaultPlugin() {\n debug('load default auth plugin');\n let authPlugin;\n try {\n authPlugin = new HTPasswd(\n { file: './htpasswd' },\n {\n config: this.config,\n logger: this.logger,\n }\n );\n this.logger.info(\n { name: 'verdaccio-htpasswd', pluginCategory: PLUGIN_CATEGORY.AUTHENTICATION },\n 'plugin @{name} successfully loaded (@{pluginCategory})'\n );\n } catch (error: any) {\n debug('error on loading auth htpasswd plugin stack: %o', error);\n this.logger.info({}, 'no auth plugin has been found');\n return [];\n }\n\n return [authPlugin];\n }\n\n private async loadPlugin() {\n return asyncLoadPlugin<pluginUtils.Auth<Config>>(\n this.config.auth,\n {\n config: this.config,\n logger: this.logger,\n },\n pluginSanity.authSanityCheck,\n this.options.legacyMergeConfigs,\n this.config?.server?.pluginPrefix ?? PLUGIN_PREFIX,\n PLUGIN_CATEGORY.AUTHENTICATION\n );\n }\n\n private applyFallbackPluginMethods(): void {\n this.plugins.push(getDefaultPluginMethods(this.logger));\n }\n\n public changePassword(\n username: string,\n password: string,\n newPassword: string,\n cb: Callback\n ): void {\n const validPlugins = filter(\n this.plugins,\n (plugin) => typeof plugin.changePassword === 'function'\n );\n\n if (isEmpty(validPlugins)) {\n return cb(errorUtils.getInternalError(SUPPORT_ERRORS.PLUGIN_MISSING_INTERFACE));\n }\n\n for (const plugin of validPlugins) {\n if (isNil(plugin) || typeof plugin.changePassword !== 'function') {\n debug('auth plugin does not implement changePassword, trying next one');\n continue;\n } else {\n debug('updating password for %o', username);\n plugin.changePassword!(username, password, newPassword, (err, profile): void => {\n if (err) {\n this.logger.error(\n { username, err },\n `An error has been produced\n updating the password for @{username}. Error: @{err.message}`\n );\n return cb(err);\n }\n\n debug('updated password for %o was successful', username);\n return cb(null, profile);\n });\n }\n }\n }\n\n public async invalidateToken(token: string) {\n // eslint-disable-next-line no-console\n console.log('invalidate token pending to implement', token);\n return Promise.resolve();\n }\n\n public authenticate(\n username: string,\n password: string,\n cb: (error: VerdaccioError | null, user?: RemoteUser) => void\n ): void {\n const plugins = this.plugins.slice(0);\n (function next(): void {\n const plugin = plugins.shift();\n\n if (typeof plugin?.authenticate !== 'function') {\n return next();\n }\n\n debug('authenticating %o', username);\n plugin.authenticate(username, password, function (err: VerdaccioError | null, groups): void {\n if (err) {\n debug('authenticating for user %o failed. Error: %o', username, err?.message);\n return cb(err);\n }\n\n // Expect: SKIP if groups is falsey and not an array\n // with at least one item (truthy length)\n // Expect: CONTINUE otherwise (will error if groups is not\n // an array, but this is current behavior)\n // Caveat: STRING (if valid) will pass successfully\n // bug give unexpected results\n // Info: Cannot use `== false to check falsey values`\n if (!!groups && groups.length !== 0) {\n // TODO: create a better understanding of expectations\n if (typeof groups === 'string') {\n throw new TypeError('plugin group error: invalid type for function');\n }\n const isGroupValid: boolean = Array.isArray(groups);\n if (!isGroupValid) {\n throw new TypeError(API_ERROR.BAD_FORMAT_USER_GROUP);\n }\n\n debug('authentication for user %o was successfully. Groups: %o', username, groups);\n return cb(err, createRemoteUser(username, groups));\n }\n next();\n });\n })();\n }\n\n public add_user(\n user: string,\n password: string,\n cb: (error: VerdaccioError | null, user?: RemoteUser) => void\n ): void {\n const self = this;\n const plugins = this.plugins.slice(0);\n debug('add user %o', user);\n\n (function next(): void {\n let method = 'adduser';\n const plugin = plugins.shift();\n // @ts-expect-error future major (7.x) should remove this section\n if (typeof plugin.adduser === 'undefined' && typeof plugin.add_user === 'function') {\n method = 'add_user';\n warningUtils.emit(warningUtils.Codes.VERWAR006);\n }\n // @ts-ignore\n if (typeof plugin[method] !== 'function') {\n next();\n } else {\n // TODO: replace by adduser whenever add_user deprecation method has been removed\n // @ts-ignore\n plugin[method](\n user,\n password,\n function (err: VerdaccioError | null, ok?: boolean | string): void {\n if (err) {\n debug('the user %o could not be added. Error: %o', user, err?.message);\n return cb(err);\n }\n if (ok) {\n debug('the user %o has been added', user);\n return self.authenticate(user, password, cb);\n }\n debug('user could not be added, skip to next auth plugin');\n next();\n }\n );\n }\n })();\n }\n\n /**\n * Allow user to access a package.\n */\n public allow_access(\n { packageName, packageVersion }: pluginUtils.AuthPluginPackage,\n user: RemoteUser,\n callback: pluginUtils.AccessCallback\n ): void {\n const plugins = this.plugins.slice(0);\n const pkg = Object.assign(\n { name: packageName, version: packageVersion },\n authUtils.getMatchedPackagesSpec(packageName, this.config.packages)\n ) as AllowAccess & PackageAccess;\n\n debug('check access permissions for user %o to package %o', user.name, packageName);\n\n // Use const instead of function declaration so we can use this.logger\n const next = (): void => {\n const plugin = plugins.shift();\n\n if (typeof plugin?.allow_access !== 'function') {\n debug('plugin does not implement allow_access');\n return next();\n }\n\n plugin.allow_access(user, pkg, (err: VerdaccioError | null, ok?: boolean): void => {\n if (err) {\n debug('forbidden access. Error: %o', err);\n return callback(err);\n }\n\n if (ok) {\n debug('access was granted');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `access was granted for @{name} by @{user}`\n );\n return callback(null, ok);\n }\n\n // cb(null, false) causes next plugin to roll\n debug('access was denied. Rolling to next plugin');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `intermediate access denial for @{name} by @{user}, rolling to next plugin`\n );\n return next();\n });\n };\n\n return next();\n }\n\n public allow_unpublish(\n { packageName, packageVersion }: pluginUtils.AuthPluginPackage,\n user: RemoteUser,\n callback: Callback\n ): void {\n const plugins = this.plugins.slice(0);\n const pkg = Object.assign(\n { name: packageName, version: packageVersion },\n authUtils.getMatchedPackagesSpec(packageName, this.config.packages)\n );\n\n debug('check unpublish permissions for user %o to package %o', user.name, packageName);\n\n // Use const instead of function declaration so we can use this.logger\n const next = (): void => {\n const plugin = plugins.shift();\n\n if (typeof plugin?.allow_unpublish !== 'function') {\n debug('plugin does not implement allow_unpublish');\n return next();\n }\n\n plugin.allow_unpublish(user, pkg, (err: VerdaccioError | null, ok?: boolean): void => {\n if (err) {\n debug('forbidden unpublish. Error: %o', err);\n return callback(err);\n }\n\n // The following is different from the allow_access and allow_publish implementations:\n // If the packages config is missing an entry for \"unpublish\", the built-in default method\n // (or a plugin) will return undefined, which will trigger the allow_publish fallback.\n // (see utils.ts, handleSpecialUnpublish, callback(null, undefined))\n if (isNil(ok) === true) {\n debug('bypass unpublish for %o, publish will handle the access', packageName);\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `bypass unpublish for @{name} by @{user}, publish will handle the access`\n );\n return this.allow_publish({ packageName, packageVersion }, user, callback);\n }\n\n if (ok) {\n debug('unpublish was granted');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `unpublish was granted for @{name} by @{user}`\n );\n return callback(null, ok);\n }\n\n // cb(null, false) causes next plugin to roll\n debug('unpublish was denied. Rolling to next plugin');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `intermediate unpublish denial for @{name} by @{user}, rolling to next plugin`\n );\n return next();\n });\n };\n\n return next();\n }\n\n /**\n * Allow a user to submit a package version for review (`npm stage publish`).\n *\n * Deliberately a weaker capability than publishing: granting `stage` to a\n * group that lacks `publish` is what turns staging into a real review gate,\n * because those users can propose a release but not make one.\n *\n * When the packages configuration says nothing about `stage`, the built-in\n * plugin answers `undefined` and this falls back to `allow_publish`, so\n * existing configurations behave exactly as before.\n */\n public allow_stage(\n { packageName, packageVersion }: pluginUtils.AuthPluginPackage,\n user: RemoteUser,\n callback: Callback\n ): void {\n const plugins = this.plugins.slice(0);\n const pkg = Object.assign(\n { name: packageName, version: packageVersion },\n authUtils.getMatchedPackagesSpec(packageName, this.config.packages)\n );\n\n debug('check stage permissions for user %o to package %o', user.name, packageName);\n\n const next = (): void => {\n const plugin = plugins.shift();\n\n if (typeof plugin?.allow_stage !== 'function') {\n debug('plugin does not implement allow_stage');\n return next();\n }\n\n plugin.allow_stage(user, pkg, (err: VerdaccioError | null, ok?: boolean): void => {\n if (err) {\n debug('forbidden stage. Error: %o', err);\n return callback(err);\n }\n\n // undefined means the packages config has no \"stage\" entry, so publish\n // decides (see utils.ts, handleActionWithPublishFallback)\n if (isNil(ok) === true) {\n debug('bypass stage for %o, publish will handle the access', packageName);\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `bypass stage for @{name} by @{user}, publish will handle the access`\n );\n return this.allow_publish({ packageName, packageVersion }, user, callback);\n }\n\n if (ok) {\n debug('stage was granted');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `stage was granted for @{name} by @{user}`\n );\n return callback(null, ok);\n }\n\n // cb(null, false) causes next plugin to roll\n debug('stage was denied. Rolling to next plugin');\n return next();\n });\n };\n\n return next();\n }\n\n /**\n * Allow user to publish a package.\n */\n public allow_publish(\n { packageName, packageVersion }: pluginUtils.AuthPluginPackage,\n user: RemoteUser,\n callback: Callback\n ): void {\n const plugins = this.plugins.slice(0);\n const pkg = Object.assign(\n { name: packageName, version: packageVersion },\n authUtils.getMatchedPackagesSpec(packageName, this.config.packages)\n );\n\n debug('check publish permissions for user %o to package %o', user.name, packageName);\n\n // Use const instead of function declaration so we can use this.logger\n const next = (): void => {\n const plugin = plugins.shift();\n\n if (typeof plugin?.allow_publish !== 'function') {\n debug('plugin does not implement allow_publish');\n return next();\n }\n\n plugin.allow_publish(user, pkg, (err: VerdaccioError | null, ok?: boolean): void => {\n if (err) {\n debug('forbidden publish. Error: %o', err);\n return callback(err);\n }\n\n if (ok) {\n debug('publish was granted');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `publish was granted for @{name} by @{user}`\n );\n return callback(null, ok);\n }\n\n // cb(null, false) causes next plugin to roll\n debug('publish was denied. Rolling to next plugin');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `intermediate publish denial for @{name} by @{user}, rolling to next plugin`\n );\n return next();\n });\n };\n\n return next();\n }\n\n public apiJWTmiddleware(): any {\n debug('jwt middleware');\n const plugins = this.plugins.slice(0);\n const helpers = { createAnonymousRemoteUser, createRemoteUser };\n for (const plugin of plugins) {\n if (plugin.apiJWTmiddleware) {\n return plugin.apiJWTmiddleware(helpers);\n }\n }\n\n return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction) => {\n req.pause();\n const next = function (err?: VerdaccioError): NextFunction {\n req.resume();\n if (err) {\n return _next(err) as unknown as NextFunction;\n }\n\n return _next() as unknown as NextFunction;\n };\n\n // FUTURE: disabled, not removed yet but seems unreacable code\n // if (this._isRemoteUserValid(req.remote_user)) {\n // debug('jwt has a valid authentication header');\n // return next();\n // }\n\n // in case auth header does not exist we return anonymous function\n const remoteUser = createAnonymousRemoteUser();\n req.remote_user = remoteUser;\n res.locals.remote_user = remoteUser;\n\n const { authorization } = req.headers;\n if (isNil(authorization)) {\n debug('jwt, authentication header is missing');\n return next();\n }\n\n if (!isAuthHeaderValid(authorization)) {\n debug('api middleware authentication heather is invalid');\n return next(errorUtils.getBadRequest(API_ERROR.BAD_AUTH_HEADER));\n }\n const { secret, security } = this.config;\n\n if (isAESLegacy(security)) {\n debug('api middleware using legacy auth token');\n this.handleAESMiddleware(req, security, secret, authorization, next);\n } else {\n debug('api middleware using JWT auth token');\n this.handleJWTAPIMiddleware(req, security, secret, authorization, next);\n }\n };\n }\n\n private handleJWTAPIMiddleware(\n req: $RequestExtend,\n security: Security,\n secret: string,\n authorization: string,\n next: any\n ): void {\n debug('handle JWT api middleware');\n const credentials: any = getMiddlewareCredentials(security, secret, authorization);\n if (credentials) {\n // if the signature is valid we rely on it\n req.remote_user = credentials;\n debug('generating a remote user');\n next();\n } else {\n // with JWT throw 401\n debug('jwt invalid token');\n next(errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));\n }\n }\n\n private handleAESMiddleware(\n req: $RequestExtend,\n security: Security,\n secret: string,\n authorization: string,\n next: Function\n ): void {\n debug('handle legacy api middleware');\n debug('api middleware has a secret? %o', typeof secret === 'string');\n debug('api middleware authorization %o', typeof authorization === 'string');\n const credentials: any = getMiddlewareCredentials(security, secret, authorization);\n debug('api middleware credentials %o', credentials?.name);\n if (credentials) {\n const cacheKey = this.getLegacyAuthCacheKey(authorization);\n const cachedUser = this.getLegacyAuthCacheEntry(cacheKey);\n if (cachedUser) {\n req.remote_user = cachedUser;\n debug('generating cached remote user');\n return next();\n }\n\n const { user, password } = credentials;\n const applyAuthResult = (err: VerdaccioError | null, user?: RemoteUser): void => {\n if (!err && user) {\n req.remote_user = credentials.tokenKey\n ? { ...user, token: { key: credentials.tokenKey } }\n : user;\n debug('generating a remote user');\n next();\n } else {\n req.remote_user = createAnonymousRemoteUser();\n debug('generating anonymous user');\n next(err || errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));\n }\n };\n // concurrent requests for the same token wait for the in-flight one\n if (this.enqueueLegacyAuthCacheWaiter(cacheKey, applyAuthResult)) {\n return;\n }\n\n debug('authenticating %o', user);\n const onAuthComplete = (err: VerdaccioError | null, user?: RemoteUser): void => {\n // only the leader writes the cache; waiters just reuse its result\n if (!err && user) {\n this.setLegacyAuthCacheEntry(\n cacheKey,\n credentials.tokenKey ? { ...user, token: { key: credentials.tokenKey } } : user\n );\n }\n applyAuthResult(err, user);\n this.resolveLegacyAuthCacheWaiters(cacheKey, err, user);\n };\n try {\n this.authenticate(user, password, onAuthComplete);\n } catch (err: any) {\n onAuthComplete(errorUtils.getInternalError(err?.message));\n }\n } else {\n const remoteUser = this.getJWTRemoteUserFromBearer(authorization);\n if (remoteUser) {\n req.remote_user = remoteUser;\n debug('generating a remote user from jwt bearer');\n return next();\n }\n\n debug('legacy invalid header');\n return next(errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));\n }\n }\n\n private getJWTRemoteUserFromBearer(authorization: string): RemoteUser | void {\n const { scheme, token } = parseAuthTokenHeader(authorization);\n if (scheme.toUpperCase() !== TOKEN_BEARER.toUpperCase() || !token) {\n return;\n }\n\n let credentials: RemoteUser | undefined;\n try {\n credentials = verifyJWTPayload(token, this.config.secret, this.config.security);\n } catch {\n return;\n }\n\n if (this._isRemoteUserValid(credentials)) {\n const { name, groups } = credentials as RemoteUser;\n return createRemoteUser(name as string, groups);\n }\n }\n\n private enqueueLegacyAuthCacheWaiter(\n cacheKey: string | void,\n waiter: LegacyAuthCacheWaiter\n ): boolean {\n if (!cacheKey) {\n return false;\n }\n\n const waiters = this.legacyAuthCacheWaiters.get(cacheKey);\n if (!waiters) {\n this.legacyAuthCacheWaiters.set(cacheKey, []);\n return false;\n }\n\n waiters.push(waiter);\n return true;\n }\n\n private resolveLegacyAuthCacheWaiters(\n cacheKey: string | void,\n err: VerdaccioError | null,\n user?: RemoteUser\n ): void {\n if (!cacheKey) {\n return;\n }\n\n const waiters = this.legacyAuthCacheWaiters.get(cacheKey);\n this.legacyAuthCacheWaiters.delete(cacheKey);\n if (!waiters) {\n return;\n }\n\n for (const waiter of waiters) {\n waiter(err, user);\n }\n }\n\n private isLegacyAuthCacheEnabled(): boolean {\n // opt-in: disabled unless explicitly turned on via config\n return this.config.server?.legacyAuthCache?.enabled === true;\n }\n\n private getLegacyAuthCacheTtlMs(): number {\n const ttlMs = this.config.server?.legacyAuthCache?.ttlMs;\n return typeof ttlMs === 'number' && ttlMs > 0 ? ttlMs : 30 * 1000;\n }\n\n private getLegacyAuthCacheMaxEntries(): number {\n const maxEntries = this.config.server?.legacyAuthCache?.maxEntries;\n return typeof maxEntries === 'number' && maxEntries > 0 ? maxEntries : 1000;\n }\n\n private getLegacyAuthCacheKey(authorization: string): string | void {\n if (!this.isLegacyAuthCacheEnabled()) {\n return;\n }\n\n const { scheme } = parseAuthTokenHeader(authorization);\n if (scheme.toUpperCase() !== TOKEN_BEARER.toUpperCase()) {\n return;\n }\n\n return createHash(SHA256_ALGORITHM).update(authorization).digest('hex');\n }\n\n private getLegacyAuthCacheEntry(cacheKey: string | void): RemoteUser | void {\n if (!cacheKey) {\n return;\n }\n\n const entry = this.legacyAuthCache.get(cacheKey);\n if (!entry) {\n return;\n }\n\n if (entry.expiresAt <= Date.now()) {\n this.legacyAuthCache.delete(cacheKey);\n return;\n }\n\n this.legacyAuthCache.delete(cacheKey);\n this.legacyAuthCache.set(cacheKey, entry);\n return cloneRemoteUser(entry.user);\n }\n\n private setLegacyAuthCacheEntry(cacheKey: string | void, user: RemoteUser): void {\n if (!cacheKey) {\n return;\n }\n\n this.legacyAuthCache.set(cacheKey, {\n expiresAt: Date.now() + this.getLegacyAuthCacheTtlMs(),\n user: cloneRemoteUser(user),\n });\n\n const maxEntries = this.getLegacyAuthCacheMaxEntries();\n while (this.legacyAuthCache.size > maxEntries) {\n const oldestKey = this.legacyAuthCache.keys().next().value;\n if (!oldestKey) {\n break;\n }\n this.legacyAuthCache.delete(oldestKey);\n }\n }\n\n private _isRemoteUserValid(remote_user?: RemoteUser): boolean {\n return isUndefined(remote_user) === false && isUndefined(remote_user?.name) === false;\n }\n\n /**\n * JWT middleware for WebUI\n */\n public webUIJWTmiddleware() {\n return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction): void => {\n if (this._isRemoteUserValid(req.remote_user)) {\n return _next();\n }\n\n req.pause();\n const next = (err: VerdaccioError | void): void => {\n req.resume();\n if (err) {\n req.remote_user.error = err.message;\n res.status(err.statusCode).send(err.message);\n }\n\n return _next();\n };\n\n const { authorization } = req.headers;\n if (isNil(authorization)) {\n req.remote_user = createAnonymousRemoteUser();\n return next();\n }\n\n if (!isAuthHeaderValid(authorization)) {\n return next(errorUtils.getBadRequest(API_ERROR.BAD_AUTH_HEADER));\n }\n\n const token = (authorization || '').replace(`${TOKEN_BEARER} `, '');\n if (!token) {\n return next();\n }\n\n let credentials: RemoteUser | undefined;\n try {\n credentials = verifyJWTPayload(token, this.config.secret, this.config.security);\n } catch {\n // FIXME: intended behaviour, do we want it?\n }\n\n if (this._isRemoteUserValid(credentials)) {\n const { name, groups } = credentials as RemoteUser;\n req.remote_user = createRemoteUser(name as string, groups);\n } else {\n req.remote_user = createAnonymousRemoteUser();\n }\n\n next();\n };\n }\n\n public async jwtEncrypt(user: RemoteUser, signOptions: JWTSignOptions): Promise<string> {\n const { real_groups, name, groups, token: tokenMetadata } = user;\n debug('jwt encrypt %o', name);\n const realGroupsValidated = isNil(real_groups) ? [] : real_groups;\n const groupedGroups = isNil(groups)\n ? real_groups\n : Array.from(new Set([...groups.concat(realGroupsValidated)]));\n const payload: RemoteUser = {\n real_groups: realGroupsValidated,\n name,\n groups: groupedGroups,\n };\n if (tokenMetadata?.key) {\n payload.token = { key: tokenMetadata.key };\n }\n const signedToken: string = await signPayload(\n payload,\n this.secret,\n signOptions as Parameters<typeof signPayload>[2]\n );\n\n return signedToken;\n }\n\n /**\n * Encrypt a string.\n */\n public aesEncrypt(value: string): string | void {\n debug('signing with aes encryption');\n const token = aesEncrypt(value, this.secret);\n return token;\n }\n}\n\nexport { Auth };\n"],"mappings":";;;;;;;;;;;;AAgDA,IAAM,WAAA,GAAQ,MAAA,QAAA,CAAW,gBAAgB;AAQzC,SAAS,gBAAgB,MAA8B;CACrD,OAAO;EACL,GAAG;EACH,QAAQ,KAAK,SAAS,CAAC,GAAG,KAAK,MAAM,IAAI,KAAK;EAC9C,aAAa,KAAK,cAAc,CAAC,GAAG,KAAK,WAAW,IAAI,KAAK;EAC7D,OAAO,KAAK,QAAQ,EAAE,GAAG,KAAK,MAAM,IAAI,KAAK;CAC/C;AACF;AAEA,IAAM,OAAN,MAA+E;CAC7E;CACA;CACA;CACA;CACA;CACA;CACA;CAEA,YAAmB,QAAgB,QAAgB,UAAU,EAAE,oBAAoB,MAAM,GAAG;EAC1F,KAAK,SAAS;EACd,KAAK,SAAS,OAAO;EACrB,KAAK,SAAS;EACd,KAAK,UAAU,CAAC;EAChB,KAAK,UAAU;EACf,KAAK,kCAAkB,IAAI,IAAI;EAC/B,KAAK,yCAAyB,IAAI,IAAI;EACtC,IAAI,CAAC,KAAK,QACR,MAAM,IAAI,UAAU,0DAA0D;CAElF;CAEA,MAAa,OAAO;EAClB,IAAI,UAAU,MAAM,KAAK,WAAW;EAEpC,QAAM,yBAAyB,QAAQ,MAAM;EAG7C,IAAI,KAAK,OAAO,SAAS,SAAS,CAAC,WAAW,QAAQ,WAAW,IAC/D,UAAU,KAAK,kBAAkB;EAEnC,KAAK,UAAU;EAEf,KAAK,2BAA2B;CAClC;CAEA,oBAA4B;EAC1B,QAAM,0BAA0B;EAChC,IAAI;EACJ,IAAI;GACF,aAAa,IAAI,mBAAA,SACf,EAAE,MAAM,aAAa,GACrB;IACE,QAAQ,KAAK;IACb,QAAQ,KAAK;GACf,CACF;GACA,KAAK,OAAO,KACV;IAAE,MAAM;IAAsB,gBAAgB,gBAAA,gBAAgB;GAAe,GAC7E,wDACF;EACF,SAAS,OAAY;GACnB,QAAM,mDAAmD,KAAK;GAC9D,KAAK,OAAO,KAAK,CAAC,GAAG,+BAA+B;GACpD,OAAO,CAAC;EACV;EAEA,OAAO,CAAC,UAAU;CACpB;CAEA,MAAc,aAAa;EACzB,QAAA,GAAO,mBAAA,gBAAA,CACL,KAAK,OAAO,MACZ;GACE,QAAQ,KAAK;GACb,QAAQ,KAAK;EACf,GACA,gBAAA,YAAa,iBACb,KAAK,QAAQ,oBACb,KAAK,QAAQ,QAAQ,gBAAgB,gBAAA,eACrC,gBAAA,gBAAgB,cAClB;CACF;CAEA,6BAA2C;EACzC,KAAK,QAAQ,KAAK,cAAA,wBAAwB,KAAK,MAAM,CAAC;CACxD;CAEA,eACE,UACA,UACA,aACA,IACM;EACN,MAAM,gBAAA,GAAe,UAAA,OAAA,CACnB,KAAK,UACJ,WAAW,OAAO,OAAO,mBAAmB,UAC/C;EAEA,KAAA,GAAI,UAAA,QAAA,CAAQ,YAAY,GACtB,OAAO,GAAG,gBAAA,WAAW,iBAAiB,gBAAA,eAAe,wBAAwB,CAAC;EAGhF,KAAK,MAAM,UAAU,cACnB,KAAA,GAAI,UAAA,MAAA,CAAM,MAAM,KAAK,OAAO,OAAO,mBAAmB,YAAY;GAChE,QAAM,gEAAgE;GACtE;EACF,OAAO;GACL,QAAM,4BAA4B,QAAQ;GAC1C,OAAO,eAAgB,UAAU,UAAU,cAAc,KAAK,YAAkB;IAC9E,IAAI,KAAK;KACP,KAAK,OAAO,MACV;MAAE;MAAU;KAAI,GAChB;yEAEF;KACA,OAAO,GAAG,GAAG;IACf;IAEA,QAAM,0CAA0C,QAAQ;IACxD,OAAO,GAAG,MAAM,OAAO;GACzB,CAAC;EACH;CAEJ;CAEA,MAAa,gBAAgB,OAAe;EAE1C,QAAQ,IAAI,yCAAyC,KAAK;EAC1D,OAAO,QAAQ,QAAQ;CACzB;CAEA,aACE,UACA,UACA,IACM;EACN,MAAM,UAAU,KAAK,QAAQ,MAAM,CAAC;EACpC,CAAC,SAAS,OAAa;GACrB,MAAM,SAAS,QAAQ,MAAM;GAE7B,IAAI,OAAO,QAAQ,iBAAiB,YAClC,OAAO,KAAK;GAGd,QAAM,qBAAqB,QAAQ;GACnC,OAAO,aAAa,UAAU,UAAU,SAAU,KAA4B,QAAc;IAC1F,IAAI,KAAK;KACP,QAAM,gDAAgD,UAAU,KAAK,OAAO;KAC5E,OAAO,GAAG,GAAG;IACf;IASA,IAAI,CAAC,CAAC,UAAU,OAAO,WAAW,GAAG;KAEnC,IAAI,OAAO,WAAW,UACpB,MAAM,IAAI,UAAU,+CAA+C;KAGrE,IAAI,CAD0B,MAAM,QAAQ,MACvC,GACH,MAAM,IAAI,UAAU,gBAAA,UAAU,qBAAqB;KAGrD,QAAM,2DAA2D,UAAU,MAAM;KACjF,OAAO,GAAG,MAAA,GAAK,kBAAA,iBAAA,CAAiB,UAAU,MAAM,CAAC;IACnD;IACA,KAAK;GACP,CAAC;EACH,EAAA,CAAG;CACL;CAEA,SACE,MACA,UACA,IACM;EACN,MAAM,OAAO;EACb,MAAM,UAAU,KAAK,QAAQ,MAAM,CAAC;EACpC,QAAM,eAAe,IAAI;EAEzB,CAAC,SAAS,OAAa;GACrB,IAAI,SAAS;GACb,MAAM,SAAS,QAAQ,MAAM;GAE7B,IAAI,OAAO,OAAO,YAAY,eAAe,OAAO,OAAO,aAAa,YAAY;IAClF,SAAS;IACT,gBAAA,aAAa,KAAK,gBAAA,aAAa,MAAM,SAAS;GAChD;GAEA,IAAI,OAAO,OAAO,YAAY,YAC5B,KAAK;QAIL,OAAO,OAAO,CACZ,MACA,UACA,SAAU,KAA4B,IAA6B;IACjE,IAAI,KAAK;KACP,QAAM,6CAA6C,MAAM,KAAK,OAAO;KACrE,OAAO,GAAG,GAAG;IACf;IACA,IAAI,IAAI;KACN,QAAM,8BAA8B,IAAI;KACxC,OAAO,KAAK,aAAa,MAAM,UAAU,EAAE;IAC7C;IACA,QAAM,mDAAmD;IACzD,KAAK;GACP,CACF;EAEJ,EAAA,CAAG;CACL;;;;CAKA,aACE,EAAE,aAAa,kBACf,MACA,UACM;EACN,MAAM,UAAU,KAAK,QAAQ,MAAM,CAAC;EACpC,MAAM,MAAM,OAAO,OACjB;GAAE,MAAM;GAAa,SAAS;EAAe,GAC7C,gBAAA,UAAU,uBAAuB,aAAa,KAAK,OAAO,QAAQ,CACpE;EAEA,QAAM,sDAAsD,KAAK,MAAM,WAAW;EAGlF,MAAM,aAAmB;GACvB,MAAM,SAAS,QAAQ,MAAM;GAE7B,IAAI,OAAO,QAAQ,iBAAiB,YAAY;IAC9C,QAAM,wCAAwC;IAC9C,OAAO,KAAK;GACd;GAEA,OAAO,aAAa,MAAM,MAAM,KAA4B,OAAuB;IACjF,IAAI,KAAK;KACP,QAAM,+BAA+B,GAAG;KACxC,OAAO,SAAS,GAAG;IACrB;IAEA,IAAI,IAAI;KACN,QAAM,oBAAoB;KAC1B,KAAK,OAAO,MACV;MAAE,MAAM,KAAK;MAAM,MAAM,IAAI;KAAK,GAClC,2CACF;KACA,OAAO,SAAS,MAAM,EAAE;IAC1B;IAGA,QAAM,2CAA2C;IACjD,KAAK,OAAO,MACV;KAAE,MAAM,KAAK;KAAM,MAAM,IAAI;IAAK,GAClC,2EACF;IACA,OAAO,KAAK;GACd,CAAC;EACH;EAEA,OAAO,KAAK;CACd;CAEA,gBACE,EAAE,aAAa,kBACf,MACA,UACM;EACN,MAAM,UAAU,KAAK,QAAQ,MAAM,CAAC;EACpC,MAAM,MAAM,OAAO,OACjB;GAAE,MAAM;GAAa,SAAS;EAAe,GAC7C,gBAAA,UAAU,uBAAuB,aAAa,KAAK,OAAO,QAAQ,CACpE;EAEA,QAAM,yDAAyD,KAAK,MAAM,WAAW;EAGrF,MAAM,aAAmB;GACvB,MAAM,SAAS,QAAQ,MAAM;GAE7B,IAAI,OAAO,QAAQ,oBAAoB,YAAY;IACjD,QAAM,2CAA2C;IACjD,OAAO,KAAK;GACd;GAEA,OAAO,gBAAgB,MAAM,MAAM,KAA4B,OAAuB;IACpF,IAAI,KAAK;KACP,QAAM,kCAAkC,GAAG;KAC3C,OAAO,SAAS,GAAG;IACrB;IAMA,KAAA,GAAI,UAAA,MAAA,CAAM,EAAE,MAAM,MAAM;KACtB,QAAM,2DAA2D,WAAW;KAC5E,KAAK,OAAO,MACV;MAAE,MAAM,KAAK;MAAM,MAAM,IAAI;KAAK,GAClC,yEACF;KACA,OAAO,KAAK,cAAc;MAAE;MAAa;KAAe,GAAG,MAAM,QAAQ;IAC3E;IAEA,IAAI,IAAI;KACN,QAAM,uBAAuB;KAC7B,KAAK,OAAO,MACV;MAAE,MAAM,KAAK;MAAM,MAAM,IAAI;KAAK,GAClC,8CACF;KACA,OAAO,SAAS,MAAM,EAAE;IAC1B;IAGA,QAAM,8CAA8C;IACpD,KAAK,OAAO,MACV;KAAE,MAAM,KAAK;KAAM,MAAM,IAAI;IAAK,GAClC,8EACF;IACA,OAAO,KAAK;GACd,CAAC;EACH;EAEA,OAAO,KAAK;CACd;;;;;;;;;;;;CAaA,YACE,EAAE,aAAa,kBACf,MACA,UACM;EACN,MAAM,UAAU,KAAK,QAAQ,MAAM,CAAC;EACpC,MAAM,MAAM,OAAO,OACjB;GAAE,MAAM;GAAa,SAAS;EAAe,GAC7C,gBAAA,UAAU,uBAAuB,aAAa,KAAK,OAAO,QAAQ,CACpE;EAEA,QAAM,qDAAqD,KAAK,MAAM,WAAW;EAEjF,MAAM,aAAmB;GACvB,MAAM,SAAS,QAAQ,MAAM;GAE7B,IAAI,OAAO,QAAQ,gBAAgB,YAAY;IAC7C,QAAM,uCAAuC;IAC7C,OAAO,KAAK;GACd;GAEA,OAAO,YAAY,MAAM,MAAM,KAA4B,OAAuB;IAChF,IAAI,KAAK;KACP,QAAM,8BAA8B,GAAG;KACvC,OAAO,SAAS,GAAG;IACrB;IAIA,KAAA,GAAI,UAAA,MAAA,CAAM,EAAE,MAAM,MAAM;KACtB,QAAM,uDAAuD,WAAW;KACxE,KAAK,OAAO,MACV;MAAE,MAAM,KAAK;MAAM,MAAM,IAAI;KAAK,GAClC,qEACF;KACA,OAAO,KAAK,cAAc;MAAE;MAAa;KAAe,GAAG,MAAM,QAAQ;IAC3E;IAEA,IAAI,IAAI;KACN,QAAM,mBAAmB;KACzB,KAAK,OAAO,MACV;MAAE,MAAM,KAAK;MAAM,MAAM,IAAI;KAAK,GAClC,0CACF;KACA,OAAO,SAAS,MAAM,EAAE;IAC1B;IAGA,QAAM,0CAA0C;IAChD,OAAO,KAAK;GACd,CAAC;EACH;EAEA,OAAO,KAAK;CACd;;;;CAKA,cACE,EAAE,aAAa,kBACf,MACA,UACM;EACN,MAAM,UAAU,KAAK,QAAQ,MAAM,CAAC;EACpC,MAAM,MAAM,OAAO,OACjB;GAAE,MAAM;GAAa,SAAS;EAAe,GAC7C,gBAAA,UAAU,uBAAuB,aAAa,KAAK,OAAO,QAAQ,CACpE;EAEA,QAAM,uDAAuD,KAAK,MAAM,WAAW;EAGnF,MAAM,aAAmB;GACvB,MAAM,SAAS,QAAQ,MAAM;GAE7B,IAAI,OAAO,QAAQ,kBAAkB,YAAY;IAC/C,QAAM,yCAAyC;IAC/C,OAAO,KAAK;GACd;GAEA,OAAO,cAAc,MAAM,MAAM,KAA4B,OAAuB;IAClF,IAAI,KAAK;KACP,QAAM,gCAAgC,GAAG;KACzC,OAAO,SAAS,GAAG;IACrB;IAEA,IAAI,IAAI;KACN,QAAM,qBAAqB;KAC3B,KAAK,OAAO,MACV;MAAE,MAAM,KAAK;MAAM,MAAM,IAAI;KAAK,GAClC,4CACF;KACA,OAAO,SAAS,MAAM,EAAE;IAC1B;IAGA,QAAM,4CAA4C;IAClD,KAAK,OAAO,MACV;KAAE,MAAM,KAAK;KAAM,MAAM,IAAI;IAAK,GAClC,4EACF;IACA,OAAO,KAAK;GACd,CAAC;EACH;EAEA,OAAO,KAAK;CACd;CAEA,mBAA+B;EAC7B,QAAM,gBAAgB;EACtB,MAAM,UAAU,KAAK,QAAQ,MAAM,CAAC;EACpC,MAAM,UAAU;GAAE,2BAAA,kBAAA;GAA2B,kBAAA,kBAAA;EAAiB;EAC9D,KAAK,MAAM,UAAU,SACnB,IAAI,OAAO,kBACT,OAAO,OAAO,iBAAiB,OAAO;EAI1C,QAAQ,KAAqB,KAAsB,UAAwB;GACzE,IAAI,MAAM;GACV,MAAM,OAAO,SAAU,KAAoC;IACzD,IAAI,OAAO;IACX,IAAI,KACF,OAAO,MAAM,GAAG;IAGlB,OAAO,MAAM;GACf;GASA,MAAM,cAAA,GAAa,kBAAA,0BAAA,CAA0B;GAC7C,IAAI,cAAc;GAClB,IAAI,OAAO,cAAc;GAEzB,MAAM,EAAE,kBAAkB,IAAI;GAC9B,KAAA,GAAI,UAAA,MAAA,CAAM,aAAa,GAAG;IACxB,QAAM,uCAAuC;IAC7C,OAAO,KAAK;GACd;GAEA,IAAI,CAAC,cAAA,kBAAkB,aAAa,GAAG;IACrC,QAAM,kDAAkD;IACxD,OAAO,KAAK,gBAAA,WAAW,cAAc,gBAAA,UAAU,eAAe,CAAC;GACjE;GACA,MAAM,EAAE,QAAQ,aAAa,KAAK;GAElC,IAAI,cAAA,YAAY,QAAQ,GAAG;IACzB,QAAM,wCAAwC;IAC9C,KAAK,oBAAoB,KAAK,UAAU,QAAQ,eAAe,IAAI;GACrE,OAAO;IACL,QAAM,qCAAqC;IAC3C,KAAK,uBAAuB,KAAK,UAAU,QAAQ,eAAe,IAAI;GACxE;EACF;CACF;CAEA,uBACE,KACA,UACA,QACA,eACA,MACM;EACN,QAAM,2BAA2B;EACjC,MAAM,cAAmB,cAAA,yBAAyB,UAAU,QAAQ,aAAa;EACjF,IAAI,aAAa;GAEf,IAAI,cAAc;GAClB,QAAM,0BAA0B;GAChC,KAAK;EACP,OAAO;GAEL,QAAM,mBAAmB;GACzB,KAAK,gBAAA,WAAW,gBAAgB,gBAAA,UAAU,qBAAqB,CAAC;EAClE;CACF;CAEA,oBACE,KACA,UACA,QACA,eACA,MACM;EACN,QAAM,8BAA8B;EACpC,QAAM,mCAAmC,OAAO,WAAW,QAAQ;EACnE,QAAM,mCAAmC,OAAO,kBAAkB,QAAQ;EAC1E,MAAM,cAAmB,cAAA,yBAAyB,UAAU,QAAQ,aAAa;EACjF,QAAM,iCAAiC,aAAa,IAAI;EACxD,IAAI,aAAa;GACf,MAAM,WAAW,KAAK,sBAAsB,aAAa;GACzD,MAAM,aAAa,KAAK,wBAAwB,QAAQ;GACxD,IAAI,YAAY;IACd,IAAI,cAAc;IAClB,QAAM,+BAA+B;IACrC,OAAO,KAAK;GACd;GAEA,MAAM,EAAE,MAAM,aAAa;GAC3B,MAAM,mBAAmB,KAA4B,SAA4B;IAC/E,IAAI,CAAC,OAAO,MAAM;KAChB,IAAI,cAAc,YAAY,WAC1B;MAAE,GAAG;MAAM,OAAO,EAAE,KAAK,YAAY,SAAS;KAAE,IAChD;KACJ,QAAM,0BAA0B;KAChC,KAAK;IACP,OAAO;KACL,IAAI,eAAA,GAAc,kBAAA,0BAAA,CAA0B;KAC5C,QAAM,2BAA2B;KACjC,KAAK,OAAO,gBAAA,WAAW,gBAAgB,gBAAA,UAAU,qBAAqB,CAAC;IACzE;GACF;GAEA,IAAI,KAAK,6BAA6B,UAAU,eAAe,GAC7D;GAGF,QAAM,qBAAqB,IAAI;GAC/B,MAAM,kBAAkB,KAA4B,SAA4B;IAE9E,IAAI,CAAC,OAAO,MACV,KAAK,wBACH,UACA,YAAY,WAAW;KAAE,GAAG;KAAM,OAAO,EAAE,KAAK,YAAY,SAAS;IAAE,IAAI,IAC7E;IAEF,gBAAgB,KAAK,IAAI;IACzB,KAAK,8BAA8B,UAAU,KAAK,IAAI;GACxD;GACA,IAAI;IACF,KAAK,aAAa,MAAM,UAAU,cAAc;GAClD,SAAS,KAAU;IACjB,eAAe,gBAAA,WAAW,iBAAiB,KAAK,OAAO,CAAC;GAC1D;EACF,OAAO;GACL,MAAM,aAAa,KAAK,2BAA2B,aAAa;GAChE,IAAI,YAAY;IACd,IAAI,cAAc;IAClB,QAAM,0CAA0C;IAChD,OAAO,KAAK;GACd;GAEA,QAAM,uBAAuB;GAC7B,OAAO,KAAK,gBAAA,WAAW,gBAAgB,gBAAA,UAAU,qBAAqB,CAAC;EACzE;CACF;CAEA,2BAAmC,eAA0C;EAC3E,MAAM,EAAE,QAAQ,UAAU,cAAA,qBAAqB,aAAa;EAC5D,IAAI,OAAO,YAAY,MAAM,gBAAA,aAAa,YAAY,KAAK,CAAC,OAC1D;EAGF,IAAI;EACJ,IAAI;GACF,cAAc,cAAA,iBAAiB,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAO,QAAQ;EAChF,QAAQ;GACN;EACF;EAEA,IAAI,KAAK,mBAAmB,WAAW,GAAG;GACxC,MAAM,EAAE,MAAM,WAAW;GACzB,QAAA,GAAO,kBAAA,iBAAA,CAAiB,MAAgB,MAAM;EAChD;CACF;CAEA,6BACE,UACA,QACS;EACT,IAAI,CAAC,UACH,OAAO;EAGT,MAAM,UAAU,KAAK,uBAAuB,IAAI,QAAQ;EACxD,IAAI,CAAC,SAAS;GACZ,KAAK,uBAAuB,IAAI,UAAU,CAAC,CAAC;GAC5C,OAAO;EACT;EAEA,QAAQ,KAAK,MAAM;EACnB,OAAO;CACT;CAEA,8BACE,UACA,KACA,MACM;EACN,IAAI,CAAC,UACH;EAGF,MAAM,UAAU,KAAK,uBAAuB,IAAI,QAAQ;EACxD,KAAK,uBAAuB,OAAO,QAAQ;EAC3C,IAAI,CAAC,SACH;EAGF,KAAK,MAAM,UAAU,SACnB,OAAO,KAAK,IAAI;CAEpB;CAEA,2BAA4C;EAE1C,OAAO,KAAK,OAAO,QAAQ,iBAAiB,YAAY;CAC1D;CAEA,0BAA0C;EACxC,MAAM,QAAQ,KAAK,OAAO,QAAQ,iBAAiB;EACnD,OAAO,OAAO,UAAU,YAAY,QAAQ,IAAI,QAAQ;CAC1D;CAEA,+BAA+C;EAC7C,MAAM,aAAa,KAAK,OAAO,QAAQ,iBAAiB;EACxD,OAAO,OAAO,eAAe,YAAY,aAAa,IAAI,aAAa;CACzE;CAEA,sBAA8B,eAAsC;EAClE,IAAI,CAAC,KAAK,yBAAyB,GACjC;EAGF,MAAM,EAAE,WAAW,cAAA,qBAAqB,aAAa;EACrD,IAAI,OAAO,YAAY,MAAM,gBAAA,aAAa,YAAY,GACpD;EAGF,QAAA,GAAO,YAAA,WAAA,CAAW,cAAA,gBAAgB,CAAC,CAAC,OAAO,aAAa,CAAC,CAAC,OAAO,KAAK;CACxE;CAEA,wBAAgC,UAA4C;EAC1E,IAAI,CAAC,UACH;EAGF,MAAM,QAAQ,KAAK,gBAAgB,IAAI,QAAQ;EAC/C,IAAI,CAAC,OACH;EAGF,IAAI,MAAM,aAAa,KAAK,IAAI,GAAG;GACjC,KAAK,gBAAgB,OAAO,QAAQ;GACpC;EACF;EAEA,KAAK,gBAAgB,OAAO,QAAQ;EACpC,KAAK,gBAAgB,IAAI,UAAU,KAAK;EACxC,OAAO,gBAAgB,MAAM,IAAI;CACnC;CAEA,wBAAgC,UAAyB,MAAwB;EAC/E,IAAI,CAAC,UACH;EAGF,KAAK,gBAAgB,IAAI,UAAU;GACjC,WAAW,KAAK,IAAI,IAAI,KAAK,wBAAwB;GACrD,MAAM,gBAAgB,IAAI;EAC5B,CAAC;EAED,MAAM,aAAa,KAAK,6BAA6B;EACrD,OAAO,KAAK,gBAAgB,OAAO,YAAY;GAC7C,MAAM,YAAY,KAAK,gBAAgB,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;GACrD,IAAI,CAAC,WACH;GAEF,KAAK,gBAAgB,OAAO,SAAS;EACvC;CACF;CAEA,mBAA2B,aAAmC;EAC5D,QAAA,GAAO,UAAA,YAAA,CAAY,WAAW,MAAM,UAAA,GAAS,UAAA,YAAA,CAAY,aAAa,IAAI,MAAM;CAClF;;;;CAKA,qBAA4B;EAC1B,QAAQ,KAAqB,KAAsB,UAA8B;GAC/E,IAAI,KAAK,mBAAmB,IAAI,WAAW,GACzC,OAAO,MAAM;GAGf,IAAI,MAAM;GACV,MAAM,QAAQ,QAAqC;IACjD,IAAI,OAAO;IACX,IAAI,KAAK;KACP,IAAI,YAAY,QAAQ,IAAI;KAC5B,IAAI,OAAO,IAAI,UAAU,CAAC,CAAC,KAAK,IAAI,OAAO;IAC7C;IAEA,OAAO,MAAM;GACf;GAEA,MAAM,EAAE,kBAAkB,IAAI;GAC9B,KAAA,GAAI,UAAA,MAAA,CAAM,aAAa,GAAG;IACxB,IAAI,eAAA,GAAc,kBAAA,0BAAA,CAA0B;IAC5C,OAAO,KAAK;GACd;GAEA,IAAI,CAAC,cAAA,kBAAkB,aAAa,GAClC,OAAO,KAAK,gBAAA,WAAW,cAAc,gBAAA,UAAU,eAAe,CAAC;GAGjE,MAAM,SAAS,iBAAiB,GAAA,CAAI,QAAQ,GAAG,gBAAA,aAAa,IAAI,EAAE;GAClE,IAAI,CAAC,OACH,OAAO,KAAK;GAGd,IAAI;GACJ,IAAI;IACF,cAAc,cAAA,iBAAiB,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAO,QAAQ;GAChF,QAAQ,CAER;GAEA,IAAI,KAAK,mBAAmB,WAAW,GAAG;IACxC,MAAM,EAAE,MAAM,WAAW;IACzB,IAAI,eAAA,GAAc,kBAAA,iBAAA,CAAiB,MAAgB,MAAM;GAC3D,OACE,IAAI,eAAA,GAAc,kBAAA,0BAAA,CAA0B;GAG9C,KAAK;EACP;CACF;CAEA,MAAa,WAAW,MAAkB,aAA8C;EACtF,MAAM,EAAE,aAAa,MAAM,QAAQ,OAAO,kBAAkB;EAC5D,QAAM,kBAAkB,IAAI;EAC5B,MAAM,uBAAA,GAAsB,UAAA,MAAA,CAAM,WAAW,IAAI,CAAC,IAAI;EAItD,MAAM,UAAsB;GAC1B,aAAa;GACb;GACA,SAAA,GANoB,UAAA,MAAA,CAAM,MAAM,IAC9B,cACA,MAAM,qBAAK,IAAI,IAAI,CAAC,GAAG,OAAO,OAAO,mBAAmB,CAAC,CAAC,CAAC;EAK/D;EACA,IAAI,eAAe,KACjB,QAAQ,QAAQ,EAAE,KAAK,cAAc,IAAI;EAQ3C,OAAO,OAAA,GAN2B,qBAAA,YAAA,CAChC,SACA,KAAK,QACL,WACF;CAGF;;;;CAKA,WAAkB,OAA8B;EAC9C,QAAM,6BAA6B;EAEnC,QAAA,GADc,qBAAA,WAAA,CAAW,OAAO,KAAK,MAC9B;CACT;AACF"}
|
package/build/auth.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getDefaultPluginMethods, getMiddlewareCredentials, isAESLegacy, isAuthHeaderValid, parseAuthTokenHeader, verifyJWTPayload } from "./utils.mjs";
|
|
1
|
+
import { SHA256_ALGORITHM, getDefaultPluginMethods, getMiddlewareCredentials, isAESLegacy, isAuthHeaderValid, parseAuthTokenHeader, verifyJWTPayload } from "./utils.mjs";
|
|
2
2
|
import buildDebug from "debug";
|
|
3
3
|
import { filter, isEmpty, isNil, isUndefined } from "lodash-es";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
@@ -230,6 +230,60 @@ var Auth = class {
|
|
|
230
230
|
return next();
|
|
231
231
|
}
|
|
232
232
|
/**
|
|
233
|
+
* Allow a user to submit a package version for review (`npm stage publish`).
|
|
234
|
+
*
|
|
235
|
+
* Deliberately a weaker capability than publishing: granting `stage` to a
|
|
236
|
+
* group that lacks `publish` is what turns staging into a real review gate,
|
|
237
|
+
* because those users can propose a release but not make one.
|
|
238
|
+
*
|
|
239
|
+
* When the packages configuration says nothing about `stage`, the built-in
|
|
240
|
+
* plugin answers `undefined` and this falls back to `allow_publish`, so
|
|
241
|
+
* existing configurations behave exactly as before.
|
|
242
|
+
*/
|
|
243
|
+
allow_stage({ packageName, packageVersion }, user, callback) {
|
|
244
|
+
const plugins = this.plugins.slice(0);
|
|
245
|
+
const pkg = Object.assign({
|
|
246
|
+
name: packageName,
|
|
247
|
+
version: packageVersion
|
|
248
|
+
}, authUtils.getMatchedPackagesSpec(packageName, this.config.packages));
|
|
249
|
+
debug("check stage permissions for user %o to package %o", user.name, packageName);
|
|
250
|
+
const next = () => {
|
|
251
|
+
const plugin = plugins.shift();
|
|
252
|
+
if (typeof plugin?.allow_stage !== "function") {
|
|
253
|
+
debug("plugin does not implement allow_stage");
|
|
254
|
+
return next();
|
|
255
|
+
}
|
|
256
|
+
plugin.allow_stage(user, pkg, (err, ok) => {
|
|
257
|
+
if (err) {
|
|
258
|
+
debug("forbidden stage. Error: %o", err);
|
|
259
|
+
return callback(err);
|
|
260
|
+
}
|
|
261
|
+
if (isNil(ok) === true) {
|
|
262
|
+
debug("bypass stage for %o, publish will handle the access", packageName);
|
|
263
|
+
this.logger.trace({
|
|
264
|
+
user: user.name,
|
|
265
|
+
name: pkg.name
|
|
266
|
+
}, `bypass stage for @{name} by @{user}, publish will handle the access`);
|
|
267
|
+
return this.allow_publish({
|
|
268
|
+
packageName,
|
|
269
|
+
packageVersion
|
|
270
|
+
}, user, callback);
|
|
271
|
+
}
|
|
272
|
+
if (ok) {
|
|
273
|
+
debug("stage was granted");
|
|
274
|
+
this.logger.trace({
|
|
275
|
+
user: user.name,
|
|
276
|
+
name: pkg.name
|
|
277
|
+
}, `stage was granted for @{name} by @{user}`);
|
|
278
|
+
return callback(null, ok);
|
|
279
|
+
}
|
|
280
|
+
debug("stage was denied. Rolling to next plugin");
|
|
281
|
+
return next();
|
|
282
|
+
});
|
|
283
|
+
};
|
|
284
|
+
return next();
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
233
287
|
* Allow user to publish a package.
|
|
234
288
|
*/
|
|
235
289
|
allow_publish({ packageName, packageVersion }, user, callback) {
|
|
@@ -418,7 +472,7 @@ var Auth = class {
|
|
|
418
472
|
if (!this.isLegacyAuthCacheEnabled()) return;
|
|
419
473
|
const { scheme } = parseAuthTokenHeader(authorization);
|
|
420
474
|
if (scheme.toUpperCase() !== TOKEN_BEARER.toUpperCase()) return;
|
|
421
|
-
return createHash(
|
|
475
|
+
return createHash(SHA256_ALGORITHM).update(authorization).digest("hex");
|
|
422
476
|
}
|
|
423
477
|
getLegacyAuthCacheEntry(cacheKey) {
|
|
424
478
|
if (!cacheKey) return;
|
package/build/auth.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.mjs","names":[],"sources":["../src/auth.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { filter, isEmpty, isNil, isUndefined } from 'lodash-es';\nimport { createHash } from 'node:crypto';\nimport { HTPasswd } from 'verdaccio-htpasswd';\n\nimport { createAnonymousRemoteUser, createRemoteUser } from '@verdaccio/config';\nimport type { VerdaccioError, pluginUtils } from '@verdaccio/core';\nimport {\n API_ERROR,\n PLUGIN_CATEGORY,\n PLUGIN_PREFIX,\n SUPPORT_ERRORS,\n TOKEN_BEARER,\n authUtils,\n errorUtils,\n pluginUtils as pluginSanity,\n warningUtils,\n} from '@verdaccio/core';\nimport { asyncLoadPlugin } from '@verdaccio/loaders';\nimport { aesEncrypt, signPayload } from '@verdaccio/signature';\nimport type {\n AllowAccess,\n Callback,\n Config,\n JWTSignOptions,\n Logger,\n PackageAccess,\n RemoteUser,\n Security,\n} from '@verdaccio/types';\n\nimport type {\n $RequestExtend,\n $ResponseExtend,\n IAuthMiddleware,\n NextFunction,\n TokenEncryption,\n} from './types';\nimport {\n getDefaultPluginMethods,\n getMiddlewareCredentials,\n isAESLegacy,\n isAuthHeaderValid,\n parseAuthTokenHeader,\n verifyJWTPayload,\n} from './utils';\n\nconst debug = buildDebug('verdaccio:auth');\ntype LegacyAuthCacheEntry = {\n expiresAt: number;\n user: RemoteUser;\n};\n\ntype LegacyAuthCacheWaiter = (err: VerdaccioError | null, user?: RemoteUser) => void;\n\nfunction cloneRemoteUser(user: RemoteUser): RemoteUser {\n return {\n ...user,\n groups: user.groups ? [...user.groups] : user.groups,\n real_groups: user.real_groups ? [...user.real_groups] : user.real_groups,\n token: user.token ? { ...user.token } : user.token,\n };\n}\n\nclass Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {\n public config: Config;\n public secret: string;\n public logger: Logger;\n public plugins: pluginUtils.Auth<Config>[];\n public options: { legacyMergeConfigs: boolean };\n private legacyAuthCache: Map<string, LegacyAuthCacheEntry>;\n private legacyAuthCacheWaiters: Map<string, LegacyAuthCacheWaiter[]>;\n\n public constructor(config: Config, logger: Logger, options = { legacyMergeConfigs: false }) {\n this.config = config;\n this.secret = config.secret;\n this.logger = logger;\n this.plugins = [];\n this.options = options;\n this.legacyAuthCache = new Map();\n this.legacyAuthCacheWaiters = new Map();\n if (!this.secret) {\n throw new TypeError('secret it is required value on initialize the auth class');\n }\n }\n\n public async init() {\n let plugins = await this.loadPlugin();\n\n debug('auth plugins found %s', plugins.length);\n // Missing auth config or no loaded plugins -> load default htpasswd plugin\n // Empty auth config (null) -> just use fallback methods\n if (this.config.auth !== null && (!plugins || plugins.length === 0)) {\n plugins = this.loadDefaultPlugin();\n }\n this.plugins = plugins;\n\n this.applyFallbackPluginMethods();\n }\n\n private loadDefaultPlugin() {\n debug('load default auth plugin');\n let authPlugin;\n try {\n authPlugin = new HTPasswd(\n { file: './htpasswd' },\n {\n config: this.config,\n logger: this.logger,\n }\n );\n this.logger.info(\n { name: 'verdaccio-htpasswd', pluginCategory: PLUGIN_CATEGORY.AUTHENTICATION },\n 'plugin @{name} successfully loaded (@{pluginCategory})'\n );\n } catch (error: any) {\n debug('error on loading auth htpasswd plugin stack: %o', error);\n this.logger.info({}, 'no auth plugin has been found');\n return [];\n }\n\n return [authPlugin];\n }\n\n private async loadPlugin() {\n return asyncLoadPlugin<pluginUtils.Auth<Config>>(\n this.config.auth,\n {\n config: this.config,\n logger: this.logger,\n },\n pluginSanity.authSanityCheck,\n this.options.legacyMergeConfigs,\n this.config?.server?.pluginPrefix ?? PLUGIN_PREFIX,\n PLUGIN_CATEGORY.AUTHENTICATION\n );\n }\n\n private applyFallbackPluginMethods(): void {\n this.plugins.push(getDefaultPluginMethods(this.logger));\n }\n\n public changePassword(\n username: string,\n password: string,\n newPassword: string,\n cb: Callback\n ): void {\n const validPlugins = filter(\n this.plugins,\n (plugin) => typeof plugin.changePassword === 'function'\n );\n\n if (isEmpty(validPlugins)) {\n return cb(errorUtils.getInternalError(SUPPORT_ERRORS.PLUGIN_MISSING_INTERFACE));\n }\n\n for (const plugin of validPlugins) {\n if (isNil(plugin) || typeof plugin.changePassword !== 'function') {\n debug('auth plugin does not implement changePassword, trying next one');\n continue;\n } else {\n debug('updating password for %o', username);\n plugin.changePassword!(username, password, newPassword, (err, profile): void => {\n if (err) {\n this.logger.error(\n { username, err },\n `An error has been produced\n updating the password for @{username}. Error: @{err.message}`\n );\n return cb(err);\n }\n\n debug('updated password for %o was successful', username);\n return cb(null, profile);\n });\n }\n }\n }\n\n public async invalidateToken(token: string) {\n // eslint-disable-next-line no-console\n console.log('invalidate token pending to implement', token);\n return Promise.resolve();\n }\n\n public authenticate(\n username: string,\n password: string,\n cb: (error: VerdaccioError | null, user?: RemoteUser) => void\n ): void {\n const plugins = this.plugins.slice(0);\n (function next(): void {\n const plugin = plugins.shift();\n\n if (typeof plugin?.authenticate !== 'function') {\n return next();\n }\n\n debug('authenticating %o', username);\n plugin.authenticate(username, password, function (err: VerdaccioError | null, groups): void {\n if (err) {\n debug('authenticating for user %o failed. Error: %o', username, err?.message);\n return cb(err);\n }\n\n // Expect: SKIP if groups is falsey and not an array\n // with at least one item (truthy length)\n // Expect: CONTINUE otherwise (will error if groups is not\n // an array, but this is current behavior)\n // Caveat: STRING (if valid) will pass successfully\n // bug give unexpected results\n // Info: Cannot use `== false to check falsey values`\n if (!!groups && groups.length !== 0) {\n // TODO: create a better understanding of expectations\n if (typeof groups === 'string') {\n throw new TypeError('plugin group error: invalid type for function');\n }\n const isGroupValid: boolean = Array.isArray(groups);\n if (!isGroupValid) {\n throw new TypeError(API_ERROR.BAD_FORMAT_USER_GROUP);\n }\n\n debug('authentication for user %o was successfully. Groups: %o', username, groups);\n return cb(err, createRemoteUser(username, groups));\n }\n next();\n });\n })();\n }\n\n public add_user(\n user: string,\n password: string,\n cb: (error: VerdaccioError | null, user?: RemoteUser) => void\n ): void {\n const self = this;\n const plugins = this.plugins.slice(0);\n debug('add user %o', user);\n\n (function next(): void {\n let method = 'adduser';\n const plugin = plugins.shift();\n // @ts-expect-error future major (7.x) should remove this section\n if (typeof plugin.adduser === 'undefined' && typeof plugin.add_user === 'function') {\n method = 'add_user';\n warningUtils.emit(warningUtils.Codes.VERWAR006);\n }\n // @ts-ignore\n if (typeof plugin[method] !== 'function') {\n next();\n } else {\n // TODO: replace by adduser whenever add_user deprecation method has been removed\n // @ts-ignore\n plugin[method](\n user,\n password,\n function (err: VerdaccioError | null, ok?: boolean | string): void {\n if (err) {\n debug('the user %o could not be added. Error: %o', user, err?.message);\n return cb(err);\n }\n if (ok) {\n debug('the user %o has been added', user);\n return self.authenticate(user, password, cb);\n }\n debug('user could not be added, skip to next auth plugin');\n next();\n }\n );\n }\n })();\n }\n\n /**\n * Allow user to access a package.\n */\n public allow_access(\n { packageName, packageVersion }: pluginUtils.AuthPluginPackage,\n user: RemoteUser,\n callback: pluginUtils.AccessCallback\n ): void {\n const plugins = this.plugins.slice(0);\n const pkg = Object.assign(\n { name: packageName, version: packageVersion },\n authUtils.getMatchedPackagesSpec(packageName, this.config.packages)\n ) as AllowAccess & PackageAccess;\n\n debug('check access permissions for user %o to package %o', user.name, packageName);\n\n // Use const instead of function declaration so we can use this.logger\n const next = (): void => {\n const plugin = plugins.shift();\n\n if (typeof plugin?.allow_access !== 'function') {\n debug('plugin does not implement allow_access');\n return next();\n }\n\n plugin.allow_access(user, pkg, (err: VerdaccioError | null, ok?: boolean): void => {\n if (err) {\n debug('forbidden access. Error: %o', err);\n return callback(err);\n }\n\n if (ok) {\n debug('access was granted');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `access was granted for @{name} by @{user}`\n );\n return callback(null, ok);\n }\n\n // cb(null, false) causes next plugin to roll\n debug('access was denied. Rolling to next plugin');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `intermediate access denial for @{name} by @{user}, rolling to next plugin`\n );\n return next();\n });\n };\n\n return next();\n }\n\n public allow_unpublish(\n { packageName, packageVersion }: pluginUtils.AuthPluginPackage,\n user: RemoteUser,\n callback: Callback\n ): void {\n const plugins = this.plugins.slice(0);\n const pkg = Object.assign(\n { name: packageName, version: packageVersion },\n authUtils.getMatchedPackagesSpec(packageName, this.config.packages)\n );\n\n debug('check unpublish permissions for user %o to package %o', user.name, packageName);\n\n // Use const instead of function declaration so we can use this.logger\n const next = (): void => {\n const plugin = plugins.shift();\n\n if (typeof plugin?.allow_unpublish !== 'function') {\n debug('plugin does not implement allow_unpublish');\n return next();\n }\n\n plugin.allow_unpublish(user, pkg, (err: VerdaccioError | null, ok?: boolean): void => {\n if (err) {\n debug('forbidden unpublish. Error: %o', err);\n return callback(err);\n }\n\n // The following is different from the allow_access and allow_publish implementations:\n // If the packages config is missing an entry for \"unpublish\", the built-in default method\n // (or a plugin) will return undefined, which will trigger the allow_publish fallback.\n // (see utils.ts, handleSpecialUnpublish, callback(null, undefined))\n if (isNil(ok) === true) {\n debug('bypass unpublish for %o, publish will handle the access', packageName);\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `bypass unpublish for @{name} by @{user}, publish will handle the access`\n );\n return this.allow_publish({ packageName, packageVersion }, user, callback);\n }\n\n if (ok) {\n debug('unpublish was granted');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `unpublish was granted for @{name} by @{user}`\n );\n return callback(null, ok);\n }\n\n // cb(null, false) causes next plugin to roll\n debug('unpublish was denied. Rolling to next plugin');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `intermediate unpublish denial for @{name} by @{user}, rolling to next plugin`\n );\n return next();\n });\n };\n\n return next();\n }\n\n /**\n * Allow user to publish a package.\n */\n public allow_publish(\n { packageName, packageVersion }: pluginUtils.AuthPluginPackage,\n user: RemoteUser,\n callback: Callback\n ): void {\n const plugins = this.plugins.slice(0);\n const pkg = Object.assign(\n { name: packageName, version: packageVersion },\n authUtils.getMatchedPackagesSpec(packageName, this.config.packages)\n );\n\n debug('check publish permissions for user %o to package %o', user.name, packageName);\n\n // Use const instead of function declaration so we can use this.logger\n const next = (): void => {\n const plugin = plugins.shift();\n\n if (typeof plugin?.allow_publish !== 'function') {\n debug('plugin does not implement allow_publish');\n return next();\n }\n\n plugin.allow_publish(user, pkg, (err: VerdaccioError | null, ok?: boolean): void => {\n if (err) {\n debug('forbidden publish. Error: %o', err);\n return callback(err);\n }\n\n if (ok) {\n debug('publish was granted');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `publish was granted for @{name} by @{user}`\n );\n return callback(null, ok);\n }\n\n // cb(null, false) causes next plugin to roll\n debug('publish was denied. Rolling to next plugin');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `intermediate publish denial for @{name} by @{user}, rolling to next plugin`\n );\n return next();\n });\n };\n\n return next();\n }\n\n public apiJWTmiddleware(): any {\n debug('jwt middleware');\n const plugins = this.plugins.slice(0);\n const helpers = { createAnonymousRemoteUser, createRemoteUser };\n for (const plugin of plugins) {\n if (plugin.apiJWTmiddleware) {\n return plugin.apiJWTmiddleware(helpers);\n }\n }\n\n return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction) => {\n req.pause();\n const next = function (err?: VerdaccioError): NextFunction {\n req.resume();\n if (err) {\n return _next(err) as unknown as NextFunction;\n }\n\n return _next() as unknown as NextFunction;\n };\n\n // FUTURE: disabled, not removed yet but seems unreacable code\n // if (this._isRemoteUserValid(req.remote_user)) {\n // debug('jwt has a valid authentication header');\n // return next();\n // }\n\n // in case auth header does not exist we return anonymous function\n const remoteUser = createAnonymousRemoteUser();\n req.remote_user = remoteUser;\n res.locals.remote_user = remoteUser;\n\n const { authorization } = req.headers;\n if (isNil(authorization)) {\n debug('jwt, authentication header is missing');\n return next();\n }\n\n if (!isAuthHeaderValid(authorization)) {\n debug('api middleware authentication heather is invalid');\n return next(errorUtils.getBadRequest(API_ERROR.BAD_AUTH_HEADER));\n }\n const { secret, security } = this.config;\n\n if (isAESLegacy(security)) {\n debug('api middleware using legacy auth token');\n this.handleAESMiddleware(req, security, secret, authorization, next);\n } else {\n debug('api middleware using JWT auth token');\n this.handleJWTAPIMiddleware(req, security, secret, authorization, next);\n }\n };\n }\n\n private handleJWTAPIMiddleware(\n req: $RequestExtend,\n security: Security,\n secret: string,\n authorization: string,\n next: any\n ): void {\n debug('handle JWT api middleware');\n const credentials: any = getMiddlewareCredentials(security, secret, authorization);\n if (credentials) {\n // if the signature is valid we rely on it\n req.remote_user = credentials;\n debug('generating a remote user');\n next();\n } else {\n // with JWT throw 401\n debug('jwt invalid token');\n next(errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));\n }\n }\n\n private handleAESMiddleware(\n req: $RequestExtend,\n security: Security,\n secret: string,\n authorization: string,\n next: Function\n ): void {\n debug('handle legacy api middleware');\n debug('api middleware has a secret? %o', typeof secret === 'string');\n debug('api middleware authorization %o', typeof authorization === 'string');\n const credentials: any = getMiddlewareCredentials(security, secret, authorization);\n debug('api middleware credentials %o', credentials?.name);\n if (credentials) {\n const cacheKey = this.getLegacyAuthCacheKey(authorization);\n const cachedUser = this.getLegacyAuthCacheEntry(cacheKey);\n if (cachedUser) {\n req.remote_user = cachedUser;\n debug('generating cached remote user');\n return next();\n }\n\n const { user, password } = credentials;\n const applyAuthResult = (err: VerdaccioError | null, user?: RemoteUser): void => {\n if (!err && user) {\n req.remote_user = credentials.tokenKey\n ? { ...user, token: { key: credentials.tokenKey } }\n : user;\n debug('generating a remote user');\n next();\n } else {\n req.remote_user = createAnonymousRemoteUser();\n debug('generating anonymous user');\n next(err || errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));\n }\n };\n // concurrent requests for the same token wait for the in-flight one\n if (this.enqueueLegacyAuthCacheWaiter(cacheKey, applyAuthResult)) {\n return;\n }\n\n debug('authenticating %o', user);\n const onAuthComplete = (err: VerdaccioError | null, user?: RemoteUser): void => {\n // only the leader writes the cache; waiters just reuse its result\n if (!err && user) {\n this.setLegacyAuthCacheEntry(\n cacheKey,\n credentials.tokenKey ? { ...user, token: { key: credentials.tokenKey } } : user\n );\n }\n applyAuthResult(err, user);\n this.resolveLegacyAuthCacheWaiters(cacheKey, err, user);\n };\n try {\n this.authenticate(user, password, onAuthComplete);\n } catch (err: any) {\n onAuthComplete(errorUtils.getInternalError(err?.message));\n }\n } else {\n const remoteUser = this.getJWTRemoteUserFromBearer(authorization);\n if (remoteUser) {\n req.remote_user = remoteUser;\n debug('generating a remote user from jwt bearer');\n return next();\n }\n\n debug('legacy invalid header');\n return next(errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));\n }\n }\n\n private getJWTRemoteUserFromBearer(authorization: string): RemoteUser | void {\n const { scheme, token } = parseAuthTokenHeader(authorization);\n if (scheme.toUpperCase() !== TOKEN_BEARER.toUpperCase() || !token) {\n return;\n }\n\n let credentials: RemoteUser | undefined;\n try {\n credentials = verifyJWTPayload(token, this.config.secret, this.config.security);\n } catch {\n return;\n }\n\n if (this._isRemoteUserValid(credentials)) {\n const { name, groups } = credentials as RemoteUser;\n return createRemoteUser(name as string, groups);\n }\n }\n\n private enqueueLegacyAuthCacheWaiter(\n cacheKey: string | void,\n waiter: LegacyAuthCacheWaiter\n ): boolean {\n if (!cacheKey) {\n return false;\n }\n\n const waiters = this.legacyAuthCacheWaiters.get(cacheKey);\n if (!waiters) {\n this.legacyAuthCacheWaiters.set(cacheKey, []);\n return false;\n }\n\n waiters.push(waiter);\n return true;\n }\n\n private resolveLegacyAuthCacheWaiters(\n cacheKey: string | void,\n err: VerdaccioError | null,\n user?: RemoteUser\n ): void {\n if (!cacheKey) {\n return;\n }\n\n const waiters = this.legacyAuthCacheWaiters.get(cacheKey);\n this.legacyAuthCacheWaiters.delete(cacheKey);\n if (!waiters) {\n return;\n }\n\n for (const waiter of waiters) {\n waiter(err, user);\n }\n }\n\n private isLegacyAuthCacheEnabled(): boolean {\n // opt-in: disabled unless explicitly turned on via config\n return this.config.server?.legacyAuthCache?.enabled === true;\n }\n\n private getLegacyAuthCacheTtlMs(): number {\n const ttlMs = this.config.server?.legacyAuthCache?.ttlMs;\n return typeof ttlMs === 'number' && ttlMs > 0 ? ttlMs : 30 * 1000;\n }\n\n private getLegacyAuthCacheMaxEntries(): number {\n const maxEntries = this.config.server?.legacyAuthCache?.maxEntries;\n return typeof maxEntries === 'number' && maxEntries > 0 ? maxEntries : 1000;\n }\n\n private getLegacyAuthCacheKey(authorization: string): string | void {\n if (!this.isLegacyAuthCacheEnabled()) {\n return;\n }\n\n const { scheme } = parseAuthTokenHeader(authorization);\n if (scheme.toUpperCase() !== TOKEN_BEARER.toUpperCase()) {\n return;\n }\n\n return createHash('sha256').update(authorization).digest('hex');\n }\n\n private getLegacyAuthCacheEntry(cacheKey: string | void): RemoteUser | void {\n if (!cacheKey) {\n return;\n }\n\n const entry = this.legacyAuthCache.get(cacheKey);\n if (!entry) {\n return;\n }\n\n if (entry.expiresAt <= Date.now()) {\n this.legacyAuthCache.delete(cacheKey);\n return;\n }\n\n this.legacyAuthCache.delete(cacheKey);\n this.legacyAuthCache.set(cacheKey, entry);\n return cloneRemoteUser(entry.user);\n }\n\n private setLegacyAuthCacheEntry(cacheKey: string | void, user: RemoteUser): void {\n if (!cacheKey) {\n return;\n }\n\n this.legacyAuthCache.set(cacheKey, {\n expiresAt: Date.now() + this.getLegacyAuthCacheTtlMs(),\n user: cloneRemoteUser(user),\n });\n\n const maxEntries = this.getLegacyAuthCacheMaxEntries();\n while (this.legacyAuthCache.size > maxEntries) {\n const oldestKey = this.legacyAuthCache.keys().next().value;\n if (!oldestKey) {\n break;\n }\n this.legacyAuthCache.delete(oldestKey);\n }\n }\n\n private _isRemoteUserValid(remote_user?: RemoteUser): boolean {\n return isUndefined(remote_user) === false && isUndefined(remote_user?.name) === false;\n }\n\n /**\n * JWT middleware for WebUI\n */\n public webUIJWTmiddleware() {\n return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction): void => {\n if (this._isRemoteUserValid(req.remote_user)) {\n return _next();\n }\n\n req.pause();\n const next = (err: VerdaccioError | void): void => {\n req.resume();\n if (err) {\n req.remote_user.error = err.message;\n res.status(err.statusCode).send(err.message);\n }\n\n return _next();\n };\n\n const { authorization } = req.headers;\n if (isNil(authorization)) {\n req.remote_user = createAnonymousRemoteUser();\n return next();\n }\n\n if (!isAuthHeaderValid(authorization)) {\n return next(errorUtils.getBadRequest(API_ERROR.BAD_AUTH_HEADER));\n }\n\n const token = (authorization || '').replace(`${TOKEN_BEARER} `, '');\n if (!token) {\n return next();\n }\n\n let credentials: RemoteUser | undefined;\n try {\n credentials = verifyJWTPayload(token, this.config.secret, this.config.security);\n } catch {\n // FIXME: intended behaviour, do we want it?\n }\n\n if (this._isRemoteUserValid(credentials)) {\n const { name, groups } = credentials as RemoteUser;\n req.remote_user = createRemoteUser(name as string, groups);\n } else {\n req.remote_user = createAnonymousRemoteUser();\n }\n\n next();\n };\n }\n\n public async jwtEncrypt(user: RemoteUser, signOptions: JWTSignOptions): Promise<string> {\n const { real_groups, name, groups, token: tokenMetadata } = user;\n debug('jwt encrypt %o', name);\n const realGroupsValidated = isNil(real_groups) ? [] : real_groups;\n const groupedGroups = isNil(groups)\n ? real_groups\n : Array.from(new Set([...groups.concat(realGroupsValidated)]));\n const payload: RemoteUser = {\n real_groups: realGroupsValidated,\n name,\n groups: groupedGroups,\n };\n if (tokenMetadata?.key) {\n payload.token = { key: tokenMetadata.key };\n }\n const signedToken: string = await signPayload(\n payload,\n this.secret,\n signOptions as Parameters<typeof signPayload>[2]\n );\n\n return signedToken;\n }\n\n /**\n * Encrypt a string.\n */\n public aesEncrypt(value: string): string | void {\n debug('signing with aes encryption');\n const token = aesEncrypt(value, this.secret);\n return token;\n }\n}\n\nexport { Auth };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auth.mjs","names":[],"sources":["../src/auth.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { filter, isEmpty, isNil, isUndefined } from 'lodash-es';\nimport { createHash } from 'node:crypto';\nimport { HTPasswd } from 'verdaccio-htpasswd';\n\nimport { createAnonymousRemoteUser, createRemoteUser } from '@verdaccio/config';\nimport type { VerdaccioError, pluginUtils } from '@verdaccio/core';\nimport {\n API_ERROR,\n PLUGIN_CATEGORY,\n PLUGIN_PREFIX,\n SUPPORT_ERRORS,\n TOKEN_BEARER,\n authUtils,\n errorUtils,\n pluginUtils as pluginSanity,\n warningUtils,\n} from '@verdaccio/core';\nimport { asyncLoadPlugin } from '@verdaccio/loaders';\nimport { aesEncrypt, signPayload } from '@verdaccio/signature';\nimport type {\n AllowAccess,\n Callback,\n Config,\n JWTSignOptions,\n Logger,\n PackageAccess,\n RemoteUser,\n Security,\n} from '@verdaccio/types';\n\nimport type {\n $RequestExtend,\n $ResponseExtend,\n IAuthMiddleware,\n NextFunction,\n TokenEncryption,\n} from './types';\nimport {\n SHA256_ALGORITHM,\n getDefaultPluginMethods,\n getMiddlewareCredentials,\n isAESLegacy,\n isAuthHeaderValid,\n parseAuthTokenHeader,\n verifyJWTPayload,\n} from './utils';\n\nconst debug = buildDebug('verdaccio:auth');\ntype LegacyAuthCacheEntry = {\n expiresAt: number;\n user: RemoteUser;\n};\n\ntype LegacyAuthCacheWaiter = (err: VerdaccioError | null, user?: RemoteUser) => void;\n\nfunction cloneRemoteUser(user: RemoteUser): RemoteUser {\n return {\n ...user,\n groups: user.groups ? [...user.groups] : user.groups,\n real_groups: user.real_groups ? [...user.real_groups] : user.real_groups,\n token: user.token ? { ...user.token } : user.token,\n };\n}\n\nclass Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {\n public config: Config;\n public secret: string;\n public logger: Logger;\n public plugins: pluginUtils.Auth<Config>[];\n public options: { legacyMergeConfigs: boolean };\n private legacyAuthCache: Map<string, LegacyAuthCacheEntry>;\n private legacyAuthCacheWaiters: Map<string, LegacyAuthCacheWaiter[]>;\n\n public constructor(config: Config, logger: Logger, options = { legacyMergeConfigs: false }) {\n this.config = config;\n this.secret = config.secret;\n this.logger = logger;\n this.plugins = [];\n this.options = options;\n this.legacyAuthCache = new Map();\n this.legacyAuthCacheWaiters = new Map();\n if (!this.secret) {\n throw new TypeError('secret it is required value on initialize the auth class');\n }\n }\n\n public async init() {\n let plugins = await this.loadPlugin();\n\n debug('auth plugins found %s', plugins.length);\n // Missing auth config or no loaded plugins -> load default htpasswd plugin\n // Empty auth config (null) -> just use fallback methods\n if (this.config.auth !== null && (!plugins || plugins.length === 0)) {\n plugins = this.loadDefaultPlugin();\n }\n this.plugins = plugins;\n\n this.applyFallbackPluginMethods();\n }\n\n private loadDefaultPlugin() {\n debug('load default auth plugin');\n let authPlugin;\n try {\n authPlugin = new HTPasswd(\n { file: './htpasswd' },\n {\n config: this.config,\n logger: this.logger,\n }\n );\n this.logger.info(\n { name: 'verdaccio-htpasswd', pluginCategory: PLUGIN_CATEGORY.AUTHENTICATION },\n 'plugin @{name} successfully loaded (@{pluginCategory})'\n );\n } catch (error: any) {\n debug('error on loading auth htpasswd plugin stack: %o', error);\n this.logger.info({}, 'no auth plugin has been found');\n return [];\n }\n\n return [authPlugin];\n }\n\n private async loadPlugin() {\n return asyncLoadPlugin<pluginUtils.Auth<Config>>(\n this.config.auth,\n {\n config: this.config,\n logger: this.logger,\n },\n pluginSanity.authSanityCheck,\n this.options.legacyMergeConfigs,\n this.config?.server?.pluginPrefix ?? PLUGIN_PREFIX,\n PLUGIN_CATEGORY.AUTHENTICATION\n );\n }\n\n private applyFallbackPluginMethods(): void {\n this.plugins.push(getDefaultPluginMethods(this.logger));\n }\n\n public changePassword(\n username: string,\n password: string,\n newPassword: string,\n cb: Callback\n ): void {\n const validPlugins = filter(\n this.plugins,\n (plugin) => typeof plugin.changePassword === 'function'\n );\n\n if (isEmpty(validPlugins)) {\n return cb(errorUtils.getInternalError(SUPPORT_ERRORS.PLUGIN_MISSING_INTERFACE));\n }\n\n for (const plugin of validPlugins) {\n if (isNil(plugin) || typeof plugin.changePassword !== 'function') {\n debug('auth plugin does not implement changePassword, trying next one');\n continue;\n } else {\n debug('updating password for %o', username);\n plugin.changePassword!(username, password, newPassword, (err, profile): void => {\n if (err) {\n this.logger.error(\n { username, err },\n `An error has been produced\n updating the password for @{username}. Error: @{err.message}`\n );\n return cb(err);\n }\n\n debug('updated password for %o was successful', username);\n return cb(null, profile);\n });\n }\n }\n }\n\n public async invalidateToken(token: string) {\n // eslint-disable-next-line no-console\n console.log('invalidate token pending to implement', token);\n return Promise.resolve();\n }\n\n public authenticate(\n username: string,\n password: string,\n cb: (error: VerdaccioError | null, user?: RemoteUser) => void\n ): void {\n const plugins = this.plugins.slice(0);\n (function next(): void {\n const plugin = plugins.shift();\n\n if (typeof plugin?.authenticate !== 'function') {\n return next();\n }\n\n debug('authenticating %o', username);\n plugin.authenticate(username, password, function (err: VerdaccioError | null, groups): void {\n if (err) {\n debug('authenticating for user %o failed. Error: %o', username, err?.message);\n return cb(err);\n }\n\n // Expect: SKIP if groups is falsey and not an array\n // with at least one item (truthy length)\n // Expect: CONTINUE otherwise (will error if groups is not\n // an array, but this is current behavior)\n // Caveat: STRING (if valid) will pass successfully\n // bug give unexpected results\n // Info: Cannot use `== false to check falsey values`\n if (!!groups && groups.length !== 0) {\n // TODO: create a better understanding of expectations\n if (typeof groups === 'string') {\n throw new TypeError('plugin group error: invalid type for function');\n }\n const isGroupValid: boolean = Array.isArray(groups);\n if (!isGroupValid) {\n throw new TypeError(API_ERROR.BAD_FORMAT_USER_GROUP);\n }\n\n debug('authentication for user %o was successfully. Groups: %o', username, groups);\n return cb(err, createRemoteUser(username, groups));\n }\n next();\n });\n })();\n }\n\n public add_user(\n user: string,\n password: string,\n cb: (error: VerdaccioError | null, user?: RemoteUser) => void\n ): void {\n const self = this;\n const plugins = this.plugins.slice(0);\n debug('add user %o', user);\n\n (function next(): void {\n let method = 'adduser';\n const plugin = plugins.shift();\n // @ts-expect-error future major (7.x) should remove this section\n if (typeof plugin.adduser === 'undefined' && typeof plugin.add_user === 'function') {\n method = 'add_user';\n warningUtils.emit(warningUtils.Codes.VERWAR006);\n }\n // @ts-ignore\n if (typeof plugin[method] !== 'function') {\n next();\n } else {\n // TODO: replace by adduser whenever add_user deprecation method has been removed\n // @ts-ignore\n plugin[method](\n user,\n password,\n function (err: VerdaccioError | null, ok?: boolean | string): void {\n if (err) {\n debug('the user %o could not be added. Error: %o', user, err?.message);\n return cb(err);\n }\n if (ok) {\n debug('the user %o has been added', user);\n return self.authenticate(user, password, cb);\n }\n debug('user could not be added, skip to next auth plugin');\n next();\n }\n );\n }\n })();\n }\n\n /**\n * Allow user to access a package.\n */\n public allow_access(\n { packageName, packageVersion }: pluginUtils.AuthPluginPackage,\n user: RemoteUser,\n callback: pluginUtils.AccessCallback\n ): void {\n const plugins = this.plugins.slice(0);\n const pkg = Object.assign(\n { name: packageName, version: packageVersion },\n authUtils.getMatchedPackagesSpec(packageName, this.config.packages)\n ) as AllowAccess & PackageAccess;\n\n debug('check access permissions for user %o to package %o', user.name, packageName);\n\n // Use const instead of function declaration so we can use this.logger\n const next = (): void => {\n const plugin = plugins.shift();\n\n if (typeof plugin?.allow_access !== 'function') {\n debug('plugin does not implement allow_access');\n return next();\n }\n\n plugin.allow_access(user, pkg, (err: VerdaccioError | null, ok?: boolean): void => {\n if (err) {\n debug('forbidden access. Error: %o', err);\n return callback(err);\n }\n\n if (ok) {\n debug('access was granted');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `access was granted for @{name} by @{user}`\n );\n return callback(null, ok);\n }\n\n // cb(null, false) causes next plugin to roll\n debug('access was denied. Rolling to next plugin');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `intermediate access denial for @{name} by @{user}, rolling to next plugin`\n );\n return next();\n });\n };\n\n return next();\n }\n\n public allow_unpublish(\n { packageName, packageVersion }: pluginUtils.AuthPluginPackage,\n user: RemoteUser,\n callback: Callback\n ): void {\n const plugins = this.plugins.slice(0);\n const pkg = Object.assign(\n { name: packageName, version: packageVersion },\n authUtils.getMatchedPackagesSpec(packageName, this.config.packages)\n );\n\n debug('check unpublish permissions for user %o to package %o', user.name, packageName);\n\n // Use const instead of function declaration so we can use this.logger\n const next = (): void => {\n const plugin = plugins.shift();\n\n if (typeof plugin?.allow_unpublish !== 'function') {\n debug('plugin does not implement allow_unpublish');\n return next();\n }\n\n plugin.allow_unpublish(user, pkg, (err: VerdaccioError | null, ok?: boolean): void => {\n if (err) {\n debug('forbidden unpublish. Error: %o', err);\n return callback(err);\n }\n\n // The following is different from the allow_access and allow_publish implementations:\n // If the packages config is missing an entry for \"unpublish\", the built-in default method\n // (or a plugin) will return undefined, which will trigger the allow_publish fallback.\n // (see utils.ts, handleSpecialUnpublish, callback(null, undefined))\n if (isNil(ok) === true) {\n debug('bypass unpublish for %o, publish will handle the access', packageName);\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `bypass unpublish for @{name} by @{user}, publish will handle the access`\n );\n return this.allow_publish({ packageName, packageVersion }, user, callback);\n }\n\n if (ok) {\n debug('unpublish was granted');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `unpublish was granted for @{name} by @{user}`\n );\n return callback(null, ok);\n }\n\n // cb(null, false) causes next plugin to roll\n debug('unpublish was denied. Rolling to next plugin');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `intermediate unpublish denial for @{name} by @{user}, rolling to next plugin`\n );\n return next();\n });\n };\n\n return next();\n }\n\n /**\n * Allow a user to submit a package version for review (`npm stage publish`).\n *\n * Deliberately a weaker capability than publishing: granting `stage` to a\n * group that lacks `publish` is what turns staging into a real review gate,\n * because those users can propose a release but not make one.\n *\n * When the packages configuration says nothing about `stage`, the built-in\n * plugin answers `undefined` and this falls back to `allow_publish`, so\n * existing configurations behave exactly as before.\n */\n public allow_stage(\n { packageName, packageVersion }: pluginUtils.AuthPluginPackage,\n user: RemoteUser,\n callback: Callback\n ): void {\n const plugins = this.plugins.slice(0);\n const pkg = Object.assign(\n { name: packageName, version: packageVersion },\n authUtils.getMatchedPackagesSpec(packageName, this.config.packages)\n );\n\n debug('check stage permissions for user %o to package %o', user.name, packageName);\n\n const next = (): void => {\n const plugin = plugins.shift();\n\n if (typeof plugin?.allow_stage !== 'function') {\n debug('plugin does not implement allow_stage');\n return next();\n }\n\n plugin.allow_stage(user, pkg, (err: VerdaccioError | null, ok?: boolean): void => {\n if (err) {\n debug('forbidden stage. Error: %o', err);\n return callback(err);\n }\n\n // undefined means the packages config has no \"stage\" entry, so publish\n // decides (see utils.ts, handleActionWithPublishFallback)\n if (isNil(ok) === true) {\n debug('bypass stage for %o, publish will handle the access', packageName);\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `bypass stage for @{name} by @{user}, publish will handle the access`\n );\n return this.allow_publish({ packageName, packageVersion }, user, callback);\n }\n\n if (ok) {\n debug('stage was granted');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `stage was granted for @{name} by @{user}`\n );\n return callback(null, ok);\n }\n\n // cb(null, false) causes next plugin to roll\n debug('stage was denied. Rolling to next plugin');\n return next();\n });\n };\n\n return next();\n }\n\n /**\n * Allow user to publish a package.\n */\n public allow_publish(\n { packageName, packageVersion }: pluginUtils.AuthPluginPackage,\n user: RemoteUser,\n callback: Callback\n ): void {\n const plugins = this.plugins.slice(0);\n const pkg = Object.assign(\n { name: packageName, version: packageVersion },\n authUtils.getMatchedPackagesSpec(packageName, this.config.packages)\n );\n\n debug('check publish permissions for user %o to package %o', user.name, packageName);\n\n // Use const instead of function declaration so we can use this.logger\n const next = (): void => {\n const plugin = plugins.shift();\n\n if (typeof plugin?.allow_publish !== 'function') {\n debug('plugin does not implement allow_publish');\n return next();\n }\n\n plugin.allow_publish(user, pkg, (err: VerdaccioError | null, ok?: boolean): void => {\n if (err) {\n debug('forbidden publish. Error: %o', err);\n return callback(err);\n }\n\n if (ok) {\n debug('publish was granted');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `publish was granted for @{name} by @{user}`\n );\n return callback(null, ok);\n }\n\n // cb(null, false) causes next plugin to roll\n debug('publish was denied. Rolling to next plugin');\n this.logger.trace(\n { user: user.name, name: pkg.name },\n `intermediate publish denial for @{name} by @{user}, rolling to next plugin`\n );\n return next();\n });\n };\n\n return next();\n }\n\n public apiJWTmiddleware(): any {\n debug('jwt middleware');\n const plugins = this.plugins.slice(0);\n const helpers = { createAnonymousRemoteUser, createRemoteUser };\n for (const plugin of plugins) {\n if (plugin.apiJWTmiddleware) {\n return plugin.apiJWTmiddleware(helpers);\n }\n }\n\n return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction) => {\n req.pause();\n const next = function (err?: VerdaccioError): NextFunction {\n req.resume();\n if (err) {\n return _next(err) as unknown as NextFunction;\n }\n\n return _next() as unknown as NextFunction;\n };\n\n // FUTURE: disabled, not removed yet but seems unreacable code\n // if (this._isRemoteUserValid(req.remote_user)) {\n // debug('jwt has a valid authentication header');\n // return next();\n // }\n\n // in case auth header does not exist we return anonymous function\n const remoteUser = createAnonymousRemoteUser();\n req.remote_user = remoteUser;\n res.locals.remote_user = remoteUser;\n\n const { authorization } = req.headers;\n if (isNil(authorization)) {\n debug('jwt, authentication header is missing');\n return next();\n }\n\n if (!isAuthHeaderValid(authorization)) {\n debug('api middleware authentication heather is invalid');\n return next(errorUtils.getBadRequest(API_ERROR.BAD_AUTH_HEADER));\n }\n const { secret, security } = this.config;\n\n if (isAESLegacy(security)) {\n debug('api middleware using legacy auth token');\n this.handleAESMiddleware(req, security, secret, authorization, next);\n } else {\n debug('api middleware using JWT auth token');\n this.handleJWTAPIMiddleware(req, security, secret, authorization, next);\n }\n };\n }\n\n private handleJWTAPIMiddleware(\n req: $RequestExtend,\n security: Security,\n secret: string,\n authorization: string,\n next: any\n ): void {\n debug('handle JWT api middleware');\n const credentials: any = getMiddlewareCredentials(security, secret, authorization);\n if (credentials) {\n // if the signature is valid we rely on it\n req.remote_user = credentials;\n debug('generating a remote user');\n next();\n } else {\n // with JWT throw 401\n debug('jwt invalid token');\n next(errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));\n }\n }\n\n private handleAESMiddleware(\n req: $RequestExtend,\n security: Security,\n secret: string,\n authorization: string,\n next: Function\n ): void {\n debug('handle legacy api middleware');\n debug('api middleware has a secret? %o', typeof secret === 'string');\n debug('api middleware authorization %o', typeof authorization === 'string');\n const credentials: any = getMiddlewareCredentials(security, secret, authorization);\n debug('api middleware credentials %o', credentials?.name);\n if (credentials) {\n const cacheKey = this.getLegacyAuthCacheKey(authorization);\n const cachedUser = this.getLegacyAuthCacheEntry(cacheKey);\n if (cachedUser) {\n req.remote_user = cachedUser;\n debug('generating cached remote user');\n return next();\n }\n\n const { user, password } = credentials;\n const applyAuthResult = (err: VerdaccioError | null, user?: RemoteUser): void => {\n if (!err && user) {\n req.remote_user = credentials.tokenKey\n ? { ...user, token: { key: credentials.tokenKey } }\n : user;\n debug('generating a remote user');\n next();\n } else {\n req.remote_user = createAnonymousRemoteUser();\n debug('generating anonymous user');\n next(err || errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));\n }\n };\n // concurrent requests for the same token wait for the in-flight one\n if (this.enqueueLegacyAuthCacheWaiter(cacheKey, applyAuthResult)) {\n return;\n }\n\n debug('authenticating %o', user);\n const onAuthComplete = (err: VerdaccioError | null, user?: RemoteUser): void => {\n // only the leader writes the cache; waiters just reuse its result\n if (!err && user) {\n this.setLegacyAuthCacheEntry(\n cacheKey,\n credentials.tokenKey ? { ...user, token: { key: credentials.tokenKey } } : user\n );\n }\n applyAuthResult(err, user);\n this.resolveLegacyAuthCacheWaiters(cacheKey, err, user);\n };\n try {\n this.authenticate(user, password, onAuthComplete);\n } catch (err: any) {\n onAuthComplete(errorUtils.getInternalError(err?.message));\n }\n } else {\n const remoteUser = this.getJWTRemoteUserFromBearer(authorization);\n if (remoteUser) {\n req.remote_user = remoteUser;\n debug('generating a remote user from jwt bearer');\n return next();\n }\n\n debug('legacy invalid header');\n return next(errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));\n }\n }\n\n private getJWTRemoteUserFromBearer(authorization: string): RemoteUser | void {\n const { scheme, token } = parseAuthTokenHeader(authorization);\n if (scheme.toUpperCase() !== TOKEN_BEARER.toUpperCase() || !token) {\n return;\n }\n\n let credentials: RemoteUser | undefined;\n try {\n credentials = verifyJWTPayload(token, this.config.secret, this.config.security);\n } catch {\n return;\n }\n\n if (this._isRemoteUserValid(credentials)) {\n const { name, groups } = credentials as RemoteUser;\n return createRemoteUser(name as string, groups);\n }\n }\n\n private enqueueLegacyAuthCacheWaiter(\n cacheKey: string | void,\n waiter: LegacyAuthCacheWaiter\n ): boolean {\n if (!cacheKey) {\n return false;\n }\n\n const waiters = this.legacyAuthCacheWaiters.get(cacheKey);\n if (!waiters) {\n this.legacyAuthCacheWaiters.set(cacheKey, []);\n return false;\n }\n\n waiters.push(waiter);\n return true;\n }\n\n private resolveLegacyAuthCacheWaiters(\n cacheKey: string | void,\n err: VerdaccioError | null,\n user?: RemoteUser\n ): void {\n if (!cacheKey) {\n return;\n }\n\n const waiters = this.legacyAuthCacheWaiters.get(cacheKey);\n this.legacyAuthCacheWaiters.delete(cacheKey);\n if (!waiters) {\n return;\n }\n\n for (const waiter of waiters) {\n waiter(err, user);\n }\n }\n\n private isLegacyAuthCacheEnabled(): boolean {\n // opt-in: disabled unless explicitly turned on via config\n return this.config.server?.legacyAuthCache?.enabled === true;\n }\n\n private getLegacyAuthCacheTtlMs(): number {\n const ttlMs = this.config.server?.legacyAuthCache?.ttlMs;\n return typeof ttlMs === 'number' && ttlMs > 0 ? ttlMs : 30 * 1000;\n }\n\n private getLegacyAuthCacheMaxEntries(): number {\n const maxEntries = this.config.server?.legacyAuthCache?.maxEntries;\n return typeof maxEntries === 'number' && maxEntries > 0 ? maxEntries : 1000;\n }\n\n private getLegacyAuthCacheKey(authorization: string): string | void {\n if (!this.isLegacyAuthCacheEnabled()) {\n return;\n }\n\n const { scheme } = parseAuthTokenHeader(authorization);\n if (scheme.toUpperCase() !== TOKEN_BEARER.toUpperCase()) {\n return;\n }\n\n return createHash(SHA256_ALGORITHM).update(authorization).digest('hex');\n }\n\n private getLegacyAuthCacheEntry(cacheKey: string | void): RemoteUser | void {\n if (!cacheKey) {\n return;\n }\n\n const entry = this.legacyAuthCache.get(cacheKey);\n if (!entry) {\n return;\n }\n\n if (entry.expiresAt <= Date.now()) {\n this.legacyAuthCache.delete(cacheKey);\n return;\n }\n\n this.legacyAuthCache.delete(cacheKey);\n this.legacyAuthCache.set(cacheKey, entry);\n return cloneRemoteUser(entry.user);\n }\n\n private setLegacyAuthCacheEntry(cacheKey: string | void, user: RemoteUser): void {\n if (!cacheKey) {\n return;\n }\n\n this.legacyAuthCache.set(cacheKey, {\n expiresAt: Date.now() + this.getLegacyAuthCacheTtlMs(),\n user: cloneRemoteUser(user),\n });\n\n const maxEntries = this.getLegacyAuthCacheMaxEntries();\n while (this.legacyAuthCache.size > maxEntries) {\n const oldestKey = this.legacyAuthCache.keys().next().value;\n if (!oldestKey) {\n break;\n }\n this.legacyAuthCache.delete(oldestKey);\n }\n }\n\n private _isRemoteUserValid(remote_user?: RemoteUser): boolean {\n return isUndefined(remote_user) === false && isUndefined(remote_user?.name) === false;\n }\n\n /**\n * JWT middleware for WebUI\n */\n public webUIJWTmiddleware() {\n return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction): void => {\n if (this._isRemoteUserValid(req.remote_user)) {\n return _next();\n }\n\n req.pause();\n const next = (err: VerdaccioError | void): void => {\n req.resume();\n if (err) {\n req.remote_user.error = err.message;\n res.status(err.statusCode).send(err.message);\n }\n\n return _next();\n };\n\n const { authorization } = req.headers;\n if (isNil(authorization)) {\n req.remote_user = createAnonymousRemoteUser();\n return next();\n }\n\n if (!isAuthHeaderValid(authorization)) {\n return next(errorUtils.getBadRequest(API_ERROR.BAD_AUTH_HEADER));\n }\n\n const token = (authorization || '').replace(`${TOKEN_BEARER} `, '');\n if (!token) {\n return next();\n }\n\n let credentials: RemoteUser | undefined;\n try {\n credentials = verifyJWTPayload(token, this.config.secret, this.config.security);\n } catch {\n // FIXME: intended behaviour, do we want it?\n }\n\n if (this._isRemoteUserValid(credentials)) {\n const { name, groups } = credentials as RemoteUser;\n req.remote_user = createRemoteUser(name as string, groups);\n } else {\n req.remote_user = createAnonymousRemoteUser();\n }\n\n next();\n };\n }\n\n public async jwtEncrypt(user: RemoteUser, signOptions: JWTSignOptions): Promise<string> {\n const { real_groups, name, groups, token: tokenMetadata } = user;\n debug('jwt encrypt %o', name);\n const realGroupsValidated = isNil(real_groups) ? [] : real_groups;\n const groupedGroups = isNil(groups)\n ? real_groups\n : Array.from(new Set([...groups.concat(realGroupsValidated)]));\n const payload: RemoteUser = {\n real_groups: realGroupsValidated,\n name,\n groups: groupedGroups,\n };\n if (tokenMetadata?.key) {\n payload.token = { key: tokenMetadata.key };\n }\n const signedToken: string = await signPayload(\n payload,\n this.secret,\n signOptions as Parameters<typeof signPayload>[2]\n );\n\n return signedToken;\n }\n\n /**\n * Encrypt a string.\n */\n public aesEncrypt(value: string): string | void {\n debug('signing with aes encryption');\n const token = aesEncrypt(value, this.secret);\n return token;\n }\n}\n\nexport { Auth };\n"],"mappings":"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"}
|
package/build/index.d.ts
CHANGED
package/build/index.js
CHANGED
|
@@ -4,16 +4,23 @@ Object.defineProperties(exports, {
|
|
|
4
4
|
});
|
|
5
5
|
const require_utils = require("./utils.js");
|
|
6
6
|
const require_auth = require("./auth.js");
|
|
7
|
+
const require_tfa_store = require("./tfa-store.js");
|
|
7
8
|
exports.Auth = require_auth.Auth;
|
|
9
|
+
exports.SHA256_ALGORITHM = require_utils.SHA256_ALGORITHM;
|
|
10
|
+
exports.TFA_TOKEN_KEY = require_tfa_store.TFA_TOKEN_KEY;
|
|
11
|
+
exports.TfaStore = require_tfa_store.TfaStore;
|
|
8
12
|
exports.allow_action = require_utils.allow_action;
|
|
9
13
|
exports.buildUser = require_utils.buildUser;
|
|
10
14
|
exports.expireReasons = require_utils.expireReasons;
|
|
11
15
|
exports.getApiToken = require_utils.getApiToken;
|
|
12
16
|
exports.getDefaultPluginMethods = require_utils.getDefaultPluginMethods;
|
|
13
17
|
exports.getMiddlewareCredentials = require_utils.getMiddlewareCredentials;
|
|
18
|
+
exports.handleActionWithPublishFallback = require_utils.handleActionWithPublishFallback;
|
|
14
19
|
exports.handleSpecialUnpublish = require_utils.handleSpecialUnpublish;
|
|
15
20
|
exports.isAESLegacy = require_utils.isAESLegacy;
|
|
16
21
|
exports.isAuthHeaderValid = require_utils.isAuthHeaderValid;
|
|
22
|
+
exports.isReservedTokenKey = require_tfa_store.isReservedTokenKey;
|
|
17
23
|
exports.parseAESCredentials = require_utils.parseAESCredentials;
|
|
18
24
|
exports.parseAuthTokenHeader = require_utils.parseAuthTokenHeader;
|
|
25
|
+
exports.tfaSafeEqual = require_tfa_store.tfaSafeEqual;
|
|
19
26
|
exports.verifyJWTPayload = require_utils.verifyJWTPayload;
|
package/build/index.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { allow_action, buildUser, expireReasons, getApiToken, getDefaultPluginMethods, getMiddlewareCredentials, handleSpecialUnpublish, isAESLegacy, isAuthHeaderValid, parseAESCredentials, parseAuthTokenHeader, verifyJWTPayload } from "./utils.mjs";
|
|
1
|
+
import { SHA256_ALGORITHM, allow_action, buildUser, expireReasons, getApiToken, getDefaultPluginMethods, getMiddlewareCredentials, handleActionWithPublishFallback, handleSpecialUnpublish, isAESLegacy, isAuthHeaderValid, parseAESCredentials, parseAuthTokenHeader, verifyJWTPayload } from "./utils.mjs";
|
|
2
2
|
import { Auth } from "./auth.mjs";
|
|
3
|
-
|
|
3
|
+
import { TFA_TOKEN_KEY, TfaStore, isReservedTokenKey, tfaSafeEqual as safeEqual } from "./tfa-store.mjs";
|
|
4
|
+
export { Auth, SHA256_ALGORITHM, TFA_TOKEN_KEY, TfaStore, allow_action, buildUser, expireReasons, getApiToken, getDefaultPluginMethods, getMiddlewareCredentials, handleActionWithPublishFallback, handleSpecialUnpublish, isAESLegacy, isAuthHeaderValid, isReservedTokenKey, parseAESCredentials, parseAuthTokenHeader, safeEqual as tfaSafeEqual, verifyJWTPayload };
|