Files
chad/server/routes/auth.ts
2026-05-22 05:08:02 +06:00

141 lines
3.4 KiB
TypeScript

import type { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox'
import bcrypt from 'bcrypt'
import { CreateUserPayloadSchema, LoginPayloadSchema, UserSchema } from '../plugins/schemas/auth.ts'
import { TypeboxRef } from '../utils/typebox-ref.ts'
const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
fastify.post(
'/auth/register',
{
schema: {
summary: 'Register',
tags: ['Auth'],
operationId: 'auth.register',
body: TypeboxRef(CreateUserPayloadSchema),
response: {
200: TypeboxRef(UserSchema),
},
},
config: {
skipAuth: true,
},
},
async (req, reply) => {
const hashed = await bcrypt.hash(req.body.password, 10)
const user = await fastify.prisma.user.create({
data: {
username: req.body.username,
password: hashed,
displayName: req.body.username,
UserPreferences: {
create: {},
},
},
})
const session = await fastify.lucia.createSession(user.username, {})
const cookie = fastify.lucia.createSessionCookie(session.id)
reply.setCookie(cookie.name, cookie.value, cookie.attributes)
return {
username: user.username,
displayName: user.username,
createdAt: user.createdAt.toISOString(),
}
},
)
fastify.post(
'/auth/login',
{
schema: {
summary: 'Login',
tags: ['Auth'],
operationId: 'auth.login',
body: TypeboxRef(LoginPayloadSchema),
response: {
200: TypeboxRef(UserSchema),
},
},
config: {
skipAuth: true,
},
},
async (req, reply) => {
const user = await fastify.prisma.user.findFirst({
where: { username: req.body.username },
select: {
username: true,
displayName: true,
createdAt: true,
password: true,
},
})
if (!user) {
return reply.notFound('Incorrect username or password')
}
const validPassword = await bcrypt.compare(req.body.password, user.password)
if (!validPassword) {
return reply.notFound('Incorrect username or password')
}
const session = await fastify.lucia.createSession(user.username, {})
const cookie = fastify.lucia.createSessionCookie(session.id)
reply.setCookie(cookie.name, cookie.value, cookie.attributes)
return {
...user,
createdAt: user.createdAt.toISOString(),
}
},
)
fastify.get(
'/auth/me',
{
schema: {
summary: 'Me',
tags: ['Auth'],
operationId: 'auth.me',
response: {
200: TypeboxRef(UserSchema),
},
},
},
async (req) => {
const user = req.user!
return {
username: user.username,
displayName: user.displayName,
createdAt: user.createdAt.toISOString(),
}
},
)
fastify.post(
'/auth/logout',
{
schema: {
summary: 'Logout',
tags: ['Auth'],
operationId: 'auth.logout',
},
},
async (req, reply) => {
if (req.session)
await fastify.lucia.invalidateSession(req.session.id)
const blank = fastify.lucia.createBlankSessionCookie()
reply.setCookie(blank.name, blank.value, blank.attributes)
},
)
}
export default plugin