92 lines
2.9 KiB
TypeScript
92 lines
2.9 KiB
TypeScript
import { mkdtemp, rm } from 'node:fs/promises'
|
|
import { tmpdir } from 'node:os'
|
|
import { join } from 'node:path'
|
|
import { afterEach, describe, expect, it } from 'vitest'
|
|
import { AuthService } from '../src/server/auth-service.js'
|
|
import { openDatabase, type AppDatabase } from '../src/server/database.js'
|
|
|
|
const directories: string[] = []
|
|
const databases: AppDatabase[] = []
|
|
|
|
afterEach(async () => {
|
|
while (databases.length > 0) {
|
|
databases.pop()?.close()
|
|
}
|
|
await Promise.all(
|
|
directories.splice(0).map((directory) =>
|
|
rm(directory, { recursive: true, force: true })
|
|
)
|
|
)
|
|
})
|
|
|
|
describe('AuthService', () => {
|
|
it('creates the initial administrator only when the database is empty', async () => {
|
|
const directory = await mkdtemp(join(tmpdir(), 'product-issue-auth-'))
|
|
directories.push(directory)
|
|
const database = openDatabase(join(directory, 'database.sqlite'))
|
|
databases.push(database)
|
|
const auth = new AuthService(database, 'secret', 60 * 60 * 1_000)
|
|
|
|
await expect(
|
|
auth.createInitialAdmin({
|
|
email: 'first@example.com',
|
|
displayName: 'First admin',
|
|
password: 'first secure password'
|
|
})
|
|
).resolves.toBe(true)
|
|
await expect(
|
|
auth.createInitialAdmin({
|
|
email: 'second@example.com',
|
|
displayName: 'Second admin',
|
|
password: 'second secure password'
|
|
})
|
|
).resolves.toBe(false)
|
|
|
|
await expect(
|
|
auth.login('first@example.com', 'first secure password')
|
|
).resolves.toMatchObject({ displayName: 'First admin' })
|
|
await expect(
|
|
auth.login('second@example.com', 'second secure password')
|
|
).resolves.toBeUndefined()
|
|
})
|
|
|
|
it('invalidates existing sessions when an administrator is reset', async () => {
|
|
const directory = await mkdtemp(join(tmpdir(), 'product-issue-auth-'))
|
|
directories.push(directory)
|
|
const database = openDatabase(join(directory, 'database.sqlite'))
|
|
databases.push(database)
|
|
const auth = new AuthService(
|
|
database,
|
|
'test-secret-that-is-at-least-thirty-two-characters',
|
|
60 * 60 * 1_000
|
|
)
|
|
await auth.createAdmin({
|
|
email: 'admin@example.com',
|
|
displayName: 'First name',
|
|
password: 'correct horse battery staple'
|
|
})
|
|
await expect(
|
|
auth.login('unknown@example.com', 'an incorrect password')
|
|
).resolves.toBeUndefined()
|
|
const session = await auth.login(
|
|
'admin@example.com',
|
|
'correct horse battery staple'
|
|
)
|
|
expect(session).toBeDefined()
|
|
|
|
await auth.createAdmin({
|
|
email: 'admin@example.com',
|
|
displayName: 'Updated name',
|
|
password: 'a different secure password'
|
|
})
|
|
|
|
expect(auth.authenticate(session?.token)).toBeUndefined()
|
|
await expect(
|
|
auth.login('admin@example.com', 'correct horse battery staple')
|
|
).resolves.toBeUndefined()
|
|
await expect(
|
|
auth.login('admin@example.com', 'a different secure password')
|
|
).resolves.toMatchObject({ displayName: 'Updated name' })
|
|
})
|
|
})
|