23
server/trpc/context.ts
Normal file
23
server/trpc/context.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import type { CreateExpressContextOptions } from '@trpc/server/adapters/express'
|
||||
import { auth } from '../auth/lucia'
|
||||
|
||||
export async function createContext({ res, req }: CreateExpressContextOptions) {
|
||||
const sessionId = auth.readSessionCookie(req.headers.cookie ?? '')
|
||||
|
||||
if (!sessionId)
|
||||
return { res, req }
|
||||
|
||||
const { session, user } = await auth.validateSession(sessionId)
|
||||
|
||||
if (session && session.fresh) {
|
||||
res.appendHeader('Set-Cookie', auth.createSessionCookie(session.id).serialize())
|
||||
}
|
||||
|
||||
if (!session) {
|
||||
res.appendHeader('Set-Cookie', auth.createBlankSessionCookie().serialize())
|
||||
}
|
||||
|
||||
return { res, req, session, user }
|
||||
}
|
||||
|
||||
export type Context = Awaited<ReturnType<typeof createContext>>
|
||||
15
server/trpc/router.ts
Normal file
15
server/trpc/router.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import type { Context } from './context'
|
||||
import { initTRPC } from '@trpc/server'
|
||||
|
||||
const t = initTRPC.context<Context>().create()
|
||||
|
||||
export const router = t.router
|
||||
|
||||
export const publicProcedure = t.procedure
|
||||
|
||||
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
|
||||
if (!ctx.session?.fresh)
|
||||
throw new Error('UNAUTHORIZED')
|
||||
|
||||
return next({ ctx: { ...ctx } })
|
||||
})
|
||||
74
server/trpc/routers/auth.ts
Normal file
74
server/trpc/routers/auth.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { TRPCError } from '@trpc/server'
|
||||
import bcrypt from 'bcrypt'
|
||||
import { z } from 'zod'
|
||||
import { auth } from '../../auth/lucia'
|
||||
import client from '../../prisma/client'
|
||||
import { protectedProcedure, publicProcedure, router } from '../router'
|
||||
|
||||
export const authRouter = router({
|
||||
register: publicProcedure
|
||||
.input(z.object({ username: z.string().min(1), password: z.string().min(6) }))
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const hashed = await bcrypt.hash(input.password, 10)
|
||||
const user = await client.user.create({
|
||||
data: {
|
||||
username: input.username,
|
||||
password: hashed,
|
||||
displayName: input.username,
|
||||
},
|
||||
})
|
||||
|
||||
const session = await auth.createSession(user.id, {})
|
||||
const cookie = auth.createSessionCookie(session.id)
|
||||
|
||||
ctx.res.setHeader('Set-Cookie', cookie.serialize())
|
||||
|
||||
return { user }
|
||||
}),
|
||||
|
||||
login: publicProcedure
|
||||
.input(z.object({ username: z.string().min(1), password: z.string() }))
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const user = await client.user.findFirst({
|
||||
where: {
|
||||
username: input.username,
|
||||
},
|
||||
})
|
||||
|
||||
if (!user) {
|
||||
throw new TRPCError({
|
||||
code: 'NOT_FOUND',
|
||||
message: 'Incorrect username or password',
|
||||
})
|
||||
}
|
||||
|
||||
const validPassword = await bcrypt.compare(input.password, user.password)
|
||||
|
||||
if (!validPassword) {
|
||||
throw new TRPCError({
|
||||
code: 'NOT_FOUND',
|
||||
message: 'Incorrect username or password',
|
||||
})
|
||||
}
|
||||
|
||||
const session = await auth.createSession(user.id, {})
|
||||
const cookie = auth.createSessionCookie(session.id)
|
||||
|
||||
ctx.res.setHeader('Set-Cookie', cookie.serialize())
|
||||
|
||||
return { user }
|
||||
}),
|
||||
|
||||
me: protectedProcedure.query(({ ctx }) => {
|
||||
return ctx.user
|
||||
}),
|
||||
|
||||
logout: publicProcedure.mutation(async ({ ctx }) => {
|
||||
if (ctx.session)
|
||||
await auth.invalidateSession(ctx.session.id)
|
||||
|
||||
ctx.res.setHeader('Set-Cookie', auth.createBlankSessionCookie().serialize())
|
||||
|
||||
return true
|
||||
}),
|
||||
})
|
||||
8
server/trpc/routers/index.ts
Normal file
8
server/trpc/routers/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { router } from '../router'
|
||||
import { authRouter } from './auth'
|
||||
|
||||
export const appRouter = router({
|
||||
auth: authRouter,
|
||||
})
|
||||
|
||||
export type AppRouter = typeof appRouter
|
||||
Reference in New Issue
Block a user