feat: migrate web login endpoint to fastify (#2624)

* feat: migrate login to fastify

* Update package.json

* Update server.ts

* fix authentication tests

* fix test
This commit is contained in:
Diana Morales 2021-11-05 16:29:48 +01:00 committed by GitHub
parent b7d319c5be
commit 18dc5f1f2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 92 additions and 2 deletions

View File

@ -94,6 +94,9 @@ class Auth implements IAuth {
this.config = config;
this.logger = LoggerApi.logger.child({ sub: 'auth' });
this.secret = config.secret;
if (!this.secret) {
throw new TypeError('secret it is required value on initialize the auth class');
}
this.plugins =
_.isNil(config?.auth) === false ? this._loadPlugin(config) : this.loadDefaultPlugin(config);

View File

@ -14,6 +14,8 @@ setup([]);
describe('AuthTest', () => {
test('should be defined', () => {
const config: Config = new AppConfig(_.cloneDeep(authProfileConf));
config.checkSecretKey('12345');
const auth: IAuth = new Auth(config);
expect(auth).toBeDefined();
@ -23,6 +25,7 @@ describe('AuthTest', () => {
describe('test authenticate states', () => {
test('should be a success login', () => {
const config: Config = new AppConfig(_.cloneDeep(authProfileConf));
config.checkSecretKey('12345');
const auth: IAuth = new Auth(config);
expect(auth).toBeDefined();
@ -49,6 +52,7 @@ describe('AuthTest', () => {
test('should be a fail on login', () => {
const config: Config = new AppConfig(_.cloneDeep(authPluginFailureConf));
config.checkSecretKey('12345');
const auth: IAuth = new Auth(config);
expect(auth).toBeDefined();
@ -67,6 +71,7 @@ describe('AuthTest', () => {
describe('test authenticate out of control inputs from plugins', () => {
test('should skip falsy values', () => {
const config: Config = new AppConfig(_.cloneDeep(authPluginPassThrougConf));
config.checkSecretKey('12345');
const auth: IAuth = new Auth(config);
expect(auth).toBeDefined();
@ -86,6 +91,7 @@ describe('AuthTest', () => {
test('should error truthy non-array', () => {
const config: Config = new AppConfig(_.cloneDeep(authPluginPassThrougConf));
config.checkSecretKey('12345');
const auth: IAuth = new Auth(config);
expect(auth).toBeDefined();
@ -103,6 +109,7 @@ describe('AuthTest', () => {
test('should skip empty array', () => {
const config: Config = new AppConfig(_.cloneDeep(authPluginPassThrougConf));
config.checkSecretKey('12345');
const auth: IAuth = new Auth(config);
expect(auth).toBeDefined();
@ -119,6 +126,7 @@ describe('AuthTest', () => {
test('should accept valid array', () => {
const config: Config = new AppConfig(_.cloneDeep(authPluginPassThrougConf));
config.checkSecretKey('12345');
const auth: IAuth = new Auth(config);
expect(auth).toBeDefined();

View File

@ -0,0 +1,75 @@
import buildDebug from 'debug';
import { FastifyInstance } from 'fastify';
import _ from 'lodash';
import { JWTSignOptions } from '@verdaccio/types';
import { validatePassword } from '@verdaccio/utils';
const debug = buildDebug('verdaccio:api:login');
async function loginRoute(fastify: FastifyInstance) {
fastify.post('/login', async (request, reply) => {
// @ts-expect-error
const { username, password } = request.body;
debug('authenticate %o', username);
fastify.auth.authenticate(
username,
password,
async function callbackAuthenticate(err, user): Promise<void> {
if (err) {
const errorCode = err.message
? fastify.statusCode.UNAUTHORIZED
: fastify.statusCode.INTERNAL_ERROR;
reply.send(fastify.errorUtils.getCode(errorCode, err.message));
} else {
const jWTSignOptions: JWTSignOptions = fastify.configInstance.security.web.sign;
debug('jwtSignOptions: %o', jWTSignOptions);
const token = await fastify.auth.jwtEncrypt(user, jWTSignOptions);
reply.code(fastify.statusCode.OK).send({ token, username });
}
}
);
});
fastify.put('/reset_password', async (request, reply) => {
if (_.isNil(request.userRemote.name)) {
reply.send(
fastify.errorUtils.getCode(
fastify.statusCode.UNAUTHORIZED,
fastify.errorUtils.API_ERROR.MUST_BE_LOGGED
)
);
}
// @ts-ignore
const { password } = request.body;
const { name } = request.userRemote;
if (validatePassword(password.new) === false) {
fastify.auth.changePassword(
name as string,
password.old,
password.new,
(err, isUpdated): void => {
if (_.isNil(err) && isUpdated) {
reply.code(fastify.statusCode.OK);
} else {
reply.send(
fastify.errorUtils.getInternalError(
fastify.errorUtils.API_ERROR.INTERNAL_SERVER_ERROR
)
);
}
}
);
} else {
reply.send(
fastify.errorUtils.getCode(
fastify.statusCode.BAD_REQUEST,
fastify.errorUtils.APP_ERROR.PASSWORD_VALIDATION
)
);
}
});
// });
}
export default loginRoute;

View File

@ -13,6 +13,7 @@ import authPlugin from './plugins/auth';
import configPlugin from './plugins/config';
import coreUtils from './plugins/coreUtils';
import storagePlugin from './plugins/storage';
import login from './routes/web/api/login';
import readme from './routes/web/api/readme';
import sidebar from './routes/web/api/sidebar';
@ -24,10 +25,10 @@ async function startServer({ logger, config }) {
debug('start server');
const fastifyInstance = fastify({ logger });
fastifyInstance.decorateRequest<RemoteUser>('userRemote', createAnonymousRemoteUser());
fastifyInstance.register(configPlugin, { config });
fastifyInstance.register(coreUtils);
fastifyInstance.register(authPlugin, { config: configInstance });
fastifyInstance.register(configPlugin, { config });
fastifyInstance.register(storagePlugin, { config: configInstance });
fastifyInstance.register(authPlugin, { config: configInstance });
// api
fastifyInstance.register((instance, opts, done) => {
@ -38,6 +39,8 @@ async function startServer({ logger, config }) {
instance.register(tarball);
instance.register(readme, { prefix: '/-/verdaccio' });
instance.register(sidebar, { prefix: '/-/verdaccio' });
instance.register(login, { prefix: '/-/verdaccio' });
done();
});

View File

@ -21,6 +21,7 @@ const getConf = (configName: string) => {
export async function initializeServer(configName: string): Promise<Application> {
const app = express();
const config = new Config(getConf(configName));
config.checkSecretKey('12345');
const storage = new Storage(config);
await storage.init(config, []);
const auth: IAuth = new Auth(config);