Skip to content
This repository has been archived by the owner on Jul 21, 2022. It is now read-only.

Commit

Permalink
Merge pull request #80 from Em1tt/ticket-pr
Browse files Browse the repository at this point in the history
Support Ticket API Pull Request.
  • Loading branch information
FireMario211 authored Jun 25, 2021
2 parents f9cd3b3 + 86290e4 commit c6fd18a
Show file tree
Hide file tree
Showing 7 changed files with 443 additions and 27 deletions.
69 changes: 54 additions & 15 deletions src/modules/api/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,19 @@ import { createHash } from 'crypto';
import ms from 'ms';

export const auth = {
login: async (req: express.Request, res: express.Response, data, rememberMe: boolean) => { // Logging in via amethyst.host
/**
* Logins in the user via amethyst.host
* @param {express.Request} req Express Request
* @param {express.Response} res Express Response
* @param {Object} data Data based from DB response
* @param {Boolean} rememberMe If JWT session should be longer or not
* @returns {Promise<Object>} Email, Access Token, and Expiration.
*
* @example
* const loginToken = await <auth>.login(req, res, account, rememberMe);
* if (loginToken == 403) return res.sendStatus(403);
*/
login: async (req: express.Request, res: express.Response, data: any, rememberMe: boolean) => { // Logging in via amethyst.host
const createdIn = parseInt(Date.now().toString().slice(0, -3)) // because for some reason node js decides to use an expanded timestamp
const ipAddr = req.socket.remoteAddress;
const salt = Buffer.alloc((process.env.SALT.length * 2) - 1, process.env.SALT)
Expand All @@ -19,26 +31,27 @@ export const auth = {
secret: Buffer.from(data.salt, 'hex')
})
if (!verifiedHash) return 403;
const userData = { email: data.email, name: data.name, id: data.user_id }
const userData = { email: data.email, name: data.name, id: data.user_id, permission_id: data.permission_id }
const accessTokenOpts = sql.jwtOptions
let expiresIn = ms('1h')
if (rememberMe) {
expiresIn = ms('90 days')
}
expiresIn = parseInt(expiresIn.toString().slice(0, -3))
accessTokenOpts.expiresIn = expiresIn
const accessToken = jwt.sign(userData, process.env.ACCESS_TOKEN, accessTokenOpts);
const accessToken = jwt.sign(userData, process.env.ACCESS_TOKEN, accessTokenOpts); // Will implement Refresh Token soon
const ip = createHash('sha256').update(ipAddr).digest('hex'); // Convert IP address to SHA256 hash
expiresIn = expiresIn + createdIn;
sql.db.prepare("INSERT INTO sessions (user_id, jwt, createdIn, expiresIn, ip) VALUES (?, ?, ?, ?, ?)").run(userData.id, accessToken, createdIn, expiresIn, ip) // Adds the token to DB in case the user decides to logout.
return { email: data.email, accessToken: accessToken, expiresIn: expiresIn };
},
setCookie: async (req: express.Request, res: express.Response, value: string, expiresIn: number) => {
setCookie: async (req: express.Request, res: express.Response, value: string, expiresIn: number): Promise<boolean> => {
res.cookie('jwt', value, { secure: true, httpOnly: true, maxAge: expiresIn, sameSite: 'strict' }); // Client Side wont access this because httpOnly.
return true;
},
getUserData: async (req: express.Request, res: express.Response) => {
getUserData: async (req: express.Request, res: express.Response): Promise<any> => {
if (req.cookies.jwt) {
const verifyToken = await auth.verifyToken(0, req, res, false, false)
const verifyToken = await auth.verifyToken(req, res, false, false)
if (verifyToken && verifyToken["accessToken"]) {
return verifyToken;
} else {
Expand All @@ -48,12 +61,39 @@ export const auth = {
return false;
}
},
verifyToken: (user_id: number, req: express.Request, res: express.Response, sendResponse: boolean, useAuthorization: boolean) => { // Probably not a good idea to do this, as most people use next()
updateJWT: async (req: express.Request, res: express.Response): Promise<boolean> => { // Wont be used until I implement Refresh Tokens
if (req.cookies.jwt) {
const verifyToken = await auth.verifyToken(req, res, false, false)
if (verifyToken && verifyToken["accessToken"]) {
const account = await sql.db.prepare("SELECT user_id, name, email, password, salt, verified, permission_id FROM users WHERE user_id = ?")
.get(verifyToken["user_id"]);
if (!account) return false;

} else {
return false;
}
} else {
return false;
}
},
/**
* Verifies if the JWT token is valid or not and gives response with User Data.
* @param {express.Request} req Express Request
* @param {express.Response} res Express Response
* @param {boolean} sendResponse If it should use res.sendStatus or not.
* @param {boolean} useAuthorization If it should use the Authorization header.
* @returns {any} User Data or Response.
*
* @example
* const userData = await <auth>.verifyToken(req, res, false, false); // Request, Response, sendResponse (False), useAuthorization (False).
* if (typeof userData != "object") return res.sendStatus(userData); // If its not an object. (Could be either undefined or number.)
*/
verifyToken: (req: express.Request, res: express.Response, sendResponse: boolean, useAuthorization: boolean): any => { // Probably not a good idea to do this, as most people use next()
const currentDate = parseInt(Date.now().toString().slice(0, -3))
let authorization;
let token;
if (useAuthorization) {
authorization = req.headers['authorization'];
authorization = req.headers['Authorization'] || req.headers['authorization'];
if (authorization) {
token = authorization.split(' ')[1];
}
Expand All @@ -64,13 +104,15 @@ export const auth = {
if (!authorization) return (sendResponse) ? res.sendStatus(403) : 403;
const tokenValid = jwt.verify(token, process.env.ACCESS_TOKEN, sql.jwtOptions)
if (!tokenValid) return (sendResponse) ? res.sendStatus(403) : 403; // Forbidden.
if (tokenValid.id != user_id && useAuthorization) return (sendResponse) ? res.sendStatus(403) : 403; // Forbidden
//if (tokenValid.id != user_id && useAuthorization) return (sendResponse) ? res.sendStatus(403) : 403; // Forbidden
const ip = createHash('sha256').update(req.ip).digest('hex');
const tokenInDB = sql.db.prepare('SELECT user_id FROM sessions WHERE user_id = ? AND jwt = ? AND expiresIn > ? AND ip = ?').pluck().all(tokenValid.id, token, currentDate, ip);
if (!tokenInDB.length) return (sendResponse) ? res.sendStatus(403) : 403;
if (tokenValid.exp < currentDate) return (sendResponse) ? res.sendStatus(403) : 403;
const userExists = sql.db.prepare('SELECT count(*) FROM users WHERE user_id = ?').pluck().get(tokenValid.id);
if (!userExists) return (sendResponse) ? res.sendStatus(404) : 404;
//res.setHeader('Authorization', 'Bearer ' + tokenValid)
const response = { accessToken: token, user_id: tokenInDB[0], name: tokenValid.name, email: tokenValid.email }
const response = { accessToken: token, user_id: tokenInDB[0], name: tokenValid.name, email: tokenValid.email, permission_id: tokenValid.permission_id }
return (sendResponse) ? res.status(200).json(response) : response;
},
discord: async (data) => { // Authenticating with Discord
Expand All @@ -87,14 +129,11 @@ export const prop = {
const { email, password, rememberMe } = req.body;
if ([email, password].includes(undefined)) return res.status(406)
.send("Please enter in an Email, and Password.");
const account = await sql.db.prepare("SELECT user_id, name, email, password, salt, verified FROM users WHERE email = ?")
.get(email); // Checks if the user exists.
//if (!account) return res.sendStatus(404); // User doesn't exist.
const account = await sql.db.prepare("SELECT user_id, name, email, password, salt, verified, permission_id FROM users WHERE email = ?")
.get(email); // Checks if the user exists.
if (!account) return res.sendStatus(404); // User doesn't exist.

const loginToken = await auth.login(req, res, account, rememberMe);
if (loginToken == 403) return res.sendStatus(403);

auth.setCookie(req, res, loginToken.accessToken, loginToken.expiresIn);
res.json(loginToken)
}
Expand Down
Loading

0 comments on commit c6fd18a

Please sign in to comment.