Created barebones for user database

This commit is contained in:
Christian Risi 2025-06-28 21:52:44 +00:00
parent 925610161e
commit 3618af361b
4 changed files with 293 additions and 9 deletions

79
src/lib/classes/users.ts Normal file
View File

@ -0,0 +1,79 @@
export interface IUserBroker {
createTable(): void
createUser(username: string, password: string): Promise<User>
getUser(username: string, password: string): Promise<User|null>
updatePassword(username: string, password: string, newPassword: string): Promise<void>
getUserFromSession(session: string): User
}
export class User {
public userID: number
public username: string
constructor(
userID: number,
username: string
) {
this.userID = userID
this.username = username
}
}
export class UserApp {
private static broker : IUserBroker
private static initialized: boolean = false
public static init(broker: IUserBroker) {
if (UserApp.initialized) {
// UGLY: make this Error more specific
throw Error("UserApp has already been initialized")
}
UserApp.initialized = true
UserApp.broker = broker
UserApp.broker.createTable()
}
public static getUserFromSession(session: string): User {
UserApp.assertInitialized()
return UserApp.broker.getUserFromSession(session)
}
public static createUser(username: string, password: string) {
UserApp.assertInitialized()
return UserApp.broker.createUser(username, password)
}
public static getUser(username: string, password: string): User {
UserApp.assertInitialized()
return UserApp.broker.getUser(username, password)
}
public static updatePassword(username: string, password: string, newPassword: string) {
UserApp.assertInitialized()
return UserApp.broker.updatePassword(username, password, newPassword)
}
private static assertInitialized() {
if (!UserApp.initialized) {
// UGLY: make more specific
throw Error("User app has't been Initialized yet!")
}
}
}

View File

@ -0,0 +1,17 @@
CREATE TABLE IF NOT EXISTS users (
user_id INTEGER PRIMARY KEY,
username TEXT UNIQUE NOT NULL ,
password_hash TEXT NOT NULL
);
INSERT INTO users (username, password_hash)
VALUES (@username, @password);
SELECT user_id, username, password_hash
FROM users
WHERE username = @username;
UPDATE users
SET password_hash = @newPassword
WHERE username = @username;

View File

@ -0,0 +1,183 @@
import { User, type IUserBroker } from "$lib/classes/users";
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 (UserDB.initialized) {
// UGLY: make more specific
throw Error("UserDB has been already initialized")
}
}
public createTable(): void {
const stmt = SSLSnifferApp.prepare(
`
CREATE TABLE IF NOT EXISTS users (
user_id INTEGER PRIMARY KEY,
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.getUserByUsername(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()
}
// TODO: implement this
public getUserFromSession(session: string): User {
throw new Error("Method not implemented.");
}
private validateUniqueness(username: string) {
const user = this.getUserByUsername(username)
if (!user) {
return
}
throw new Error("User is already on the system")
}
private getUserByUsername(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
)
}
}

View File

@ -5,20 +5,24 @@ export class SSLSnifferApp {
private static initialized = false
private __db: Database
private static db: Database
// UGLY: should be more flexible
constructor() {
this.__db = SSLSnifferApp.initDatabase()
public static init() {
if (SSLSnifferApp.initialized) {
throw new Error("SSLSniffer has already been initialized")
}
SSLSnifferApp.db = SSLSnifferApp.initDatabase()
SSLSnifferApp.initialized = true
}
public get db() {
return this.__db
public static prepare(query: string) {
return SSLSnifferApp.db.prepare(query)
}
// This needs to be static as it doesn't need the object
private static initDatabase() {
const db = new Database(
@ -35,14 +39,15 @@ export class SSLSnifferApp {
}
private closeDatabase(graceful?: boolean) {
private static closeDatabase(graceful?: boolean) {
if (!graceful) {
graceful = true
graceful = true
}
// Change of variable to make it more readable
const forceful = !graceful
this.db.close(forceful)
SSLSnifferApp.db.close(forceful)
}
}