55 lines
1.7 KiB
TypeScript
55 lines
1.7 KiB
TypeScript
import type { Handler } from 'hono';
|
|
import type { User } from 'types';
|
|
import { getUserById, updateUser } from 'officerdb';
|
|
import { verify as verifyJwt, sign } from '@@/jwt';
|
|
import argon2 from 'argon2';
|
|
import * as errors from '@@/custom-errors';
|
|
import { validatePassword } from './validate-password';
|
|
|
|
export const verifyHandler: Handler = async function (ctx) {
|
|
const { verificationCode, name, username, password, confirmPassword } = ctx.get('body');
|
|
const userInfo = (await verifyJwt(verificationCode)) as User;
|
|
if (!userInfo) throw errors.BAD_REQUEST();
|
|
|
|
const user = getUserById(userInfo.id);
|
|
if (!user) throw errors.NOT_FOUND('User not found');
|
|
|
|
const updates: Record<string, unknown> = { status: 'Active' };
|
|
|
|
if (name) {
|
|
if (typeof name !== 'string' || !name.trim() || name.length > 128) {
|
|
throw errors.BAD_REQUEST('Name must be between 1 and 128 characters');
|
|
}
|
|
updates.name = name.trim();
|
|
}
|
|
|
|
if (username && typeof username === 'string' && username.trim()) {
|
|
updates.username = username.trim();
|
|
}
|
|
|
|
if (password) {
|
|
validatePassword(password);
|
|
if (password !== confirmPassword) {
|
|
throw errors.BAD_REQUEST('Passwords do not match');
|
|
}
|
|
updates.password = await argon2.hash(password);
|
|
}
|
|
|
|
await updateUser(userInfo.id, updates);
|
|
|
|
// Re-fetch user to get final values after update
|
|
const finalUser = getUserById(userInfo.id);
|
|
if (!finalUser) throw errors.NOT_FOUND('User not found');
|
|
|
|
// Issue a token so the user is logged in immediately
|
|
const token = await sign({
|
|
id: finalUser.id,
|
|
email: finalUser.email,
|
|
name: finalUser.name,
|
|
username: finalUser.username,
|
|
role: finalUser.role,
|
|
});
|
|
|
|
return ctx.json({ ok: true, token });
|
|
};
|