From 24c2445ff8f42d9f6f93bbec6e42283491a3d041 Mon Sep 17 00:00:00 2001 From: Benjamin Toby Date: Sat, 13 Jul 2024 07:23:46 +0100 Subject: [PATCH] Add Email Login --- engine/user/login-user.js | 58 +++++++++++++++++++++++++++++++-------- package-lock.json | 16 +++++++++-- package.json | 3 +- users/login-user.js | 19 +++++++++++++ utils/get.js | 2 +- 5 files changed, 82 insertions(+), 16 deletions(-) diff --git a/engine/user/login-user.js b/engine/user/login-user.js index 8471cd7..41e4330 100644 --- a/engine/user/login-user.js +++ b/engine/user/login-user.js @@ -13,9 +13,19 @@ const varDatabaseDbHandler = require("../engine/utils/varDatabaseDbHandler"); * }} param0.payload * @param {string[]} [param0.additionalFields] * @param {import("../../types/database-schema.td").DSQL_DatabaseSchemaType} [param0.dbSchema] + * @param {boolean} [param0.email_login] + * @param {string} [param0.email_login_code] + * @param {string | null} [param0.email_login_field] * @returns */ -async function loginLocalUser({ payload, additionalFields, dbSchema }) { +async function loginLocalUser({ + payload, + additionalFields, + dbSchema, + email_login, + email_login_code, + email_login_field, +}) { try { /** * User auth @@ -23,7 +33,9 @@ async function loginLocalUser({ payload, additionalFields, dbSchema }) { * @description Authenticate user */ - const { email, username, password } = payload; + const email = payload.email; + const username = payload.username; + const password = payload.password; const dbFullName = process.env.DSQL_DB_NAME || ""; const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; @@ -34,7 +46,11 @@ async function loginLocalUser({ payload, additionalFields, dbSchema }) { * * @description Check input validity */ - if (email?.match(/ /) || username?.match(/ /) || password?.match(/ /)) { + if ( + email?.match(/ /) || + (username && username?.match(/ /)) || + (password && password?.match(/ /)) + ) { return { success: false, msg: "Invalid Email/Password format", @@ -46,16 +62,20 @@ async function loginLocalUser({ payload, additionalFields, dbSchema }) { * * @description Password hash */ - let hashedPassword = hashPassword({ - password: password, - encryptionKey: encryptionKey, - }); + let hashedPassword = password + ? hashPassword({ + password: password, + encryptionKey: encryptionKey, + }) + : null; //////////////////////////////////////// //////////////////////////////////////// //////////////////////////////////////// - const tableSchema = dbSchema?.tables.find((tb) => tb?.tableName === "users"); + const tableSchema = dbSchema?.tables.find( + (tb) => tb?.tableName === "users" + ); let foundUser = await varDatabaseDbHandler({ queryString: `SELECT * FROM users WHERE email = ? OR username = ?`, @@ -77,8 +97,17 @@ async function loginLocalUser({ payload, additionalFields, dbSchema }) { let isPasswordCorrect = false; - if (foundUser && foundUser[0]) { + if (foundUser && foundUser[0] && !email_login) { isPasswordCorrect = hashedPassword === foundUser[0].password; + } else if ( + foundUser && + foundUser[0] && + email_login && + email_login_code && + email_login_field + ) { + const tempCode = foundUser[0][email_login_field]; + isPasswordCorrect = tempCode === email_login_code; } let socialUserValid = false; @@ -99,7 +128,10 @@ async function loginLocalUser({ payload, additionalFields, dbSchema }) { //////////////////////////////////////// //////////////////////////////////////// - let csrfKey = Math.random().toString(36).substring(2) + "-" + Math.random().toString(36).substring(2); + let csrfKey = + Math.random().toString(36).substring(2) + + "-" + + Math.random().toString(36).substring(2); let userPayload = { id: foundUser[0].id, @@ -120,7 +152,11 @@ async function loginLocalUser({ payload, additionalFields, dbSchema }) { date: Date.now(), }; - if (additionalFields && Array.isArray(additionalFields) && additionalFields.length > 0) { + if ( + additionalFields && + Array.isArray(additionalFields) && + additionalFields.length > 0 + ) { additionalFields.forEach((key) => { // @ts-ignore userPayload[key] = foundUser?.[0][key]; diff --git a/package-lock.json b/package-lock.json index 29b1dae..a7f9b9c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,17 @@ { "name": "datasquirel", - "version": "1.8.2", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "datasquirel", - "version": "1.8.2", + "version": "2.0.0", "license": "ISC", "dependencies": { "dotenv": "^16.3.1", - "mysql": "^2.18.1" + "mysql": "^2.18.1", + "nodemailer": "^6.9.14" }, "bin": { "dsql-dump": "engine/dump.js", @@ -83,6 +84,15 @@ "node": ">= 0.6" } }, + "node_modules/nodemailer": { + "version": "6.9.14", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.14.tgz", + "integrity": "sha512-Dobp/ebDKBvz91sbtRKhcznLThrKxKt97GI2FAlAyy+fk19j73Uz3sBXolVtmcXjaorivqsbbbjDY+Jkt4/bQA==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", diff --git a/package.json b/package.json index 21c8445..5196f58 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,8 @@ "homepage": "https://datasquirel.com/", "dependencies": { "dotenv": "^16.3.1", - "mysql": "^2.18.1" + "mysql": "^2.18.1", + "nodemailer": "^6.9.14" }, "devDependencies": { "@types/mysql": "^2.15.21" diff --git a/users/login-user.js b/users/login-user.js index b20b1db..7a9f98a 100644 --- a/users/login-user.js +++ b/users/login-user.js @@ -44,6 +44,9 @@ const loginLocalUser = require("../engine/user/login-user"); * @param {http.ServerResponse} params.response - Http response object * @param {String} params.encryptionKey - Encryption Key * @param {String} params.encryptionSalt - Encryption Salt + * @param {boolean} [params.email_login] - Email only Login + * @param {string} [params.email_login_code] - Email login code + * @param {string} [params.temp_code_field] - Database table field name for temporary code * * @returns { Promise} */ @@ -55,11 +58,21 @@ async function loginUser({ response, encryptionKey, encryptionSalt, + email_login, + email_login_code, + temp_code_field, }) { const scheme = process.env.DSQL_HTTP_SCHEME; const localHost = process.env.DSQL_LOCAL_HOST; const localHostPort = process.env.DSQL_LOCAL_HOST_PORT; + const defaultTempLoginFieldName = "temp_login_code"; + const emailLoginTempCodeFieldName = email_login + ? temp_code_field + ? temp_code_field + : defaultTempLoginFieldName + : null; + /** * Check Encryption Keys * @@ -135,6 +148,9 @@ async function loginUser({ payload, additionalFields, dbSchema, + email_login, + email_login_code, + email_login_field: emailLoginTempCodeFieldName, }); } } else { @@ -150,6 +166,9 @@ async function loginUser({ payload, database, additionalFields, + email_login, + email_login_code, + email_login_field: emailLoginTempCodeFieldName, }); const httpsRequest = ( diff --git a/utils/get.js b/utils/get.js index b6e695d..f83b40e 100644 --- a/utils/get.js +++ b/utils/get.js @@ -114,7 +114,7 @@ async function get({ key, db, query, queryValues, tableName }) { }, port: localHostPort || 443, hostname: localHost || "datasquirel.com", - path: path, + path: encodeURIComponent(path), }, /**