@verdaccio/server-fastify
Version:
fastify server api implementation
153 lines (141 loc) • 5.05 kB
text/typescript
/* eslint-disable no-console */
/* eslint-disable no-invalid-this */
import buildDebug from 'debug';
import { FastifyInstance } from 'fastify';
import _ from 'lodash';
import { getApiToken } from '@verdaccio/auth';
import { createRemoteUser } from '@verdaccio/config';
import { validatioUtils } from '@verdaccio/core';
import { logger } from '@verdaccio/logger';
import { RemoteUser } from '@verdaccio/types';
import { getAuthenticatedMessage } from '@verdaccio/utils';
const debug = buildDebug('verdaccio:fastify:user');
async function userRoute(fastify: FastifyInstance) {
interface UserParamsInterface {
org_couchdb_user: string;
}
fastify.get<{ Params: UserParamsInterface }>('/:org_couchdb_user', async (request, reply) => {
// @ts-ignore
// TODO: compare org_couchdb_user with remote user name
const message = getAuthenticatedMessage(request.userRemote.name);
logger.info('user authenticated message %o', message);
reply.code(fastify.statusCode.OK);
return { ok: message };
});
interface DeleteTokenParamsInterface {
token: string;
}
fastify.delete<{ Params: DeleteTokenParamsInterface }>(
'/token/:token',
async (request, reply) => {
debug('loging out');
const { token } = request.params;
const userRemote: RemoteUser = request.userRemote;
await fastify.auth.invalidateToken(token);
console.log('userRoute', userRemote);
reply.code(fastify.statusCode.OK);
return { ok: fastify.apiMessage.LOGGED_OUT };
}
);
interface UpdateUserParamsInterface {
username: string;
}
fastify.put<{
Body: { name: string; password: string };
Params: UpdateUserParamsInterface;
}>('/:username', async (request, reply) => {
const { name, password } = request.body;
const remoteName = request.userRemote.name;
if (_.isNil(remoteName) === false && _.isNil(name) === false && remoteName === name) {
// debug('login: no remote user detected');
fastify.auth.authenticate(
name,
password,
async function callbackAuthenticate(err, user): Promise<void> {
if (err) {
logger.trace(
{ name, err },
'authenticating for user @{username} failed. Error: @{err.message}'
);
reply
.code(fastify.statusCode.UNAUTHORIZED)
.send(
fastify.errorUtils.getCode(
fastify.statusCode.UNAUTHORIZED,
fastify.apiError.BAD_USERNAME_PASSWORD
)
);
}
const restoredRemoteUser: RemoteUser = createRemoteUser(name, user?.groups || []);
const token = await getApiToken(
fastify.auth,
fastify.configInstance,
restoredRemoteUser,
password
);
debug('login: new token');
if (!token) {
return reply.send(fastify.errorUtils.getUnauthorized());
} else {
reply.code(fastify.statusCode.CREATED);
const message = getAuthenticatedMessage(remoteName);
debug('login: created user message %o', message);
reply.send({
ok: message,
token,
});
}
}
);
} else {
if (
validatioUtils.validatePassword(
password as string,
fastify.configInstance?.server?.passwordValidationRegex
) === false
) {
debug('adduser: invalid password');
reply.code(fastify.statusCode.BAD_REQUEST).send(
fastify.errorUtils.getCode(
fastify.statusCode.BAD_REQUEST,
// eslint-disable-next-line new-cap
fastify.apiError.PASSWORD_SHORT
)
);
return;
}
fastify.auth.add_user(name, password, async function (err, user): Promise<void> {
if (err) {
if (
err.status >= fastify.statusCode.BAD_REQUEST &&
err.status < fastify.statusCode.INTERNAL_ERROR
) {
debug('adduser: error on create user');
// With npm registering is the same as logging in,
// and npm accepts only an 409 error.
// So, changing status code here.
const addUserError =
fastify.errorUtils.getCode(err.status, err.message) ||
fastify.errorUtils.getConflict(err.message);
reply.send(addUserError);
return;
}
}
const token =
name && password
? await getApiToken(fastify.auth, fastify.configInstance, user as RemoteUser, password)
: undefined;
debug('adduser: new token %o', token);
if (!token) {
return reply.send(fastify.errorUtils.getUnauthorized());
}
debug('adduser: user has been created');
reply.code(fastify.statusCode.CREATED).send({
ok: `user '${name}' created`,
token,
});
});
}
});
}
export default userRoute;