import { getKysely } from "./kysely"; import { type IUser, Password, type UserAccessor, type UserCreateInput } from "../model/user"; class SqliteUser implements IUser { readonly username: string; readonly password: Password; constructor(username: string, pw: Password, private kysely = getKysely()) { this.username = username; this.password = pw; } async reset_password(password: string) { this.password.set_password(password); await this.kysely .updateTable("users") .where("username", "=", this.username) .set({ password_hash: this.password.hash, password_salt: this.password.salt }) .execute(); } async get_permissions() { const permissions = await this.kysely .selectFrom("permissions") .selectAll() .where("username", "=", this.username) .execute(); return permissions.map((x) => x.name); } async add(name: string) { const result = await this.kysely .insertInto("permissions") .values({ username: this.username, name }) .onConflict((oc) => oc.doNothing()) .executeTakeFirst(); return (result.numInsertedOrUpdatedRows ?? 0n) > 0; } async remove(name: string) { const result = await this.kysely .deleteFrom("permissions") .where("username", "=", this.username) .where("name", "=", name) .executeTakeFirst(); return (result.numDeletedRows ?? 0n) > 0; } } export const createSqliteUserController = (kysely = getKysely()): UserAccessor => { const createUser = async (input: UserCreateInput) => { if (undefined !== (await findUser(input.username))) { return undefined; } const user = new SqliteUser(input.username, new Password(input.password), kysely); await kysely .insertInto("users") .values({ username: user.username, password_hash: user.password.hash, password_salt: user.password.salt }) .execute(); return user; }; const findUser = async (id: string) => { const user = await kysely .selectFrom("users") .selectAll() .where("username", "=", id) .executeTakeFirst(); if (!user) return undefined; if (!user.password_hash || !user.password_salt) { throw new Error("password hash or salt is missing"); } if (user.username === null) { throw new Error("username is null"); } return new SqliteUser(user.username, new Password({ hash: user.password_hash, salt: user.password_salt }), kysely); }; const delUser = async (id: string) => { const result = await kysely.deleteFrom("users") .where("username", "=", id) .executeTakeFirst(); return (result.numDeletedRows ?? 0n) > 0; }; return { createUser: createUser, findUser: findUser, delUser: delUser, }; };