49 lines
1.3 KiB
TypeScript
49 lines
1.3 KiB
TypeScript
import bcrypt from 'bcryptjs'
|
|
import { SignJWT, jwtVerify } from 'jose'
|
|
import { getDatabase } from './database.server'
|
|
|
|
export interface User {
|
|
id: number
|
|
username: string
|
|
password_hash: string
|
|
created_at: string
|
|
}
|
|
|
|
export async function authenticateUser(username: string, password: string): Promise<User | null> {
|
|
const db = await getDatabase()
|
|
const user = db.prepare('SELECT * FROM users WHERE username = ?').get(username) as User | undefined
|
|
|
|
if (!user) return null
|
|
|
|
const isValid = await bcrypt.compare(password, user.password_hash)
|
|
if (!isValid) return null
|
|
|
|
return user
|
|
}
|
|
|
|
export async function createJWT(user: User): Promise<string> {
|
|
const config = useRuntimeConfig()
|
|
const secret = new TextEncoder().encode(config.jwtSecret)
|
|
|
|
return await new SignJWT({ userId: user.id, username: user.username })
|
|
.setProtectedHeader({ alg: 'HS256' })
|
|
.setIssuedAt()
|
|
.setExpirationTime('7d')
|
|
.sign(secret)
|
|
}
|
|
|
|
export async function verifyJWT(token: string): Promise<{ userId: number; username: string } | null> {
|
|
try {
|
|
const config = useRuntimeConfig()
|
|
const secret = new TextEncoder().encode(config.jwtSecret)
|
|
|
|
const { payload } = await jwtVerify(token, secret)
|
|
return {
|
|
userId: payload.userId as number,
|
|
username: payload.username as string
|
|
}
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|