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,
|
|
};
|
|
}
|
|
}
|