214 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			214 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import http from "http";
 | |
| import decrypt from "../../functions/dsql/decrypt";
 | |
| import getAuthCookieNames from "../../functions/backend/cookies/get-auth-cookie-names";
 | |
| import { checkAuthFile } from "../../functions/backend/auth/write-auth-files";
 | |
| import parseCookies from "../../utils/backend/parseCookies";
 | |
| import { AuthenticatedUser } from "../../types";
 | |
| import getCsrfHeaderName from "../../actions/get-csrf-header-name";
 | |
| import grabHostNames from "../../utils/grab-host-names";
 | |
| 
 | |
| const minuteInMilliseconds = 60000;
 | |
| const hourInMilliseconds = minuteInMilliseconds * 60;
 | |
| const dayInMilliseconds = hourInMilliseconds * 24;
 | |
| const weekInMilliseconds = dayInMilliseconds * 7;
 | |
| const monthInMilliseconds = dayInMilliseconds * 30;
 | |
| const yearInMilliseconds = dayInMilliseconds * 365;
 | |
| 
 | |
| type Param = {
 | |
|     request?: http.IncomingMessage & { [s: string]: any };
 | |
|     req?: http.IncomingMessage & { [s: string]: any };
 | |
|     cookieString?: string;
 | |
|     encryptedUserString?: string;
 | |
|     encryptionKey?: string;
 | |
|     encryptionSalt?: string;
 | |
|     level?: "deep" | "normal";
 | |
|     database?: string;
 | |
|     dsqlUserId?: string | number;
 | |
|     expiry?: number;
 | |
|     csrfHeaderName?: string;
 | |
|     debug?: boolean;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Authenticate User from request
 | |
|  * ==============================================================================
 | |
|  * @description This Function takes in a request object and returns a user object
 | |
|  * with the user's data
 | |
|  */
 | |
| export default function userAuth({
 | |
|     request,
 | |
|     req,
 | |
|     encryptionKey,
 | |
|     encryptionSalt,
 | |
|     level,
 | |
|     database,
 | |
|     dsqlUserId,
 | |
|     encryptedUserString,
 | |
|     expiry = weekInMilliseconds,
 | |
|     cookieString,
 | |
|     csrfHeaderName,
 | |
|     debug,
 | |
| }: Param): AuthenticatedUser {
 | |
|     try {
 | |
|         const finalRequest = req || request;
 | |
| 
 | |
|         const { user_id } = grabHostNames({ userId: dsqlUserId });
 | |
| 
 | |
|         const cookies = parseCookies({
 | |
|             request: finalRequest,
 | |
|             cookieString,
 | |
|         });
 | |
| 
 | |
|         if (debug) {
 | |
|             console.log("userAuth:cookies:", cookies);
 | |
|         }
 | |
| 
 | |
|         const keyNames = getAuthCookieNames({
 | |
|             userId: user_id,
 | |
|             database: database || process.env.DSQL_DB_NAME,
 | |
|         });
 | |
| 
 | |
|         if (debug) {
 | |
|             console.log("userAuth:keyNames:", keyNames);
 | |
|         }
 | |
| 
 | |
|         const key = encryptedUserString
 | |
|             ? encryptedUserString
 | |
|             : cookies[keyNames.keyCookieName];
 | |
| 
 | |
|         if (debug) {
 | |
|             console.log("userAuth:key:", key);
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Grab the payload
 | |
|          *
 | |
|          * @description Grab the payload
 | |
|          */
 | |
|         let userPayloadJSON = decrypt({
 | |
|             encryptedString: key,
 | |
|             encryptionKey,
 | |
|             encryptionSalt,
 | |
|         });
 | |
| 
 | |
|         if (debug) {
 | |
|             console.log("userAuth:userPayloadJSON:", userPayloadJSON);
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Grab the payload
 | |
|          *
 | |
|          * @description Grab the payload
 | |
|          */
 | |
|         if (!userPayloadJSON) {
 | |
|             return {
 | |
|                 success: false,
 | |
|                 payload: null,
 | |
|                 msg: "Couldn't Decrypt cookie",
 | |
|                 cookieNames: keyNames,
 | |
|             };
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Grab the payload
 | |
|          *
 | |
|          * @description Grab the payload
 | |
|          */
 | |
| 
 | |
|         /** @type {import("../../types").DATASQUIREL_LoggedInUser} */
 | |
|         let userObject: import("../../types").DATASQUIREL_LoggedInUser =
 | |
|             JSON.parse(userPayloadJSON);
 | |
| 
 | |
|         if (debug) {
 | |
|             console.log("userAuth:userObject:", userObject);
 | |
|         }
 | |
| 
 | |
|         if (!userObject.csrf_k) {
 | |
|             return {
 | |
|                 success: false,
 | |
|                 payload: null,
 | |
|                 msg: "No CSRF_K in decrypted payload",
 | |
|                 cookieNames: keyNames,
 | |
|             };
 | |
|         }
 | |
| 
 | |
|         if (!checkAuthFile(userObject.csrf_k)) {
 | |
|             return {
 | |
|                 success: false,
 | |
|                 payload: null,
 | |
|                 msg: "Auth file doesn't exist",
 | |
|                 cookieNames: keyNames,
 | |
|             };
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Grab the payload
 | |
|          *
 | |
|          * @description Grab the payload
 | |
|          */
 | |
|         if (level?.match(/deep/i) && finalRequest) {
 | |
|             const finalCsrfHeaderName = csrfHeaderName || getCsrfHeaderName();
 | |
|             if (
 | |
|                 finalRequest.headers[finalCsrfHeaderName] !== userObject.csrf_k
 | |
|             ) {
 | |
|                 return {
 | |
|                     success: false,
 | |
|                     payload: null,
 | |
|                     msg: "CSRF_K mismatch",
 | |
|                     cookieNames: keyNames,
 | |
|                 };
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         const payloadCreationDate = Number(userObject.date);
 | |
| 
 | |
|         if (
 | |
|             Number.isNaN(payloadCreationDate) ||
 | |
|             typeof payloadCreationDate !== "number"
 | |
|         ) {
 | |
|             return {
 | |
|                 success: false,
 | |
|                 payload: null,
 | |
|                 msg: "Payload Creation Date is not a number",
 | |
|                 cookieNames: keyNames,
 | |
|             };
 | |
|         }
 | |
| 
 | |
|         const timeElapsed = Date.now() - payloadCreationDate;
 | |
| 
 | |
|         const finalExpiry = process.env.DSQL_SESSION_EXPIRY_TIME
 | |
|             ? Number(process.env.DSQL_SESSION_EXPIRY_TIME)
 | |
|             : expiry;
 | |
| 
 | |
|         if (timeElapsed > finalExpiry) {
 | |
|             return {
 | |
|                 success: false,
 | |
|                 payload: null,
 | |
|                 msg: "Session has expired",
 | |
|                 cookieNames: keyNames,
 | |
|             };
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Return User Object
 | |
|          *
 | |
|          * @description Return User Object
 | |
|          */
 | |
|         return {
 | |
|             success: true,
 | |
|             payload: userObject,
 | |
|         };
 | |
|     } catch (error: any) {
 | |
|         /**
 | |
|          * Return User Object
 | |
|          *
 | |
|          * @description Return User Object
 | |
|          */
 | |
|         return {
 | |
|             success: false,
 | |
|             payload: null,
 | |
|             msg: error.message,
 | |
|         };
 | |
|     }
 | |
| }
 | 
