2023-09-21 14:00:04 +00:00
|
|
|
// @ts-check
|
|
|
|
|
|
|
|
const http = require("http");
|
2024-12-06 10:31:24 +00:00
|
|
|
const decrypt = require("../package-shared/functions/dsql/decrypt");
|
2024-12-06 11:55:03 +00:00
|
|
|
const getAuthCookieNames = require("../package-shared/functions/backend/cookies/get-auth-cookie-names");
|
2024-12-08 08:58:57 +00:00
|
|
|
const {
|
|
|
|
checkAuthFile,
|
|
|
|
} = require("../package-shared/functions/backend/auth/write-auth-files");
|
2024-12-10 14:20:48 +00:00
|
|
|
const parseCookies = require("../package-shared/utils/backend/parseCookies");
|
2024-12-08 08:58:57 +00:00
|
|
|
|
|
|
|
const minuteInMilliseconds = 60000;
|
|
|
|
const hourInMilliseconds = minuteInMilliseconds * 60;
|
|
|
|
const dayInMilliseconds = hourInMilliseconds * 24;
|
|
|
|
const weekInMilliseconds = dayInMilliseconds * 7;
|
|
|
|
const monthInMilliseconds = dayInMilliseconds * 30;
|
|
|
|
const yearInMilliseconds = dayInMilliseconds * 365;
|
2023-09-21 14:00:04 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Authenticate User from request
|
|
|
|
* ==============================================================================
|
|
|
|
* @description This Function takes in a request object and returns a user object
|
|
|
|
* with the user's data
|
|
|
|
*
|
|
|
|
* @param {Object} params - Arg
|
2024-12-08 08:58:57 +00:00
|
|
|
* @param {http.IncomingMessage & Object<string, any>} [params.request] - Http request object
|
|
|
|
* @param {http.IncomingMessage & Object<string, any>} [params.req] - Http request object
|
|
|
|
* @param {string} [params.encryptedUserString] - Encrypted user string to use instead of getting from cookie header
|
|
|
|
* @param {string} [params.encryptionKey] - Encryption Key: alt env: DSQL_ENCRYPTION_PASSWORD
|
|
|
|
* @param {string} [params.encryptionSalt] - Encryption Salt: alt env: DSQL_ENCRYPTION_SALT
|
2023-09-21 14:00:04 +00:00
|
|
|
* @param {("deep" | "normal")} [params.level] - Optional. "Deep" value indicates an extra layer of security
|
2024-12-08 08:58:57 +00:00
|
|
|
* @param {string} [params.database] - Database Name (slug)
|
|
|
|
* @param {string | number} [params.dsqlUserId] - alt env: DSQL_API_USER_ID
|
|
|
|
* @param {number} [params.expiry] - Expiry time in milliseconds
|
2023-09-21 14:00:04 +00:00
|
|
|
*
|
2024-10-19 16:45:42 +00:00
|
|
|
* @returns { import("../package-shared/types").AuthenticatedUser }
|
2023-09-21 14:00:04 +00:00
|
|
|
*/
|
2024-08-16 06:48:12 +00:00
|
|
|
function userAuth({
|
|
|
|
request,
|
2024-12-08 08:58:57 +00:00
|
|
|
req,
|
2024-08-16 06:48:12 +00:00
|
|
|
encryptionKey,
|
|
|
|
encryptionSalt,
|
|
|
|
level,
|
|
|
|
database,
|
2024-12-08 08:58:57 +00:00
|
|
|
dsqlUserId,
|
|
|
|
encryptedUserString,
|
|
|
|
expiry = weekInMilliseconds,
|
2024-08-16 06:48:12 +00:00
|
|
|
}) {
|
2023-09-21 14:00:04 +00:00
|
|
|
try {
|
2024-12-08 08:58:57 +00:00
|
|
|
const finalEncryptionKey =
|
|
|
|
encryptionKey || process.env.DSQL_ENCRYPTION_PASSWORD;
|
|
|
|
const finalEncryptionSalt =
|
|
|
|
encryptionSalt || process.env.DSQL_ENCRYPTION_SALT;
|
2024-12-06 11:55:03 +00:00
|
|
|
|
2024-12-08 08:58:57 +00:00
|
|
|
const cookies = parseCookies({ request: request || req });
|
|
|
|
|
|
|
|
const keyNames = getAuthCookieNames({
|
|
|
|
userId: dsqlUserId || process.env.DSQL_API_USER_ID,
|
|
|
|
database: database || process.env.DSQL_DB_NAME,
|
|
|
|
});
|
2024-12-06 11:55:03 +00:00
|
|
|
|
|
|
|
const authKeyName = keyNames.keyCookieName;
|
|
|
|
const csrfName = keyNames.csrfCookieName;
|
2023-09-21 14:00:04 +00:00
|
|
|
|
2024-12-08 08:58:57 +00:00
|
|
|
const key = encryptedUserString
|
|
|
|
? encryptedUserString
|
|
|
|
: cookies[authKeyName];
|
2023-09-21 14:00:04 +00:00
|
|
|
const csrf = cookies[csrfName];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Grab the payload
|
|
|
|
*
|
|
|
|
* @description Grab the payload
|
|
|
|
*/
|
2024-12-08 08:58:57 +00:00
|
|
|
let userPayloadJSON = decrypt({
|
2023-09-21 14:00:04 +00:00
|
|
|
encryptedString: key,
|
2024-12-08 08:58:57 +00:00
|
|
|
encryptionKey: finalEncryptionKey,
|
|
|
|
encryptionSalt: finalEncryptionSalt,
|
2023-09-21 14:00:04 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Grab the payload
|
|
|
|
*
|
|
|
|
* @description Grab the payload
|
|
|
|
*/
|
2024-12-08 08:58:57 +00:00
|
|
|
if (!userPayloadJSON) {
|
2023-09-21 14:00:04 +00:00
|
|
|
return {
|
|
|
|
success: false,
|
|
|
|
payload: null,
|
|
|
|
msg: "Couldn't Decrypt cookie",
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Grab the payload
|
|
|
|
*
|
|
|
|
* @description Grab the payload
|
|
|
|
*/
|
2024-12-08 08:58:57 +00:00
|
|
|
|
|
|
|
/** @type {import("../package-shared/types").DATASQUIREL_LoggedInUser} */
|
|
|
|
let userObject = JSON.parse(userPayloadJSON);
|
2023-09-21 14:00:04 +00:00
|
|
|
|
|
|
|
if (!userObject.csrf_k) {
|
|
|
|
return {
|
|
|
|
success: false,
|
|
|
|
payload: null,
|
|
|
|
msg: "No CSRF_K in decrypted payload",
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-12-08 08:58:57 +00:00
|
|
|
if (!checkAuthFile(userObject.csrf_k)) {
|
|
|
|
return {
|
|
|
|
success: false,
|
|
|
|
payload: null,
|
|
|
|
msg: "Auth file doesn't exist",
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-09-21 14:00:04 +00:00
|
|
|
/**
|
|
|
|
* Grab the payload
|
|
|
|
*
|
|
|
|
* @description Grab the payload
|
|
|
|
*/
|
2024-08-16 06:48:12 +00:00
|
|
|
if (
|
|
|
|
level?.match(/deep/i) &&
|
|
|
|
!csrf?.match(new RegExp(`${userObject.csrf_k}`))
|
|
|
|
) {
|
2023-09-21 14:00:04 +00:00
|
|
|
return {
|
|
|
|
success: false,
|
|
|
|
payload: null,
|
|
|
|
msg: "CSRF_K requested but does not match payload",
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-12-08 08:58:57 +00:00
|
|
|
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",
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
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",
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-09-21 14:00:04 +00:00
|
|
|
/**
|
|
|
|
* Return User Object
|
|
|
|
*
|
|
|
|
* @description Return User Object
|
|
|
|
*/
|
|
|
|
return {
|
|
|
|
success: true,
|
|
|
|
payload: userObject,
|
|
|
|
};
|
2024-10-11 09:15:29 +00:00
|
|
|
} catch (/** @type {any} */ error) {
|
2023-09-21 14:00:04 +00:00
|
|
|
/**
|
|
|
|
* Return User Object
|
|
|
|
*
|
|
|
|
* @description Return User Object
|
|
|
|
*/
|
|
|
|
return {
|
|
|
|
success: false,
|
|
|
|
payload: null,
|
2024-10-11 09:15:29 +00:00
|
|
|
msg: error.message,
|
2023-09-21 14:00:04 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = userAuth;
|