From 816036dbdfe9e5211d90b076ea5ae2599ea01cf9 Mon Sep 17 00:00:00 2001 From: Patrick <50352812+Mueller-Patrick@users.noreply.github.com> Date: Mon, 3 May 2021 16:29:25 +0200 Subject: [PATCH] BETTERZON-84: Adding service method to check if a session is valid (#37) --- Backend/src/models/users/user.interface.ts | 1 - Backend/src/models/users/users.router.ts | 29 ++++++++ Backend/src/models/users/users.service.ts | 85 +++++++++++++++++++++- 3 files changed, 111 insertions(+), 4 deletions(-) diff --git a/Backend/src/models/users/user.interface.ts b/Backend/src/models/users/user.interface.ts index b4e433c..5912115 100644 --- a/Backend/src/models/users/user.interface.ts +++ b/Backend/src/models/users/user.interface.ts @@ -3,7 +3,6 @@ export interface User { username: string; email: string; password_hash: string; - hashing_salt: string; registration_date: Date; last_login_date: Date; } diff --git a/Backend/src/models/users/users.router.ts b/Backend/src/models/users/users.router.ts index 4dd4c92..6f13fe0 100644 --- a/Backend/src/models/users/users.router.ts +++ b/Backend/src/models/users/users.router.ts @@ -81,3 +81,32 @@ usersRouter.post('/login', async (req: Request, res: Response) => { res.status(404).send(e.message); } }); + +// POST users/checkSessionValid +usersRouter.post('/checkSessionValid', async (req: Request, res: Response) => { + try { + const sessionId: string = req.body.sessionId; + const sessionKey: string = req.body.sessionKey; + const ip: string = req.connection.remoteAddress ?? ''; + + if (!sessionId || !sessionKey) { + // Missing + res.status(400).send(JSON.stringify({message: 'Missing parameters'})); + return; + } + + // Update the user entry and create a session + const user: User = await UserService.checkSession(sessionId, sessionKey, ip); + + if(!user.user_id) { + // Error logging in, probably wrong username / password + res.status(401).send(JSON.stringify({messages: ["Invalid session"], codes: [5]})); + return; + } + + // Send the session details back to the user + res.status(201).send(user); + } catch (e) { + res.status(404).send(e.message); + } +}); diff --git a/Backend/src/models/users/users.service.ts b/Backend/src/models/users/users.service.ts index 0501c4a..d1af37b 100644 --- a/Backend/src/models/users/users.service.ts +++ b/Backend/src/models/users/users.service.ts @@ -92,7 +92,7 @@ export const login = async (username: string, password: string, ip: string): Pro try { // Get saved password hash conn = await pool.getConnection(); - const query = "SELECT user_id, bcrypt_password_hash FROM users WHERE username = ?" + const query = 'SELECT user_id, bcrypt_password_hash FROM users WHERE username = ?'; const userRows = await conn.query(query, username); let savedHash = ''; let userId = -1; @@ -104,7 +104,7 @@ export const login = async (username: string, password: string, ip: string): Pro } // Check for correct password - if(!bcrypt.compareSync(password, savedHash)) { + if (!bcrypt.compareSync(password, savedHash)) { // Wrong password, return invalid return {} as Session; } @@ -150,13 +150,92 @@ export const login = async (username: string, password: string, ip: string): Pro return {} as Session; }; +/** + * Checks if the given session information are valid and returns the user information if they are + */ +export const checkSession = async (sessionId: string, sessionKey: string, ip: string): Promise => { + let conn; + try { + // Get saved session key hash + conn = await pool.getConnection(); + const query = 'SELECT user_id, session_key_hash, validUntil FROM sessions WHERE session_id = ?'; + const sessionRows = await conn.query(query, sessionId); + let savedHash = ''; + let userId = -1; + let validUntil = new Date(); + for (const row in sessionRows) { + if (row !== 'meta' && sessionRows[row].user_id != null) { + savedHash = sessionRows[row].session_key_hash; + userId = sessionRows[row].user_id; + validUntil = sessionRows[row].validUntil; + } + } + + // Check for correct key + if (!bcrypt.compareSync(sessionKey, savedHash)) { + // Wrong key, return invalid + return {} as User; + } + // Key is valid, continue + + // Check if the session is still valid + if(validUntil <= new Date()) { + // Session expired, return invalid + return {} as User; + } + // Session still valid, continue + + // Update session entry in SQL + const updateSessionsQuery = 'UPDATE sessions SET lastLogin = NOW(), last_IP = ? WHERE session_id = ?'; + const updateUsersQuery = 'UPDATE users SET last_login_date = NOW() WHERE user_id = ?'; + const userIdRes = await conn.query(updateSessionsQuery, [ip, sessionId]); + await conn.query(updateUsersQuery, userId); + await conn.commit(); + + // Get the other required user information and update the user + const userQuery = "SELECT user_id, username, email, registration_date, last_login_date FROM users WHERE user_id = ?"; + const userRows = await conn.query(userQuery, userId); + let username = ''; + let email = ''; + let registrationDate = new Date(); + let lastLoginDate = new Date(); + for (const row in userRows) { + if (row !== 'meta' && userRows[row].user_id != null) { + username = userRows[row].username; + email = userRows[row].email; + registrationDate = userRows[row].registration_date; + lastLoginDate = userRows[row].last_login_date; + } + } + + // Everything is fine, return user information + return { + user_id: userId, + username: username, + email: email, + password_hash: '', + registration_date: registrationDate, + last_login_date: lastLoginDate + }; + + } catch (err) { + throw err; + } finally { + if (conn) { + conn.end(); + } + } + + return {} as User; +}; + /** * Used in the checkUsernameAndEmail method as return value */ export interface Status { hasProblems: boolean; messages: string[]; - codes: number[]; // 0 = all good, 1 = wrong username, 2 = wrong email, 3 = server error, 4 = wrong password + codes: number[]; // 0 = all good, 1 = wrong username, 2 = wrong email, 3 = server error, 4 = wrong password, 5 = wrong session } /**