diff --git a/index.d.ts b/index.d.ts index 8e319bf..ce26c7c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -31,6 +31,8 @@ export namespace sql { export { sqlDeleteGenerator }; export { trimSql as trim }; } +import serializeQuery = require("./package-shared/utils/serialize-query"); +import serializeCookies = require("./package-shared/utils/serialize-cookies"); import uploadImage = require("./utils/upload-image"); import uploadFile = require("./utils/upload-file"); import deleteFile = require("./utils/delete-file"); @@ -51,7 +53,7 @@ import sqlInsertGenerator = require("./package-shared/functions/dsql/sql/sql-ins import sqlDeleteGenerator = require("./package-shared/functions/dsql/sql/sql-delete-generator"); import trimSql = require("./package-shared/utils/trim-sql"); export declare namespace utils { - namespace crypto { + export namespace crypto { let encrypt: ({ data, encryptionKey, encryptionSalt }: { data: string; encryptionKey?: string; @@ -67,5 +69,7 @@ export declare namespace utils { encryptionKey?: string; }) => string; } + export { serializeQuery }; + export { serializeCookies }; } export { get, post, getSchema, datasquirelClient as client }; diff --git a/index.js b/index.js index aa2408f..fb4fb77 100644 --- a/index.js +++ b/index.js @@ -31,6 +31,8 @@ const sqlGenerator = require("./package-shared/functions/dsql/sql/sql-generator" const sqlInsertGenerator = require("./package-shared/functions/dsql/sql/sql-insert-generator"); const sqlDeleteGenerator = require("./package-shared/functions/dsql/sql/sql-delete-generator"); const trimSql = require("./package-shared/utils/trim-sql"); +const serializeQuery = require("./package-shared/utils/serialize-query"); +const serializeCookies = require("./package-shared/utils/serialize-cookies"); //////////////////////////////////////// //////////////////////////////////////// @@ -94,6 +96,8 @@ const datasquirel = { decrypt: require("./package-shared/functions/dsql/decrypt"), hash: require("./package-shared/functions/dsql/hashPassword"), }, + serializeQuery, + serializeCookies, }, }; diff --git a/package-shared/functions/api/users/api-send-email-code.d.ts b/package-shared/functions/api/users/api-send-email-code.d.ts index 140dc34..5cbcb68 100644 --- a/package-shared/functions/api/users/api-send-email-code.d.ts +++ b/package-shared/functions/api/users/api-send-email-code.d.ts @@ -1,4 +1,4 @@ -declare function _exports({ email, database, email_login_field, mail_domain, mail_port, sender, mail_username, mail_password, html, useLocal, response, }: { +declare function _exports({ email, database, email_login_field, mail_domain, mail_port, sender, mail_username, mail_password, html, useLocal, response, extraCookies, }: { email: string; database: string; email_login_field?: string; @@ -12,6 +12,7 @@ declare function _exports({ email, database, email_login_field, mail_domain, mai response?: http.ServerResponse & { [x: string]: any; }; + extraCookies?: import("../../../../package-shared/types").CookieObject[]; }): Promise; export = _exports; import http = require("http"); diff --git a/package-shared/functions/api/users/api-send-email-code.js b/package-shared/functions/api/users/api-send-email-code.js index 690b820..1192c58 100644 --- a/package-shared/functions/api/users/api-send-email-code.js +++ b/package-shared/functions/api/users/api-send-email-code.js @@ -1,11 +1,11 @@ // @ts-check -const LOCAL_DB_HANDLER = require("../../../utils/backend/global-db/LOCAL_DB_HANDLER"); 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 @@ -22,6 +22,7 @@ const encrypt = require("../../dsql/encrypt"); * @param {string} param.html * @param {boolean} [param.useLocal] * @param {http.ServerResponse & Object} [param.response] + * @param {import("../../../../package-shared/types").CookieObject[]} [param.extraCookies] * * @returns {Promise} */ @@ -37,6 +38,7 @@ module.exports = async function apiSendEmailCode({ html, useLocal, response, + extraCookies, }) { if (email?.match(/ /)) { return { @@ -123,16 +125,39 @@ module.exports = async function apiSendEmailCode({ }; if (response) { - const keyNames = getAuthCookieNames(); - const oneTimeCodeCookieName = keyNames.oneTimeCodeName; + const cookieKeyNames = getAuthCookieNames(); + const oneTimeCodeCookieName = cookieKeyNames.oneTimeCodeName; const encryptedPayload = encrypt({ data: JSON.stringify(resObject), }); - response?.setHeader("Set-Cookie", [ - `${oneTimeCodeCookieName}=${encryptedPayload};samesite=strict;path=/;HttpOnly=true;Secure=true`, - ]); + 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; diff --git a/package-shared/types/index.d.ts b/package-shared/types/index.d.ts index 23c4ca7..38e6726 100644 --- a/package-shared/types/index.d.ts +++ b/package-shared/types/index.d.ts @@ -1199,4 +1199,16 @@ export type SendOneTimeCodeEmailResponse = { email?: string; msg?: string; }; +export type CookieObject = { + name: string; + value: string; + domain?: string; + path?: string; + expires?: Date; + maxAge?: number; + secure?: boolean; + httpOnly?: boolean; + sameSite?: "Strict" | "Lax" | "None"; + priority?: "Low" | "Medium" | "High"; +}; export {}; diff --git a/package-shared/types/index.ts b/package-shared/types/index.ts index 031b433..3c638f8 100644 --- a/package-shared/types/index.ts +++ b/package-shared/types/index.ts @@ -1421,3 +1421,16 @@ export type SendOneTimeCodeEmailResponse = { email?: string; msg?: string; }; + +export type CookieObject = { + name: string; + value: string; + domain?: string; + path?: string; + expires?: Date; + maxAge?: number; + secure?: boolean; + httpOnly?: boolean; + sameSite?: "Strict" | "Lax" | "None"; + priority?: "Low" | "Medium" | "High"; +}; diff --git a/package-shared/utils/serialize-cookies.d.ts b/package-shared/utils/serialize-cookies.d.ts new file mode 100644 index 0000000..2576f13 --- /dev/null +++ b/package-shared/utils/serialize-cookies.d.ts @@ -0,0 +1,10 @@ +export = serializeCookies; +/** + * + * @param {object} params + * @param {import("../types").CookieObject[]} params.cookies + * @returns {string[]} + */ +declare function serializeCookies({ cookies }: { + cookies: import("../types").CookieObject[]; +}): string[]; diff --git a/package-shared/utils/serialize-cookies.js b/package-shared/utils/serialize-cookies.js new file mode 100644 index 0000000..fdcfdeb --- /dev/null +++ b/package-shared/utils/serialize-cookies.js @@ -0,0 +1,48 @@ +// @ts-check + +/** + * + * @param {object} params + * @param {import("../types").CookieObject[]} params.cookies + * @returns {string[]} + */ +function serializeCookies({ cookies }) { + /** @type {string[]} */ + let cookiesStringsArray = []; + + for (let i = 0; i < cookies.length; i++) { + const cookieObject = cookies[i]; + let cookieString = `${cookieObject.name}=${cookieObject.value}`; + + if (cookieObject.maxAge) { + cookieString += `;Max-Age=${cookieObject.maxAge}`; + } + if (cookieObject.path) { + cookieString += `;Path=${cookieObject.path}`; + } + if (cookieObject.domain) { + cookieString += `;Domain=${cookieObject.domain}`; + } + if (cookieObject.secure) { + cookieString += ";Secure"; + } + if (cookieObject.httpOnly) { + cookieString += ";HttpOnly"; + } + if (cookieObject.sameSite) { + cookieString += `;SameSite=${cookieObject.sameSite}`; + } + if (cookieObject.expires) { + cookieString += `;expires=${cookieObject.expires}`; + } + if (cookieObject.priority) { + cookieString += `;priority=${cookieObject.priority}`; + } + + cookiesStringsArray.push(cookieString); + } + + return cookiesStringsArray; +} + +module.exports = serializeCookies; diff --git a/package.json b/package.json index af7c470..8f55a73 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,18 @@ { "name": "@moduletrace/datasquirel", - "version": "2.9.4", + "version": "2.9.5", "description": "Cloud-based SQL data management tool", "main": "index.js", "bin": { "dsql-watch": "./engine/dsql.js", "dsql-dump": "./engine/dump.js" }, + "exports": { + ".": "./index.js", + "./client": { + "default": "./client/index.js" + } + }, "scripts": { "delete-ts": "find . -name \"*.d.ts\" -type f -not -path \"./node_modules/*\" -delete", "compile": "find . -name \"*.d.ts\" -type f -not -path \"./node_modules/*\" -delete && tsc --declaration --allowJs --emitDeclarationOnly --resolveJsonModule index.js", diff --git a/users/send-email-code.d.ts b/users/send-email-code.d.ts index 72ddc5c..aed507e 100644 --- a/users/send-email-code.d.ts +++ b/users/send-email-code.d.ts @@ -1,10 +1,4 @@ export = sendEmailCode; -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ /** * Send Email Code to a User * ============================================================================== @@ -23,10 +17,11 @@ export = sendEmailCode; * @param {string} [params.sender] * @param {boolean} [params.user_id] - User ID * @param {boolean} [params.useLocal] + * @param {import("../package-shared/types").CookieObject[]} [params.extraCookies] * * @returns { Promise} */ -declare function sendEmailCode({ key, email, database, temp_code_field_name, mail_domain, mail_password, mail_username, mail_port, sender, user_id, useLocal, response, }: { +declare function sendEmailCode({ key, email, database, temp_code_field_name, mail_domain, mail_password, mail_username, mail_port, sender, user_id, useLocal, response, extraCookies, }: { key?: string; database?: string; email: string; @@ -41,5 +36,6 @@ declare function sendEmailCode({ key, email, database, temp_code_field_name, mai sender?: string; user_id?: boolean; useLocal?: boolean; + extraCookies?: import("../package-shared/types").CookieObject[]; }): Promise; import http = require("http"); diff --git a/users/send-email-code.js b/users/send-email-code.js index 556413c..8c5fe78 100644 --- a/users/send-email-code.js +++ b/users/send-email-code.js @@ -1,23 +1,11 @@ // @ts-check -/** - * ============================================================================== - * Imports - * ============================================================================== - */ const http = require("http"); const fs = require("fs"); const path = require("path"); const grabHostNames = require("../package-shared/utils/grab-host-names"); const apiSendEmailCode = require("../package-shared/functions/api/users/api-send-email-code"); -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - /** * Send Email Code to a User * ============================================================================== @@ -36,6 +24,7 @@ const apiSendEmailCode = require("../package-shared/functions/api/users/api-send * @param {string} [params.sender] * @param {boolean} [params.user_id] - User ID * @param {boolean} [params.useLocal] + * @param {import("../package-shared/types").CookieObject[]} [params.extraCookies] * * @returns { Promise} */ @@ -52,6 +41,7 @@ async function sendEmailCode({ user_id, useLocal, response, + extraCookies, }) { const grabedHostNames = grabHostNames(); const { host, port, scheme } = grabedHostNames; @@ -104,6 +94,7 @@ async function sendEmailCode({ sender, useLocal, response, + extraCookies, }); } else { /**