87 lines
2.6 KiB
TypeScript
87 lines
2.6 KiB
TypeScript
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,
|
|
};
|
|
};
|