diff --git a/src/lib/server/auth-utils.ts b/src/lib/server/auth-utils.ts new file mode 100644 index 0000000..53123f0 --- /dev/null +++ b/src/lib/server/auth-utils.ts @@ -0,0 +1,22 @@ +import { hash, verify } from '@node-rs/argon2'; +import crypto from 'crypto'; + +export async function hashPassword(password: string): Promise { + return hash(password); +} + +export async function verifyPassword(hashedPassword: string, password: string): Promise { + try { + return await verify(hashedPassword, password); + } catch { + return false; + } +} + +export function generateSessionToken(): string { + return crypto.randomBytes(32).toString('hex'); +} + +export function hashSessionToken(token: string): string { + return crypto.createHash('sha256').update(token).digest('hex'); +} diff --git a/tests/unit/auth.test.ts b/tests/unit/auth.test.ts new file mode 100644 index 0000000..6f1bac0 --- /dev/null +++ b/tests/unit/auth.test.ts @@ -0,0 +1,29 @@ +import { describe, it, expect } from 'vitest'; +import { + hashPassword, verifyPassword, generateSessionToken, hashSessionToken +} from '$lib/server/auth-utils'; + +describe('auth-utils', () => { + it('hashes and verifies a password', async () => { + const hash = await hashPassword('testpassword'); + expect(hash).not.toBe('testpassword'); + expect(await verifyPassword(hash, 'testpassword')).toBe(true); + expect(await verifyPassword(hash, 'wrongpassword')).toBe(false); + }); + + it('generates unique session tokens', () => { + const token1 = generateSessionToken(); + const token2 = generateSessionToken(); + expect(token1).toHaveLength(64); + expect(token2).toHaveLength(64); + expect(token1).not.toBe(token2); + }); + + it('hashes session tokens deterministically', () => { + const token = generateSessionToken(); + const hash1 = hashSessionToken(token); + const hash2 = hashSessionToken(token); + expect(hash1).toBe(hash2); + expect(hash1).not.toBe(token); + }); +});