2025-06-30 11:56:09 +00:00

230 lines
5.4 KiB
TypeScript

import type { Session, SessionApp } from "$lib/classes/sessions";
import { User, type IUserBroker } from "$lib/classes/users";
import { logger } from "$lib/utils/logger";
import { SSLSnifferApp } from "./sqlite";
import * as argon2 from "argon2";
class UserDB {
public user_id: number
public username: string
public password_hash: string
constructor(
user_id: number,
username: string,
password_hash: string
) {
this.user_id = user_id
this.username = username
this.password_hash = password_hash
}
}
export class UserDBBroker implements IUserBroker {
private static initialized = false
constructor() {
if (UserDBBroker.initialized) {
// UGLY: make more specific
throw Error("UserDB has been already initialized")
}
logger.debug("Correctly initialized", "UserDBBroker")
}
public createTable(): void {
const stmt = SSLSnifferApp.prepare(
`
CREATE TABLE IF NOT EXISTS users (
user_id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL ,
password_hash TEXT NOT NULL
);
`
)
stmt.run()
stmt.finalize()
}
public async createUser(username: string, password: string): Promise<User> {
this.validateUniqueness(username)
const insertUser = SSLSnifferApp.prepare(
`
INSERT INTO users (username, password_hash)
VALUES (@username, @password);
`
)
const passwordHash = await argon2.hash(password)
try {
insertUser.run({
username: username,
password: passwordHash
})
} catch (error) {
// UGLY: make this more specific
console.error("Duplicate after check??")
// UGLY: create a logger
console.error(`Insert User ${Date.now()}:\n\t${error}\n\n`)
throw new Error("You can't have duplicates")
}
insertUser.finalize()
const user = await this.getUser(username, password)
if (!user) {
// UGLY: make this more specific
throw new Error("Something went wrong during the creation of the user")
}
return user
}
public async getUser(username: string, password: string): Promise<User | null> {
const userToVerify = this.getUserFromUsername(username)
if (!userToVerify) {
// UGLY: make this more specific
throw new Error("The specified user does not exist on the database")
}
let match = false
try {
match = await argon2.verify(userToVerify.password_hash, password)
} catch (error) {
// UGLY: make this more specific
throw new Error("Argon2 had an error")
}
if (!match) {
return null
}
return new User(
userToVerify.user_id,
userToVerify.username
)
}
public async updatePassword(username: string, password: string, newPassword: string): Promise<void> {
const userToUpdate = await this.getUser(username, password)
if (!userToUpdate) {
// UGLY: make this more specific
throw new Error("Something went wrong while fetching the user")
}
const passwordHash = await argon2.hash(newPassword)
const stmt = SSLSnifferApp.prepare(
`
UPDATE users
SET password_hash = @newPassword
WHERE username = @username;
`
)
stmt.run({
username: userToUpdate.username,
newPassword: passwordHash
})
stmt.finalize()
}
public getUserFromSession(session: Session): User {
const userDB = this.getUserFromUserID(session.userID)
if (!userDB) {
// UGLY: be specific
throw new Error("Could not find user inside database")
}
return new User(
userDB.user_id,
userDB.username
)
}
private validateUniqueness(username: string) {
const user = this.getUserFromUsername(username)
if (!user) {
return
}
throw new Error("User is already on the system")
}
private getUserFromUsername(username: string): UserDB | null {
const stmt = SSLSnifferApp.prepare(
`
SELECT user_id, username, password_hash
FROM users
WHERE username = @username;
`
)
const user: any | null = stmt.get({
username: username,
})
stmt.finalize()
if (!user) {
return null
}
return new UserDB(
user.user_id,
user.username,
user.password_hash
)
}
private getUserFromUserID(userID: number): UserDB | null {
const stmt = SSLSnifferApp.prepare(
`
SELECT user_id, username, password_hash
FROM users
WHERE user_id = @user_id;
`
)
const user: any | null = stmt.get({
user_id: userID,
})
stmt.finalize()
if (!user) {
return null
}
return new UserDB(
user.user_id,
user.username,
user.password_hash
)
}
}