From 4c80caa52a43d513be7de977b496492d268aafea Mon Sep 17 00:00:00 2001 From: Esad Mustafoski Date: Sun, 2 Feb 2025 12:33:47 +0100 Subject: [PATCH] Attempted adding of 'Salting' for the password, a method which adds random numbers or letters to make rainbowtable password cracking impossible, not tested yet --- api/helpers.ts | 63 +++++---- api/main.ts | 294 +++++++++++++++++++++----------------- database/create_db.ts | 31 ++-- database/utils.ts | 322 +++++++++++++++++++++++------------------- 4 files changed, 399 insertions(+), 311 deletions(-) diff --git a/api/helpers.ts b/api/helpers.ts index 60a18e5..137f4cf 100644 --- a/api/helpers.ts +++ b/api/helpers.ts @@ -1,18 +1,16 @@ /// - -/** +/** * @author Esad Mustafoski * @file api/helpers.ts * @description Helper functions for the API - * */ import { Context } from "https://deno.land/x/oak/mod.ts"; import { encodeHex } from "jsr:@std/encoding/hex"; // import { hash } from "node:crypto"; export type ApiResponse = { - status: number; - body: unknown; + status: number; + body: unknown; }; // --- Helper Functions --- // @@ -22,9 +20,9 @@ export type ApiResponse = { * Status is the HTTP Status code * Body is the response body/message/data. */ -const sendResponse = (ctx: Context, {status, body}: ApiResponse): void => { - ctx.response.status = status; - ctx.response.body = body as any; +const sendResponse = (ctx: Context, { status, body }: ApiResponse): void => { + ctx.response.status = status; + ctx.response.body = body as any; }; /** @@ -32,24 +30,41 @@ const sendResponse = (ctx: Context, {status, body}: ApiResponse): void => { * @see sendResponse */ const errorResponse = (ctx: Context, status: number, message: string): void => { - sendResponse(ctx, { status, body: { error: message } }); + sendResponse(ctx, { status, body: { error: message } }); }; -/** - * @description Hashing Function for Passwords/etc - * @param password The password to hash +/** + * @description password "Salter", used to salt the passwords before the hash, this salt will be + * returned seperately to save the salt in the DB + * @param password The password to salt + * @returns {saltedPassword: string, salt: string} Password with the salt + Salt seperately, both strings */ -const hashPassword = async(password: string): Promise => { - const to_hash = password; - const buffer = new TextEncoder().encode(to_hash); - const hash_buffer = await crypto.subtle.digest("SHA-256", buffer); - const hash = await encodeHex(hash_buffer); - - return hash; -} +const saltPassword = async ( + password: string, +): Promise<{ saltedPassword: string; salt: string }> => { + const saltBytes = new Uint8Array(16); // 16 bytes = 128 bits for randomness + await crypto.getRandomValues(saltBytes); + const salt = encodeHex(saltBytes); -export { - sendResponse, - errorResponse, - hashPassword + const saltedPassword = `${password}${salt}`; + + return { + saltedPassword, + salt, + }; }; + +/** + * @description Hashing Function for Passwords/etc + * @param password The password to hash + * @returns {hash: string} The hashed password as a string + */ +const hashPassword = async (password: string): Promise => { + const to_hash = password; + const buffer = new TextEncoder().encode(to_hash); + const hash_buffer = await crypto.subtle.digest("SHA-256", buffer); + const hash = await encodeHex(hash_buffer); + return hash; +}; + +export { errorResponse, hashPassword, saltPassword, sendResponse }; diff --git a/api/main.ts b/api/main.ts index ec72002..b362598 100644 --- a/api/main.ts +++ b/api/main.ts @@ -1,11 +1,16 @@ /// /** * @author Esad Mustafoski - * Main API file, Handles all the routing/api stuff + * @ðescription Main API file, Handles all the routing/api stuff */ // +++ IMPORTS ------------------------------------------------------ // -import { Application, Router, Context, Next } from "https://deno.land/x/oak/mod.ts"; +import { + Application, + Context, + Next, + Router, +} from "https://deno.land/x/oak/mod.ts"; import { oakCors } from "https://deno.land/x/cors/mod.ts"; import * as db_utils from "../database/utils.ts"; import * as helper_utils from "./helpers.ts"; @@ -14,11 +19,11 @@ import * as helper_utils from "./helpers.ts"; const router = new Router(); const app = new Application(); -// For the future +// unused for now type ApiResponse = { - status: number; - body: unknown; - } + status: number; + body: unknown; +}; // +++ ROUTER ------------------------------------------------------- // // Creates the routes for the API server. @@ -27,13 +32,17 @@ type ApiResponse = { // Docs Routes router - .get("/", (ctx) => { ctx.response.body = "For endpoints, use /api/{name}"; }) - .get("/api", (ctx) => { ctx.response.body = "For API Documentation, visit /docs"; }) + .get("/", (ctx) => { + ctx.response.body = "For endpoints, use /api/{name}"; + }) + .get("/api", (ctx) => { + ctx.response.body = "For API Documentation, visit /docs"; + }); -// Account routes +// -- Account routes -- router - .post("/api/account/login", api_login) // TODO - .post("/api/account/register", api_register) // TODO + .post("/api/account/login", api_login) + .post("/api/account/register", api_register) .post("/api/account/logout", () => {}) // TODO .post("/api/account/password/forgot", () => {}) // TODO .post("/api/account/password/reset", () => {}) // TODO @@ -41,177 +50,196 @@ router .post("/api/account/email/change-email", () => {}) // TODO .post("/api/account/email/verify-email", () => {}) // TODO .post("/api/account/delete-account", () => {}) // TODO - .post("/api/account/block", () => {}) // TODO + .post("/api/account/block", () => {}); // TODO -// Auth Routes +// -- Auth Routes -- router .get("/api/auth", () => {}) // TODO .get("/api/auth/verify", () => {}) // TODO - .get("/api/auth/refresh", () => {}) // TODO + .get("/api/auth/refresh", () => {}); // TODO -// User routes +// -- User routes -- router .get("/api/users", api_getAllUsers) - .get("/api/user/:id/info", api_user_getInfo); // @error GEHT NICHT + .get("/api/user/:id/info", api_user_getInfo); -// Post routes +// -- Post routes -- router .get("/api/posts", api_posts_getAll); + // +++ FUNCTIONS ----------------------------------------------------- // - - - - -/** - * @description Stands between the client and the API - * It checks if the client is authorized to access the API with a token/Multiple tokens - * Currently not implemented - * Middleware - */ - async function authenticator(ctx: Context, next: Next): Promise { - const authHeader = ctx.request.headers.get('Authorization'); + const authHeader = ctx.request.headers.get("Authorization"); - if (!authHeader) { - ctx.response.status = 401; - ctx.response.body = { error: "No header" }; - return; - } - - const match = authHeader.match(/^Bearer (.+)$/); - if (!match) { - ctx.response.status = 401; - ctx.response.body = { error: "Invalid format" }; - return; - } + if (!authHeader) { + ctx.response.status = 401; + ctx.response.body = { error: "No header" }; + return; + } - const token = match[1]; + const match = authHeader.match(/^Bearer (.+)$/); + if (!match) { + ctx.response.status = 401; + ctx.response.body = { error: "Invalid format" }; + return; + } - try { - // Token logic missing, not tried or attempted yet. - await next(); - } catch (error) { - ctx.response.status = 401; - ctx.response.body = { error: "Invalid token" }; - } + const token = match[1]; + + try { + // Token logic missing, not tried or attempted yet. + await next(); + } catch (error) { + ctx.response.status = 401; + ctx.response.body = { error: "Invalid token" }; + } } -async function tokenChecker(ctx: Context, next: Next): Promise { - // logic below (TODO): - /** - * 1. check if the token is valid - * 2. if valid, set the user in the context - * 3. if not valid, return 401 - * 4. if token is missing, return 401 - * 5. if token is expired, return 401 - * 6. if token is blacklisted, return 401 - * 7. if token is not in the database, return 401 - * 8. if token is not associated with a user, return 401 - * 9. if token is not associated with the correct user, return 401 - */ +async function tokenChecker(ctx: Context, next: Next): Promise { + // logic below (TODO): + /** + * 1. check if the token is valid + * 2. if valid, set the user in the context + * 3. if not valid, return 401 + * 4. if: token missing, expired, blacklisted, !DB, !user or !correct user, return 401 with associated error + * eg: wrong user: 401 -> "Token not associated with this user" + */ } async function api_getAllUsers(ctx: Context): Promise { - const getUsers = await db_utils.getAllUsersFromDB(); - ctx.response.body = getUsers; + const getUsers = await db_utils.getAllUsersFromDB(); + ctx.response.body = getUsers; } // Users async function api_user_getInfo(ctx: any): Promise { - const id = ctx.params.id; - - if (!id) { - ctx.response.status = 400; // Bad Request status - ctx.response.body = { error: "User ID required" }; - return; + const id = ctx.params.id; + + if (!id) { + ctx.response.status = 400; + ctx.response.body = { error: "User ID required" }; + return; + } + + try { + const user = await db_utils.getAllUserInfoByID(id); + if (user === null || user === undefined) { + helper_utils.errorResponse(ctx, 404, "User not found"); + return; } - try { - const user = await db_utils.getAllUserInfoByID(id); - if (user === null || user === undefined) { - helper_utils.errorResponse(ctx, 404, "User not found"); - return; - } - - ctx.response.body = user; - } catch (error) { - helper_utils.errorResponse(ctx, 500, "Internal Server Error"); - } + ctx.response.body = user; + } catch (error) { + helper_utils.errorResponse(ctx, 500, error as string); + } } // Posts async function api_posts_getAll(ctx: Context): Promise { - const posts = await db_utils.getPostsFromDB(); - ctx.response.body = posts; + const posts = await db_utils.getPostsFromDB(); + ctx.response.body = posts; } -// Comments +// Comments (missing) // login/register async function api_register(ctx: Context): Promise { - try { - const body = ctx.request.body; - const result = await body.json(); - const { username, password, userGroup, displayname, user_email, firstname, surname} = result; - const account_created = `${Math.floor(Date.now() / 1000)}-${new Date().toLocaleDateString('en-GB').split('/').join('-')}`; + try { + const body = ctx.request.body; + const result = await body.json(); + const { + username, + password, + userGroup, + displayname, + user_email, + firstname, + surname, + } = result; + const account_created = `${Math.floor(Date.now() / 1000)}-${ + new Date().toLocaleDateString("en-GB").split("/").join("-") + }`; - - if ( !username || !password || !userGroup || !displayname || !user_email || !firstname || !surname) { - helper_utils.errorResponse(ctx, 400, "Missing required fields"); - return; - } - - const hash = await helper_utils.hashPassword(password); - const userId = await db_utils.registerUser(username, hash, userGroup, displayname, user_email, firstname, surname, account_created); - helper_utils.sendResponse(ctx, { status: 200, body: `Registered under name: ${userId}` }); - } catch (error) { - console.log(error); - helper_utils.errorResponse(ctx, 500, "Invalid request"); - return; + if ( + !username || !password || !userGroup || !displayname || !user_email || + !firstname || !surname + ) { + helper_utils.errorResponse(ctx, 400, "Missing required fields"); + return; } + + // First salt the password + const { saltedPassword, salt } = await helper_utils.saltPassword(password); + // Then hash the salted password + const hash = await helper_utils.hashPassword(saltedPassword); + + const userId = await db_utils.registerUser( + username, + hash, + salt, + userGroup, + displayname, + user_email, + firstname, + surname, + account_created, + ); + + helper_utils.sendResponse(ctx, { + status: 200, + body: `Registered under name: ${userId}`, + }); + } catch (error) { + console.log(error); + helper_utils.errorResponse(ctx, 500, "Invalid request"); + return; + } } async function api_login(ctx: Context): Promise { - try { - const body = ctx.request.body; - const result = await body.json(); - const { username, password } = result; + try { + const body = ctx.request.body; + const result = await body.json(); + const { username, password } = result; - if (!username || !password) { - helper_utils.errorResponse(ctx, 400, "Missing required fields"); - return "Error"; - } - - const user = await db_utils.getUserByUsername(username); - if (!user) { - helper_utils.errorResponse(ctx, 404, "User not found"); - return "Error"; - } - - const hash = await helper_utils.hashPassword(password); - if (user.password !== hash) { - helper_utils.errorResponse(ctx, 401, "Invalid password"); - return "Error"; - } - - - } catch (error) { - console.log(error); - helper_utils.errorResponse(ctx, 500, "Invalid request"); - return "Error"; + if (!username || !password) { + helper_utils.errorResponse(ctx, 400, "Missing required fields"); + return "Error"; } - + + const user = await db_utils.getUserByUsername(username); + if (!user) { + helper_utils.errorResponse(ctx, 404, "User not found"); + return "Error"; + } + + // Get the stored salt for this user + const storedSalt = user.password_salt; + // Salt the provided password with the stored salt + const saltedPassword = `${password}${storedSalt}`; + // Hash the salted password + const hash = await helper_utils.hashPassword(saltedPassword); + + // Compare with stored hash + if (user.password !== hash) { + helper_utils.errorResponse(ctx, 401, "Invalid password"); + return "Error"; + } + helper_utils.sendResponse(ctx, { status: 200, body: "Success" }); return "Success"; + } catch (error) { + console.log(error); + helper_utils.errorResponse(ctx, 500, "Invalid request"); + return "Error"; + } } -// Filtering - // +++ APP ---------------------------------------------------------- // app.use(oakCors({ - origin: '*', - credentials: true, + origin: "*", + credentials: true, })); app.use(router.routes()); app.use(router.allowedMethods()); diff --git a/database/create_db.ts b/database/create_db.ts index 932c7f3..8704cce 100644 --- a/database/create_db.ts +++ b/database/create_db.ts @@ -15,7 +15,7 @@ const dbPath: string = join(_dirname, "../database/esp-projekt.sqlite"); const db = new DB(dbPath); export function createDatabase(): void { - db.execute(` + db.execute(` CREATE TABLE IF NOT EXISTS accounts ( uuid INTEGER PRIMARY KEY AUTOINCREMENT, user_group TEXT, @@ -24,6 +24,7 @@ export function createDatabase(): void { user_username TEXT, user_e-mail TEXT, password TEXT, + password_salt TEXT, firstname TEXT, surname TEXT, account_created TEXT, @@ -50,28 +51,34 @@ export function createDatabase(): void { likes INTEGER ) `); -}; +} // Sample data generated using AI, does not work yet and will be adjusted export function insertSampleData(): void { - db.query(`INSERT INTO accounts (user_group, user_bio, user_displayname, user_username, user_email, password, firstname, surname, account_created, followers, following, contacts) VALUES - ('admin', 'Admin bio', 'Admin User', 'admin', 'admin@example.com', 'hashedpass1', 'Admin', 'User', '2024-01-01', '[]', '[]', '[]', '[]'), - ('user', 'I love coding!', 'John Dev', 'johndev', 'john@example.com', 'hashedpass2', 'John', 'Smith', '2024-01-02', '[]', '[3,4]', '[1,2]', '[]'), - ('user', 'Photography enthusiast', 'Alice', 'alice_photo', 'alice@example.com', 'hashedpass3', 'Alice', 'Johnson', '2024-01-03', '[5]', '[1]', '[2]', '[]') - `); + db.query( + `INSERT INTO accounts (user_group, user_bio, user_displayname, user_username, user_email, password, password_salt, firstname, surname, account_created, followers, following, contacts) VALUES + ('admin', 'Admin bio', 'Admin User', 'admin', 'admin@example.com', 'hashedpass1', 'salt1', 'Admin', 'User', '2024-01-01', '[]', '[]', '[]', '[]'), + ('user', 'I love coding!', 'John Dev', 'johndev', 'john@example.com', 'hashedpass2', 'salt2', 'John', 'Smith', '2024-01-02', '[]', '[3,4]', '[1,2]', '[]'), + ('user', 'Photography enthusiast', 'Alice', 'alice_photo', 'alice@example.com', 'hashedpass3', 'salt3', 'Alice', 'Johnson', '2024-01-03', '[5]', '[1]', '[2]', '[]') + `, + ); - db.query(`INSERT INTO posts (user_id, created_at, post_text, likes, comments) VALUES + db.query( + `INSERT INTO posts (user_id, created_at, post_text, likes, comments) VALUES (1, '2024-01-15 10:00:00', 'First post about programming!', 5, 2), (1, '2024-01-15 11:30:00', 'Check out this new feature', 10, 3), (2, '2024-01-16 09:15:00', 'Just learned about TypeScript', 8, 1), (3, '2024-01-16 14:20:00', 'Posted my new photo collection', 15, 4) - `); + `, + ); - db.query(`INSERT INTO comments (post_id, author_user_id, date_created_at, text, likes) VALUES + db.query( + `INSERT INTO comments (post_id, author_user_id, date_created_at, text, likes) VALUES (1, 2, '2024-01-15 10:05:00', 'Great post!', 3), (1, 3, '2024-01-15 10:10:00', 'Very informative', 2), (2, 3, '2024-01-15 11:35:00', 'Nice feature', 4), (3, 1, '2024-01-16 09:20:00', 'TypeScript is awesome', 5), (4, 2, '2024-01-16 14:25:00', 'Beautiful photos!', 6) - `); -}; \ No newline at end of file + `, + ); +} diff --git a/database/utils.ts b/database/utils.ts index baa9e24..5ec1b81 100644 --- a/database/utils.ts +++ b/database/utils.ts @@ -11,10 +11,9 @@ import { dirname, fromFileUrl, join } from "https://deno.land/std/path/mod.ts"; import * as db_create from "./create_db.ts"; // +++ VARIABLES ---------------------------------------------------- // -// __dirname Is never getting used again, It's only needed because the DB Import +// _dirname Is never getting used again, It's only needed because the DB Import // from SQLite doesn't like relative paths, so I use this as // A Workaround - const _dirname: string = dirname(fromFileUrl(import.meta.url)); const dbPath: string = join(_dirname, "../database/esp-projekt.sqlite"); const db = new DB(dbPath); @@ -22,119 +21,126 @@ const db = new DB(dbPath); // +++ INTERFACES --------------------------------------------------- // // Used in the Functions to define the return type/Avoid type errors interface Post { - posts_uuid: number; - user_id: number; - created_at: string; - post_text: string; - likes: number; - comments: number; + posts_uuid: number; + user_id: number; + created_at: string; + post_text: string; + likes: number; + comments: number; } interface Accounts { - user_id: number; - user_group: string; - bio: string; - displayname: string; - username: string; - user_email: string; - password: string; - firstname: string; - surname: string; - account_created: string; - blocked_users: string; - followers: string; - following: string; - contacts: string; + user_id: number; + user_group: string; + bio: string; + displayname: string; + username: string; + user_email: string; + password: string; + password_salt: string; + firstname: string; + surname: string; + account_created: string; + blocked_users: string; + followers: string; + following: string; + contacts: string; } interface Comments { - comment_id: number; - post_id: number; - author_user_id: number; - date_created_at: string; - text: string; - likes: number; + comment_id: number; + post_id: number; + author_user_id: number; + date_created_at: string; + text: string; + likes: number; } // +++ Helper ------------------------------------------------------ // function mapPostRow(row: Row): Post { - const [posts_uuid, user_id, created_at, post_text, likes, comments] = row; - return { - posts_uuid: Number(posts_uuid), - user_id: Number(user_id), - created_at: String(created_at), - post_text: String(post_text), - likes: Number(likes), - comments: Number(comments), - }; + const [posts_uuid, user_id, created_at, post_text, likes, comments] = row; + return { + posts_uuid: Number(posts_uuid), + user_id: Number(user_id), + created_at: String(created_at), + post_text: String(post_text), + likes: Number(likes), + comments: Number(comments), + }; } function mapAccountRow(row: Row): Accounts { - const [ - user_id, - user_group, - bio, - displayname, - username, - user_email, - password, - firstname, - surname, - account_created, - blocked_users, - followers, - following, - contacts, - ] = row; - return { - user_id: Number(user_id), - user_group: String(user_group), - bio: String(bio), - displayname: String(displayname), - username: String(username), - user_email: String(user_email), - password: String(password), - firstname: String(firstname), - surname: String(surname), - account_created: String(account_created), - blocked_users: String(blocked_users), - followers: String(followers), - following: String(following), - contacts: String(contacts), - }; + const [ + user_id, + user_group, + bio, + displayname, + username, + user_email, + password, + password_salt, + firstname, + surname, + account_created, + blocked_users, + followers, + following, + contacts, + ] = row; + return { + user_id: Number(user_id), + user_group: String(user_group), + bio: String(bio), + displayname: String(displayname), + username: String(username), + user_email: String(user_email), + password: String(password), + password_salt: String(password_salt), + firstname: String(firstname), + surname: String(surname), + account_created: String(account_created), + blocked_users: String(blocked_users), + followers: String(followers), + following: String(following), + contacts: String(contacts), + }; } function mapCommentRow(row: Row): Comments { - const [ - comment_id, - post_id, - author_user_id, - date_created_at, - text, - likes, - ] = row; - return { - comment_id: Number(comment_id), - post_id: Number(post_id), - author_user_id: Number(author_user_id), - date_created_at: String(date_created_at), - text: String(text), - likes: Number(likes), - }; + const [ + comment_id, + post_id, + author_user_id, + date_created_at, + text, + likes, + ] = row; + return { + comment_id: Number(comment_id), + post_id: Number(post_id), + author_user_id: Number(author_user_id), + date_created_at: String(date_created_at), + text: String(text), + likes: Number(likes), + }; } // "T" is a generic type, it can be anything and makes the function "flexible"(?) -async function queryDatabase(query: string, params: any[], mapRow: (row: Row) => T,): Promise { - const results: T[] = []; - try { - const rows = await db.query(query, params); - for (const row of rows) { - results.push(mapRow(row)); - } - } catch (error) { - console.error("Database query error:", error); +async function queryDatabase( + query: string, + params: any[], + mapRow: (row: Row) => T, +): Promise { + const results: T[] = []; + try { + const rows = await db.query(query, params); + for (const row of rows) { + results.push(mapRow(row)); } - return results; + } catch (error) { + console.error("Database query error:", error); + } + return results; } // +++ FUNCTIONS --------------------------------------------------- // @@ -144,11 +150,11 @@ async function queryDatabase(query: string, params: any[], mapRow: (row: Row) * @file ./create_db.ts */ function insertSamples(): void { - db_create.insertSampleData(); + db_create.insertSampleData(); } function createDatabaseIfNotExist(): void { - db_create.createDatabase(); + db_create.createDatabase(); } /** @@ -158,30 +164,30 @@ function createDatabaseIfNotExist(): void { * @returns Array of all Posts in the Database */ async function getPostsFromDB(user_uuid?: string): Promise { - const query = user_uuid - ? `SELECT * FROM posts WHERE user_id = ?` - : `SELECT * FROM posts`; - const params = user_uuid ? [user_uuid] : []; - return await queryDatabase(query, params, mapPostRow); - } + const query = user_uuid + ? `SELECT * FROM posts WHERE user_id = ?` + : `SELECT * FROM posts`; + const params = user_uuid ? [user_uuid] : []; + return await queryDatabase(query, params, mapPostRow); +} /** * @returns Array of all Users in the Database */ async function getAllUsersFromDB(): Promise { - const query = `SELECT * FROM accounts`; - return await queryDatabase(query, [], mapAccountRow); + const query = `SELECT * FROM accounts`; + return await queryDatabase(query, [], mapAccountRow); } /** - * @param username + * @param username * @returns Returns the Accounts for the User with the given username */ async function getUserByUsername(username: string): Promise { - const query = `SELECT * FROM accounts WHERE user_username = '${username}'`; - const params:string[] = []; - const result = await queryDatabase(query, params, mapAccountRow); - return result[0]; + const query = `SELECT * FROM accounts WHERE user_username = '${username}'`; + const params: string[] = []; + const result = await queryDatabase(query, params, mapAccountRow); + return result[0]; } /** @@ -191,11 +197,11 @@ async function getUserByUsername(username: string): Promise { * @returns Array of Comments for the Post, or an empty Array if there are no Comments */ async function getCommentsFromDB(post_id?: number): Promise { - const query = post_id - ? `SELECT * FROM comments WHERE post_id = ?` - : `SELECT * FROM comments`; - const params = post_id ? [post_id] : []; - return await queryDatabase(query, params, mapCommentRow); + const query = post_id + ? `SELECT * FROM comments WHERE post_id = ?` + : `SELECT * FROM comments`; + const params = post_id ? [post_id] : []; + return await queryDatabase(query, params, mapCommentRow); } /** @@ -203,7 +209,7 @@ async function getCommentsFromDB(post_id?: number): Promise { * @returns Array of Comments for the Comment, or an empty Array if there are no Comments */ function getCommentsForComments(comment_id: number) { - // Will be rewritten to use the queryDatabase function + // Will be rewritten to use the queryDatabase function } /** @@ -213,7 +219,7 @@ function getCommentsForComments(comment_id: number) { * Might be required for Administrating the User */ async function getAllUserInfoByID(user_id: string) { - // Will be rewritten to use the queryDatabase function + // Will be rewritten to use the queryDatabase function } /** @@ -222,47 +228,79 @@ async function getAllUserInfoByID(user_id: string) { */ // Filter Functions, Not yet implemented function filterForImagePosts(posts_to_filter: Array) { - return []; + return []; } function filterForVideoPosts(posts_to_filter: Array) { - return []; + return []; } function filterForTextPosts(posts_to_filter: Array) { - return []; + return []; } - // Register/Login/User /** - * @param user The name of the User to add - * @param password The password of the User to add - * @returns Array of Posts from the User, or an empty Array if the User doesn't exist or has no Posts + * @param user The username of the User to add + * @param password The hashed password of the User to add + * @param salt The salt used for the password + * @returns "noUser" if user exists, "newUser" if registration successful */ -function registerUser (user: string, password: string, userGroup: string, displayname: string, user_email: string, firstname: string, surname: string, account_created: string): string { - const query_user_exists = `SELECT * FROM accounts WHERE user_username = '${user}'`; - if (!query_user_exists) { - return "noUser"; - } +function registerUser( + user: string, + password: string, + salt: string, + userGroup: string, + displayname: string, + user_email: string, + firstname: string, + surname: string, + account_created: string, +): string { + const query_user_exists = + `SELECT * FROM accounts WHERE user_username = '${user}'`; + if (!query_user_exists) { + return "noUser"; + } - const query_add_user = `INSERT INTO accounts (user_username, password, user_group, user_displayname, user_email, firstname, surname, account_created) VALUES ('${user}', '${password}', '${userGroup}', '${displayname}', '${user_email}', '${firstname}', '${surname}', '${account_created}')`; - db.query(query_add_user); - console.log(`New user: ${user}`) + const query_add_user = ` + INSERT INTO accounts ( + user_username, + password, + password_salt, + user_group, + user_displayname, + user_email, + firstname, + surname, + account_created + ) VALUES ( + '${user}', + '${password}', + '${salt}', + '${userGroup}', + '${displayname}', + '${user_email}', + '${firstname}', + '${surname}', + '${account_created}' + )`; + db.query(query_add_user); + console.log(`New user: ${user}`); - return "newUser"; + return "newUser"; } // Exporting all functions as this is a module export { - registerUser, - createDatabaseIfNotExist, - getAllUserInfoByID, - getAllUsersFromDB, - getUserByUsername, - getCommentsForComments, - getCommentsFromDB, - getPostsFromDB, - insertSamples, + createDatabaseIfNotExist, + getAllUserInfoByID, + getAllUsersFromDB, + getCommentsForComments, + getCommentsFromDB, + getPostsFromDB, + getUserByUsername, + insertSamples, + registerUser, };