1
0

feat: argon2 passwords and sqlite-backed sessions

This commit is contained in:
2026-08-29 15:11:15 +02:00
parent dff7b4826d
commit f48093319b
2 changed files with 116 additions and 0 deletions

50
server/test/auth.test.ts Normal file
View File

@@ -0,0 +1,50 @@
import { describe, it, expect } from 'vitest'
import { openDatabase } from '../src/db.js'
import {
hashPassword,
verifyPassword,
createUser,
createSession,
getUserBySession,
deleteSession,
} from '../src/auth.js'
describe('passwords', () => {
it('hashes and verifies', async () => {
const hash = await hashPassword('correct horse battery staple')
expect(hash).not.toContain('correct')
expect(await verifyPassword(hash, 'correct horse battery staple')).toBe(true)
expect(await verifyPassword(hash, 'wrong')).toBe(false)
})
})
describe('sessions', () => {
it('creates a user and resolves a valid session, rejects expired', async () => {
const db = openDatabase(':memory:')
const user = createUser(db, 'sam', await hashPassword('password123'), true)
expect(user.is_admin).toBe(1)
const token = await createSession(db, user.id)
const resolved = getUserBySession(db, token, () => Date.now())
expect(resolved?.username).toBe('sam')
const expiredToken = await createSession(db, user.id)
db.prepare('UPDATE sessions SET expires_at = ? WHERE token = ?').run(
'2000-01-01T00:00:00.000Z',
expiredToken
)
expect(getUserBySession(db, expiredToken, () => Date.now())).toBeNull()
expect(
db.prepare('SELECT COUNT(*) AS n FROM sessions').get() as { n: number }
).toEqual({ n: 1 })
deleteSession(db, token)
expect(getUserBySession(db, token, () => Date.now())).toBeNull()
})
it('rejects duplicate usernames', async () => {
const db = openDatabase(':memory:')
createUser(db, 'sam', 'hash1', false)
expect(() => createUser(db, 'sam', 'hash2', false)).toThrow()
})
})