Compare commits

...

3 Commits

Author SHA1 Message Date
Juan Picado
28244477d2 changeset 2025-03-16 11:24:35 +01:00
Juan Picado
1b6115f2d6 Update index.spec.ts 2025-03-16 11:17:16 +01:00
Juan Picado
6ade2de358 fix: auth plugin callback types 2025-03-16 11:17:16 +01:00
9 changed files with 38 additions and 17 deletions

View File

@@ -0,0 +1,7 @@
---
'verdaccio-auth-memory': minor
'@verdaccio/core': minor
'@verdaccio/auth': minor
---
fix: auth callback types

View File

@@ -68,7 +68,9 @@ jobs:
fail-fast: true
matrix:
os: [ubuntu-latest]
node_version: [18, 20, 21, 22, 23]
## updated according official maintained releases
## https://nodejs.org/en/about/previous-releases
node_version: [18, 20, 22, 23]
name: ${{ matrix.os }} / Node ${{ matrix.node_version }}
runs-on: ${{ matrix.os }}
steps:

View File

@@ -191,7 +191,7 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
plugin.authenticate(username, password, function (err: VerdaccioError | null, groups): void {
if (err) {
debug('authenticating for user %o failed. Error: %o', username, err?.message);
return cb(err);
return cb(err, undefined);
}
// Expect: SKIP if groups is falsey and not an array
@@ -201,7 +201,7 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
// Caveat: STRING (if valid) will pass successfully
// bug give unexpected results
// Info: Cannot use `== false to check falsey values`
if (!!groups && groups.length !== 0) {
if (!!groups && groups?.length !== 0) {
// TODO: create a better understanding of expectations
if (_.isString(groups)) {
throw new TypeError('plugin group error: invalid type for function');
@@ -212,7 +212,7 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
}
debug('authentication for user %o was successfully. Groups: %o', username, groups);
return cb(err, createRemoteUser(username, groups));
return cb(err, createRemoteUser(username, groups as string[]));
}
next();
});

View File

@@ -161,7 +161,7 @@ export function getDefaultPlugins(logger: Logger): pluginUtils.Auth<Config> {
return {
authenticate(_user: string, _password: string, cb: pluginUtils.AuthCallback): void {
debug('triggered default authenticate method');
cb(errorUtils.getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));
cb(errorUtils.getForbidden(API_ERROR.BAD_USERNAME_PASSWORD), undefined);
},
adduser(_user: string, _password: string, cb: pluginUtils.AuthUserCallback): void {

View File

@@ -4,7 +4,14 @@ import supertest from 'supertest';
import { describe, expect, test, vi } from 'vitest';
import { Config as AppConfig, ROLES, createRemoteUser, getDefaultConfig } from '@verdaccio/config';
import { HEADERS, HTTP_STATUS, SUPPORT_ERRORS, TOKEN_BEARER, errorUtils } from '@verdaccio/core';
import {
API_ERROR,
HEADERS,
HTTP_STATUS,
SUPPORT_ERRORS,
TOKEN_BEARER,
errorUtils,
} from '@verdaccio/core';
import { logger, setup } from '@verdaccio/logger';
import { errorReportingMiddleware, final, handleError } from '@verdaccio/middleware';
import { Config } from '@verdaccio/types';
@@ -96,7 +103,7 @@ describe('AuthTest', () => {
});
});
test('should be a fail on login', async () => {
test('should be a fail on login due plugin failure', async () => {
const config: Config = new AppConfig(authPluginFailureConf);
config.checkSecretKey('12345');
const auth: Auth = new Auth(config, logger);
@@ -107,7 +114,7 @@ describe('AuthTest', () => {
auth.authenticate('foo', 'bar', callback);
expect(callback).toHaveBeenCalledTimes(1);
expect(callback).toHaveBeenCalledWith(errorUtils.getInternalError());
expect(callback).toHaveBeenCalledWith(errorUtils.getInternalError(), undefined);
});
});
@@ -131,6 +138,7 @@ describe('AuthTest', () => {
auth.authenticate(null, value, callback);
const call = callback.mock.calls[index++];
expect(call[0]).toBeDefined();
expect(call[0]).toEqual(errorUtils.getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));
expect(call[1]).toBeUndefined();
}
});

View File

@@ -28,6 +28,7 @@ export {
PLUGIN_CATEGORY,
HtpasswdHashAlgorithm,
} from './constants';
export * from './plugin-utils';
const validationUtils = validatioUtils;
export {
fileUtils,

View File

@@ -98,7 +98,7 @@ export interface Storage<PluginConfig> extends Plugin<PluginConfig> {
*
* ```ts
* import express, { Request, Response } from 'express';
*
*
* class Middleware extends Plugin {
* // instances of auth and storage are injected
* register_middlewares(app, auth, storage) {
@@ -119,7 +119,10 @@ export interface ExpressMiddleware<PluginConfig, Storage, Auth> extends Plugin<P
// --- AUTH PLUGIN ---
export type AuthCallback = (error: VerdaccioError | null, groups?: string[] | false) => void;
export type AuthCallback = (
error: VerdaccioError | null,
user: string[] | false | undefined
) => void;
export type AuthAccessCallback = (error: VerdaccioError | null, access?: boolean) => void;
export type AuthUserCallback = (error: VerdaccioError | null, access?: boolean | string) => void;
@@ -147,7 +150,7 @@ export interface Auth<T> extends Plugin<T> {
return done(errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));
}
// always return an array of users
return done(null, [user]);
return done(null, [user]);
* }
* ```
*/
@@ -161,7 +164,7 @@ export interface Auth<T> extends Plugin<T> {
return done(errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));
}
// return boolean
return done(null, true);
return done(null, true);
* }
* ```
*/

View File

@@ -32,14 +32,14 @@ export default class Memory
if (!userCredentials) {
debug('user %o does not exist', user);
return cb(null, false);
return cb(errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD), undefined);
}
if (password !== userCredentials.password) {
const err = errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD);
debug('password invalid for: %o', user);
return cb(err);
return cb(err, undefined);
}
// authentication succeeded!

View File

@@ -1,7 +1,7 @@
import { beforeEach, describe, expect, test, vi } from 'vitest';
import { Config, getDefaultConfig } from '@verdaccio/config';
import { pluginUtils } from '@verdaccio/core';
import { API_ERROR, errorUtils, pluginUtils } from '@verdaccio/core';
import Memory from '../src/index';
import { Users, VerdaccioMemoryConfig } from '../src/types';
@@ -307,8 +307,8 @@ describe('Memory', function () {
test('fails if user does not exist', function () {
return new Promise((done) => {
auth.authenticate('john', 'secret', function (err, groups) {
expect(err).toBeNull();
expect(groups).toBeFalsy();
expect(err).toEqual(errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));
expect(groups).toBeUndefined();
done(true);
});
});