import { createHmac, randomBytes } from "node:crypto"; function hashForPassword(salt: string, password: string) { return createHmac("sha256", salt).update(password).digest("hex"); } function createPasswordHashAndSalt(password: string): { salt: string; hash: string } { const secret = randomBytes(32).toString("hex"); return { salt: secret, hash: hashForPassword(secret, password), }; } export class Password { private _salt: string; private _hash: string; constructor(pw: string | { salt: string; hash: string }) { const { salt, hash } = typeof pw === "string" ? createPasswordHashAndSalt(pw) : pw; this._hash = hash; this._salt = salt; } set_password(password: string) { const { salt, hash } = createPasswordHashAndSalt(password); this._hash = hash; this._salt = salt; } check_password(password: string): boolean { return this._hash === hashForPassword(this._salt, password); } get salt() { return this._salt; } get hash() { return this._hash; } } export interface UserCreateInput { username: string; password: string; } export interface IUser { readonly username: string; readonly password: Password; /** * return user's permission list. */ get_permissions(): Promise; /** * add permission * @param name permission name to add * @returns if `name` doesn't exist, return true */ add(name: string): Promise; /** * remove permission * @param name permission name to remove * @returns if `name` exist, return true */ remove(name: string): Promise; /** * reset password. * @param password password to set */ reset_password(password: string): Promise; } export interface UserAccessor { /** * create user * @returns if user exist, return undefined */ createUser: (input: UserCreateInput) => Promise; /** * find user */ findUser: (username: string) => Promise; /** * remove user * @returns if user exist, true */ delUser: (username: string) => Promise; }