From 010e5188280421cce5a4f38f34e836e45947d54f Mon Sep 17 00:00:00 2001 From: Lynixenn Date: Tue, 17 Dec 2024 19:01:14 +0100 Subject: [PATCH] Login and Register API added, further info shared between Owners --- api/helpers.ts | 21 ++++++--- api/main.ts | 84 ++++++++++++++++++++++++++++++------ database/esp-projekt.sqlite | Bin 20480 -> 20480 bytes database/utils.ts | 35 +++++++++++++++ deno.lock | 1 + 5 files changed, 122 insertions(+), 19 deletions(-) diff --git a/api/helpers.ts b/api/helpers.ts index 477c7e4..60a18e5 100644 --- a/api/helpers.ts +++ b/api/helpers.ts @@ -7,7 +7,8 @@ * */ import { Context } from "https://deno.land/x/oak/mod.ts"; -import { hash } from "node:crypto"; +import { encodeHex } from "jsr:@std/encoding/hex"; +// import { hash } from "node:crypto"; export type ApiResponse = { status: number; @@ -37,8 +38,18 @@ const errorResponse = (ctx: Context, status: number, message: string): void => { /** * @description Hashing Function for Passwords/etc * @param password The password to hash - * Works only up to 5 Megabytes */ -const hashPassword = async (password: string): Promise => { - return hash("sha256", password); -} \ No newline at end of file +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 { + sendResponse, + errorResponse, + hashPassword +}; diff --git a/api/main.ts b/api/main.ts index 5ef4864..49d3cfc 100644 --- a/api/main.ts +++ b/api/main.ts @@ -32,8 +32,8 @@ router // Account routes router - .post("/api/account/login", () => {}) // TODO - .post("/api/account/register", () => {}) // TODO + .post("/api/account/login", api_login) // TODO + .post("/api/account/register", api_register) // TODO .post("/api/account/logout", () => {}) // TODO .post("/api/account/password/forgot", () => {}) // TODO .post("/api/account/password/reset", () => {}) // TODO @@ -52,7 +52,7 @@ router // User routes router .get("/api/users", api_getAllUsers) - .get("/api/user/:id/info", api_user_getInfo); + .get("/api/user/:id/info", api_user_getInfo); // @error GEHT NICHT // Post routes router @@ -69,6 +69,7 @@ router * Currently not implemented * Middleware */ + async function authenticator(ctx: Context, next: Next): Promise { const authHeader = ctx.request.headers.get('Authorization'); @@ -111,8 +112,7 @@ async function tokenChecker(ctx: Context, next: Next): Promise { */ } - -async function api_getAllUsers(ctx: any): Promise { +async function api_getAllUsers(ctx: Context): Promise { const getUsers = await db_utils.getAllUsersFromDB(); ctx.response.body = getUsers; } @@ -129,33 +129,89 @@ async function api_user_getInfo(ctx: any): Promise { try { const user = await db_utils.getAllUserInfoByID(id); - - if (!user) { - ctx.response.status = 404; // Not Found status/Doesn't exist - ctx.response.body = { error: "User not found" }; + if (user === null || user === undefined) { + helper_utils.errorResponse(ctx, 404, "User not found"); return; } ctx.response.body = user; } catch (error) { - ctx.response.status = 500; // Internal Server Error status - ctx.response.body = { error: "Error" }; + helper_utils.errorResponse(ctx, 500, "Internal Server Error"); } } - // Posts -async function api_posts_getAll(ctx: any): Promise { +async function api_posts_getAll(ctx: Context): Promise { const posts = await db_utils.getPostsFromDB(); ctx.response.body = posts; } // Comments +// 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('.')}`; + + + 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; + } +} + +async function api_login(ctx: Context): Promise { + 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"; + } + + return "Success"; +} + // Filtering // +++ APP ---------------------------------------------------------- // -app.use(oakCors()); +app.use(oakCors({ + origin: '*', + credentials: true, +})); app.use(router.routes()); app.use(router.allowedMethods()); diff --git a/database/esp-projekt.sqlite b/database/esp-projekt.sqlite index 8674e2378be561efbe20be0c8157e4c991b3ebf0..bc9807a87cc0a74ac9e99d44baa4a94483d02ff5 100644 GIT binary patch delta 195 zcmWlSOAdlC07OfoJNcN%O8guEn|^58?lfLO4^Y~&FcOVm;!e1MUchh#!vVO0M-o=^ zGB25_8mDTU*W7X6(SGa#c=~-!<4;Cj4E&Ezz0QlS?@8U3L#CTv4Uu8 il+jW$PJ~Pm8xDs38Rj%e80Ugu4l#iQk)-XGJNyUUNjD?_ delta 44 zcmZozz}T>Wae_1>&qNt#Rvreus=|#a3;4O1`SvsL&*L}d+rOF7U?bn={c?_m03Ig| A6aWAK diff --git a/database/utils.ts b/database/utils.ts index 38d1c0d..baa9e24 100644 --- a/database/utils.ts +++ b/database/utils.ts @@ -173,6 +173,17 @@ async function getAllUsersFromDB(): Promise { return await queryDatabase(query, [], mapAccountRow); } +/** + * @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]; +} + /** * @param post_id The ID of the Post to get the Comments for. Not required * @description If no post_id is provided, all Comments will be returned @@ -192,6 +203,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 } /** @@ -221,11 +233,34 @@ function filterForTextPosts(posts_to_filter: Array) { 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 + */ +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"; + } + + 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}`) + + return "newUser"; +} + // Exporting all functions as this is a module export { + registerUser, createDatabaseIfNotExist, getAllUserInfoByID, getAllUsersFromDB, + getUserByUsername, getCommentsForComments, getCommentsFromDB, getPostsFromDB, diff --git a/deno.lock b/deno.lock index 28a473c..b4766b3 100644 --- a/deno.lock +++ b/deno.lock @@ -6,6 +6,7 @@ "jsr:@std/bytes@1": "1.0.2", "jsr:@std/bytes@^1.0.2": "1.0.2", "jsr:@std/crypto@1": "1.0.3", + "jsr:@std/encoding@*": "1.0.5", "jsr:@std/encoding@1": "1.0.5", "jsr:@std/encoding@^1.0.5": "1.0.5", "jsr:@std/http@1": "1.0.9",