// @ts-check const varDatabaseDbHandler = require("../../backend/varDatabaseDbHandler"); const nodemailer = require("nodemailer"); const http = require("http"); const getAuthCookieNames = require("../../backend/cookies/get-auth-cookie-names"); const encrypt = require("../../dsql/encrypt"); const serializeCookies = require("../../../utils/serialize-cookies"); /** * # Send Email Login Code * * @param {object} param * @param {string} param.email * @param {string} param.database * @param {string} [param.email_login_field] * @param {string} [param.mail_domain] * @param {number} [param.mail_port] * @param {string} [param.sender] * @param {string} [param.mail_username] * @param {string} [param.mail_password] * @param {string} param.html * @param {boolean} [param.useLocal] * @param {http.ServerResponse & Object} [param.response] * @param {import("../../../../package-shared/types").CookieObject[]} [param.extraCookies] * * @returns {Promise} */ module.exports = async function apiSendEmailCode({ email, database, email_login_field, mail_domain, mail_port, sender, mail_username, mail_password, html, useLocal, response, extraCookies, }) { if (email?.match(/ /)) { return { success: false, msg: "Invalid Email/Password format", }; } const createdAt = Date.now(); const foundUserQuery = `SELECT * FROM users WHERE email = ?`; const foundUserValues = [email]; let foundUser = await varDatabaseDbHandler({ queryString: foundUserQuery, queryValuesArray: foundUserValues, database, useLocal, }); //////////////////////////////////////// //////////////////////////////////////// //////////////////////////////////////// if (!foundUser || !foundUser[0]) { return { success: false, msg: "No user found", }; } function generateCode() { const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; let code = ""; for (let i = 0; i < 8; i++) { code += chars[Math.floor(Math.random() * chars.length)]; } return code; } if (foundUser?.[0] && email_login_field) { const tempCode = generateCode(); let transporter = nodemailer.createTransport({ host: mail_domain || process.env.DSQL_MAIL_HOST, port: mail_port || process.env.DSQL_MAIL_PORT || 465, secure: true, auth: { user: mail_username || process.env.DSQL_MAIL_EMAIL, pass: mail_password || process.env.DSQL_MAIL_PASSWORD, }, }); let mailObject = {}; mailObject["from"] = `"Datasquirel SSO" <${ sender || "support@datasquirel.com" }>`; mailObject["sender"] = sender || "support@datasquirel.com"; mailObject["to"] = email; mailObject["subject"] = "One Time Login Code"; mailObject["html"] = html.replace(/{{code}}/, tempCode); const info = await transporter.sendMail(mailObject); if (!info?.accepted) throw new Error("Mail not Sent!"); const setTempCodeQuery = `UPDATE users SET ${email_login_field} = ? WHERE email = ?`; const setTempCodeValues = [tempCode + `-${createdAt}`, email]; let setTempCode = await varDatabaseDbHandler({ queryString: setTempCodeQuery, queryValuesArray: setTempCodeValues, database: database, useLocal, }); /** @type {import("../../../types").SendOneTimeCodeEmailResponse} */ const resObject = { success: true, code: tempCode, email: email, createdAt, msg: "Success", }; if (response) { const cookieKeyNames = getAuthCookieNames(); const oneTimeCodeCookieName = cookieKeyNames.oneTimeCodeName; const encryptedPayload = encrypt({ data: JSON.stringify(resObject), }); if (!encryptedPayload) { throw new Error( "apiSendEmailCode Error: Failed to encrypt payload" ); } /** @type {import("../../../../package-shared/types").CookieObject} */ const oneTimeCookieObject = { name: oneTimeCodeCookieName, value: encryptedPayload, sameSite: "Strict", path: "/", httpOnly: true, secure: true, }; /** @type {import("../../../../package-shared/types").CookieObject[]} */ const cookiesObjectArray = extraCookies ? [...extraCookies, oneTimeCookieObject] : [oneTimeCookieObject]; const serializedCookies = serializeCookies({ cookies: cookiesObjectArray, }); response.setHeader("Set-Cookie", serializedCookies); } return resObject; } else { return { success: false, msg: "Invalid Email/Password format", }; } };