1
0
Files
record-shop/server/src/auth.ts

67 lines
2.1 KiB
TypeScript
Raw Normal View History

import crypto from 'node:crypto'
import argon2 from 'argon2'
import type { DB } from './db.js'
export interface UserRow {
id: number
username: string
password_hash: string
is_admin: number
created_at: string
}
const SESSION_TTL_MS = 30 * 24 * 60 * 60 * 1000 // 30 days
export function hashPassword(password: string): Promise<string> {
return argon2.hash(password)
}
export function verifyPassword(hash: string, password: string): Promise<boolean> {
return argon2.verify(hash, password)
}
export function createUser(db: DB, username: string, passwordHash: string, isAdmin: boolean): UserRow {
const info = db
.prepare('INSERT INTO users (username, password_hash, is_admin) VALUES (?, ?, ?)')
.run(username, passwordHash, isAdmin ? 1 : 0)
return db.prepare('SELECT * FROM users WHERE id = ?').get(info.lastInsertRowid) as UserRow
}
export function getUserByUsername(db: DB, username: string): UserRow | undefined {
return db.prepare('SELECT * FROM users WHERE username = ?').get(username) as UserRow | undefined
}
export function getUserById(db: DB, id: number): UserRow | undefined {
return db.prepare('SELECT * FROM users WHERE id = ?').get(id) as UserRow | undefined
}
export function createSession(db: DB, userId: number): string {
const token = crypto.randomBytes(32).toString('hex')
const expiresAt = new Date(Date.now() + SESSION_TTL_MS).toISOString()
db.prepare('INSERT INTO sessions (token, user_id, expires_at) VALUES (?, ?, ?)').run(
token,
userId,
expiresAt
)
return token
}
export function getUserBySession(db: DB, token: string, now: () => number = Date.now): UserRow | null {
const row = db
.prepare(
`SELECT u.*, s.expires_at FROM sessions s
JOIN users u ON u.id = s.user_id WHERE s.token = ?`
)
.get(token) as (UserRow & { expires_at: string }) | undefined
if (!row) return null
if (new Date(row.expires_at).getTime() < now()) {
deleteSession(db, token)
return null
}
return row
}
export function deleteSession(db: DB, token: string): void {
db.prepare('DELETE FROM sessions WHERE token = ?').run(token)
}