From 8ca2779741b61f2867d07619bb2cd5db506987eb Mon Sep 17 00:00:00 2001 From: Benjamin Toby Date: Fri, 6 Dec 2024 11:31:24 +0100 Subject: [PATCH] Updates --- engine/dsql.js | 9 +- engine/dump.js | 12 +- engine/engine/addUsersTableToDb.d.ts | 4 - engine/engine/addUsersTableToDb.js | 88 -- engine/engine/createDbFromSchema.js | 300 ----- .../engine/utils/camelJoinedtoCamelSpace.d.ts | 12 - engine/engine/utils/dbHandler.d.ts | 8 - engine/engine/utils/dbHandler.js | 173 --- engine/engine/utils/defaultFieldsRegexp.d.ts | 8 - engine/engine/utils/defaultFieldsRegexp.js | 13 - engine/engine/utils/noDatabaseDbHandler.js | 92 -- engine/engine/utils/parseDbResults.d.ts | 5 - engine/engine/utils/parseDbResults.js | 83 -- engine/engine/utils/varDatabaseDbHandler.d.ts | 23 - engine/engine/utils/varDatabaseDbHandler.js | 129 -- engine/query/get.d.ts | 64 - engine/query/get.js | 94 -- engine/query/post.d.ts | 16 - engine/query/post.js | 62 - .../update-api-schema-from-local-db.d.ts | 38 - .../query/update-api-schema-from-local-db.js | 149 --- engine/user/add-user.d.ts | 20 - engine/user/add-user.js | 169 --- engine/user/get-user.d.ts | 22 - engine/user/get-user.js | 55 - engine/user/login-user.d.ts | 39 - engine/user/login-user.js | 188 --- engine/user/reauth-user.d.ts | 46 - engine/user/reauth-user.js | 115 -- engine/user/send-email-code.d.ts | 32 - engine/user/send-email-code.js | 153 --- engine/user/social/github-auth.d.ts | 71 -- engine/user/social/github-auth.js | 151 --- engine/user/social/google-auth.d.ts | 28 - engine/user/social/google-auth.js | 174 --- engine/user/social/utils/githubLogin.d.ts | 182 --- engine/user/social/utils/handleSocialDb.d.ts | 99 -- engine/user/social/utils/httpsRequest.d.ts | 23 - engine/user/update-user.d.ts | 44 - engine/user/update-user.js | 91 -- functions/decrypt.d.ts | 14 - functions/encrypt.d.ts | 14 - functions/sql/sql-generator.d.ts | 8 - index.d.ts | 52 - index.js | 6 +- package-lock.json | 1113 ++++++++++++++++- .../data/dataTypes.json | 6 + .../data/defaultFields.json | 16 +- .../data/possibleFields.json | 6 +- .../data/presets/users.json | 42 +- package-shared/functions/api/query/get.js | 93 ++ package-shared/functions/api/query/post.js | 100 ++ .../api/social-login/facebookLogin.js | 126 ++ .../api/social-login}/githubLogin.js | 50 +- .../functions/api/social-login/googleLogin.js | 178 +++ .../api/social-login}/handleSocialDb.js | 219 ++-- .../functions/api/users/api-create-user.js | 117 ++ .../functions/api/users/api-get-user.js | 26 + .../functions/api/users/api-login.js | 159 +++ .../functions/api/users/api-reauth-user.js | 92 ++ .../api/users/api-send-email-code.js | 116 ++ .../functions/api/users/api-update-user.js | 43 + .../api/users/social/api-github-login.js | 110 ++ .../api/users/social/api-google-login.js | 88 ++ .../functions/backend/addAdminUserOnLogin.js | 191 +++ .../functions/backend/addMariadbUser.js | 4 +- .../functions/backend/addUsersTableToDb.js | 95 ++ package-shared/functions/backend/api-cred.js | 4 +- .../backend/cookies/get-auth-cookie-names.js | 13 + .../functions/backend/db/addDbEntry.js | 11 +- .../functions/backend/db/runQuery.d.ts | 30 - .../functions/backend/db/runQuery.js | 6 +- .../functions/backend/db/updateDbEntry.js | 8 +- package-shared/functions/backend/decrypt.d.ts | 6 - package-shared/functions/backend/decrypt.js | 29 - package-shared/functions/backend/encrypt.d.ts | 9 - package-shared/functions/backend/encrypt.js | 43 - .../functions/backend/grabUserSchemaData.js | 46 + .../functions/backend/handleNodemailer.js | 129 ++ .../functions/backend}/httpsRequest.js | 69 +- .../functions/backend/parseDbResults.js | 6 +- .../functions/backend/serverError.d.ts | 12 - .../functions/backend/serverError.js | 74 +- .../functions/backend/setUserSchemaData.js | 49 + .../functions/backend/suSocketAuth.js | 13 +- .../functions/dsql}/decrypt.js | 19 +- .../functions/dsql}/encrypt.js | 21 +- .../functions/dsql}/hashPassword.d.ts | 0 .../functions/dsql}/hashPassword.js | 0 .../dsql}/sql/sql-delete-generator.d.ts | 0 .../dsql}/sql/sql-delete-generator.js | 0 .../functions/dsql/sql/sql-generator.d.ts | 10 + .../functions/dsql}/sql/sql-generator.js | 6 +- .../dsql}/sql/sql-insert-generator.d.ts | 0 .../dsql}/sql/sql-insert-generator.js | 0 .../html}/one-time-code.html | 0 package-shared/shell/checkDb.js | 57 + package-shared/shell/createDbFromSchema.js | 302 +++++ package-shared/shell/deploy.js | 7 + package-shared/shell/encodingUpdate.js | 58 + .../shell/functions/jsonToBase64.js | 10 + package-shared/shell/grantFullPriviledges.js | 79 ++ package-shared/shell/lessWatch.js | 79 ++ package-shared/shell/mariadb-users/README.md | 7 + .../shell/mariadb-users/handleGrants.js | 105 ++ .../mariadb-users/refreshUsersAndGrants.js | 269 ++++ .../shell/mariadb-users/resetSQLPasswords.js | 105 ++ .../shell/mariadb-users/users/create-user.js | 185 +++ .../shell/mariadb-users/users/update-user.js | 74 ++ .../mariadb-users/users/update-user.json | 4 + package-shared/shell/readImage.js | 24 + package-shared/shell/recoverMainJsonFromDb.js | 120 ++ package-shared/shell/resetSQLCredentials.js | 103 ++ .../shell/resetSQLCredentialsPasswords.js | 90 ++ package-shared/shell/setSQLCredentials.js | 93 ++ package-shared/shell/tailwindWatch.js | 29 + package-shared/shell/test-external-server.js | 58 + package-shared/shell/test.js | 221 ++++ package-shared/shell/testSQLEscape.js | 102 ++ .../shell/updateChildrenTablesOnDb.js | 80 ++ package-shared/shell/updateDateTimestamps.js | 60 + .../shell/updateDbSlugsForTableRecords.js | 56 + package-shared/shell/updateSSLUsers.js | 70 ++ .../shell/utils/camelJoinedtoCamelSpace.js | 59 + .../shell}/utils/createTable.js | 96 +- package-shared/shell/utils/dbHandler.js | 118 ++ .../shell/utils/generateColumnDescription.js | 108 ++ .../shell/utils/noDatabaseDbHandler.js | 45 + .../shell/utils/slugToCamelTitle.js | 18 + .../shell}/utils/supplementTable.js | 4 +- .../shell}/utils/updateTable.js | 349 +++--- .../shell/utils/varDatabaseDbHandler.js | 71 ++ package-shared/types/index.d.ts | 135 +- .../utils/camelJoinedtoCamelSpace.js | 0 .../utils/endConnection.js | 0 .../utils/generateColumnDescription.js | 2 +- .../utils/slugToCamelTitle.js | 0 package.json | 17 +- tsconfig.json | 2 +- users/add-user.js | 42 +- users/get-token.js | 2 +- users/get-user.d.ts | 27 - users/get-user.js | 22 +- users/login-user.js | 64 +- users/reauth-user.js | 8 +- users/send-email-code.js | 24 +- users/social/github-auth.js | 8 +- users/social/google-auth.js | 30 +- users/update-user.js | 6 +- users/user-auth.js | 2 +- users/validate-token.js | 2 +- utils/get.js | 16 +- utils/post.js | 15 +- 153 files changed, 6621 insertions(+), 3899 deletions(-) delete mode 100644 engine/engine/addUsersTableToDb.d.ts delete mode 100644 engine/engine/addUsersTableToDb.js delete mode 100644 engine/engine/createDbFromSchema.js delete mode 100644 engine/engine/utils/camelJoinedtoCamelSpace.d.ts delete mode 100644 engine/engine/utils/dbHandler.d.ts delete mode 100644 engine/engine/utils/dbHandler.js delete mode 100644 engine/engine/utils/defaultFieldsRegexp.d.ts delete mode 100644 engine/engine/utils/defaultFieldsRegexp.js delete mode 100644 engine/engine/utils/noDatabaseDbHandler.js delete mode 100644 engine/engine/utils/parseDbResults.d.ts delete mode 100644 engine/engine/utils/parseDbResults.js delete mode 100644 engine/engine/utils/varDatabaseDbHandler.d.ts delete mode 100644 engine/engine/utils/varDatabaseDbHandler.js delete mode 100644 engine/query/get.d.ts delete mode 100644 engine/query/get.js delete mode 100644 engine/query/post.d.ts delete mode 100644 engine/query/post.js delete mode 100644 engine/query/update-api-schema-from-local-db.d.ts delete mode 100644 engine/query/update-api-schema-from-local-db.js delete mode 100644 engine/user/add-user.d.ts delete mode 100644 engine/user/add-user.js delete mode 100644 engine/user/get-user.d.ts delete mode 100644 engine/user/get-user.js delete mode 100644 engine/user/login-user.d.ts delete mode 100644 engine/user/login-user.js delete mode 100644 engine/user/reauth-user.d.ts delete mode 100644 engine/user/reauth-user.js delete mode 100644 engine/user/send-email-code.d.ts delete mode 100644 engine/user/send-email-code.js delete mode 100644 engine/user/social/github-auth.d.ts delete mode 100644 engine/user/social/github-auth.js delete mode 100644 engine/user/social/google-auth.d.ts delete mode 100644 engine/user/social/google-auth.js delete mode 100644 engine/user/social/utils/githubLogin.d.ts delete mode 100644 engine/user/social/utils/handleSocialDb.d.ts delete mode 100644 engine/user/social/utils/httpsRequest.d.ts delete mode 100644 engine/user/update-user.d.ts delete mode 100644 engine/user/update-user.js delete mode 100644 functions/decrypt.d.ts delete mode 100644 functions/encrypt.d.ts delete mode 100644 functions/sql/sql-generator.d.ts delete mode 100644 index.d.ts rename {engine/engine => package-shared}/data/dataTypes.json (90%) mode change 100644 => 100755 rename {engine/engine => package-shared}/data/defaultFields.json (67%) mode change 100644 => 100755 rename {engine/engine => package-shared}/data/possibleFields.json (70%) mode change 100644 => 100755 rename {engine/engine => package-shared}/data/presets/users.json (63%) mode change 100644 => 100755 create mode 100644 package-shared/functions/api/query/get.js create mode 100644 package-shared/functions/api/query/post.js create mode 100755 package-shared/functions/api/social-login/facebookLogin.js rename {engine/user/social/utils => package-shared/functions/api/social-login}/githubLogin.js (78%) mode change 100644 => 100755 create mode 100755 package-shared/functions/api/social-login/googleLogin.js rename {engine/user/social/utils => package-shared/functions/api/social-login}/handleSocialDb.js (70%) mode change 100644 => 100755 create mode 100644 package-shared/functions/api/users/api-create-user.js create mode 100644 package-shared/functions/api/users/api-get-user.js create mode 100644 package-shared/functions/api/users/api-login.js create mode 100644 package-shared/functions/api/users/api-reauth-user.js create mode 100644 package-shared/functions/api/users/api-send-email-code.js create mode 100644 package-shared/functions/api/users/api-update-user.js create mode 100644 package-shared/functions/api/users/social/api-github-login.js create mode 100644 package-shared/functions/api/users/social/api-google-login.js create mode 100755 package-shared/functions/backend/addAdminUserOnLogin.js create mode 100755 package-shared/functions/backend/addUsersTableToDb.js create mode 100644 package-shared/functions/backend/cookies/get-auth-cookie-names.js delete mode 100644 package-shared/functions/backend/db/runQuery.d.ts delete mode 100644 package-shared/functions/backend/decrypt.d.ts delete mode 100644 package-shared/functions/backend/decrypt.js delete mode 100644 package-shared/functions/backend/encrypt.d.ts delete mode 100644 package-shared/functions/backend/encrypt.js create mode 100755 package-shared/functions/backend/grabUserSchemaData.js create mode 100755 package-shared/functions/backend/handleNodemailer.js rename {engine/user/social/utils => package-shared/functions/backend}/httpsRequest.js (66%) delete mode 100644 package-shared/functions/backend/serverError.d.ts mode change 100644 => 100755 package-shared/functions/backend/serverError.js create mode 100755 package-shared/functions/backend/setUserSchemaData.js rename {functions => package-shared/functions/dsql}/decrypt.js (62%) rename {functions => package-shared/functions/dsql}/encrypt.js (59%) rename {functions => package-shared/functions/dsql}/hashPassword.d.ts (100%) rename {functions => package-shared/functions/dsql}/hashPassword.js (100%) rename {functions => package-shared/functions/dsql}/sql/sql-delete-generator.d.ts (100%) rename {functions => package-shared/functions/dsql}/sql/sql-delete-generator.js (100%) create mode 100644 package-shared/functions/dsql/sql/sql-generator.d.ts rename {functions => package-shared/functions/dsql}/sql/sql-generator.js (96%) rename {functions => package-shared/functions/dsql}/sql/sql-insert-generator.d.ts (100%) rename {functions => package-shared/functions/dsql}/sql/sql-insert-generator.js (100%) rename {engine/user => package-shared/html}/one-time-code.html (100%) create mode 100755 package-shared/shell/checkDb.js create mode 100755 package-shared/shell/createDbFromSchema.js create mode 100755 package-shared/shell/deploy.js create mode 100755 package-shared/shell/encodingUpdate.js create mode 100644 package-shared/shell/functions/jsonToBase64.js create mode 100755 package-shared/shell/grantFullPriviledges.js create mode 100755 package-shared/shell/lessWatch.js create mode 100644 package-shared/shell/mariadb-users/README.md create mode 100755 package-shared/shell/mariadb-users/handleGrants.js create mode 100755 package-shared/shell/mariadb-users/refreshUsersAndGrants.js create mode 100755 package-shared/shell/mariadb-users/resetSQLPasswords.js create mode 100755 package-shared/shell/mariadb-users/users/create-user.js create mode 100755 package-shared/shell/mariadb-users/users/update-user.js create mode 100644 package-shared/shell/mariadb-users/users/update-user.json create mode 100755 package-shared/shell/readImage.js create mode 100755 package-shared/shell/recoverMainJsonFromDb.js create mode 100755 package-shared/shell/resetSQLCredentials.js create mode 100755 package-shared/shell/resetSQLCredentialsPasswords.js create mode 100755 package-shared/shell/setSQLCredentials.js create mode 100755 package-shared/shell/tailwindWatch.js create mode 100755 package-shared/shell/test-external-server.js create mode 100755 package-shared/shell/test.js create mode 100755 package-shared/shell/testSQLEscape.js create mode 100755 package-shared/shell/updateChildrenTablesOnDb.js create mode 100755 package-shared/shell/updateDateTimestamps.js create mode 100755 package-shared/shell/updateDbSlugsForTableRecords.js create mode 100755 package-shared/shell/updateSSLUsers.js create mode 100755 package-shared/shell/utils/camelJoinedtoCamelSpace.js rename {engine/engine => package-shared/shell}/utils/createTable.js (56%) mode change 100644 => 100755 create mode 100755 package-shared/shell/utils/dbHandler.js create mode 100755 package-shared/shell/utils/generateColumnDescription.js create mode 100755 package-shared/shell/utils/noDatabaseDbHandler.js create mode 100755 package-shared/shell/utils/slugToCamelTitle.js rename {engine/engine => package-shared/shell}/utils/supplementTable.js (89%) mode change 100644 => 100755 rename {engine/engine => package-shared/shell}/utils/updateTable.js (60%) mode change 100644 => 100755 create mode 100755 package-shared/shell/utils/varDatabaseDbHandler.js rename {engine/engine => package-shared}/utils/camelJoinedtoCamelSpace.js (100%) rename {engine/engine => package-shared}/utils/endConnection.js (100%) rename {engine/engine => package-shared}/utils/generateColumnDescription.js (93%) rename {engine/engine => package-shared}/utils/slugToCamelTitle.js (100%) delete mode 100644 users/get-user.d.ts diff --git a/engine/dsql.js b/engine/dsql.js index 543d81f..dfa6522 100644 --- a/engine/dsql.js +++ b/engine/dsql.js @@ -10,8 +10,8 @@ require("dotenv").config({ }); const datasquirel = require("../index"); -const createDbFromSchema = require("./engine/createDbFromSchema"); const colors = require("../console-colors"); +const createDbFromSchema = require("../package-shared/shell/createDbFromSchema"); if (!fs.existsSync(path.resolve(process.cwd(), ".env"))) { console.log(".env file not found"); @@ -26,8 +26,6 @@ const { DSQL_KEY, DSQL_REF_DB_NAME, DSQL_FULL_SYNC, - DSQL_ENCRYPTION_KEY, - DSQL_ENCRYPTION_SALT, } = process.env; if (!DSQL_HOST?.match(/./)) { @@ -123,7 +121,10 @@ async function run() { ); // deepcode ignore reDOS: - await createDbFromSchema(schemaData); + await createDbFromSchema({ + dbSchemaData: schemaData, + }); + console.log( ` - ${colors.FgGreen}Success:${colors.Reset} Databases created Successfully!` ); diff --git a/engine/dump.js b/engine/dump.js index 5bc0f21..a19d519 100644 --- a/engine/dump.js +++ b/engine/dump.js @@ -18,17 +18,7 @@ const mysqlDumpPath = process.platform?.match(/win/i) "'" : "mysqldump"; -const { - DSQL_HOST, - DSQL_USER, - DSQL_PASS, - DSQL_DB_NAME, - DSQL_KEY, - DSQL_REF_DB_NAME, - DSQL_FULL_SYNC, - DSQL_ENCRYPTION_KEY, - DSQL_ENCRYPTION_SALT, -} = process.env; +const { DSQL_USER, DSQL_PASS, DSQL_DB_NAME } = process.env; const dbName = DSQL_DB_NAME || ""; const dumpFilePathArg = process.argv.indexOf("--file"); diff --git a/engine/engine/addUsersTableToDb.d.ts b/engine/engine/addUsersTableToDb.d.ts deleted file mode 100644 index bb1d6b3..0000000 --- a/engine/engine/addUsersTableToDb.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare function _exports({ dbSchema }: { - dbSchema: import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined; -}): Promise; -export = _exports; diff --git a/engine/engine/addUsersTableToDb.js b/engine/engine/addUsersTableToDb.js deleted file mode 100644 index 02dbcb4..0000000 --- a/engine/engine/addUsersTableToDb.js +++ /dev/null @@ -1,88 +0,0 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const fs = require("fs"); -const path = require("path"); -const { execSync } = require("child_process"); -const updateApiSchemaFromLocalDb = require("../query/update-api-schema-from-local-db"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * Add `users` table to user database - * ============================================================================== - * - * @param {object} params - Single object passed - * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} params.dbSchema - Database Schema Object - * - * @returns {Promise<*>} new user auth object payload - */ -module.exports = async function addUsersTableToDb({ dbSchema }) { - /** - * Initialize - * - * @description Initialize - */ - const database = process.env.DSQL_DB_NAME || ""; - /** @type {import("../../package-shared/types").DSQL_TableSchemaType} */ - const userPreset = require("./data/presets/users.json"); - - try { - /** - * Fetch user - * - * @description Fetch user from db - */ - const userSchemaMainFilePath = path.resolve( - process.cwd(), - "dsql.schema.json" - ); - let targetDatabase = dbSchema; - - if (!targetDatabase) throw new Error("Target database not found!"); - - let existingTableIndex = targetDatabase.tables.findIndex( - (table, index) => { - if (table.tableName === "users") { - existingTableIndex = index; - return true; - } - } - ); - - if (existingTableIndex >= 0) { - targetDatabase.tables[existingTableIndex] = userPreset; - } else { - targetDatabase.tables.push(userPreset); - } - - fs.writeFileSync( - `${userSchemaMainFilePath}`, - JSON.stringify(dbSchema, null, 4), - "utf8" - ); - - //////////////////////////////////////// - - await updateApiSchemaFromLocalDb(); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log(error.message); - } -}; - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// diff --git a/engine/engine/createDbFromSchema.js b/engine/engine/createDbFromSchema.js deleted file mode 100644 index a269284..0000000 --- a/engine/engine/createDbFromSchema.js +++ /dev/null @@ -1,300 +0,0 @@ -// @ts-check - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// - -const path = require("path"); - -//////////////////////////////////////// - -const noDatabaseDbHandler = require("./utils/noDatabaseDbHandler"); -const varDatabaseDbHandler = require("./utils/varDatabaseDbHandler"); -const createTable = require("./utils/createTable"); -const updateTable = require("./utils/updateTable"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * Create database from Schema - * ============================================================================== - * @description Create database from Schema. This function is called when the user - * runs the "dsql create" command. `NOTE`: there must be a "dsql.schema.json" file - * in the root of the project for this function to work - * - * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} dbSchema - An array of database schema objects - */ -async function createDbFromSchema(dbSchema) { - try { - /** - * Grab Schema - * - * @description Grab Schema - */ - - if (!dbSchema || !Array.isArray(dbSchema) || !dbSchema[0]) { - return; - } - - for (let i = 0; i < dbSchema.length; i++) { - /** @type {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} */ - const database = dbSchema[i]; - - if (!database) { - continue; - } - - const { dbFullName, tables } = database; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** @type {{ dbFullName: string }[] | null} */ - const dbCheck = await noDatabaseDbHandler({ - query: `SELECT SCHEMA_NAME AS dbFullName FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '${dbFullName}'`, - }); - - if (dbCheck && dbCheck[0]?.dbFullName) { - // Database Exists - } else { - const newDatabase = await noDatabaseDbHandler({ - query: `CREATE DATABASE IF NOT EXISTS \`${dbFullName}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_bin`, - }); - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Select all tables - * @type {{ TABLE_NAME: string }[] | null} - * @description Select All tables in target database - */ - const allTables = await noDatabaseDbHandler({ - query: `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='${dbFullName}'`, - }); - - let tableDropped; - - if (!allTables) { - console.log("No Tables to Update"); - continue; - } - - for (let tb = 0; tb < allTables.length; tb++) { - const { TABLE_NAME } = allTables[tb]; - - /** - * @description Check if TABLE_NAME is part of the tables contained - * in the user schema JSON. If it's not, the table is either deleted - * or the table name has been recently changed - */ - if ( - !tables.filter( - (_table) => _table.tableName === TABLE_NAME - )[0] - ) { - const oldTableFilteredArray = tables.filter( - (_table) => - _table.tableNameOld && - _table.tableNameOld === TABLE_NAME - ); - - /** - * @description Check if this table has been recently renamed. Rename - * table id true. Drop table if false - */ - if (oldTableFilteredArray && oldTableFilteredArray[0]) { - console.log("Renaming Table"); - await varDatabaseDbHandler({ - queryString: `RENAME TABLE \`${oldTableFilteredArray[0].tableNameOld}\` TO \`${oldTableFilteredArray[0].tableName}\``, - database: dbFullName, - }); - } else { - console.log(`Dropping Table from ${dbFullName}`); - // deepcode ignore reDOS: - await varDatabaseDbHandler({ - queryString: `DROP TABLE \`${TABLE_NAME}\``, - database: dbFullName, - }); - - tableDropped = true; - } - } - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * @description Iterate through each table and perform table actions - */ - for (let t = 0; t < tables.length; t++) { - const table = tables[t]; - - if (tableDropped) continue; - - const { tableName, fields, indexes } = table; - - /** - * @description Check if table exists - */ - const tableCheck = await varDatabaseDbHandler({ - queryString: ` - SELECT EXISTS ( - SELECT - TABLE_NAME - FROM - information_schema.TABLES - WHERE - TABLE_SCHEMA = ? AND - TABLE_NAME = ? - ) AS tableExists`, - queryValuesArray: [dbFullName, table.tableName], - database: dbFullName, - }); - - //////////////////////////////////////// - - if (tableCheck && tableCheck[0]?.tableExists > 0) { - /** - * @description Update table if table exists - */ - const updateExistingTable = await updateTable({ - dbFullName: dbFullName, - tableName: tableName, - tableInfoArray: fields, - dbSchema, - tableIndexes: indexes, - tableIndex: t, - }); - - if (table.childrenTables && table.childrenTables[0]) { - for ( - let ch = 0; - ch < table.childrenTables.length; - ch++ - ) { - const childTable = table.childrenTables[ch]; - - const updateExistingChildTable = await updateTable({ - dbFullName: childTable.dbNameFull, - tableName: childTable.tableName, - tableInfoArray: fields, - dbSchema, - tableIndexes: indexes, - clone: true, - }); - - // console.log(updateExistingChildTable); - } - } - - //////////////////////////////////////// - } else { - //////////////////////////////////////// - - /** - * @description Create new Table if table doesnt exist - */ - const createNewTable = await createTable({ - tableName: tableName, - tableInfoArray: fields, - varDatabaseDbHandler, - dbFullName: dbFullName, - dbSchema, - }); - - if (indexes && indexes[0]) { - /** - * Handle DATASQUIREL Table Indexes - * =================================================== - * @description Iterate through each datasquirel schema - * table index(if available), and perform operations - */ - if (indexes && indexes[0]) { - for (let g = 0; g < indexes.length; g++) { - const { - indexType, - indexName, - indexTableFields, - alias, - } = indexes[g]; - - if (!alias?.match(/./)) continue; - - /** - * @type {any[] | null} - * @description All indexes from MYSQL db - */ - const allExistingIndexes = - await varDatabaseDbHandler({ - queryString: `SHOW INDEXES FROM \`${tableName}\``, - database: dbFullName, - }); - - /** - * @description Check for existing Index in MYSQL db - */ - try { - const existingKeyInDb = allExistingIndexes - ? allExistingIndexes.filter( - (indexObject) => - indexObject.Key_name === alias - ) - : null; - if (!existingKeyInDb?.[0]) - throw new Error( - "This Index Does not Exist" - ); - } catch (error) { - /** - * @description Create new index if determined that it - * doesn't exist in MYSQL db - */ - await varDatabaseDbHandler({ - queryString: `CREATE${ - indexType?.match(/fullText/i) - ? " FULLTEXT" - : "" - } INDEX \`${alias}\` ON ${tableName}(${indexTableFields - ?.map((nm) => nm.value) - .map((nm) => `\`${nm}\``) - .join( - "," - )}) COMMENT 'schema_index'`, - database: dbFullName, - }); - } - } - } - } - } - - //////////////////////////////////////// - } - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log("Error in createDbFromSchema => ", error.message); - } -} - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -module.exports = createDbFromSchema; diff --git a/engine/engine/utils/camelJoinedtoCamelSpace.d.ts b/engine/engine/utils/camelJoinedtoCamelSpace.d.ts deleted file mode 100644 index 809740c..0000000 --- a/engine/engine/utils/camelJoinedtoCamelSpace.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -export = camelJoinedtoCamelSpace; -/** - * Convert Camel Joined Text to Camel Spaced Text - * ============================================================================== - * @description this function takes a camel cased text without spaces, and returns - * a camel-case-spaced text - * - * @param {string} text - text string without spaces - * - * @returns {string | null} - */ -declare function camelJoinedtoCamelSpace(text: string): string | null; diff --git a/engine/engine/utils/dbHandler.d.ts b/engine/engine/utils/dbHandler.d.ts deleted file mode 100644 index 7f29e75..0000000 --- a/engine/engine/utils/dbHandler.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -declare function _exports({ query, values, database, dbSchema, tableName, }: { - query: string; - values?: (string | number)[]; - dbSchema?: import("../../../package-shared/types").DSQL_DatabaseSchemaType; - database?: string; - tableName?: string; -}): Promise; -export = _exports; diff --git a/engine/engine/utils/dbHandler.js b/engine/engine/utils/dbHandler.js deleted file mode 100644 index 95f387c..0000000 --- a/engine/engine/utils/dbHandler.js +++ /dev/null @@ -1,173 +0,0 @@ -/** # MODULE TRACE -====================================================================== - * Detected 8 files that call this module. The files are listed below: -====================================================================== - * `require` Statement Found in [noDatabaseDbHandler.js](d:\GitHub\dsql\engine\engine\utils\noDatabaseDbHandler.js) - * `require` Statement Found in [varDatabaseDbHandler.js](d:\GitHub\dsql\engine\engine\utils\varDatabaseDbHandler.js) - * `require` Statement Found in [addDbEntry.js](d:\GitHub\dsql\engine\query\utils\addDbEntry.js) - * `require` Statement Found in [deleteDbEntry.js](d:\GitHub\dsql\engine\query\utils\deleteDbEntry.js) - * `require` Statement Found in [runQuery.js](d:\GitHub\dsql\engine\query\utils\runQuery.js) - * `require` Statement Found in [updateDbEntry.js](d:\GitHub\dsql\engine\query\utils\updateDbEntry.js) - * `require` Statement Found in [githubLogin.js](d:\GitHub\dsql\engine\user\social\utils\githubLogin.js) - * `require` Statement Found in [googleLogin.js](d:\GitHub\dsql\engine\user\social\utils\googleLogin.js) -==== MODULE TRACE END ==== */ - -// @ts-check - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// - -const fs = require("fs"); -const mysql = require("mysql"); -const path = require("path"); -const grabDbSSL = require("../../../package-shared/utils/backend/grabDbSSL"); - -const connection = mysql.createConnection({ - host: process.env.DSQL_HOST, - user: process.env.DSQL_USER, - database: process.env.DSQL_DB_NAME, - password: process.env.DSQL_PASS, - charset: "utf8mb4", - port: process.env.DSQL_PORT?.match(/.../) - ? parseInt(process.env.DSQL_PORT) - : undefined, - timeout: 5000, - ssl: grabDbSSL(), -}); - -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// - -/** - * Main DB Handler Function - * ============================================================================== - * @async - * @param {object} params - Single Param object containing params - * @param {string} params.query - Query String - * @param {(string | number)[]} [params.values] - Values - * @param {import("../../../package-shared/types").DSQL_DatabaseSchemaType} [params.dbSchema] - Database Schema - * @param {string} [params.database] - Target Database - * @param {string} [params.tableName] - Target Table Name - * - * @returns {Promise<*>} - */ -module.exports = async function dbHandler({ - query, - values, - database, - dbSchema, - tableName, -}) { - /** - * Declare variables - * - * @description Declare "results" variable - */ - let changeDbError; - - if (database) { - connection.changeUser({ database: database }, (error) => { - if (error) { - console.log( - "DB handler error in switching database:", - error.message - ); - changeDbError = error.message; - } - }); - } - - if (changeDbError) { - return { error: changeDbError }; - } - - /** - * Declare variables - * - * @description Declare "results" variable - */ - let results; - - /** - * Fetch from db - * - * @description Fetch data from db if no cache - */ - try { - results = await new Promise((resolve, reject) => { - if (values?.[0]) { - connection.query(query, values, (error, results, fields) => { - if (error) { - console.log( - "DB handler error with values array:", - error.message - ); - console.log("SQL:", error.sql); - console.log("State:", error.sqlState, error.sqlMessage); - - resolve({ - error: error.message, - }); - } else { - resolve(JSON.parse(JSON.stringify(results))); - } - - // setTimeout(() => { - // endConnection(connection); - // }, 500); - }); - } else { - connection.query(query, (error, results, fields) => { - if (error) { - console.log("DB handler error:", error.message); - console.log("SQL:", error.sql); - console.log("State:", error.sqlState, error.sqlMessage); - - resolve({ - error: error.message, - }); - } else { - resolve(JSON.parse(JSON.stringify(results))); - } - // setTimeout(() => { - // endConnection(connection); - // }, 500); - }); - } - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log("DB handler error:", error.message); - - results = null; - } - - /** - * Return results - * - * @description Return results add to cache if "req" param is passed - */ - // if (results && dbSchema && tableName) { - // const tableSchema = dbSchema.tables.find((table) => table.tableName === tableName); - // const parsedResults = parseDbResults({ - // unparsedResults: results, - // tableSchema: tableSchema, - // }); - - // return parsedResults; - // } else - if (results) { - return results; - } else { - console.log("DSQL DB handler no results received for Query =>", query); - return null; - } -}; diff --git a/engine/engine/utils/defaultFieldsRegexp.d.ts b/engine/engine/utils/defaultFieldsRegexp.d.ts deleted file mode 100644 index 078cc05..0000000 --- a/engine/engine/utils/defaultFieldsRegexp.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -export = defaultFieldsRegexp; -/** - * Regular expression to match default fields - * - * @description Regular expression to match default fields - * @type {RegExp} - */ -declare const defaultFieldsRegexp: RegExp; diff --git a/engine/engine/utils/defaultFieldsRegexp.js b/engine/engine/utils/defaultFieldsRegexp.js deleted file mode 100644 index 0e6f212..0000000 --- a/engine/engine/utils/defaultFieldsRegexp.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Regular expression to match default fields - * - * @description Regular expression to match default fields - * @type {RegExp} - */ -const defaultFieldsRegexp = /^id$|^date_created$|^date_created_code$|^date_created_timestamp$|^date_updated$|^date_updated_code$|^date_updated_timestamp$/; - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// - -module.exports = defaultFieldsRegexp; diff --git a/engine/engine/utils/noDatabaseDbHandler.js b/engine/engine/utils/noDatabaseDbHandler.js deleted file mode 100644 index 30a9faa..0000000 --- a/engine/engine/utils/noDatabaseDbHandler.js +++ /dev/null @@ -1,92 +0,0 @@ -// @ts-check - -const fs = require("fs"); -const mysql = require("mysql"); -const path = require("path"); -const grabDbSSL = require("../../../package-shared/utils/backend/grabDbSSL"); - -const connection = mysql.createConnection({ - host: process.env.DSQL_HOST, - user: process.env.DSQL_USER, - password: process.env.DSQL_PASS, - charset: "utf8mb4", - port: process.env.DSQL_PORT?.match(/.../) - ? parseInt(process.env.DSQL_PORT) - : undefined, - timeout: 5000, - ssl: grabDbSSL(), -}); - -/** - * Create database from Schema Function - * ============================================================================== - * @param {object} params - Single Param object containing params - * @param {string} params.query - Query String - * @param {string[]} [params.values] - Values - * - * @returns {Promise} - */ -module.exports = async function noDatabaseDbHandler({ query, values }) { - /** - * Declare variables - * - * @description Declare "results" variable - */ - let results; - - /** - * Fetch from db - * - * @description Fetch data from db if no cache - */ - try { - /** ********************* Run Query */ - results = await new Promise((resolve, reject) => { - if (values) { - connection.query(query, values, (error, results, fields) => { - if (error) { - console.log("NO-DB handler error:", error.message); - resolve({ - error: error.message, - }); - } else { - resolve(JSON.parse(JSON.stringify(results))); - } - // setTimeout(() => { - // endConnection(connection); - // }, 500); - }); - } else { - connection.query(query, (error, results, fields) => { - if (error) { - console.log("NO-DB handler error:", error.message); - resolve({ - error: error.message, - }); - } else { - resolve(JSON.parse(JSON.stringify(results))); - } - // setTimeout(() => { - // endConnection(connection); - // }, 500); - }); - } - }); - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log("ERROR in noDatabaseDbHandler =>", error.message); - } - - /** - * Return results - * - * @description Return results add to cache if "req" param is passed - */ - if (results) { - return results; - } else { - return null; - } -}; diff --git a/engine/engine/utils/parseDbResults.d.ts b/engine/engine/utils/parseDbResults.d.ts deleted file mode 100644 index b2b39a3..0000000 --- a/engine/engine/utils/parseDbResults.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -declare function _exports({ unparsedResults, tableSchema, }: { - unparsedResults: any[]; - tableSchema?: import("../../../package-shared/types").DSQL_TableSchemaType; -}): Promise; -export = _exports; diff --git a/engine/engine/utils/parseDbResults.js b/engine/engine/utils/parseDbResults.js deleted file mode 100644 index f78fa7b..0000000 --- a/engine/engine/utils/parseDbResults.js +++ /dev/null @@ -1,83 +0,0 @@ -// @ts-check - -const decrypt = require("../../../functions/decrypt"); -// @ts-ignore -const defaultFieldsRegexp = require("./defaultFieldsRegexp"); - -/** - * Parse Database results - * ============================================================================== - * @description this function takes a database results array gotten from a DB handler - * function, decrypts encrypted fields, and returns an updated array with no encrypted - * fields - * - * @param {object} params - Single object params - * @param {*[]} params.unparsedResults - Array of data objects containing Fields(keys) - * and corresponding values of the fields(values) - * @param {import("../../../package-shared/types").DSQL_TableSchemaType} [params.tableSchema] - Table schema - * @returns {Promise} - */ -module.exports = async function parseDbResults({ - unparsedResults, - tableSchema, -}) { - /** - * Declare variables - * - * @description Declare "results" variable - * @type {*[]} - */ - let parsedResults = []; - - const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; - const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; - - try { - /** - * Declare variables - * - * @description Declare "results" variable - */ - for (let pr = 0; pr < unparsedResults.length; pr++) { - let result = unparsedResults[pr]; - - let resultFieldNames = Object.keys(result); - - for (let i = 0; i < resultFieldNames.length; i++) { - const resultFieldName = resultFieldNames[i]; - let resultFieldSchema = tableSchema?.fields[i]; - - if (resultFieldName?.match(defaultFieldsRegexp)) { - continue; - } - - let value = result[resultFieldName]; - - if (typeof value !== "number" && !value) { - // parsedResults.push(result); - continue; - } - - if (resultFieldSchema?.encrypted && value?.match(/./)) { - result[resultFieldName] = decrypt({ - encryptedString: value, - encryptionKey, - encryptionSalt, - }); - } - } - - parsedResults.push(result); - } - - /** - * Declare variables - * - * @description Declare "results" variable - */ - return parsedResults; - } catch (/** @type {*} */ error) { - console.log("ERROR in parseDbResults Function =>", error.message); - return unparsedResults; - } -}; diff --git a/engine/engine/utils/varDatabaseDbHandler.d.ts b/engine/engine/utils/varDatabaseDbHandler.d.ts deleted file mode 100644 index 501f597..0000000 --- a/engine/engine/utils/varDatabaseDbHandler.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -declare namespace _exports { - export { VarDbHandlerParam }; -} -declare function _exports({ queryString, queryValuesArray, database, tableSchema, }: VarDbHandlerParam): Promise; -export = _exports; -type VarDbHandlerParam = { - /** - * - SQL string - */ - queryString: string; - /** - * - Values Array - */ - queryValuesArray?: string[]; - /** - * - Database name - */ - database: string; - /** - * - Table schema - */ - tableSchema?: import("../../../package-shared/types").DSQL_TableSchemaType; -}; diff --git a/engine/engine/utils/varDatabaseDbHandler.js b/engine/engine/utils/varDatabaseDbHandler.js deleted file mode 100644 index e9042d0..0000000 --- a/engine/engine/utils/varDatabaseDbHandler.js +++ /dev/null @@ -1,129 +0,0 @@ -/** # MODULE TRACE -====================================================================== - * Detected 9 files that call this module. The files are listed below: -====================================================================== - * `require` Statement Found in [createDbFromSchema.js](d:\GitHub\dsql\engine\engine\createDbFromSchema.js) - * `require` Statement Found in [updateTable.js](d:\GitHub\dsql\engine\engine\utils\updateTable.js) - * `require` Statement Found in [runQuery.js](d:\GitHub\dsql\engine\query\utils\runQuery.js) - * `require` Statement Found in [add-user.js](d:\GitHub\dsql\engine\user\add-user.js) - * `require` Statement Found in [get-user.js](d:\GitHub\dsql\engine\user\get-user.js) - * `require` Statement Found in [login-user.js](d:\GitHub\dsql\engine\user\login-user.js) - * `require` Statement Found in [reauth-user.js](d:\GitHub\dsql\engine\user\reauth-user.js) - * `require` Statement Found in [handleSocialDb.js](d:\GitHub\dsql\engine\user\social\utils\handleSocialDb.js) - * `require` Statement Found in [update-user.js](d:\GitHub\dsql\engine\user\update-user.js) -==== MODULE TRACE END ==== */ - -// @ts-check - -const fs = require("fs"); -const parseDbResults = require("./parseDbResults"); -const dbHandler = require("./dbHandler"); - -/** - * @typedef {object} VarDbHandlerParam - * @property {string} queryString - SQL string - * @property {string[]} [queryValuesArray] - Values Array - * @property {string} database - Database name - * @property {import("../../../package-shared/types").DSQL_TableSchemaType} [tableSchema] - Table schema - */ - -/** - * DB handler for specific database - * ============================================================================== - * @async - * @param {VarDbHandlerParam} params - * @returns {Promise} - */ -module.exports = async function varDatabaseDbHandler({ - queryString, - queryValuesArray, - database, - tableSchema, -}) { - /** - * Create Connection - * - * @description Create Connection - */ - - const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; - const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; - - /** - * Declare variables - * - * @description Declare "results" variable - * @type {*} - */ - let results; - - /** - * Fetch from db - * - * @description Fetch data from db if no cache - */ - try { - if ( - queryString && - Array.isArray(queryValuesArray) && - queryValuesArray[0] - ) { - results = await dbHandler({ - query: queryString, - values: queryValuesArray, - database: database, - }); - } else if (queryString && !Array.isArray(queryValuesArray)) { - results = await dbHandler({ - query: queryString, - database: database, - }); - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } catch (error) { - console.log( - "\x1b[31mvarDatabaseDbHandler ERROR\x1b[0m =>", - database, - error - ); - } - - /** - * Return results - * - * @description Return results add to cache if "req" param is passed - */ - if (results && tableSchema) { - try { - const unparsedResults = results; - // deepcode ignore reDOS: - const parsedResults = await parseDbResults({ - unparsedResults: unparsedResults, - tableSchema: tableSchema, - }); - return parsedResults; - } catch (error) { - console.log( - "\x1b[31mvarDatabaseDbHandler ERROR\x1b[0m =>", - database, - error - ); - return null; - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } else if (results) { - return results; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } else { - return null; - } -}; diff --git a/engine/query/get.d.ts b/engine/query/get.d.ts deleted file mode 100644 index d36026a..0000000 --- a/engine/query/get.d.ts +++ /dev/null @@ -1,64 +0,0 @@ -export = localGet; -/** - * @typedef {Object} LocalGetReturn - * @property {boolean} success - Did the function run successfully? - * @property {*} [payload] - GET request results - * @property {string} [msg] - Message - * @property {string} [error] - Error Message - */ -/** - * @typedef {Object} LocalQueryObject - * @property {string} query - Table Name - * @property {string} [tableName] - Table Name - * @property {string[]} [queryValues] - GET request results - */ -/** - * Make a get request to Datasquirel API - * ============================================================================== - * @async - * - * @param {Object} params - Single object passed - * @param {LocalQueryObject} params.options - SQL Query - * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} [params.dbSchema] - Name of the table to query - * - * @returns { Promise } - Return Object - */ -declare function localGet({ options, dbSchema }: { - options: LocalQueryObject; - dbSchema?: import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined; -}): Promise; -declare namespace localGet { - export { LocalGetReturn, LocalQueryObject }; -} -type LocalGetReturn = { - /** - * - Did the function run successfully? - */ - success: boolean; - /** - * - GET request results - */ - payload?: any; - /** - * - Message - */ - msg?: string; - /** - * - Error Message - */ - error?: string; -}; -type LocalQueryObject = { - /** - * - Table Name - */ - query: string; - /** - * - Table Name - */ - tableName?: string; - /** - * - GET request results - */ - queryValues?: string[]; -}; diff --git a/engine/query/get.js b/engine/query/get.js deleted file mode 100644 index f24adbd..0000000 --- a/engine/query/get.js +++ /dev/null @@ -1,94 +0,0 @@ -/** # MODULE TRACE -====================================================================== - * No imports found for this Module -==== MODULE TRACE END ==== */ - -const runQuery = require("../../package-shared/functions/backend/db/runQuery"); - -// @ts-check - -/** - * @typedef {Object} LocalGetReturn - * @property {boolean} success - Did the function run successfully? - * @property {*} [payload] - GET request results - * @property {string} [msg] - Message - * @property {string} [error] - Error Message - */ - -/** - * @typedef {Object} LocalQueryObject - * @property {string} query - Table Name - * @property {string} [tableName] - Table Name - * @property {string[]} [queryValues] - GET request results - */ - -/** - * Make a get request to Datasquirel API - * ============================================================================== - * @async - * - * @param {Object} params - Single object passed - * @param {LocalQueryObject} params.options - SQL Query - * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} [params.dbSchema] - Name of the table to query - * - * @returns { Promise } - Return Object - */ -async function localGet({ options, dbSchema }) { - try { - const { query, queryValues } = options; - - /** @type {string | undefined | any } */ - const tableName = options?.tableName ? options.tableName : undefined; - const dbFullName = process.env.DSQL_DB_NAME || ""; - - /** - * Create new user folder and file - * - * @description Create new user folder and file - */ - let results; - - try { - let { result, error } = await runQuery({ - dbFullName: dbFullName, - query: query, - queryValuesArray: queryValues, - dbSchema, - tableName, - local: true, - readOnly: true, - }); - - if (error) throw error; - if (!result) - throw new Error("No Result received for query => " + query); - if (result?.error) throw new Error(result.error); - - results = result; - return { success: true, payload: results }; - - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - //////////////////////////////////////// - - console.log("Error in local get Request =>", error.message); - - return { - success: false, - payload: null, - error: error.message, - }; - } - - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - //////////////////////////////////////// - console.log("Error in local get Request =>", error.message); - - return { success: false, msg: "Something went wrong!" }; - - //////////////////////////////////////// - } -} - -module.exports = localGet; diff --git a/engine/query/post.d.ts b/engine/query/post.d.ts deleted file mode 100644 index 51df2f4..0000000 --- a/engine/query/post.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -export = localPost; -/** - * Make a get request to Datasquirel API - * ============================================================================== - * @async - * - * @param {Object} params - Single object passed - * @param {import("../../package-shared/types").LocalPostQueryObject} params.options - * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} [params.dbSchema] - * - * @returns { Promise } - */ -declare function localPost({ options, dbSchema }: { - options: import("../../package-shared/types").LocalPostQueryObject; - dbSchema?: import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined; -}): Promise; diff --git a/engine/query/post.js b/engine/query/post.js deleted file mode 100644 index 5d47ec8..0000000 --- a/engine/query/post.js +++ /dev/null @@ -1,62 +0,0 @@ -// @ts-check - -const runQuery = require("../../package-shared/functions/backend/db/runQuery"); - -/** - * Make a get request to Datasquirel API - * ============================================================================== - * @async - * - * @param {Object} params - Single object passed - * @param {import("../../package-shared/types").LocalPostQueryObject} params.options - * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} [params.dbSchema] - * - * @returns { Promise } - */ -async function localPost({ options, dbSchema }) { - try { - /** - * Grab Body - */ - const { query, tableName, queryValues } = options; - const dbFullName = process.env.DSQL_DB_NAME || ""; - - /** - * Create new user folder and file - * - * @description Create new user folder and file - */ - try { - let { result, error } = await runQuery({ - dbFullName: dbFullName, - query: query, - dbSchema: dbSchema, - queryValuesArray: queryValues, - tableName, - local: true, - }); - - if (error) throw error; - - return { - success: true, - payload: result, - error: error, - }; - } catch (/** @type {*} */ error) { - return { - success: false, - error: error.message, - }; - } - } catch (/** @type {*} */ error) { - console.log("Error in local post Request =>", error.message); - - return { - success: false, - msg: "Something went wrong!", - }; - } -} - -module.exports = localPost; diff --git a/engine/query/update-api-schema-from-local-db.d.ts b/engine/query/update-api-schema-from-local-db.d.ts deleted file mode 100644 index d6a504b..0000000 --- a/engine/query/update-api-schema-from-local-db.d.ts +++ /dev/null @@ -1,38 +0,0 @@ -export = updateApiSchemaFromLocalDb; -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** - * @typedef {Object} PostReturn - * @property {boolean} success - Did the function run successfully? - * @property {*} [payload] - The Y Coordinate - * @property {string} [error] - The Y Coordinate - */ -/** - * # Update API Schema From Local DB - * - * @async - * - * @returns { Promise } - Return Object - */ -declare function updateApiSchemaFromLocalDb(): Promise; -declare namespace updateApiSchemaFromLocalDb { - export { PostReturn }; -} -type PostReturn = { - /** - * - Did the function run successfully? - */ - success: boolean; - /** - * - The Y Coordinate - */ - payload?: any; - /** - * - The Y Coordinate - */ - error?: string; -}; diff --git a/engine/query/update-api-schema-from-local-db.js b/engine/query/update-api-schema-from-local-db.js deleted file mode 100644 index c5267a0..0000000 --- a/engine/query/update-api-schema-from-local-db.js +++ /dev/null @@ -1,149 +0,0 @@ -// @ts-check - -/** - * Imports - */ -const https = require("https"); -const http = require("http"); -const path = require("path"); -const fs = require("fs"); -const grabHostNames = require("../../package-shared/utils/grab-host-names"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * @typedef {Object} PostReturn - * @property {boolean} success - Did the function run successfully? - * @property {*} [payload] - The Y Coordinate - * @property {string} [error] - The Y Coordinate - */ - -/** - * # Update API Schema From Local DB - * - * @async - * - * @returns { Promise } - Return Object - */ -async function updateApiSchemaFromLocalDb() { - try { - /** - * Initialize - */ - const dbSchemaPath = path.resolve(process.cwd(), "dsql.schema.json"); - const key = process.env.DSQL_KEY || ""; - - const dbSchema = JSON.parse(fs.readFileSync(dbSchemaPath, "utf8")); - const { host, port, scheme, user_id } = grabHostNames(); - - /** - * Make https request - * - * @description make a request to datasquirel.com - */ - const httpResponse = await new Promise((resolve, reject) => { - const reqPayloadString = JSON.stringify({ - schema: dbSchema, - }).replace(/\n|\r|\n\r/gm, ""); - - try { - JSON.parse(reqPayloadString); - } catch (error) { - console.log(error); - console.log(reqPayloadString); - - return { - success: false, - payload: null, - error: "Query object is invalid. Please Check query data values", - }; - } - - const reqPayload = reqPayloadString; - - const httpsRequest = scheme.request( - { - method: "POST", - headers: { - "Content-Type": "application/json", - "Content-Length": Buffer.from(reqPayload).length, - Authorization: - key || - process.env.DSQL_FULL_ACCESS_API_KEY || - process.env.DSQL_API_KEY, - }, - port, - hostname: host, - path: `/api/query/${user_id}/update-schema-from-single-database`, - }, - - /** - * Callback Function - * - * @description https request callback - */ - (response) => { - var str = ""; - - response.on("data", function (chunk) { - str += chunk; - }); - - response.on("end", function () { - try { - resolve(JSON.parse(str)); - } catch (error) { - console.log(error); - console.log("Fetched Payload =>", str); - - resolve({ - success: false, - payload: null, - error: error, - }); - } - }); - - response.on("error", (err) => { - resolve({ - success: false, - payload: null, - error: err.message, - }); - }); - } - ); - - httpsRequest.write(reqPayload); - - httpsRequest.on("error", (error) => { - console.log("HTTPS request ERROR =>", error); - }); - - httpsRequest.end(); - }); - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - return httpResponse; - } catch (/** @type {*} */ error) { - return { - success: false, - payload: null, - error: error.message, - }; - } -} - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - -module.exports = updateApiSchemaFromLocalDb; diff --git a/engine/user/add-user.d.ts b/engine/user/add-user.d.ts deleted file mode 100644 index 51307ad..0000000 --- a/engine/user/add-user.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -export = localAddUser; -/** - * Make a get request to Datasquirel API - * ============================================================================== - * @async - * - * @param {Object} params - Single object passed - * @param {import("../../package-shared/types").UserDataPayload} params.payload - SQL Query - * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} params.dbSchema - Name of the table to query - * @param {string} [params.encryptionKey] - * @param {string} [params.encryptionSalt] - * - * @returns { Promise } - Return Object - */ -declare function localAddUser({ payload, dbSchema, encryptionKey, encryptionSalt, }: { - payload: import("../../package-shared/types").UserDataPayload; - dbSchema: import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined; - encryptionKey?: string; - encryptionSalt?: string; -}): Promise; diff --git a/engine/user/add-user.js b/engine/user/add-user.js deleted file mode 100644 index 766f0b3..0000000 --- a/engine/user/add-user.js +++ /dev/null @@ -1,169 +0,0 @@ -// @ts-check - -const hashPassword = require("../../functions/hashPassword"); -const addDbEntry = require("../../package-shared/functions/backend/db/addDbEntry"); -const addUsersTableToDb = require("../engine/addUsersTableToDb"); -const varDatabaseDbHandler = require("../engine/utils/varDatabaseDbHandler"); - -/** - * Make a get request to Datasquirel API - * ============================================================================== - * @async - * - * @param {Object} params - Single object passed - * @param {import("../../package-shared/types").UserDataPayload} params.payload - SQL Query - * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} params.dbSchema - Name of the table to query - * @param {string} [params.encryptionKey] - * @param {string} [params.encryptionSalt] - * - * @returns { Promise } - Return Object - */ -async function localAddUser({ - payload, - dbSchema, - encryptionKey, - encryptionSalt, -}) { - try { - /** - * Initialize Variables - */ - const dbFullName = process.env.DSQL_DB_NAME || ""; - - const encryptionKeyFinal = process.env.DSQL_ENCRYPTION_KEY || ""; - const encryptionSaltFinal = process.env.DSQL_ENCRYPTION_SALT || ""; - - /** - * Hash Password - * - * @description Hash Password - */ - if (!payload?.password) { - return { - success: false, - msg: `Password is required to create an account`, - }; - } - - const hashedPassword = hashPassword({ - password: payload.password, - encryptionKey: encryptionKeyFinal, - }); - payload.password = hashedPassword; - - let fields = await varDatabaseDbHandler({ - queryString: `SHOW COLUMNS FROM users`, - database: dbFullName, - }); - - if (!fields) { - const newTable = await addUsersTableToDb({ dbSchema }); - - console.log(newTable); - - fields = await varDatabaseDbHandler({ - queryString: `SHOW COLUMNS FROM users`, - database: dbFullName, - }); - } - - if (!fields) { - return { - success: false, - msg: "Could not create users table", - }; - } - - const fieldsTitles = fields.map( - (/** @type {*} */ fieldObject) => fieldObject.Field - ); - - let invalidField = null; - - for (let i = 0; i < Object.keys(payload).length; i++) { - const key = Object.keys(payload)[i]; - if (!fieldsTitles.includes(key)) { - invalidField = key; - break; - } - } - - if (invalidField) { - return { - success: false, - msg: `${invalidField} is not a valid field!`, - }; - } - - if (!dbSchema) { - throw new Error("Db Schema not found!"); - } - - const tableSchema = dbSchema.tables.find( - (tb) => tb?.tableName === "users" - ); - - const existingUser = await varDatabaseDbHandler({ - queryString: `SELECT * FROM users WHERE email = ?${ - payload.username ? "OR username = ?" : "" - }}`, - queryValuesArray: payload.username - ? [payload.email, payload.username] - : [payload.email], - database: dbFullName, - tableSchema: tableSchema, - }); - - if (existingUser && existingUser[0]) { - return { - success: false, - msg: "User Already Exists", - }; - } - - const addUser = await addDbEntry({ - dbFullName: dbFullName, - tableName: "users", - data: { - ...payload, - image: "/images/user_images/user-preset.png", - image_thumbnail: - "/images/user_images/user-preset-thumbnail.png", - }, - encryptionKey: encryptionKeyFinal, - encryptionSalt: encryptionSaltFinal, - tableSchema, - }); - - if (addUser?.insertId) { - const newlyAddedUser = await varDatabaseDbHandler({ - queryString: `SELECT id,first_name,last_name,email,username,phone,image,image_thumbnail,city,state,country,zip_code,address,verification_status,more_user_data FROM users WHERE id='${addUser.insertId}'`, - database: dbFullName, - }); - - return { - success: true, - payload: newlyAddedUser?.[0], - }; - } else { - return { - success: false, - msg: "Could not create user", - }; - } - - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - //////////////////////////////////////// - console.log("Error in local add-user Request =>", error.message); - - return { - success: false, - msg: "Something went wrong!", - }; - - //////////////////////////////////////// - } -} - -module.exports = localAddUser; diff --git a/engine/user/get-user.d.ts b/engine/user/get-user.d.ts deleted file mode 100644 index 09b99c3..0000000 --- a/engine/user/get-user.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -export = getLocalUser; -/** - * - * @param {object} param0 - * @param {number} param0.userId - * @param {string[]} param0.fields - * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} [param0.dbSchema] - * @returns - */ -declare function getLocalUser({ userId, fields, dbSchema }: { - userId: number; - fields: string[]; - dbSchema?: import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined; -}): Promise<{ - success: boolean; - payload: any; - msg: string; -} | { - success: boolean; - payload: any; - msg?: undefined; -}>; diff --git a/engine/user/get-user.js b/engine/user/get-user.js deleted file mode 100644 index 71f33e4..0000000 --- a/engine/user/get-user.js +++ /dev/null @@ -1,55 +0,0 @@ -// @ts-check - -const varDatabaseDbHandler = require("../engine/utils/varDatabaseDbHandler"); - -/** - * - * @param {object} param0 - * @param {number} param0.userId - * @param {string[]} param0.fields - * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} [param0.dbSchema] - * @returns - */ -async function getLocalUser({ userId, fields, dbSchema }) { - /** - * GRAB user - * - * @description GRAB user - */ - const sanitizedFields = fields.map((fld) => fld.replace(/[^a-z\_]/g, "")); - const query = `SELECT ${sanitizedFields.join(",")} FROM users WHERE id = ?`; - - const tableSchema = dbSchema?.tables.find( - (tb) => tb?.tableName === "users" - ); - - let foundUser = await varDatabaseDbHandler({ - queryString: query, - queryValuesArray: [userId.toString()], - database: process.env.DSQL_DB_NAME || "", - tableSchema, - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - if (!foundUser || !foundUser[0]) - return { - success: false, - payload: null, - msg: "User not found!", - }; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** ********************* Send Response */ - return { - success: true, - payload: foundUser[0], - }; -} - -module.exports = getLocalUser; diff --git a/engine/user/login-user.d.ts b/engine/user/login-user.d.ts deleted file mode 100644 index c76adb2..0000000 --- a/engine/user/login-user.d.ts +++ /dev/null @@ -1,39 +0,0 @@ -export = loginLocalUser; -/** - * - * @param {import("../../package-shared/types").PackageUserLoginLocalBody} param0 - * @returns - */ -declare function loginLocalUser({ payload, additionalFields, dbSchema, email_login, email_login_code, email_login_field, }: import("../../package-shared/types").PackageUserLoginLocalBody): Promise<{ - success: boolean; - msg: string; - payload?: undefined; - userId?: undefined; -} | { - success: boolean; - payload: any; - msg: string; - userId?: undefined; -} | { - success: boolean; - msg: string; - payload: { - id: any; - first_name: any; - last_name: any; - username: any; - email: any; - phone: any; - social_id: any; - image: any; - image_thumbnail: any; - verification_status: any; - social_login: any; - social_platform: any; - csrf_k: string; - more_data: any; - logged_in_status: boolean; - date: number; - }; - userId: string; -}>; diff --git a/engine/user/login-user.js b/engine/user/login-user.js deleted file mode 100644 index 1a6ac92..0000000 --- a/engine/user/login-user.js +++ /dev/null @@ -1,188 +0,0 @@ -// @ts-check - -const hashPassword = require("../../functions/hashPassword"); -const varDatabaseDbHandler = require("../engine/utils/varDatabaseDbHandler"); - -/** - * - * @param {import("../../package-shared/types").PackageUserLoginLocalBody} param0 - * @returns - */ -async function loginLocalUser({ - payload, - additionalFields, - dbSchema, - email_login, - email_login_code, - email_login_field, -}) { - try { - /** - * User auth - * - * @description Authenticate user - */ - - 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 || ""; - const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; - - /** - * Check input validity - * - * @description Check input validity - */ - if ( - email?.match(/ /) || - (username && username?.match(/ /)) || - (password && password?.match(/ /)) - ) { - return { - success: false, - msg: "Invalid Email/Password format", - }; - } - - /** - * Password hash - * - * @description Password hash - */ - let hashedPassword = password - ? hashPassword({ - password: password, - encryptionKey: encryptionKey, - }) - : null; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - const tableSchema = dbSchema?.tables.find( - (tb) => tb?.tableName === "users" - ); - - let foundUser = await varDatabaseDbHandler({ - queryString: `SELECT * FROM users WHERE email = ? OR username = ?`, - queryValuesArray: [email || "", username || ""], - database: dbFullName.replace(/[^a-z0-9_]/g, ""), - tableSchema, - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - if (!foundUser || !foundUser[0]) - return { - success: false, - payload: null, - msg: "No user found", - }; - - let isPasswordCorrect = false; - - 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]; - - if (!tempCode) throw new Error("No code Found!"); - - const tempCodeArray = tempCode.split("-"); - const [code, codeDate] = tempCodeArray; - const millisecond15mins = 1000 * 60 * 15; - - if (Date.now() - Number(codeDate) > millisecond15mins) { - throw new Error("Code Expired"); - } - isPasswordCorrect = code === email_login_code; - } - - let socialUserValid = false; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - if (!isPasswordCorrect && !socialUserValid) { - return { - success: false, - msg: "Wrong password, no social login validity", - payload: null, - }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - let csrfKey = - Math.random().toString(36).substring(2) + - "-" + - Math.random().toString(36).substring(2); - - let userPayload = { - id: foundUser[0].id, - first_name: foundUser[0].first_name, - last_name: foundUser[0].last_name, - username: foundUser[0].username, - email: foundUser[0].email, - phone: foundUser[0].phone, - social_id: foundUser[0].social_id, - image: foundUser[0].image, - image_thumbnail: foundUser[0].image_thumbnail, - verification_status: foundUser[0].verification_status, - social_login: foundUser[0].social_login, - social_platform: foundUser[0].social_platform, - csrf_k: csrfKey, - more_data: foundUser[0].more_user_data, - logged_in_status: true, - date: Date.now(), - }; - - if ( - additionalFields && - Array.isArray(additionalFields) && - additionalFields.length > 0 - ) { - additionalFields.forEach((key) => { - // @ts-ignore - userPayload[key] = foundUser?.[0][key]; - }); - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** ********************* Send Response */ - return { - success: true, - msg: "Login Successful", - payload: userPayload, - userId: "0", - }; - - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log("Error in local login-user Request =>", error.message); - return { - success: false, - msg: "Login Failed", - }; - } -} - -module.exports = loginLocalUser; diff --git a/engine/user/reauth-user.d.ts b/engine/user/reauth-user.d.ts deleted file mode 100644 index d138bb3..0000000 --- a/engine/user/reauth-user.d.ts +++ /dev/null @@ -1,46 +0,0 @@ -export = localReauthUser; -/** - * - * @param {object} param0 - * @param {*} param0.existingUser - * @param {string[]} [param0.additionalFields] - * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} [param0.dbSchema] - * @returns - */ -declare function localReauthUser({ existingUser, additionalFields, dbSchema }: { - existingUser: any; - additionalFields?: string[]; - dbSchema?: import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined; -}): Promise<{ - success: boolean; - payload: any; - msg: string; - userId?: undefined; -} | { - success: boolean; - msg: string; - payload: { - id: any; - first_name: any; - last_name: any; - username: any; - email: any; - phone: any; - social_id: any; - image: any; - image_thumbnail: any; - verification_status: any; - social_login: any; - social_platform: any; - csrf_k: string; - more_data: any; - logged_in_status: boolean; - date: number; - }; - userId: string; -} | { - success: boolean; - msg: string; - payload?: undefined; - userId?: undefined; -}>; diff --git a/engine/user/reauth-user.js b/engine/user/reauth-user.js deleted file mode 100644 index dab5a54..0000000 --- a/engine/user/reauth-user.js +++ /dev/null @@ -1,115 +0,0 @@ -// @ts-check - -const varDatabaseDbHandler = require("../engine/utils/varDatabaseDbHandler"); - -/** - * - * @param {object} param0 - * @param {*} param0.existingUser - * @param {string[]} [param0.additionalFields] - * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} [param0.dbSchema] - * @returns - */ -async function localReauthUser({ existingUser, additionalFields, dbSchema }) { - try { - /** - * Grab data - * - * @description Grab data - */ - const dbFullName = process.env.DSQL_DB_NAME || ""; - - /** - * GRAB user - * - * @description GRAB user - */ - const tableSchema = dbSchema?.tables.find( - (tb) => tb?.tableName === "users" - ); - - let foundUser = - existingUser?.id && existingUser.id.toString().match(/./) - ? await varDatabaseDbHandler({ - queryString: `SELECT * FROM users WHERE id=?`, - queryValuesArray: [existingUser.id], - database: dbFullName.replace(/[^a-z0-9_]/g, ""), - tableSchema, - }) - : null; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - if (!foundUser || !foundUser[0]) - return { - success: false, - payload: null, - msg: "No user found", - }; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - let csrfKey = - Math.random().toString(36).substring(2) + - "-" + - Math.random().toString(36).substring(2); - - let userPayload = { - id: foundUser[0].id, - first_name: foundUser[0].first_name, - last_name: foundUser[0].last_name, - username: foundUser[0].username, - email: foundUser[0].email, - phone: foundUser[0].phone, - social_id: foundUser[0].social_id, - image: foundUser[0].image, - image_thumbnail: foundUser[0].image_thumbnail, - verification_status: foundUser[0].verification_status, - social_login: foundUser[0].social_login, - social_platform: foundUser[0].social_platform, - csrf_k: csrfKey, - more_data: foundUser[0].more_user_data, - logged_in_status: true, - date: Date.now(), - }; - - if ( - additionalFields && - Array.isArray(additionalFields) && - additionalFields.length > 0 - ) { - additionalFields.forEach((key) => { - // @ts-ignore - userPayload[key] = foundUser?.[0][key]; - }); - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** ********************* Send Response */ - return { - success: true, - msg: "Login Successful", - payload: userPayload, - userId: "0", - }; - - //////////////////////////////////////// - - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log("Error in local login-user Request =>", error.message); - return { - success: false, - msg: "Login Failed", - }; - } -} - -module.exports = localReauthUser; diff --git a/engine/user/send-email-code.d.ts b/engine/user/send-email-code.d.ts deleted file mode 100644 index 5e5da3a..0000000 --- a/engine/user/send-email-code.d.ts +++ /dev/null @@ -1,32 +0,0 @@ -export = localSendEmailCode; -/** - * - * @param {object} param0 - * @param {string} param0.email - * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} [param0.dbSchema] - * @param {string} param0.email_login_field - * @param {string} [param0.mail_domain] - * @param {string} [param0.mail_username] - * @param {string} [param0.mail_password] - * @param {number} [param0.mail_port] - * @param {string} [param0.sender] - * @returns - */ -declare function localSendEmailCode({ email, dbSchema, email_login_field, mail_domain, mail_username, mail_password, mail_port, sender, }: { - email: string; - dbSchema?: import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined; - email_login_field: string; - mail_domain?: string; - mail_username?: string; - mail_password?: string; - mail_port?: number; - sender?: string; -}): Promise<{ - success: boolean; - msg: string; - payload?: undefined; -} | { - success: boolean; - payload: any; - msg: string; -}>; diff --git a/engine/user/send-email-code.js b/engine/user/send-email-code.js deleted file mode 100644 index a53abd9..0000000 --- a/engine/user/send-email-code.js +++ /dev/null @@ -1,153 +0,0 @@ -// @ts-check - -const hashPassword = require("../../functions/hashPassword"); -const varDatabaseDbHandler = require("../engine/utils/varDatabaseDbHandler"); -const nodemailer = require("nodemailer"); -const fs = require("fs"); -const path = require("path"); - -/** - * - * @param {object} param0 - * @param {string} param0.email - * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} [param0.dbSchema] - * @param {string} param0.email_login_field - * @param {string} [param0.mail_domain] - * @param {string} [param0.mail_username] - * @param {string} [param0.mail_password] - * @param {number} [param0.mail_port] - * @param {string} [param0.sender] - * @returns - */ -async function localSendEmailCode({ - email, - dbSchema, - email_login_field, - mail_domain, - mail_username, - mail_password, - mail_port, - sender, -}) { - try { - /** - * User auth - * - * @description Authenticate user - */ - const dbFullName = process.env.DSQL_DB_NAME || ""; - const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; - const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; - - /** - * Check input validity - * - * @description Check input validity - */ - if (email?.match(/ /)) { - return { - success: false, - msg: "Invalid Email/Password format", - }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - const tableSchema = dbSchema?.tables.find( - (tb) => tb?.tableName === "users" - ); - - let foundUser = await varDatabaseDbHandler({ - queryString: `SELECT * FROM users WHERE email = ?`, - queryValuesArray: [email], - database: dbFullName.replace(/[^a-z0-9_]/g, ""), - tableSchema, - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - if (!foundUser || !foundUser[0]) - return { - success: false, - payload: null, - msg: "No user found", - }; - - if (foundUser && foundUser[0] && email_login_field) { - const tempCode = generateCode(); - - let transporter = nodemailer.createTransport({ - host: mail_domain, - port: mail_port || 465, - secure: true, - auth: { - user: mail_username, - pass: 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"] = fs - .readFileSync( - path.resolve(__dirname, "one-time-code.html"), - "utf-8" - ) - .replace(/{{code}}/, tempCode); - - const info = await transporter.sendMail(mailObject); - - if (!info?.accepted) throw new Error("Mail not Sent!"); - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - let setTempCode = await varDatabaseDbHandler({ - queryString: `UPDATE users SET ${email_login_field} = ? WHERE email = ?`, - queryValuesArray: [tempCode + `-${Date.now()}`, email], - database: dbFullName.replace(/[^a-z0-9_]/g, ""), - tableSchema, - }); - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** ********************* Send Response */ - return { - success: true, - msg: "Success", - }; - - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log("Error in local login-user Request =>", error.message); - return { - success: false, - msg: "Failed: " + error.message, - }; - } -} - -function generateCode() { - const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - let code = ""; - for (let i = 0; i < 8; i++) { - code += chars[Math.floor(Math.random() * chars.length)]; - } - return code; -} - -module.exports = localSendEmailCode; diff --git a/engine/user/social/github-auth.d.ts b/engine/user/social/github-auth.d.ts deleted file mode 100644 index 77e6c44..0000000 --- a/engine/user/social/github-auth.d.ts +++ /dev/null @@ -1,71 +0,0 @@ -export = localGithubAuth; -/** - * SERVER FUNCTION: Login with google Function - * ============================================================================== - * - * @async - * - * @param {object} params - main params object - * @param {http.ServerResponse} params.res - HTTPS response object - * @param {string} params.code - * @param {string} [params.email] - * @param {string} params.clientId - * @param {string} params.clientSecret - * @param {object} [params.additionalFields] - * @param {import("../../../package-shared/types").DSQL_DatabaseSchemaType} params.dbSchema - */ -declare function localGithubAuth({ res, code, email, clientId, clientSecret, additionalFields, dbSchema, }: { - res: http.ServerResponse; - code: string; - email?: string; - clientId: string; - clientSecret: string; - additionalFields?: object; - dbSchema: import("../../../package-shared/types").DSQL_DatabaseSchemaType; -}): Promise<{ - success: boolean; - msg: string; -} | { - dsqlUserId: string; - /** - * - Did the operation complete successfully or not? - */ - success: boolean; - /** - * - User payload object: or "null" - */ - user: { - id: number; - first_name: string; - last_name: string; - } | null; - /** - * - Message - */ - msg?: string; - /** - * - Error Message - */ - error?: string; - /** - * - Social Id - */ - social_id?: string | number; - /** - * - Social Platform - */ - social_platform?: string; - /** - * - Payload - */ - payload?: object; - /** - * - Alert - */ - alert?: boolean; - /** - * - New User - */ - newUser?: any; -}>; -import http = require("http"); diff --git a/engine/user/social/github-auth.js b/engine/user/social/github-auth.js deleted file mode 100644 index c497b99..0000000 --- a/engine/user/social/github-auth.js +++ /dev/null @@ -1,151 +0,0 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const http = require("http"); -const https = require("https"); -const encrypt = require("../../../functions/encrypt"); -const camelJoinedtoCamelSpace = require("../../engine/utils/camelJoinedtoCamelSpace"); -const githubLogin = require("./utils/githubLogin"); -const handleSocialDb = require("./utils/handleSocialDb"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -const database = process.env.DSQL_DB_NAME || ""; -const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; -const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; - -/** - * SERVER FUNCTION: Login with google Function - * ============================================================================== - * - * @async - * - * @param {object} params - main params object - * @param {http.ServerResponse} params.res - HTTPS response object - * @param {string} params.code - * @param {string} [params.email] - * @param {string} params.clientId - * @param {string} params.clientSecret - * @param {object} [params.additionalFields] - * @param {import("../../../package-shared/types").DSQL_DatabaseSchemaType} params.dbSchema - */ -async function localGithubAuth({ - res, - code, - email, - clientId, - clientSecret, - additionalFields, - dbSchema, -}) { - try { - /** - * User auth - * - * @description Authenticate user - */ - if (!code || !clientId || !clientSecret) { - return { - success: false, - msg: "Missing query params", - }; - } - - if ( - typeof code !== "string" || - typeof clientId !== "string" || - typeof clientSecret !== "string" || - typeof database !== "string" - ) { - return { - success: false, - msg: "Wrong Parameters", - }; - } - - /** - * Create new user folder and file - * - * @description Create new user folder and file - */ - const gitHubUser = await githubLogin({ - code: code, - clientId: clientId, - clientSecret: clientSecret, - }); - - if (!gitHubUser) { - return { - success: false, - msg: "No github user returned", - }; - } - - const targetDbName = database; - - const socialId = gitHubUser.name || gitHubUser.id || gitHubUser.login; - const targetName = gitHubUser.name || gitHubUser.login; - const nameArray = targetName?.match(/ /) - ? targetName?.split(" ") - : targetName?.match(/\-/) - ? targetName?.split("-") - : [targetName]; - - const payload = { - email: gitHubUser.email, - first_name: camelJoinedtoCamelSpace(nameArray[0]) || "", - last_name: camelJoinedtoCamelSpace(nameArray[1]) || "", - social_id: socialId, - social_platform: "github", - image: gitHubUser.avatar_url, - image_thumbnail: gitHubUser.avatar_url, - username: "github-user-" + socialId, - }; - - if (additionalFields && Object.keys(additionalFields).length > 0) { - Object.keys(additionalFields).forEach((key) => { - // @ts-ignore - payload[key] = additionalFields[key]; - }); - } - - const loggedInGithubUser = await handleSocialDb({ - database: targetDbName, - email: gitHubUser.email, - payload: payload, - social_platform: "github", - res: res, - social_id: socialId, - supEmail: email, - additionalFields, - dbSchema: dbSchema, - }); - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - - return { ...loggedInGithubUser, dsqlUserId: "0" }; - - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log("localGithubAuth error", error.message); - - return { success: false, msg: "Failed!" }; - } -} - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// - -module.exports = localGithubAuth; diff --git a/engine/user/social/google-auth.d.ts b/engine/user/social/google-auth.d.ts deleted file mode 100644 index 0f9db15..0000000 --- a/engine/user/social/google-auth.d.ts +++ /dev/null @@ -1,28 +0,0 @@ -export = localGoogleAuth; -/** - * SERVER FUNCTION: Login with google Function - * ============================================================================== - * - * @async - * - * @param {object} params - main params object - * @param {string} params.token - Google access token gotten from the client side - * @param {string} params.clientId - Google client id - * @param {http.ServerResponse} params.response - HTTPS response object - * @param {object} [params.additionalFields] - Additional Fields to be added to the user object - * @param {import("../../../package-shared/types").DSQL_DatabaseSchemaType} [params.dbSchema] - Database Schema - * - * @returns { Promise } - */ -declare function localGoogleAuth({ dbSchema, token, clientId, response, additionalFields, }: { - token: string; - clientId: string; - response: http.ServerResponse; - additionalFields?: object; - dbSchema?: import("../../../package-shared/types").DSQL_DatabaseSchemaType; -}): Promise; -declare namespace localGoogleAuth { - export { FunctionReturn }; -} -import http = require("http"); -type FunctionReturn = object | null; diff --git a/engine/user/social/google-auth.js b/engine/user/social/google-auth.js deleted file mode 100644 index 571b902..0000000 --- a/engine/user/social/google-auth.js +++ /dev/null @@ -1,174 +0,0 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const http = require("http"); -const handleSocialDb = require("./utils/handleSocialDb"); -const httpsRequest = require("./utils/httpsRequest"); -const grabHostNames = require("../../../package-shared/utils/grab-host-names"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * @typedef {object | null} FunctionReturn - * @property {boolean} success - Did the function run successfully? - * @property {import("../../types/user.td").DATASQUIREL_LoggedInUser | null} user - Returned User - * @property {number} [dsqlUserId] - Dsql User Id - * @property {string} [msg] - Response message - */ - -const database = process.env.DSQL_DB_NAME || ""; -const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; -const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; - -/** - * SERVER FUNCTION: Login with google Function - * ============================================================================== - * - * @async - * - * @param {object} params - main params object - * @param {string} params.token - Google access token gotten from the client side - * @param {string} params.clientId - Google client id - * @param {http.ServerResponse} params.response - HTTPS response object - * @param {object} [params.additionalFields] - Additional Fields to be added to the user object - * @param {import("../../../package-shared/types").DSQL_DatabaseSchemaType} [params.dbSchema] - Database Schema - * - * @returns { Promise } - */ -async function localGoogleAuth({ - dbSchema, - token, - clientId, - response, - additionalFields, -}) { - /** - * Send Response - * - * @description Send a boolean response - */ - const { host, port, scheme } = grabHostNames(); - - try { - /** - * Grab User data - * - * @description Grab User data - * @type {{ success: boolean, payload: any, msg: string }} - */ - const payloadResponse = await httpsRequest({ - method: "POST", - hostname: host, - path: "/user/grab-google-user-from-token", - body: { - token: token, - clientId: clientId, - }, - headers: { - Authorization: process.env.DSQL_API_KEY, - }, - }); - - const payload = payloadResponse.payload; - - if (!payloadResponse.success || !payload) { - console.log("payloadResponse Failed =>", payloadResponse); - return { - success: false, - msg: "User fetch Error", - }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - if (!database || typeof database != "string" || database?.match(/ /)) { - return { - success: false, - user: undefined, - msg: "Please provide a database slug(database name in lowercase with no spaces)", - }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Create new user folder and file - * - * @description Create new user folder and file - */ - const targetDbName = database; - - if (!payload) { - return { - success: false, - msg: "No payload", - }; - } - - const { given_name, family_name, email, sub, picture, email_verified } = - payload; - - const payloadObject = { - email: email || "", - first_name: given_name || "", - last_name: family_name || "", - social_id: sub, - social_platform: "google", - image: picture || "", - image_thumbnail: picture || "", - username: `google-user-${sub}`, - }; - - if (additionalFields && Object.keys(additionalFields).length > 0) { - Object.keys(additionalFields).forEach((key) => { - // @ts-ignore - payloadObject[key] = additionalFields[key]; - }); - } - - const loggedInGoogleUser = await handleSocialDb({ - database: targetDbName, - email: email || "", - payload: payloadObject, - social_platform: "google", - res: response, - social_id: sub, - additionalFields, - dbSchema, - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - return { ...loggedInGoogleUser, dsqlUserId: "0" }; - - //////////////////////////////////////// - } catch (error) { - return { - success: false, - msg: "User fetch Error", - }; - - //////////////////////////////////////// - } -} - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// - -module.exports = localGoogleAuth; diff --git a/engine/user/social/utils/githubLogin.d.ts b/engine/user/social/utils/githubLogin.d.ts deleted file mode 100644 index de8d308..0000000 --- a/engine/user/social/utils/githubLogin.d.ts +++ /dev/null @@ -1,182 +0,0 @@ -export = githubLogin; -/** - * - * @typedef {object} GithubUserPayload - * @property {string} login - Full name merged eg. "JohnDoe" - * @property {number} id - github user id - * @property {string} node_id - Some other id - * @property {string} avatar_url - profile picture - * @property {string} gravatar_id - some other id - * @property {string} url - Github user URL - * @property {string} html_url - User html URL - whatever that means - * @property {string} followers_url - Followers URL - * @property {string} following_url - Following URL - * @property {string} gists_url - Gists URL - * @property {string} starred_url - Starred URL - * @property {string} subscriptions_url - Subscriptions URL - * @property {string} organizations_url - Organizations URL - * @property {string} repos_url - Repositories URL - * @property {string} received_events_url - Received Events URL - * @property {string} type - Common value => "User" - * @property {boolean} site_admin - Is site admin or not? Boolean - * @property {string} name - More like "username" - * @property {string} company - User company - * @property {string} blog - User blog URL - * @property {string} location - User Location - * @property {string} email - User Email - * @property {string} hireable - Is user hireable - * @property {string} bio - User bio - * @property {string} twitter_username - User twitter username - * @property {number} public_repos - Number of public repositories - * @property {number} public_gists - Number of public gists - * @property {number} followers - Number of followers - * @property {number} following - Number of following - * @property {string} created_at - Date created - * @property {string} updated_at - Date updated - */ -/** - * Login/signup a github user - * ============================================================================== - * @async - * - * @param {Object} params - foundUser if any - * @param {string} params.code - github auth token - * @param {string} params.clientId - github client Id - * @param {string} params.clientSecret - github client Secret - * - * @returns {Promise} - */ -declare function githubLogin({ code, clientId, clientSecret }: { - code: string; - clientId: string; - clientSecret: string; -}): Promise; -declare namespace githubLogin { - export { GithubUserPayload }; -} -type GithubUserPayload = { - /** - * - Full name merged eg. "JohnDoe" - */ - login: string; - /** - * - github user id - */ - id: number; - /** - * - Some other id - */ - node_id: string; - /** - * - profile picture - */ - avatar_url: string; - /** - * - some other id - */ - gravatar_id: string; - /** - * - Github user URL - */ - url: string; - /** - * - User html URL - whatever that means - */ - html_url: string; - /** - * - Followers URL - */ - followers_url: string; - /** - * - Following URL - */ - following_url: string; - /** - * - Gists URL - */ - gists_url: string; - /** - * - Starred URL - */ - starred_url: string; - /** - * - Subscriptions URL - */ - subscriptions_url: string; - /** - * - Organizations URL - */ - organizations_url: string; - /** - * - Repositories URL - */ - repos_url: string; - /** - * - Received Events URL - */ - received_events_url: string; - /** - * - Common value => "User" - */ - type: string; - /** - * - Is site admin or not? Boolean - */ - site_admin: boolean; - /** - * - More like "username" - */ - name: string; - /** - * - User company - */ - company: string; - /** - * - User blog URL - */ - blog: string; - /** - * - User Location - */ - location: string; - /** - * - User Email - */ - email: string; - /** - * - Is user hireable - */ - hireable: string; - /** - * - User bio - */ - bio: string; - /** - * - User twitter username - */ - twitter_username: string; - /** - * - Number of public repositories - */ - public_repos: number; - /** - * - Number of public gists - */ - public_gists: number; - /** - * - Number of followers - */ - followers: number; - /** - * - Number of following - */ - following: number; - /** - * - Date created - */ - created_at: string; - /** - * - Date updated - */ - updated_at: string; -}; diff --git a/engine/user/social/utils/handleSocialDb.d.ts b/engine/user/social/utils/handleSocialDb.d.ts deleted file mode 100644 index 11603b3..0000000 --- a/engine/user/social/utils/handleSocialDb.d.ts +++ /dev/null @@ -1,99 +0,0 @@ -export = handleSocialDb; -/** - * Handle Social User Auth on Datasquirel Database - * ============================================================================== - * - * @description This function handles all social login logic after the social user - * has been authenticated and userpayload is present. The payload MUST contain the - * specified fields because this funciton will create a new user if the authenticated - * user does not exist. - * - * @param {{ - * database: string|null|undefined, - * social_id: string|number, - * email: string, - * social_platform: string, - * payload: { - * social_id: string | number, - * email: string, - * social_platform: string, - * first_name: string, - * last_name: string, - * image: string, - * image_thumbnail: string, - * username: string, - * }, - * res: http.ServerResponse, - * supEmail?: string | null, - * additionalFields?: object, - * dbSchema: import("../../../../package-shared/types").DSQL_DatabaseSchemaType | undefined - * }} params - function parameters inside an object - * - * @returns {Promise} - Response object - */ -declare function handleSocialDb({ social_id, email, social_platform, payload, res, supEmail, additionalFields, dbSchema, }: { - database: string | null | undefined; - social_id: string | number; - email: string; - social_platform: string; - payload: { - social_id: string | number; - email: string; - social_platform: string; - first_name: string; - last_name: string; - image: string; - image_thumbnail: string; - username: string; - }; - res: http.ServerResponse; - supEmail?: string | null; - additionalFields?: object; - dbSchema: import("../../../../package-shared/types").DSQL_DatabaseSchemaType | undefined; -}): Promise; -declare namespace handleSocialDb { - export { FunctionReturn }; -} -import http = require("http"); -type FunctionReturn = { - /** - * - Did the operation complete successfully or not? - */ - success: boolean; - /** - * - User payload object: or "null" - */ - user: { - id: number; - first_name: string; - last_name: string; - } | null; - /** - * - Message - */ - msg?: string; - /** - * - Error Message - */ - error?: string; - /** - * - Social Id - */ - social_id?: string | number; - /** - * - Social Platform - */ - social_platform?: string; - /** - * - Payload - */ - payload?: object; - /** - * - Alert - */ - alert?: boolean; - /** - * - New User - */ - newUser?: any; -}; diff --git a/engine/user/social/utils/httpsRequest.d.ts b/engine/user/social/utils/httpsRequest.d.ts deleted file mode 100644 index 32b77a8..0000000 --- a/engine/user/social/utils/httpsRequest.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -export = httpsRequest; -/** - * Main Function - * ============================================================================== - * @param {{ - * url?: string, - * method: string, - * hostname: string, - * path?: string, - * href?: string, - * headers?: object, - * body?: object, - * }} params - params - */ -declare function httpsRequest({ url, method, hostname, path, href, headers, body }: { - url?: string; - method: string; - hostname: string; - path?: string; - href?: string; - headers?: object; - body?: object; -}): Promise; diff --git a/engine/user/update-user.d.ts b/engine/user/update-user.d.ts deleted file mode 100644 index 4ced0c4..0000000 --- a/engine/user/update-user.d.ts +++ /dev/null @@ -1,44 +0,0 @@ -export = localUpdateUser; -/** - * @typedef {Object} LocalPostReturn - * @property {boolean} success - Did the function run successfully? - * @property {*} [payload] - GET request results - * @property {string} [msg] - Message - * @property {string} [error] - Error Message - */ -/** - * Make a get request to Datasquirel API - * ============================================================================== - * @async - * - * @param {Object} params - Single object passed - * @param {*} params.payload - SQL Query - * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} params.dbSchema - Name of the table to query - * - * @returns { Promise } - Return Object - */ -declare function localUpdateUser({ payload, dbSchema }: { - payload: any; - dbSchema: import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined; -}): Promise; -declare namespace localUpdateUser { - export { LocalPostReturn }; -} -type LocalPostReturn = { - /** - * - Did the function run successfully? - */ - success: boolean; - /** - * - GET request results - */ - payload?: any; - /** - * - Message - */ - msg?: string; - /** - * - Error Message - */ - error?: string; -}; diff --git a/engine/user/update-user.js b/engine/user/update-user.js deleted file mode 100644 index 2af40e0..0000000 --- a/engine/user/update-user.js +++ /dev/null @@ -1,91 +0,0 @@ -// @ts-check - -const updateDbEntry = require("../../package-shared/functions/backend/db/updateDbEntry"); - -/** - * @typedef {Object} LocalPostReturn - * @property {boolean} success - Did the function run successfully? - * @property {*} [payload] - GET request results - * @property {string} [msg] - Message - * @property {string} [error] - Error Message - */ - -/** - * Make a get request to Datasquirel API - * ============================================================================== - * @async - * - * @param {Object} params - Single object passed - * @param {*} params.payload - SQL Query - * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} params.dbSchema - Name of the table to query - * - * @returns { Promise } - Return Object - */ -async function localUpdateUser({ payload, dbSchema }) { - try { - /** - * User auth - * - * @description Authenticate user - */ - /** - * Initialize Variables - */ - const dbFullName = process.env.DSQL_DB_NAME || ""; - - const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; - const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; - - const data = (() => { - const reqBodyKeys = Object.keys(payload); - const finalData = {}; - - reqBodyKeys.forEach((key) => { - if (key?.match(/^date_|^id$/)) return; - // @ts-ignore - finalData[key] = payload[key]; - }); - - return finalData; - })(); - - if (!dbSchema) { - throw new Error("Db Schema not found!"); - } - - const tableSchema = dbSchema.tables.find( - (tb) => tb?.tableName === "users" - ); - - const updateUser = await updateDbEntry({ - dbContext: "Dsql User", - paradigm: "Full Access", - dbFullName: dbFullName, - tableName: "users", - identifierColumnName: "id", - identifierValue: payload.id, - data: data, - encryptionKey, - encryptionSalt, - tableSchema, - }); - - return { - success: true, - payload: updateUser, - }; - } catch (/** @type {*} */ error) { - //////////////////////////////////////// - console.log("Error in local add-user Request =>", error.message); - - return { - success: false, - payload: null, - msg: "Something went wrong!", - }; - - //////////////////////////////////////// - } -} - -module.exports = localUpdateUser; diff --git a/functions/decrypt.d.ts b/functions/decrypt.d.ts deleted file mode 100644 index 51f1be4..0000000 --- a/functions/decrypt.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -export = decrypt; -/** - * - * @param {object} param0 - * @param {string} param0.encryptedString - * @param {string} param0.encryptionKey - * @param {string} param0.encryptionSalt - * @returns - */ -declare function decrypt({ encryptedString, encryptionKey, encryptionSalt }: { - encryptedString: string; - encryptionKey: string; - encryptionSalt: string; -}): string; diff --git a/functions/encrypt.d.ts b/functions/encrypt.d.ts deleted file mode 100644 index e05e80c..0000000 --- a/functions/encrypt.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -export = encrypt; -/** - * - * @param {object} param0 - * @param {string} param0.data - * @param {string} param0.encryptionKey - * @param {string} param0.encryptionSalt - * @returns {string | null} - */ -declare function encrypt({ data, encryptionKey, encryptionSalt }: { - data: string; - encryptionKey: string; - encryptionSalt: string; -}): string | null; diff --git a/functions/sql/sql-generator.d.ts b/functions/sql/sql-generator.d.ts deleted file mode 100644 index 2fed80c..0000000 --- a/functions/sql/sql-generator.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -export = sqlGenerator; -declare function sqlGenerator(Param0: { - genObject?: import("../../package-shared/types").ServerQueryParam; - tableName: string; -}): { - string: string; - values: string[]; -} | undefined; diff --git a/index.d.ts b/index.d.ts deleted file mode 100644 index f4d2bb0..0000000 --- a/index.d.ts +++ /dev/null @@ -1,52 +0,0 @@ -import get = require("./utils/get"); -import post = require("./utils/post"); -export namespace media { - export { uploadImage }; - export { uploadFile }; - export { deleteFile }; -} -export namespace user { - export { createUser }; - export { loginUser }; - export { sendEmailCode }; - export { logoutUser }; - export { userAuth }; - export { reAuthUser }; - export { updateUser }; - export { getUser }; - export { getToken }; - export { validateToken }; - export namespace social { - export { loginWithGoogle }; - export { loginWithGithub }; - } -} -import getSchema = require("./utils/get-schema"); -import sanitizeSql = require("./utils/functions/sanitizeSql"); -import datasquirelClient = require("./client"); -export namespace sql { - export { sqlGenerator }; - export { sqlInsertGenerator }; - export { sqlDeleteGenerator }; - export { trimSql as trim }; -} -import uploadImage = require("./utils/upload-image"); -import uploadFile = require("./utils/upload-file"); -import deleteFile = require("./utils/delete-file"); -import createUser = require("./users/add-user"); -import loginUser = require("./users/login-user"); -import sendEmailCode = require("./users/send-email-code"); -import logoutUser = require("./users/logout-user"); -import userAuth = require("./users/user-auth"); -import reAuthUser = require("./users/reauth-user"); -import updateUser = require("./users/update-user"); -import getUser = require("./users/get-user"); -import getToken = require("./users/get-token"); -import validateToken = require("./users/validate-token"); -import loginWithGoogle = require("./users/social/google-auth"); -import loginWithGithub = require("./users/social/github-auth"); -import sqlGenerator = require("./functions/sql/sql-generator"); -import sqlInsertGenerator = require("./functions/sql/sql-insert-generator"); -import sqlDeleteGenerator = require("./functions/sql/sql-delete-generator"); -import trimSql = require("./package-shared/utils/trim-sql"); -export { get, post, getSchema, sanitizeSql, datasquirelClient as client }; diff --git a/index.js b/index.js index 45cd091..8f66b79 100644 --- a/index.js +++ b/index.js @@ -28,9 +28,9 @@ const validateToken = require("./users/validate-token"); const sanitizeSql = require("./utils/functions/sanitizeSql"); const datasquirelClient = require("./client"); -const sqlGenerator = require("./functions/sql/sql-generator"); -const sqlInsertGenerator = require("./functions/sql/sql-insert-generator"); -const sqlDeleteGenerator = require("./functions/sql/sql-delete-generator"); +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"); //////////////////////////////////////// diff --git a/package-lock.json b/package-lock.json index 90b880a..faf88c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,33 +1,556 @@ { "name": "@moduletrace/datasquirel", - "version": "2.6.7", + "version": "2.7.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@moduletrace/datasquirel", - "version": "2.6.7", + "version": "2.7.5", "license": "ISC", "dependencies": { "@types/ace": "^0.0.52", - "@types/react": "^18.3.12", + "@types/lodash": "^4.17.13", + "@types/mysql": "^2.15.21", + "@types/next": "^9.0.0", + "@types/node": "^22.7.5", + "@types/react": "^18.2.21", + "@types/react-dom": "^19.0.0", "@types/tinymce": "^4.6.9", "dotenv": "^16.3.1", "generate-password": "^1.7.1", + "google-auth-library": "^9.15.0", "lodash": "^4.17.21", "mysql": "^2.18.1", "nodemailer": "^6.9.14", + "react": "^19.0.0", + "react-dom": "^19.0.0", "sanitize-html": "^2.13.1", "serverless-mysql": "^1.5.5" }, "bin": { "dsql-dump": "engine/dump.js", "dsql-watch": "engine/dsql.js" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", + "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, - "devDependencies": { - "@types/lodash": "^4.17.13", - "@types/mysql": "^2.15.21", - "@types/node": "^22.7.5" + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.5" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.2.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@next/env": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.0.4.tgz", + "integrity": "sha512-WNRvtgnRVDD4oM8gbUcRc27IAhaL4eXQ/2ovGbgLnPGUvdyDr8UdXP4Q/IBDdAdojnD2eScryIDirv0YUCjUVw==", + "license": "MIT" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.0.4.tgz", + "integrity": "sha512-QecQXPD0yRHxSXWL5Ff80nD+A56sUXZG9koUsjWJwA2Z0ZgVQfuy7gd0/otjxoOovPVHR2eVEvPMHbtZP+pf9w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.0.4.tgz", + "integrity": "sha512-pb7Bye3y1Og3PlCtnz2oO4z+/b3pH2/HSYkLbL0hbVuTGil7fPen8/3pyyLjdiTLcFJ+ymeU3bck5hd4IPFFCA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.0.4.tgz", + "integrity": "sha512-12oSaBFjGpB227VHzoXF3gJoK2SlVGmFJMaBJSu5rbpaoT5OjP5OuCLuR9/jnyBF1BAWMs/boa6mLMoJPRriMA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.0.4.tgz", + "integrity": "sha512-QARO88fR/a+wg+OFC3dGytJVVviiYFEyjc/Zzkjn/HevUuJ7qGUUAUYy5PGVWY1YgTzeRYz78akQrVQ8r+sMjw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.0.4.tgz", + "integrity": "sha512-Z50b0gvYiUU1vLzfAMiChV8Y+6u/T2mdfpXPHraqpypP7yIT2UV9YBBhcwYkxujmCvGEcRTVWOj3EP7XW/wUnw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.0.4.tgz", + "integrity": "sha512-7H9C4FAsrTAbA/ENzvFWsVytqRYhaJYKa2B3fyQcv96TkOGVMcvyS6s+sj4jZlacxxTcn7ygaMXUPkEk7b78zw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.0.4.tgz", + "integrity": "sha512-Z/v3WV5xRaeWlgJzN9r4PydWD8sXV35ywc28W63i37G2jnUgScA4OOgS8hQdiXLxE3gqfSuHTicUhr7931OXPQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.0.4.tgz", + "integrity": "sha512-NGLchGruagh8lQpDr98bHLyWJXOBSmkEAfK980OiNBa7vNm6PsNoPvzTfstT78WyOeMRQphEQ455rggd7Eo+Dw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, + "node_modules/@swc/helpers": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.13.tgz", + "integrity": "sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.4.0" } }, "node_modules/@types/ace": { @@ -49,23 +572,30 @@ "version": "4.17.13", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.13.tgz", "integrity": "sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==", - "dev": true, "license": "MIT" }, "node_modules/@types/mysql": { "version": "2.15.21", "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.21.tgz", "integrity": "sha512-NPotx5CVful7yB+qZbWtXL2fA4e7aEHkihHLjklc6ID8aq7bhguHgeIoC1EmSNTAuCgI6ZXrjt2ZSaXnYX0EUg==", - "devOptional": true, "dependencies": { "@types/node": "*" } }, + "node_modules/@types/next": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@types/next/-/next-9.0.0.tgz", + "integrity": "sha512-gnBXM8rP1mnCgT1uE2z8SnpFTKRWReJlhbZLZkOLq/CH1ifvTNwjIVtXvsywTy1dwVklf+y/MB0Eh6FOa94yrg==", + "deprecated": "This is a stub types definition. next provides its own type definitions, so you do not need this installed.", + "license": "MIT", + "dependencies": { + "next": "*" + } + }, "node_modules/@types/node": { "version": "22.7.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", - "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~6.19.2" @@ -87,6 +617,15 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-dom": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.0.tgz", + "integrity": "sha512-1KfiQKsH1o00p9m5ag12axHQSb3FOU9H20UTrujVSkNhuCrRHiQWFqgEnTNK5ZNfnzZv8UWrnXVqCmCF9fgY3w==", + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/sizzle": { "version": "2.3.9", "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.9.tgz", @@ -102,6 +641,38 @@ "@types/jquery": "*" } }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/bignumber.js": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", @@ -110,6 +681,94 @@ "node": "*" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001686", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001686.tgz", + "integrity": "sha512-Y7deg0Aergpa24M3qLC5xjNklnKnhsmSyR/V89dLZ1n0ucJIFNs7PgR2Yfa/Zf6W79SbBicgtGxZr2juHkEUIA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT", + "optional": true + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -121,6 +780,23 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "license": "MIT" }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -130,6 +806,16 @@ "node": ">=0.10.0" } }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", @@ -196,6 +882,15 @@ "url": "https://github.com/motdotla/dotenv?sponsor=1" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -220,12 +915,77 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/gaxios": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", + "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^6.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/generate-password": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/generate-password/-/generate-password-1.7.1.tgz", "integrity": "sha512-9bVYY+16m7W7GczRBDqXE+VVuCX+bWNrfYKC/2p2JkZukFb2sKxT6E3zZ3mJGz7GMe5iRK0A/WawSL3jQfJuNQ==", "license": "MIT" }, + "node_modules/google-auth-library": { + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.0.tgz", + "integrity": "sha512-7ccSEJFDFO7exFbO6NRyC+xH8/mZ1GZGG2xxx9iHxZWcjUjJpjWxIMw3cofAKcueZ6DATiukmmprD7yavQHOyQ==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gtoken": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "license": "MIT", + "dependencies": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/htmlparser2": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", @@ -245,11 +1005,31 @@ "entities": "^4.4.0" } }, + "node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT", + "optional": true + }, "node_modules/is-plain-object": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", @@ -259,17 +1039,65 @@ "node": ">=0.10.0" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, "node_modules/mysql": { "version": "2.18.1", "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", @@ -302,6 +1130,108 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/next": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/next/-/next-15.0.4.tgz", + "integrity": "sha512-nuy8FH6M1FG0lktGotamQDCXhh5hZ19Vo0ht1AOIQWrYJLP598TIUagKtvJrfJ5AGwB/WmDqkKaKhMpVifvGPA==", + "license": "MIT", + "dependencies": { + "@next/env": "15.0.4", + "@swc/counter": "0.1.3", + "@swc/helpers": "0.5.13", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "15.0.4", + "@next/swc-darwin-x64": "15.0.4", + "@next/swc-linux-arm64-gnu": "15.0.4", + "@next/swc-linux-arm64-musl": "15.0.4", + "@next/swc-linux-x64-gnu": "15.0.4", + "@next/swc-linux-x64-musl": "15.0.4", + "@next/swc-win32-arm64-msvc": "15.0.4", + "@next/swc-win32-x64-msvc": "15.0.4", + "sharp": "^0.33.5" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-66855b96-20241106 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-66855b96-20241106 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/nodemailer": { "version": "6.9.14", "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.14.tgz", @@ -356,6 +1286,27 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "node_modules/react": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", + "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", + "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.25.0" + }, + "peerDependencies": { + "react": "^19.0.0" + } + }, "node_modules/readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -389,6 +1340,25 @@ "postcss": "^8.3.11" } }, + "node_modules/scheduler": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", + "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/serverless-mysql": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/serverless-mysql/-/serverless-mysql-1.5.5.tgz", @@ -401,6 +1371,56 @@ "@types/mysql": "^2.15.6" } }, + "node_modules/sharp": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", + "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.5", + "@img/sharp-darwin-x64": "0.33.5", + "@img/sharp-libvips-darwin-arm64": "1.0.4", + "@img/sharp-libvips-darwin-x64": "1.0.4", + "@img/sharp-libvips-linux-arm": "1.0.5", + "@img/sharp-libvips-linux-arm64": "1.0.4", + "@img/sharp-libvips-linux-s390x": "1.0.4", + "@img/sharp-libvips-linux-x64": "1.0.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", + "@img/sharp-libvips-linuxmusl-x64": "1.0.4", + "@img/sharp-linux-arm": "0.33.5", + "@img/sharp-linux-arm64": "0.33.5", + "@img/sharp-linux-s390x": "0.33.5", + "@img/sharp-linux-x64": "0.33.5", + "@img/sharp-linuxmusl-arm64": "0.33.5", + "@img/sharp-linuxmusl-x64": "0.33.5", + "@img/sharp-wasm32": "0.33.5", + "@img/sharp-win32-ia32": "0.33.5", + "@img/sharp-win32-x64": "0.33.5" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -418,6 +1438,14 @@ "node": ">= 0.6" } }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -426,17 +1454,80 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/undici-types": { "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "devOptional": true, "license": "MIT" }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } } } } diff --git a/engine/engine/data/dataTypes.json b/package-shared/data/dataTypes.json old mode 100644 new mode 100755 similarity index 90% rename from engine/engine/data/dataTypes.json rename to package-shared/data/dataTypes.json index daf282a..0b2db7d --- a/engine/engine/data/dataTypes.json +++ b/package-shared/data/dataTypes.json @@ -69,5 +69,11 @@ "value": "0-255", "description": "LONGTEXT is just text with max length 4,294,967,295", "maxValue": 127 + }, + { + "title": "UUID", + "name": "UUID", + "valueLiteral": "UUID()", + "description": "A Unique ID" } ] diff --git a/engine/engine/data/defaultFields.json b/package-shared/data/defaultFields.json old mode 100644 new mode 100755 similarity index 67% rename from engine/engine/data/defaultFields.json rename to package-shared/data/defaultFields.json index aaaa742..4fedc3c --- a/engine/engine/data/defaultFields.json +++ b/package-shared/data/defaultFields.json @@ -6,15 +6,20 @@ "primaryKey": true, "autoIncrement": true }, + { + "fieldName": "uuid", + "dataType": "UUID", + "defaultValueLiteral": "UUID()" + }, { "fieldName": "date_created", "dataType": "VARCHAR(250)", - "notNullValue": true + "nullValue": true }, { "fieldName": "date_created_code", "dataType": "BIGINT", - "notNullValue": true + "nullValue": true }, { "fieldName": "date_created_timestamp", @@ -24,16 +29,17 @@ { "fieldName": "date_updated", "dataType": "VARCHAR(250)", - "notNullValue": true + "nullValue": true }, { "fieldName": "date_updated_code", "dataType": "BIGINT", - "notNullValue": true + "nullValue": true }, { "fieldName": "date_updated_timestamp", "dataType": "TIMESTAMP", - "defaultValueLiteral": "CURRENT_TIMESTAMP" + "defaultValueLiteral": "CURRENT_TIMESTAMP", + "onUpdateLiteral": "CURRENT_TIMESTAMP" } ] diff --git a/engine/engine/data/possibleFields.json b/package-shared/data/possibleFields.json old mode 100644 new mode 100755 similarity index 70% rename from engine/engine/data/possibleFields.json rename to package-shared/data/possibleFields.json index 9ba10d1..02eb7e9 --- a/engine/engine/data/possibleFields.json +++ b/package-shared/data/possibleFields.json @@ -13,5 +13,9 @@ "destinationTableColumnName": "Column Name", "cascadeDelete": true, "cascadeUpdate": true - } + }, + "onUpdate": "CURRENT_TIMESTAMP", + "onUpdateLiteral": "CURRENT_TIMESTAMP", + "onDelete": "CURRENT_TIMESTAMP", + "onDeleteLiteral": "CURRENT_TIMESTAMP" } diff --git a/engine/engine/data/presets/users.json b/package-shared/data/presets/users.json old mode 100644 new mode 100755 similarity index 63% rename from engine/engine/data/presets/users.json rename to package-shared/data/presets/users.json index 843b473..bfed22e --- a/engine/engine/data/presets/users.json +++ b/package-shared/data/presets/users.json @@ -2,13 +2,6 @@ "tableName": "users", "tableFullName": "Users", "fields": [ - { - "fieldName": "id", - "dataType": "BIGINT", - "notNullValue": true, - "primaryKey": true, - "autoIncrement": true - }, { "fieldName": "first_name", "dataType": "VARCHAR(100)", @@ -46,12 +39,12 @@ { "fieldName": "image", "dataType": "VARCHAR(250)", - "defaultValue": "/images/user_images/user-preset.png" + "defaultValue": "/images/user-preset.png" }, { "fieldName": "image_thumbnail", "dataType": "VARCHAR(250)", - "defaultValue": "/images/user_images/user-preset-thumbnail.png" + "defaultValue": "/images/user-preset-thumbnail.png" }, { "fieldName": "address", @@ -99,34 +92,9 @@ "defaultValue": "0" }, { - "fieldName": "date_created", - "dataType": "VARCHAR(250)", - "notNullValue": true - }, - { - "fieldName": "date_created_code", - "dataType": "BIGINT", - "notNullValue": true - }, - { - "fieldName": "date_created_timestamp", - "dataType": "TIMESTAMP", - "defaultValueLiteral": "CURRENT_TIMESTAMP" - }, - { - "fieldName": "date_updated", - "dataType": "VARCHAR(250)", - "notNullValue": true - }, - { - "fieldName": "date_updated_code", - "dataType": "BIGINT", - "notNullValue": true - }, - { - "fieldName": "date_updated_timestamp", - "dataType": "TIMESTAMP", - "defaultValueLiteral": "CURRENT_TIMESTAMP" + "fieldName": "temp_login_code", + "dataType": "VARCHAR(50)", + "nullValue": true } ] } diff --git a/package-shared/functions/api/query/get.js b/package-shared/functions/api/query/get.js new file mode 100644 index 0000000..4227ad7 --- /dev/null +++ b/package-shared/functions/api/query/get.js @@ -0,0 +1,93 @@ +// @ts-check + +const _ = require("lodash"); +const serverError = require("../../backend/serverError"); +const runQuery = require("../../backend/db/runQuery"); + +/** + * # Get Function FOr API + * + * @param {object} params + * @param {string} params.query + * @param {(string|number)[]} [params.queryValues] + * @param {string} params.dbFullName + * @param {string} [params.tableName] + * @param {import("../../../types").DSQL_DatabaseSchemaType} [params.dbSchema] + * + * @returns {Promise} + */ +module.exports = async function apiGet({ + query, + dbFullName, + queryValues, + tableName, + dbSchema, +}) { + if ( + typeof query == "string" && + (query.match(/^alter|^delete|information_schema|databases|^create/i) || + !query.match(/^select/i)) + ) { + return { success: false, msg: "Wrong Input" }; + } + + /** + * Create new user folder and file + * + * @description Create new user folder and file + */ + let results; + + try { + let { result, error } = await runQuery({ + dbFullName: dbFullName, + query: query, + queryValuesArray: queryValues, + readOnly: true, + dbSchema, + tableName, + }); + + /** @type {import("../../../types").DSQL_TableSchemaType | undefined} */ + let tableSchema; + + if (dbSchema) { + const targetTable = dbSchema.tables.find( + (table) => table.tableName === tableName + ); + + if (targetTable) { + const clonedTargetTable = _.cloneDeep(targetTable); + delete clonedTargetTable.childTable; + delete clonedTargetTable.childTableDbFullName; + delete clonedTargetTable.childTableName; + delete clonedTargetTable.childrenTables; + delete clonedTargetTable.updateData; + delete clonedTargetTable.tableNameOld; + delete clonedTargetTable.indexes; + tableSchema = clonedTargetTable; + } + } + + if (error) throw error; + if (result.error) throw new Error(result.error); + + results = result; + + /** @type {import("../../../types").GetReturn} */ + const resObject = { + success: true, + payload: results, + schema: tableName && tableSchema ? tableSchema : undefined, + }; + + return resObject; + } catch (/** @type {any} */ error) { + serverError({ + component: "/api/query/get/lines-85-94", + message: error.message, + }); + + return { success: false, payload: null, error: error.message }; + } +}; diff --git a/package-shared/functions/api/query/post.js b/package-shared/functions/api/query/post.js new file mode 100644 index 0000000..a197f88 --- /dev/null +++ b/package-shared/functions/api/query/post.js @@ -0,0 +1,100 @@ +// @ts-check + +const _ = require("lodash"); +const serverError = require("../../backend/serverError"); +const runQuery = require("../../backend/db/runQuery"); + +/** + * # Post Function For API + * + * @param {object} params + * @param {any} params.query + * @param {(string|number)[]} [params.queryValues] + * @param {string} params.dbFullName + * @param {string} [params.tableName] + * @param {import("../../../types").DSQL_DatabaseSchemaType} [params.dbSchema] + * + * @returns {Promise} + */ +module.exports = async function apiPost({ + query, + dbFullName, + queryValues, + tableName, + dbSchema, +}) { + if (typeof query === "string" && query?.match(/^create |^alter |^drop /i)) { + return { success: false, msg: "Wrong Input" }; + } + + if ( + typeof query === "object" && + query?.action?.match(/^create |^alter |^drop /i) + ) { + return { success: false, msg: "Wrong Input" }; + } + + /** @type {any} */ + let results; + + /** + * Create new user folder and file + * + * @description Create new user folder and file + */ + try { + let { result, error } = await runQuery({ + dbFullName: dbFullName, + query: query, + dbSchema: dbSchema, + queryValuesArray: queryValues, + tableName, + }); + + results = result; + + if (error) throw error; + + /** @type {import("../../../types").DSQL_TableSchemaType | undefined} */ + let tableSchema; + + if (dbSchema) { + const targetTable = dbSchema.tables.find( + (table) => table.tableName === tableName + ); + + if (targetTable) { + const clonedTargetTable = _.cloneDeep(targetTable); + + delete clonedTargetTable.childTable; + delete clonedTargetTable.childTableDbFullName; + delete clonedTargetTable.childTableName; + delete clonedTargetTable.childrenTables; + delete clonedTargetTable.updateData; + delete clonedTargetTable.tableNameOld; + delete clonedTargetTable.indexes; + tableSchema = clonedTargetTable; + } + } + + return { + success: true, + payload: results, + error: error, + schema: tableName && tableSchema ? tableSchema : undefined, + }; + + //////////////////////////////////////// + } catch (/** @type {any} */ error) { + serverError({ + component: "/api/query/post/lines-132-142", + message: error.message, + }); + + return { + success: false, + payload: results, + error: error.message, + }; + } +}; diff --git a/package-shared/functions/api/social-login/facebookLogin.js b/package-shared/functions/api/social-login/facebookLogin.js new file mode 100755 index 0000000..ff48de4 --- /dev/null +++ b/package-shared/functions/api/social-login/facebookLogin.js @@ -0,0 +1,126 @@ +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ + +const DB_HANDLER = require("../../../utils/backend/global-db/DB_HANDLER"); +const handleNodemailer = require("../../backend/handleNodemailer"); +const { hashPassword } = require("../../backend/passwordHash"); +const serverError = require("../../backend/serverError"); + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +/** + * ============================================================================== + * Main Function + * ============================================================================== + * @param {object} params - parameters object + * @param {any} params.body + * @param {import("../../../types").UserType} params.usertype + */ +module.exports = async function facebookLogin({ usertype, body }) { + try { + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + const foundUser = await DB_HANDLER( + `SELECT * FROM users WHERE email='${body.facebookUserEmail}' AND social_login='1'` + ); + + if (foundUser && foundUser[0]) { + return foundUser[0]; + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + let socialHashedPassword = hashPassword(body.facebookUserId); + + let newUser = await DB_HANDLER(`INSERT INTO ${usertype} ( + first_name, + last_name, + social_platform, + social_name, + email, + image, + image_thumbnail, + password, + verification_status, + social_login, + social_id, + terms_agreement, + date_created, + date_code + ) VALUES ( + '${body.facebookUserFirstName}', + '${body.facebookUserLastName}', + 'facebook', + 'facebook_${ + body.facebookUserEmail + ? body.facebookUserEmail.replace(/@.*/, "") + : body.facebookUserFirstName.toLowerCase() + }', + '${body.facebookUserEmail}', + '${body.facebookUserImage}', + '${body.facebookUserImage}', + '${socialHashedPassword}', + '1', + '1', + '${body.facebookUserId}', + '1', + '${Date()}', + '${Date.now()}' + )`); + + const newFoundUser = await DB_HANDLER( + `SELECT * FROM ${usertype} WHERE id='${newUser.insertId}'` + ); + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + /** + * Send email notifications to admin + * + * @description Send verification email to newly created agent + */ + // handleNodemailer({ + // to: "", + // subject: "New Registered Buyer", + // text: "We have a new registered Buyer from facebook", + // html: ` + //

${newFoundUser[0].first_name} ${newFoundUser[0].last_name} just registered from facebook.

+ //

We have a new buyer registration

+ //
Name: ${newFoundUser[0].first_name} ${newFoundUser[0].last_name}
+ //
Email: ${newFoundUser[0].email}
+ //
Site: ${process.env.DSQL_HOST}
+ // `, + // }).catch((error) => { + // console.log( + // "error in mail notification for new Facebook user =>", + // error.message + // ); + // }); + } catch (/** @type {any} */ error) { + serverError({ + component: "functions/backend/facebookLogin", + message: error.message, + }); + } + + return { + isFacebookAuthValid: false, + newFoundUser: null, + }; +}; diff --git a/engine/user/social/utils/githubLogin.js b/package-shared/functions/api/social-login/githubLogin.js old mode 100644 new mode 100755 similarity index 78% rename from engine/user/social/utils/githubLogin.js rename to package-shared/functions/api/social-login/githubLogin.js index c7e6f1b..1bb2329 --- a/engine/user/social/utils/githubLogin.js +++ b/package-shared/functions/api/social-login/githubLogin.js @@ -1,13 +1,7 @@ // @ts-check -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const fs = require("fs"); -const httpsRequest = require("./httpsRequest"); -const dbHandler = require("../../../engine/utils/dbHandler"); +const DB_HANDLER = require("../../../utils/backend/global-db/DB_HANDLER"); +const httpsRequest = require("../../backend/httpsRequest"); ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// @@ -62,11 +56,11 @@ const dbHandler = require("../../../engine/utils/dbHandler"); * @param {string} params.clientId - github client Id * @param {string} params.clientSecret - github client Secret * - * @returns {Promise} + * @returns {Promise} */ -async function githubLogin({ code, clientId, clientSecret }) { - /** @type {GithubUserPayload | null} */ - let gitHubUser = null; +module.exports = async function githubLogin({ code, clientId, clientSecret }) { + /** @type {GithubUserPayload | undefined} */ + let gitHubUser; //////////////////////////////////////////////// //////////////////////////////////////////////// @@ -78,7 +72,7 @@ async function githubLogin({ code, clientId, clientSecret }) { * * @description Create new user folder and file */ - // const response = await fetch(`https://github.com/login/oauth/access_token?client_id=${process.env.GITHUB_ID}`); + // const response = await fetch(`https://github.com/login/oauth/access_token?client_id=${process.env.DSQL_GITHUB_ID}`); const response = await httpsRequest({ method: "POST", hostname: "github.com", @@ -87,12 +81,13 @@ async function githubLogin({ code, clientId, clientSecret }) { Accept: "application/json", "User-Agent": "*", }, + scheme: "https", }); - // `https://github.com/login/oauth/access_token?client_id=${process.env.GITHUB_ID}&client_secret=${process.env.GITHUB_SECRET}&code=${code}`, + // `https://github.com/login/oauth/access_token?client_id=${process.env.DSQL_GITHUB_ID}&client_secret=${process.env.DSQL_GITHUB_SECRET}&code=${code}`, // body: JSON.stringify({ - // client_id: process.env.GITHUB_ID, - // client_secret: process.env.GITHUB_SECRET, + // client_id: process.env.DSQL_GITHUB_ID, + // client_secret: process.env.DSQL_GITHUB_SECRET, // code: code, // }), @@ -114,6 +109,7 @@ async function githubLogin({ code, clientId, clientSecret }) { Authorization: `Bearer ${accessTokenObject.access_token}`, "User-Agent": "*", }, + scheme: "https", }); gitHubUser = JSON.parse(userDataResponse); @@ -122,13 +118,12 @@ async function githubLogin({ code, clientId, clientSecret }) { //////////////////////////////////////////////// //////////////////////////////////////////////// - if (!gitHubUser?.email) { - const existingGithubUser = await dbHandler({ - query: `SELECT email FROM users WHERE social_login='1' AND social_platform='github' AND social_id= ?`, - values: [gitHubUser?.id || ""], - }); + if (!gitHubUser?.email && gitHubUser) { + const existingGithubUser = await DB_HANDLER( + `SELECT email FROM users WHERE social_login='1' AND social_platform='github' AND social_id='${gitHubUser.id}'` + ); - if (existingGithubUser && existingGithubUser[0] && gitHubUser) { + if (existingGithubUser && existingGithubUser[0]) { gitHubUser.email = existingGithubUser[0].email; } } @@ -136,12 +131,15 @@ async function githubLogin({ code, clientId, clientSecret }) { //////////////////////////////////////////////// //////////////////////////////////////////////// //////////////////////////////////////////////// - } catch (/** @type {*} */ error) { + } catch (/** @type {any} */ error) { //////////////////////////////////////////////// //////////////////////////////////////////////// //////////////////////////////////////////////// - console.log("ERROR in githubLogin.js backend function =>", error.message); + console.log( + "ERROR in githubLogin.js backend function =>", + error.message + ); // serverError({ // component: "/api/social-login/github-auth/catch-error", @@ -159,6 +157,4 @@ async function githubLogin({ code, clientId, clientSecret }) { //////////////////////////////////////////////// return gitHubUser; -} - -module.exports = githubLogin; +}; diff --git a/package-shared/functions/api/social-login/googleLogin.js b/package-shared/functions/api/social-login/googleLogin.js new file mode 100755 index 0000000..ceee95b --- /dev/null +++ b/package-shared/functions/api/social-login/googleLogin.js @@ -0,0 +1,178 @@ +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const fs = require("fs"); + +//////////////////////////////////////////////// +//////////////////////////////////////////////// +//////////////////////////////////////////////// + +const { OAuth2Client } = require("google-auth-library"); + +const { hashPassword } = require("../../backend/passwordHash"); +const serverError = require("../../backend/serverError"); +const { ServerResponse } = require("http"); +const DB_HANDLER = require("../../../utils/backend/global-db/DB_HANDLER"); + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +/** + * ============================================================================== + * Main Function + * ============================================================================== + * @param {Object} params + * @param {string} params.usertype + * @param {any} params.foundUser + * @param {boolean} params.isSocialValidated + * @param {boolean} params.isUserValid + * @param {any} params.reqBody + * @param {any} params.serverRes + * @param {any} params.loginFailureReason + */ +module.exports = async function googleLogin({ + usertype, + foundUser, + isSocialValidated, + isUserValid, + reqBody, + serverRes, + loginFailureReason, +}) { + const client = new OAuth2Client( + process.env.NEXT_PUBLIC_DSQL_GOOGLE_CLIENT_ID + ); + let isGoogleAuthValid = false; + let newFoundUser = null; + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + try { + const ticket = await client.verifyIdToken({ + idToken: reqBody.token, + audience: process.env.NEXT_PUBLIC_DSQL_GOOGLE_CLIENT_ID, // Specify the CLIENT_ID of the app that accesses the backend + // Or, if multiple clients access the backend: + //[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3] + }); + + const payload = ticket.getPayload(); + const userid = payload?.["sub"]; + + if (!payload) + throw new Error("Google login failed. Credentials invalid"); + + isUserValid = Boolean(payload.email_verified); + + if (!isUserValid || !payload || !payload.email_verified) return; + + serverRes.isUserValid = payload.email_verified; + isSocialValidated = payload.email_verified; + isGoogleAuthValid = payload.email_verified; + ////// If request specified a G Suite domain: + ////// const domain = payload['hd']; + + let socialHashedPassword = hashPassword(payload.at_hash || ""); + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + let existinEmail = await DB_HANDLER( + `SELECT * FROM ${usertype} WHERE email='${payload.email}' AND social_login!='1' AND social_platform!='google'` + ); + + if (existinEmail && existinEmail[0]) { + loginFailureReason = "Email Exists Already"; + isGoogleAuthValid = false; + return { + isGoogleAuthValid: isGoogleAuthValid, + newFoundUser: newFoundUser, + loginFailureReason: loginFailureReason, + }; + } + + //////////////////////////////////////// + + foundUser = await DB_HANDLER( + `SELECT * FROM ${usertype} WHERE email='${payload.email}' AND social_login='1' AND social_platform='google'` + ); + + if (foundUser && foundUser[0]) { + newFoundUser = foundUser; + return { + isGoogleAuthValid: isGoogleAuthValid, + newFoundUser: newFoundUser, + }; + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + let newUser = await DB_HANDLER(`INSERT INTO ${usertype} ( + first_name, + last_name, + social_platform, + social_name, + social_id, + email, + image, + image_thumbnail, + password, + verification_status, + social_login, + terms_agreement, + date_created, + date_code + ) VALUES ( + '${payload.given_name}', + '${payload.family_name}', + 'google', + 'google_${payload.email?.replace(/@.*/, "")}', + '${payload.sub}', + '${payload.email}', + '${payload.picture}', + '${payload.picture}', + '${socialHashedPassword}', + '1', + '1', + '1', + '${Date()}', + '${Date.now()}' + )`); + + newFoundUser = await DB_HANDLER( + `SELECT * FROM ${usertype} WHERE id='${newUser.insertId}'` + ); + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + } catch (/** @type {any} */ error) { + serverError({ + component: "googleLogin", + message: error.message, + }); + + loginFailureReason = error; + + isUserValid = false; + isSocialValidated = false; + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + return { isGoogleAuthValid: isGoogleAuthValid, newFoundUser: newFoundUser }; +}; diff --git a/engine/user/social/utils/handleSocialDb.js b/package-shared/functions/api/social-login/handleSocialDb.js old mode 100644 new mode 100755 similarity index 70% rename from engine/user/social/utils/handleSocialDb.js rename to package-shared/functions/api/social-login/handleSocialDb.js index baf9de3..f57474e --- a/engine/user/social/utils/handleSocialDb.js +++ b/package-shared/functions/api/social-login/handleSocialDb.js @@ -6,10 +6,20 @@ * ============================================================================== */ const fs = require("fs"); -const http = require("http"); -const varDatabaseDbHandler = require("../../../engine/utils/varDatabaseDbHandler"); -const encrypt = require("../../../../functions/encrypt"); -const addDbEntry = require("../../../../package-shared/functions/backend/db/addDbEntry"); + +//////////////////////////////////////////////// +//////////////////////////////////////////////// +//////////////////////////////////////////////// + +const addAdminUserOnLogin = require("../../backend/addAdminUserOnLogin"); +const handleNodemailer = require("../../backend/handleNodemailer"); +const { ServerResponse } = require("http"); +const path = require("path"); +const addMariadbUser = require("../../backend/addMariadbUser"); +const varDatabaseDbHandler = require("../../backend/varDatabaseDbHandler"); +const encrypt = require("../../dsql/encrypt"); +const addDbEntry = require("../../backend/db/addDbEntry"); +const getAuthCookieNames = require("../../backend/cookies/get-auth-cookie-names"); ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// @@ -26,72 +36,25 @@ const addDbEntry = require("../../../../package-shared/functions/backend/db/addD * first_name: string, * last_name: string, * }|null} user - User payload object: or "null" - * @property {string} [msg] - Message - * @property {string} [error] - Error Message - * @property {string | number} [social_id] - Social Id - * @property {string} [social_platform] - Social Platform - * @property {object} [payload] - Payload - * @property {boolean} [alert] - Alert - * @property {*} [newUser] - New User */ -//////////////////////////////////////////////// -//////////////////////////////////////////////// -//////////////////////////////////////////////// - -const database = process.env.DSQL_DB_NAME || ""; -const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; -const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; - -//////////////////////////////////////////////// -//////////////////////////////////////////////// -//////////////////////////////////////////////// - /** - * Handle Social User Auth on Datasquirel Database - * ============================================================================== - * - * @description This function handles all social login logic after the social user - * has been authenticated and userpayload is present. The payload MUST contain the - * specified fields because this funciton will create a new user if the authenticated - * user does not exist. - * - * @param {{ - * database: string|null|undefined, - * social_id: string|number, - * email: string, - * social_platform: string, - * payload: { - * social_id: string | number, - * email: string, - * social_platform: string, - * first_name: string, - * last_name: string, - * image: string, - * image_thumbnail: string, - * username: string, - * }, - * res: http.ServerResponse, - * supEmail?: string | null, - * additionalFields?: object, - * dbSchema: import("../../../../package-shared/types").DSQL_DatabaseSchemaType | undefined - * }} params - function parameters inside an object - * - * @returns {Promise} - Response object + * @type {import("../../../types").HandleSocialDbFunction} */ -async function handleSocialDb({ +module.exports = async function handleSocialDb({ + database, social_id, email, social_platform, payload, res, + invitation, supEmail, additionalFields, - dbSchema, }) { - const tableSchema = dbSchema?.tables.find( - (tb) => tb?.tableName === "users" - ); + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// try { //////////////////////////////////////////////// @@ -109,6 +72,7 @@ async function handleSocialDb({ user: existingSocialIdUser[0], social_platform, res, + invitation, database, additionalFields, }); @@ -137,9 +101,7 @@ async function handleSocialDb({ let existingEmailOnly = await varDatabaseDbHandler({ database: database ? database : "datasquirel", - queryString: `SELECT * FROM users WHERE email = ?`, - queryValuesArray: [finalEmail], - tableSchema, + queryString: `SELECT * FROM users WHERE email='${finalEmail}'`, }); if (existingEmailOnly && existingEmailOnly[0]) { @@ -165,6 +127,7 @@ async function handleSocialDb({ user: payload, social_platform, res, + invitation, database, additionalFields, }); @@ -176,10 +139,9 @@ async function handleSocialDb({ const socialHashedPassword = encrypt({ data: social_id.toString(), - encryptionKey, - encryptionSalt, }); + /** @type {any} */ const data = { social_login: "1", verification_status: supEmail ? "0" : "1", @@ -187,11 +149,13 @@ async function handleSocialDb({ }; Object.keys(payload).forEach((key) => { - // @ts-ignore data[key] = payload[key]; }); + /** @type {any} */ const newUser = await addDbEntry({ + dbContext: database ? "Dsql User" : undefined, + paradigm: database ? "Full Access" : undefined, dbFullName: database ? database : "datasquirel", tableName: "users", duplicateColumnName: "email", @@ -200,12 +164,16 @@ async function handleSocialDb({ ...data, email: finalEmail, }, - encryptionKey, - encryptionSalt, - tableSchema, }); if (newUser?.insertId) { + if (!database) { + /** + * Add a Mariadb User for this User + */ + await addMariadbUser({ userId: newUser.insertId }); + } + const newUserQueried = await varDatabaseDbHandler({ database: database ? database : "datasquirel", queryString: `SELECT * FROM users WHERE id='${newUser.insertId}'`, @@ -234,9 +202,54 @@ async function handleSocialDb({ email: supEmail, dateCode: Date.now(), }), - encryptionKey, - encryptionSalt, }); + + handleNodemailer({ + to: supEmail, + subject: "Verify Email Address", + text: "Please click the link to verify your email address", + html: fs + .readFileSync( + "./email/send-email-verification-link.html", + "utf8" + ) + .replace(/{{host}}/, process.env.DSQL_HOST || "") + .replace(/{{token}}/, generatedToken || ""), + }).then((mail) => {}); + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + const STATIC_ROOT = process.env.DSQL_STATIC_SERVER_DIR; + + if (!STATIC_ROOT) { + console.log("Static File ENV not Found!"); + return null; + } + + /** + * Create new user folder and file + * + * @description Create new user folder and file + */ + if (!database || database?.match(/^datasquirel$/)) { + let newUserSchemaFolderPath = `${process.env.DSQL_USER_DB_SCHEMA_PATH}/user-${newUser.insertId}`; + + let newUserMediaFolderPath = path.join( + STATIC_ROOT, + `images/user-images/user-${newUser.insertId}` + ); + + fs.mkdirSync(newUserSchemaFolderPath); + fs.mkdirSync(newUserMediaFolderPath); + + fs.writeFileSync( + `${newUserSchemaFolderPath}/main.json`, + JSON.stringify([]), + "utf8" + ); } //////////////////////////////////////////////// @@ -247,6 +260,7 @@ async function handleSocialDb({ user: newUserQueried[0], social_platform, res, + invitation, database, additionalFields, }); @@ -271,7 +285,7 @@ async function handleSocialDb({ //////////////////////////////////////////////// //////////////////////////////////////////////// //////////////////////////////////////////////// - } catch (/** @type {*} */ error) { + } catch (/** @type {any} */ error) { console.log( "ERROR in 'handleSocialDb.js' backend function =>", error.message @@ -282,18 +296,8 @@ async function handleSocialDb({ user: null, error: error.message, }; - - // serverError({ - // component: "/functions/backend/social-login/handleSocialDb.js - main-catch-error", - // message: error.message, - // user: { first_name, last_name }, - // }); } - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// -} +}; ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// @@ -318,20 +322,18 @@ async function handleSocialDb({ * social_id: string|number, * }} params.user - user object * @param {string} params.social_platform - Whether its "google" or "facebook" or "github" - * @param {http.ServerResponse} params.res - Https response object - * @param {string|null} params.database - Target Database + * @param {ServerResponse} [params.res] - Https response object + * @param {any} [params.invitation] - A query object if user was invited + * @param {string} [params.database] - Target Database * @param {object} [params.additionalFields] - Additional fields to be added to the user payload * - * @returns {Promise<{ - * success: boolean, - * user: { id: number, first_name: string, last_name: string } | null - * msg?: string - * }>} + * @returns {Promise} */ async function loginSocialUser({ user, social_platform, res, + invitation, database, additionalFields, }) { @@ -340,19 +342,18 @@ async function loginSocialUser({ queryString: `SELECT * FROM users WHERE email='${user.email}' AND social_id='${user.social_id}' AND social_platform='${social_platform}'`, }); + if (!foundUser?.[0]) + return { + success: false, + user: null, + }; + let csrfKey = Math.random().toString(36).substring(2) + "-" + Math.random().toString(36).substring(2); - if (!foundUser?.[0]) { - return { - success: false, - user: null, - msg: "User Not Found", - }; - } - + /** @type {any} */ let userPayload = { id: foundUser[0].id, type: foundUser[0].type || "", @@ -374,21 +375,18 @@ async function loginSocialUser({ if (additionalFields && Object.keys(additionalFields).length > 0) { Object.keys(additionalFields).forEach((key) => { - // @ts-ignore userPayload[key] = foundUser[0][key]; }); } - let encryptedPayload = encrypt({ - data: JSON.stringify(userPayload), - encryptionKey, - encryptionSalt, - }); + let encryptedPayload = encrypt({ data: JSON.stringify(userPayload) }); + + const { keyCookieName, csrfCookieName } = getAuthCookieNames(); if (res?.setHeader) { res.setHeader("Set-Cookie", [ - `datasquirelAuthKey=${encryptedPayload};samesite=strict;path=/;HttpOnly=true;Secure=true`, - `csrf=${csrfKey};samesite=strict;path=/;HttpOnly=true`, + `${keyCookieName}=${encryptedPayload};samesite=strict;path=/;HttpOnly=true;Secure=true`, + `${csrfCookieName}=${csrfKey};samesite=strict;path=/;HttpOnly=true`, ]); } @@ -396,10 +394,19 @@ async function loginSocialUser({ //////////////////////////////////////////////// //////////////////////////////////////////////// + if (invitation && (!database || database?.match(/^datasquirel$/))) { + addAdminUserOnLogin({ + query: invitation, + user: userPayload, + }); + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + return { success: true, user: userPayload, }; } - -module.exports = handleSocialDb; diff --git a/package-shared/functions/api/users/api-create-user.js b/package-shared/functions/api/users/api-create-user.js new file mode 100644 index 0000000..63a0cdc --- /dev/null +++ b/package-shared/functions/api/users/api-create-user.js @@ -0,0 +1,117 @@ +// @ts-check + +const addUsersTableToDb = require("../../backend/addUsersTableToDb"); +const addDbEntry = require("../../backend/db/addDbEntry"); +const varDatabaseDbHandler = require("../../backend/varDatabaseDbHandler"); +const hashPassword = require("../../dsql/hashPassword"); + +/** @type {import("../../../types").APICreateUserFunction} */ +module.exports = async function apiCreateUser({ + encryptionKey, + payload, + database, + userId, +}) { + const dbFullName = database; + + const hashedPassword = hashPassword({ + encryptionKey: encryptionKey, + password: String(payload.password), + }); + + payload.password = hashedPassword; + + let fields = await varDatabaseDbHandler({ + queryString: `SHOW COLUMNS FROM users`, + database: dbFullName, + }); + + if (!fields) { + const newTable = await addUsersTableToDb({ + userId: Number(userId), + database: database, + }); + + fields = await varDatabaseDbHandler({ + queryString: `SHOW COLUMNS FROM users`, + database: dbFullName, + }); + } + + if (!fields) { + return { + success: false, + msg: "Could not create users table", + }; + } + + const fieldsTitles = fields.map( + (/** @type {any} */ fieldObject) => fieldObject.Field + ); + + let invalidField = null; + + for (let i = 0; i < Object.keys(payload).length; i++) { + const key = Object.keys(payload)[i]; + if (!fieldsTitles.includes(key)) { + invalidField = key; + break; + } + } + + if (invalidField) { + return { + success: false, + msg: `${invalidField} is not a valid field!`, + }; + } + + const existingUser = await varDatabaseDbHandler({ + queryString: `SELECT * FROM users WHERE email = ?${ + payload.username ? " OR username = ?" : "" + }`, + queryValuesArray: payload.username + ? [payload.email, payload.username] + : [payload.email], + database: dbFullName, + }); + + if (existingUser?.[0]) { + return { + success: false, + msg: "User Already Exists", + payload: null, + }; + } + + const addUser = await addDbEntry({ + dbContext: "Dsql User", + paradigm: "Full Access", + dbFullName: dbFullName, + tableName: "users", + data: { + ...payload, + image: "/images/user-preset.png", + image_thumbnail: "/images/user-preset-thumbnail.png", + }, + }); + + if (addUser?.insertId) { + const newlyAddedUser = await varDatabaseDbHandler({ + queryString: `SELECT id,first_name,last_name,email,username,phone,image,image_thumbnail,city,state,country,zip_code,address,verification_status,more_user_data FROM users WHERE id='${addUser.insertId}'`, + database: dbFullName, + }); + + return { + success: true, + payload: newlyAddedUser[0], + }; + } else { + return { + success: false, + msg: "Could not create user", + sqlResult: addUser, + payload: null, + }; + } +}; diff --git a/package-shared/functions/api/users/api-get-user.js b/package-shared/functions/api/users/api-get-user.js new file mode 100644 index 0000000..daf7d7f --- /dev/null +++ b/package-shared/functions/api/users/api-get-user.js @@ -0,0 +1,26 @@ +// @ts-check + +const varDatabaseDbHandler = require("../../backend/varDatabaseDbHandler"); + +/** @type {import("../../../types").APIGetUserFunction} */ +module.exports = async function apiGetUser({ fields, dbFullName, userId }) { + const query = `SELECT ${fields.join(",")} FROM users WHERE id=?`; + + let foundUser = await varDatabaseDbHandler({ + queryString: query, + queryValuesArray: [userId], + database: dbFullName.replace(/[^a-z0-9_]/g, ""), + }); + + if (!foundUser || !foundUser[0]) { + return { + success: false, + payload: null, + }; + } + + return { + success: true, + payload: foundUser[0], + }; +}; diff --git a/package-shared/functions/api/users/api-login.js b/package-shared/functions/api/users/api-login.js new file mode 100644 index 0000000..c45a000 --- /dev/null +++ b/package-shared/functions/api/users/api-login.js @@ -0,0 +1,159 @@ +// @ts-check + +const varDatabaseDbHandler = require("../../backend/varDatabaseDbHandler"); +const hashPassword = require("../../dsql/hashPassword"); + +/** @type {import("../../../types").APILoginFunction} */ +module.exports = async function apiLoginUser({ + encryptionKey, + email, + username, + password, + database, + additionalFields, + email_login, + email_login_code, + email_login_field, + token, + skipPassword, + social, +}) { + const dbFullName = database; + + /** + * Check input validity + * + * @description Check input validity + */ + if ( + email?.match(/ /) || + (username && username?.match(/ /)) || + (password && password?.match(/ /)) + ) { + return { + success: false, + msg: "Invalid Email/Password format", + }; + } + + /** + * Password hash + * + * @description Password hash + */ + let hashedPassword = password + ? hashPassword({ + encryptionKey: encryptionKey, + password: password, + }) + : null; + + let isSocialValidated = false; + let loginFailureReason = null; + + let foundUser = await varDatabaseDbHandler({ + queryString: `SELECT * FROM users WHERE email = ? OR username = ?`, + queryValuesArray: [email, username], + database: dbFullName.replace(/[^a-z0-9_]/g, ""), + }); + + if ((!foundUser || !foundUser[0]) && !social) + return { + success: false, + payload: null, + msg: "No user found", + }; + + let isPasswordCorrect = false; + + if (foundUser?.[0] && !email_login && skipPassword) { + isPasswordCorrect = true; + } else if (foundUser?.[0] && !email_login) { + isPasswordCorrect = hashedPassword === foundUser[0].password; + } else if ( + foundUser && + foundUser[0] && + email_login && + email_login_code && + email_login_field + ) { + /** @type {string} */ + const tempCode = foundUser[0][email_login_field]; + + if (!tempCode) throw new Error("No code Found!"); + + const tempCodeArray = tempCode.split("-"); + const [code, codeDate] = tempCodeArray; + const millisecond15mins = 1000 * 60 * 15; + + if (Date.now() - Number(codeDate) > millisecond15mins) { + throw new Error("Code Expired"); + } + isPasswordCorrect = code === email_login_code; + } + + let socialUserValid = false; + + if (!isPasswordCorrect && !socialUserValid) { + return { + success: false, + msg: "Wrong password, no social login validity", + payload: null, + }; + } + + if (isPasswordCorrect && email_login) { + const resetTempCode = await varDatabaseDbHandler({ + queryString: `UPDATE users SET ${email_login_field} = ? WHERE email = ? OR username = ?`, + queryValuesArray: ["", email, username], + database: dbFullName.replace(/[^a-z0-9_]/g, ""), + }); + } + + let csrfKey = + Math.random().toString(36).substring(2) + + "-" + + Math.random().toString(36).substring(2); + + /** @type {import("../../../types").DATASQUIREL_LoggedInUser} */ + let userPayload = { + id: foundUser[0].id, + first_name: foundUser[0].first_name, + last_name: foundUser[0].last_name, + username: foundUser[0].username, + email: foundUser[0].email, + phone: foundUser[0].phone, + social_id: foundUser[0].social_id, + image: foundUser[0].image, + image_thumbnail: foundUser[0].image_thumbnail, + verification_status: foundUser[0].verification_status, + social_login: foundUser[0].social_login, + social_platform: foundUser[0].social_platform, + csrf_k: csrfKey, + more_data: foundUser[0].more_user_data, + logged_in_status: true, + date: Date.now(), + }; + + const resposeObject = { + success: true, + msg: "Login Successful", + payload: + /** @type {import("../../../types").DATASQUIREL_LoggedInUser} */ ( + userPayload + ), + userId: foundUser[0].id, + }; + + if ( + additionalFields && + Array.isArray(additionalFields) && + additionalFields.length > 0 + ) { + additionalFields.forEach((key) => { + userPayload[key] = foundUser[0][key]; + }); + } + + return resposeObject; +}; diff --git a/package-shared/functions/api/users/api-reauth-user.js b/package-shared/functions/api/users/api-reauth-user.js new file mode 100644 index 0000000..e3be35e --- /dev/null +++ b/package-shared/functions/api/users/api-reauth-user.js @@ -0,0 +1,92 @@ +// @ts-check + +const varDatabaseDbHandler = require("../../backend/varDatabaseDbHandler"); +const nodemailer = require("nodemailer"); + +/** + * # Re-authenticate API user + * @param {object} param + * @param {Object} param.existingUser + * @param {string} param.database + * @param {string | number} [param.userId] + * @param {string[]} [param.additionalFields] + * + * @returns {Promise} + */ +module.exports = async function apiReauthUser({ + existingUser, + database, + userId, + additionalFields, +}) { + let foundUser = + existingUser?.id && existingUser.id.toString().match(/./) + ? await varDatabaseDbHandler({ + queryString: `SELECT * FROM users WHERE id=?`, + queryValuesArray: [existingUser.id.toString()], + database, + }) + : null; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + if (!foundUser || !foundUser[0]) + return { + success: false, + payload: null, + msg: "No user found", + }; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + let csrfKey = + Math.random().toString(36).substring(2) + + "-" + + Math.random().toString(36).substring(2); + + /** @type {Object} */ + let userPayload = { + id: foundUser[0].id, + first_name: foundUser[0].first_name, + last_name: foundUser[0].last_name, + username: foundUser[0].username, + email: foundUser[0].email, + phone: foundUser[0].phone, + social_id: foundUser[0].social_id, + image: foundUser[0].image, + image_thumbnail: foundUser[0].image_thumbnail, + verification_status: foundUser[0].verification_status, + social_login: foundUser[0].social_login, + social_platform: foundUser[0].social_platform, + csrf_k: csrfKey, + more_data: foundUser[0].more_user_data, + logged_in_status: true, + date: Date.now(), + }; + + if ( + additionalFields && + Array.isArray(additionalFields) && + additionalFields.length > 0 + ) { + additionalFields.forEach((key) => { + userPayload[key] = foundUser[0][key]; + }); + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** ********************* Send Response */ + return { + success: true, + msg: "Login Successful", + payload: userPayload, + userId, + }; +}; diff --git a/package-shared/functions/api/users/api-send-email-code.js b/package-shared/functions/api/users/api-send-email-code.js new file mode 100644 index 0000000..3e93870 --- /dev/null +++ b/package-shared/functions/api/users/api-send-email-code.js @@ -0,0 +1,116 @@ +// @ts-check + +const varDatabaseDbHandler = require("../../backend/varDatabaseDbHandler"); +const nodemailer = require("nodemailer"); + +/** + * # 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 + * + * @returns {Promise<{success: boolean, msg?: string}>} + */ +module.exports = async function apiSendEmailCode({ + email, + database, + email_login_field, + mail_domain, + mail_port, + sender, + mail_username, + mail_password, + html, +}) { + if (email?.match(/ /)) { + return { + success: false, + msg: "Invalid Email/Password format", + }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + let foundUser = await varDatabaseDbHandler({ + queryString: `SELECT * FROM users WHERE email = ?`, + queryValuesArray: [email], + database, + }); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + 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 && foundUser[0] && email_login_field) { + const tempCode = generateCode(); + + let transporter = nodemailer.createTransport({ + host: mail_domain || process.env.DSQL_MAIL_HOST, + port: 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!"); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + let setTempCode = await varDatabaseDbHandler({ + queryString: `UPDATE users SET ${email_login_field} = ? WHERE email = ?`, + queryValuesArray: [tempCode + `-${Date.now()}`, email], + database: database, + }); + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + return { + success: true, + msg: "Success", + }; +}; diff --git a/package-shared/functions/api/users/api-update-user.js b/package-shared/functions/api/users/api-update-user.js new file mode 100644 index 0000000..9a52d63 --- /dev/null +++ b/package-shared/functions/api/users/api-update-user.js @@ -0,0 +1,43 @@ +// @ts-check + +const updateDbEntry = require("../../backend/db/updateDbEntry"); + +/** + * # Update API User Function + * + * @param {object} params + * @param {{ id: string | number } & Object} params.payload + * @param {string} params.dbFullName + * + * @returns {Promise<{ success: boolean, payload: any }>} + */ +module.exports = async function apiUpdateUser({ payload, dbFullName }) { + const data = (() => { + const reqBodyKeys = Object.keys(payload); + + /** @type {any} */ + const finalData = {}; + + reqBodyKeys.forEach((key) => { + if (key?.match(/^date_|^id$/)) return; + finalData[key] = payload[key]; + }); + + return finalData; + })(); + + const updateUser = await updateDbEntry({ + dbContext: "Dsql User", + paradigm: "Full Access", + dbFullName, + tableName: "users", + identifierColumnName: "id", + identifierValue: payload.id, + data: data, + }); + + return { + success: true, + payload: updateUser, + }; +}; diff --git a/package-shared/functions/api/users/social/api-github-login.js b/package-shared/functions/api/users/social/api-github-login.js new file mode 100644 index 0000000..1efb5a7 --- /dev/null +++ b/package-shared/functions/api/users/social/api-github-login.js @@ -0,0 +1,110 @@ +// @ts-check + +const handleSocialDb = require("../../social-login/handleSocialDb"); +const githubLogin = require("../../social-login/githubLogin"); +const camelJoinedtoCamelSpace = require("../../../../utils/camelJoinedtoCamelSpace"); + +/** + * # Login with Github + * @param {object} param + * @param {string} [param.code] + * @param {string} [param.clientId] + * @param {string} [param.clientSecret] + * @param {string} [param.database] + * @param {Object} [param.additionalFields] + * @param {any} [param.res] + * @param {string} [param.email] + * @param {string | number} [param.userId] + * + * @returns {Promise} + */ +module.exports = async function apiGithubLogin({ + code, + clientId, + clientSecret, + database, + additionalFields, + res, + email, + userId, +}) { + if (!code || !clientId || !clientSecret || !database) { + return { + success: false, + msg: "Missing query params", + }; + } + + if ( + typeof code !== "string" || + typeof clientId !== "string" || + typeof clientSecret !== "string" || + typeof database !== "string" + ) { + return { + success: false, + msg: "Wrong Parameters", + }; + } + + /** + * Create new user folder and file + * + * @description Create new user folder and file + */ + const gitHubUser = await githubLogin({ + code: code, + clientId: clientId, + clientSecret: clientSecret, + }); + + if (!gitHubUser) { + return { + success: false, + msg: "No github user returned", + }; + } + + const socialId = gitHubUser.name || gitHubUser.id || gitHubUser.login; + const targetName = gitHubUser.name || gitHubUser.login; + const nameArray = targetName?.match(/ /) + ? targetName?.split(" ") + : targetName?.match(/\-/) + ? targetName?.split("-") + : [targetName]; + + const payload = { + email: gitHubUser.email, + first_name: camelJoinedtoCamelSpace(nameArray[0]), + last_name: camelJoinedtoCamelSpace(nameArray[1]), + social_id: socialId, + social_platform: "github", + image: gitHubUser.avatar_url, + image_thumbnail: gitHubUser.avatar_url, + username: "github-user-" + socialId, + }; + + if (additionalFields && Object.keys(additionalFields).length > 0) { + Object.keys(additionalFields).forEach((key) => { + // @ts-ignore + payload[key] = additionalFields[key]; + }); + } + + const loggedInGithubUser = await handleSocialDb({ + database, + email: gitHubUser.email, + payload: payload, + social_platform: "github", + res: res, + social_id: socialId, + supEmail: email, + additionalFields, + }); + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + return { success: true, ...loggedInGithubUser, dsqlUserId: userId }; +}; diff --git a/package-shared/functions/api/users/social/api-google-login.js b/package-shared/functions/api/users/social/api-google-login.js new file mode 100644 index 0000000..61ec7dd --- /dev/null +++ b/package-shared/functions/api/users/social/api-google-login.js @@ -0,0 +1,88 @@ +// @ts-check + +const { OAuth2Client } = require("google-auth-library"); +const handleSocialDb = require("../../social-login/handleSocialDb"); + +/** @type {import("../../../../types").APIGoogleLoginFunction} */ +module.exports = async function apiGoogleLogin({ + clientId, + token, + database, + userId, + additionalFields, + res, +}) { + const client = new OAuth2Client(clientId); + + const ticket = await client.verifyIdToken({ + idToken: token, + audience: clientId, + }); + + if (!ticket?.getPayload()?.email_verified) { + return { + success: false, + user: null, + }; + } + + const payload = ticket.getPayload(); + + if (!payload) throw new Error("No Payload"); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + if (!database || typeof database != "string" || database?.match(/ /)) { + return { + success: false, + user: undefined, + msg: "Please provide a database slug(database name in lowercase with no spaces)", + }; + } + + /** + * Create new user folder and file + * + * @description Create new user folder and file + */ + const targetDbName = `datasquirel_user_${userId}_${database}`; + + const { given_name, family_name, email, sub, picture, email_verified } = + payload; + + /** @type {Object} */ + const payloadObject = { + email: email, + first_name: given_name, + last_name: family_name, + social_id: sub, + social_platform: "google", + image: picture, + image_thumbnail: picture, + username: `google-user-${sub}`, + }; + + if (additionalFields && Object.keys(additionalFields).length > 0) { + Object.keys(additionalFields).forEach((key) => { + payloadObject[key] = additionalFields[key]; + }); + } + + const loggedInGoogleUser = await handleSocialDb({ + res, + database: targetDbName, + email: email || "", + payload: payloadObject, + social_platform: "google", + social_id: sub, + additionalFields, + }); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + return { success: true, ...loggedInGoogleUser, dsqlUserId: userId }; +}; diff --git a/package-shared/functions/backend/addAdminUserOnLogin.js b/package-shared/functions/backend/addAdminUserOnLogin.js new file mode 100755 index 0000000..fce9069 --- /dev/null +++ b/package-shared/functions/backend/addAdminUserOnLogin.js @@ -0,0 +1,191 @@ +// @ts-check + +const serverError = require("./serverError"); +const DB_HANDLER = require("../../utils/backend/global-db/DB_HANDLER"); +const addDbEntry = require("./db/addDbEntry"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Add Admin User on Login + * ============================================================================== + * + * @description this function handles admin users that have been invited by another + * admin user. This fires when the invited user has been logged in or a new account + * has been created for the invited user + * + * @param {object} params - parameters object + * + * @param {object} params.query - query object + * @param {number} params.query.invite - Invitation user id + * @param {string} params.query.database_access - String containing authorized databases + * @param {string} params.query.priviledge - String containing databases priviledges + * @param {string} params.query.email - Inviting user email address + * + * @param {import("../../types").UserType} params.user - invited user object + * + * @returns {Promise} new user auth object payload + */ +module.exports = async function addAdminUserOnLogin({ query, user }) { + try { + /** + * Fetch user + * + * @description Fetch user from db + */ // @ts-ignore + const { invite, database_access, priviledge, email } = query; + + const lastInviteTimeArray = await DB_HANDLER( + `SELECT date_created_code FROM invitations WHERE inviting_user_id=? AND invited_user_email=?`, + [invite, email] + ); + + // if (lastInviteTimeArray && lastInviteTimeArray[0]?.date_created_code) { + // const timeSinceLastInvite = Date.now() - parseInt(lastInviteTimeArray[0].date_created_code); + // if (timeSinceLastInvite > 21600000) { + // throw new Error("Invitation expired"); + // } + // } else if (!lastInviteTimeArray || !lastInviteTimeArray[0]) { + // throw new Error("No Invitation Found"); + // } + + if (!lastInviteTimeArray || !lastInviteTimeArray[0]) { + throw new Error("No Invitation Found"); + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + // @ts-ignore + const invitingUserDb = await DB_HANDLER( + `SELECT first_name,last_name,email FROM users WHERE id=?`, + [invite] + ); + + if (invitingUserDb?.[0]) { + const existingUserUser = await DB_HANDLER( + `SELECT email FROM user_users WHERE user_id=? AND invited_user_id=? AND user_type='admin' AND email=?`, + [invite, user.id, email] + ); + + if (existingUserUser?.[0]) { + console.log("User already added"); + } else { + // const newUserUser = await DB_HANDLER( + // `INSERT IGNORE INTO user_users + // (user_id, invited_user_id, database_access, first_name, last_name, phone, email, username, user_type, user_priviledge) + // VALUES + // (?,?,?,?,?,?,?,?,?,?) + // )`, + // [ + // invite, + // user.id, + // database_access, + // user.first_name, + // user.last_name, + // user.phone, + // user.email, + // user.username, + // "admin", + // priviledge, + // ] + // ); + addDbEntry({ + dbFullName: "datasquirel", + tableName: "user_users", + data: { + user_id: invite, + invited_user_id: user.id, + database_access: database_access, + first_name: user.first_name, + last_name: user.last_name, + phone: user.phone, + email: user.email, + username: user.username, + user_type: "admin", + user_priviledge: priviledge, + image: user.image, + image_thumbnail: user.image_thumbnail, + }, + }); + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + // @ts-ignore + const dbTableData = await DB_HANDLER( + `SELECT db_tables_data FROM invitations WHERE inviting_user_id=? AND invited_user_email=?`, + [invite, email] + ); + + // @ts-ignore + const clearEntries = await DB_HANDLER( + `DELETE FROM delegated_user_tables WHERE root_user_id=? AND delegated_user_id=?`, + [invite, user.id] + ); + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + if (dbTableData && dbTableData[0]) { + const dbTableEntries = + dbTableData[0].db_tables_data.split("|"); + + for (let i = 0; i < dbTableEntries.length; i++) { + const dbTableEntry = dbTableEntries[i]; + const dbTableEntryArray = dbTableEntry.split("-"); + const [db_slug, table_slug] = dbTableEntryArray; + + const newEntry = await addDbEntry({ + dbFullName: "datasquirel", + tableName: "delegated_user_tables", + data: { + delegated_user_id: user.id, + root_user_id: invite, + database: db_slug, + table: table_slug, + priviledge: priviledge, + }, + }); + } + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + } + + // @ts-ignore + const inviteAccepted = await DB_HANDLER( + `UPDATE invitations SET invitation_status='Accepted' WHERE inviting_user_id=? AND invited_user_email=?`, + [invite, email] + ); + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + } catch (/** @type {any} */ error) { + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + serverError({ + component: "addAdminUserOnLogin", + message: error.message, + user: user, + }); + } +}; + +//////////////////////////////////////////////// +//////////////////////////////////////////////// +//////////////////////////////////////////////// diff --git a/package-shared/functions/backend/addMariadbUser.js b/package-shared/functions/backend/addMariadbUser.js index 8343def..0b1de05 100644 --- a/package-shared/functions/backend/addMariadbUser.js +++ b/package-shared/functions/backend/addMariadbUser.js @@ -3,8 +3,8 @@ const generator = require("generate-password"); const DB_HANDLER = require("../../utils/backend/global-db/DB_HANDLER"); const NO_DB_HANDLER = require("../../utils/backend/global-db/NO_DB_HANDLER"); -const encrypt = require("./encrypt"); const addDbEntry = require("./db/addDbEntry"); +const encrypt = require("../dsql/encrypt"); /** * # Add Mariadb User @@ -28,7 +28,7 @@ module.exports = async function addMariadbUser({ userId }) { uppercase: true, exclude: "*#.'`\"", }); - const encryptedPassword = encrypt(password); + const encryptedPassword = encrypt({ data: password }); await NO_DB_HANDLER( `CREATE USER IF NOT EXISTS '${username}'@'127.0.0.1' IDENTIFIED BY '${password}' REQUIRE SSL` diff --git a/package-shared/functions/backend/addUsersTableToDb.js b/package-shared/functions/backend/addUsersTableToDb.js new file mode 100755 index 0000000..a34cbf4 --- /dev/null +++ b/package-shared/functions/backend/addUsersTableToDb.js @@ -0,0 +1,95 @@ +// @ts-check + +const fs = require("fs"); +const path = require("path"); +const { execSync } = require("child_process"); +const serverError = require("./serverError"); +const DB_HANDLER = require("../../utils/backend/global-db/DB_HANDLER"); +const { default: grabUserSchemaData } = require("./grabUserSchemaData"); +const { default: setUserSchemaData } = require("./setUserSchemaData"); +const addDbEntry = require("./db/addDbEntry"); +const createDbFromSchema = require("../../shell/createDbFromSchema"); + +/** + * # Add User Table to Database + * + * @param {object} params + * @param {number} params.userId - user id + * @param {string} params.database + * + * @returns {Promise} new user auth object payload + */ +module.exports = async function addUsersTableToDb({ userId, database }) { + /** + * Initialize + * + * @description Initialize + */ + const dbFullName = `datasquirel_user_${userId}_${database}`; + /** @type {import("../../types").DSQL_TableSchemaType} */ + const userPreset = require("../../data/presets/users.json"); + + try { + /** + * Fetch user + * + * @description Fetch user from db + */ + const userSchemaData = grabUserSchemaData({ userId }); + if (!userSchemaData) throw new Error("User schema data not found!"); + + let targetDatabase = userSchemaData.filter( + (db) => db.dbSlug === database + )[0]; + + let existingTableIndex; + // @ts-ignore + let existingTable = targetDatabase.tables.filter((table, index) => { + if (table.tableName === "users") { + existingTableIndex = index; + return true; + } + }); + + if (existingTable && existingTable[0] && existingTableIndex) { + targetDatabase.tables[existingTableIndex] = userPreset; + } else { + targetDatabase.tables.push(userPreset); + } + + setUserSchemaData({ schemaData: userSchemaData, userId }); + + const targetDb = await DB_HANDLER( + `SELECT id FROM user_databases WHERE user_id=? AND db_slug=?`, + [userId, database] + ); + + if (targetDb && targetDb[0]) { + const newTableEntry = await addDbEntry({ + dbFullName: "datasquirel", + tableName: "user_database_tables", + data: { + user_id: userId, + db_id: targetDb[0].id, + db_slug: database, + table_name: "Users", + table_slug: "users", + }, + }); + } + + const dbShellUpdate = await createDbFromSchema({ + userId, + targetDatabase: dbFullName, + }); + + return `Done!`; + } catch (/** @type {any} */ error) { + serverError({ + component: "addUsersTableToDb", + message: error.message, + user: { id: userId }, + }); + return error.message; + } +}; diff --git a/package-shared/functions/backend/api-cred.js b/package-shared/functions/backend/api-cred.js index ebfa7bb..892968a 100644 --- a/package-shared/functions/backend/api-cred.js +++ b/package-shared/functions/backend/api-cred.js @@ -1,7 +1,7 @@ // @ts-check const fs = require("fs"); -const decrypt = require("./decrypt"); +const decrypt = require("../dsql/decrypt"); /** @type {import("../../types").CheckApiCredentialsFn} */ const grabApiCred = ({ key, database, table, user_id }) => { @@ -16,7 +16,7 @@ const grabApiCred = ({ key, database, table, user_id }) => { "process.env.DSQL_API_KEYS_PATH variable not found" ); - const ApiJSON = decrypt(key); + const ApiJSON = decrypt({ encryptedString: key }); /** @type {import("../../types").ApiKeyObject} */ const ApiObject = JSON.parse(ApiJSON || ""); const isApiKeyValid = fs.existsSync( diff --git a/package-shared/functions/backend/cookies/get-auth-cookie-names.js b/package-shared/functions/backend/cookies/get-auth-cookie-names.js new file mode 100644 index 0000000..374dd26 --- /dev/null +++ b/package-shared/functions/backend/cookies/get-auth-cookie-names.js @@ -0,0 +1,13 @@ +module.exports = function getAuthCookieNames() { + const cookiesPrefix = process.env.DSQL_COOKIES_PREFIX || "dsql_"; + const cookiesKeyName = process.env.DSQL_COOKIES_KEY_NAME || "key"; + const cookiesCSRFName = process.env.DSQL_COOKIES_CSRF_NAME || "csrf"; + + const keyCookieName = cookiesPrefix + cookiesKeyName; + const csrfCookieName = cookiesPrefix + cookiesCSRFName; + + return { + keyCookieName, + csrfCookieName, + }; +}; diff --git a/package-shared/functions/backend/db/addDbEntry.js b/package-shared/functions/backend/db/addDbEntry.js index 1c57dee..7434a74 100644 --- a/package-shared/functions/backend/db/addDbEntry.js +++ b/package-shared/functions/backend/db/addDbEntry.js @@ -1,9 +1,5 @@ // @ts-check -/** - * Imports: Handle imports - */ -const encrypt = require("../encrypt"); const sanitizeHtml = require("sanitize-html"); const sanitizeHtmlOptions = require("../html/sanitizeHtmlOptions"); const updateDb = require("./updateDbEntry"); @@ -11,6 +7,7 @@ const updateDbEntry = require("./updateDbEntry"); const _ = require("lodash"); const DB_HANDLER = require("../../../utils/backend/global-db/DB_HANDLER"); const DSQL_USER_DB_HANDLER = require("../../../utils/backend/global-db/DSQL_USER_DB_HANDLER"); +const encrypt = require("../../dsql/encrypt"); /** * Add a db Entry Function @@ -146,7 +143,11 @@ async function addDbEntry({ continue; if (targetFieldSchema?.encrypted) { - value = encrypt(value, encryptionKey, encryptionSalt); + value = encrypt({ + data: value, + encryptionKey, + encryptionSalt, + }); console.log("DSQL: Encrypted value =>", value); } diff --git a/package-shared/functions/backend/db/runQuery.d.ts b/package-shared/functions/backend/db/runQuery.d.ts deleted file mode 100644 index b797a3d..0000000 --- a/package-shared/functions/backend/db/runQuery.d.ts +++ /dev/null @@ -1,30 +0,0 @@ -export = runQuery; -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** - * Run DSQL users queries - * ============================================================================== - * @param {object} params - An object containing the function parameters. - * @param {string} params.dbFullName - Database full name. Eg. "datasquire_user_2_test" - * @param {string | any} params.query - Query string or object - * @param {boolean} [params.readOnly] - Is this operation read only? - * @param {boolean} [params.local] - Is this operation read only? - * @param {import("../../../types").DSQL_DatabaseSchemaType} [params.dbSchema] - Database schema - * @param {string[]} [params.queryValuesArray] - An optional array of query values if "?" is used in the query string - * @param {string} [params.tableName] - Table Name - * - * @return {Promise} - */ -declare function runQuery({ dbFullName, query, readOnly, dbSchema, queryValuesArray, tableName, local, }: { - dbFullName: string; - query: string | any; - readOnly?: boolean; - local?: boolean; - dbSchema?: import("../../../types").DSQL_DatabaseSchemaType; - queryValuesArray?: string[]; - tableName?: string; -}): Promise; diff --git a/package-shared/functions/backend/db/runQuery.js b/package-shared/functions/backend/db/runQuery.js index e9194f9..1e5b767 100644 --- a/package-shared/functions/backend/db/runQuery.js +++ b/package-shared/functions/backend/db/runQuery.js @@ -38,7 +38,7 @@ const trimSql = require("../../../utils/trim-sql"); * @param {boolean} [params.readOnly] - Is this operation read only? * @param {boolean} [params.local] - Is this operation read only? * @param {import("../../../types").DSQL_DatabaseSchemaType} [params.dbSchema] - Database schema - * @param {string[]} [params.queryValuesArray] - An optional array of query values if "?" is used in the query string + * @param {(string | number)[]} [params.queryValuesArray] - An optional array of query values if "?" is used in the query string * @param {string} [params.tableName] - Table Name * * @return {Promise} @@ -120,14 +120,14 @@ async function runQuery({ } else if (readOnly) { result = await varReadOnlyDatabaseDbHandler({ queryString: formattedQuery, - queryValuesArray, + queryValuesArray: queryValuesArray?.map((vl) => String(vl)), database: dbFullName, tableSchema, }); } else { result = await fullAccessDbHandler({ queryString: formattedQuery, - queryValuesArray, + queryValuesArray: queryValuesArray?.map((vl) => String(vl)), database: dbFullName, tableSchema, }); diff --git a/package-shared/functions/backend/db/updateDbEntry.js b/package-shared/functions/backend/db/updateDbEntry.js index 93e103b..d85e323 100644 --- a/package-shared/functions/backend/db/updateDbEntry.js +++ b/package-shared/functions/backend/db/updateDbEntry.js @@ -3,11 +3,11 @@ /** * Imports: Handle imports */ -const encrypt = require("../encrypt"); const sanitizeHtml = require("sanitize-html"); const sanitizeHtmlOptions = require("../html/sanitizeHtmlOptions"); const DB_HANDLER = require("../../../utils/backend/global-db/DB_HANDLER"); const DSQL_USER_DB_HANDLER = require("../../../utils/backend/global-db/DSQL_USER_DB_HANDLER"); +const encrypt = require("../../dsql/encrypt"); /** * Update DB Function @@ -94,7 +94,11 @@ async function updateDbEntry({ } if (targetFieldSchema?.encrypted) { - value = encrypt(value, encryptionKey, encryptionSalt); + value = encrypt({ + data: value, + encryptionKey, + encryptionSalt, + }); } if (typeof value === "object") { diff --git a/package-shared/functions/backend/decrypt.d.ts b/package-shared/functions/backend/decrypt.d.ts deleted file mode 100644 index 35a1bb6..0000000 --- a/package-shared/functions/backend/decrypt.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -export = decrypt; -/** - * @param {string} encryptedString - * @returns {string | null} - */ -declare function decrypt(encryptedString: string): string | null; diff --git a/package-shared/functions/backend/decrypt.js b/package-shared/functions/backend/decrypt.js deleted file mode 100644 index b4b12d1..0000000 --- a/package-shared/functions/backend/decrypt.js +++ /dev/null @@ -1,29 +0,0 @@ -// @ts-check - -const { scryptSync, createDecipheriv } = require("crypto"); -const { Buffer } = require("buffer"); - -/** - * @param {string} encryptedString - * @returns {string | null} - */ -const decrypt = (encryptedString) => { - const algorithm = "aes-192-cbc"; - const password = process.env.DSQL_ENCRYPTION_PASSWORD || ""; - const salt = process.env.DSQL_ENCRYPTION_SALT || ""; - - let key = scryptSync(password, salt, 24); - let iv = Buffer.alloc(16, 0); - // @ts-ignore - const decipher = createDecipheriv(algorithm, key, iv); - - try { - let decrypted = decipher.update(encryptedString, "hex", "utf8"); - decrypted += decipher.final("utf8"); - return decrypted; - } catch (error) { - return null; - } -}; - -module.exports = decrypt; diff --git a/package-shared/functions/backend/encrypt.d.ts b/package-shared/functions/backend/encrypt.d.ts deleted file mode 100644 index 24f82f5..0000000 --- a/package-shared/functions/backend/encrypt.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -export = encrypt; -/** - * @async - * @param {string} data - * @param {string} [encryptionKey] - * @param {string} [encryptionSalt] - * @returns {string | null} - */ -declare function encrypt(data: string, encryptionKey?: string, encryptionSalt?: string): string | null; diff --git a/package-shared/functions/backend/encrypt.js b/package-shared/functions/backend/encrypt.js deleted file mode 100644 index b80807d..0000000 --- a/package-shared/functions/backend/encrypt.js +++ /dev/null @@ -1,43 +0,0 @@ -// @ts-check - -const { scryptSync, createCipheriv } = require("crypto"); -const { Buffer } = require("buffer"); -const serverError = require("./serverError"); - -/** - * @async - * @param {string} data - * @param {string} [encryptionKey] - * @param {string} [encryptionSalt] - * @returns {string | null} - */ -const encrypt = (data, encryptionKey, encryptionSalt) => { - const algorithm = "aes-192-cbc"; - const password = encryptionKey - ? encryptionKey - : process.env.DSQL_ENCRYPTION_PASSWORD || ""; - - /** ********************* Generate key */ - const salt = encryptionSalt - ? encryptionSalt - : process.env.DSQL_ENCRYPTION_SALT || ""; - let key = scryptSync(password, salt, 24); - let iv = Buffer.alloc(16, 0); - // @ts-ignore - const cipher = createCipheriv(algorithm, key, iv); - - /** ********************* Encrypt data */ - try { - let encrypted = cipher.update(data, "utf8", "hex"); - encrypted += cipher.final("hex"); - return encrypted; - } catch (/** @type {any} */ error) { - serverError({ - component: "encrypt", - message: error.message, - }); - return null; - } -}; - -module.exports = encrypt; diff --git a/package-shared/functions/backend/grabUserSchemaData.js b/package-shared/functions/backend/grabUserSchemaData.js new file mode 100755 index 0000000..8cdbd0c --- /dev/null +++ b/package-shared/functions/backend/grabUserSchemaData.js @@ -0,0 +1,46 @@ +// @ts-check + +const serverError = require("./serverError"); +const fs = require("fs"); +const path = require("path"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * ============================================================================== + * @param {Object} params + * @param {string | number} params.userId + * @returns {import("../../types").DSQL_DatabaseSchemaType[] | null} + */ +export default function grabUserSchemaData({ userId }) { + try { + const userSchemaFilePath = path.resolve( + process.cwd(), + `${process.env.DSQL_USER_DB_SCHEMA_PATH}/user-${userId}/main.json` + ); + const userSchemaData = JSON.parse( + fs.readFileSync(userSchemaFilePath, "utf-8") + ); + + return userSchemaData; + } catch (/** @type {any} */ error) { + serverError({ + component: "grabUserSchemaData", + message: error.message, + }); + + return null; + } +} + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ diff --git a/package-shared/functions/backend/handleNodemailer.js b/package-shared/functions/backend/handleNodemailer.js new file mode 100755 index 0000000..aeb91eb --- /dev/null +++ b/package-shared/functions/backend/handleNodemailer.js @@ -0,0 +1,129 @@ +// @ts-check + +/** + * Imports + * ============================================================================== + */ + +const fs = require("fs"); + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +const nodemailer = require("nodemailer"); + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +let transporter = nodemailer.createTransport({ + host: process.env.DSQL_MAIL_HOST, + port: 465, + secure: true, + auth: { + user: process.env.DSQL_MAIL_EMAIL, + pass: process.env.DSQL_MAIL_PASSWORD, + }, +}); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * # Handle mails + * @param {object} mailObject - Mail Object with params + * @param {string} [mailObject.to] - who is recieving this email? Comma separated for multiple recipients + * @param {string} [mailObject.subject] - Mail Subject + * @param {string} [mailObject.text] - Mail text + * @param {string} [mailObject.html] - Mail HTML + * @param {string | null} [mailObject.alias] - Sender alias: "support" or null + * + * @returns {Promise} mail object + */ +module.exports = async function handleNodemailer({ + to, + subject, + text, + html, + alias, +}) { + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + if ( + !process.env.DSQL_MAIL_HOST || + !process.env.DSQL_MAIL_EMAIL || + !process.env.DSQL_MAIL_PASSWORD + ) { + return null; + } + + const sender = (() => { + if (alias?.match(/support/i)) return process.env.DSQL_MAIL_EMAIL; + return process.env.DSQL_MAIL_EMAIL; + })(); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + let sentMessage; + + if (!fs.existsSync("./email/index.html")) { + return; + } + + let mailRoot = fs.readFileSync("./email/index.html", "utf8"); + let finalHtml = mailRoot + .replace(/{{email_body}}/, html ? html : "") + .replace(/{{issue_date}}/, Date().substring(0, 24)); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + try { + let mailObject = {}; + + mailObject["from"] = `"Datasquirel" <${sender}>`; + mailObject["sender"] = sender; + if (alias) mailObject["replyTo "] = sender; + // mailObject["priority"] = "high"; + mailObject["to"] = to; + mailObject["subject"] = subject; + mailObject["text"] = text; + mailObject["html"] = finalHtml; + + // send mail with defined transport object + let info = await transporter.sendMail(mailObject); + + sentMessage = info; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + } catch (/** @type {any} */ error) { + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + console.log("ERROR in handleNodemailer Function =>", error.message); + // serverError({ + // component: "handleNodemailer", + // message: error.message, + // user: { email: to }, + // }); + } + + return sentMessage; +}; + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// diff --git a/engine/user/social/utils/httpsRequest.js b/package-shared/functions/backend/httpsRequest.js similarity index 66% rename from engine/user/social/utils/httpsRequest.js rename to package-shared/functions/backend/httpsRequest.js index 7710af6..90d912e 100644 --- a/engine/user/social/utils/httpsRequest.js +++ b/package-shared/functions/backend/httpsRequest.js @@ -4,7 +4,9 @@ * Imports * ============================================================================== */ -const grabHostNames = require("../../../../package-shared/utils/grab-host-names"); +const https = require("https"); +const http = require("http"); +const { URL } = require("url"); ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// @@ -17,19 +19,29 @@ const grabHostNames = require("../../../../package-shared/utils/grab-host-names" * Main Function * ============================================================================== * @param {{ + * scheme?: string, * url?: string, - * method: string, - * hostname: string, + * method?: string, + * hostname?: string, * path?: string, - * href?: string, + * port?: number | string, * headers?: object, * body?: object, * }} params - params */ -function httpsRequest({ url, method, hostname, path, href, headers, body }) { +module.exports = function httpsRequest({ + url, + method, + hostname, + path, + headers, + body, + port, + scheme, +}) { const reqPayloadString = body ? JSON.stringify(body) : null; - const { host, port, scheme } = grabHostNames(); + const PARSED_URL = url ? new URL(url) : null; //////////////////////////////////////////////// //////////////////////////////////////////////// @@ -37,21 +49,29 @@ function httpsRequest({ url, method, hostname, path, href, headers, body }) { /** @type {any} */ let requestOptions = { - method: method, - hostname: host, - port, + method: method || "GET", + hostname: PARSED_URL ? PARSED_URL.hostname : hostname, + port: scheme?.match(/https/i) + ? 443 + : PARSED_URL + ? PARSED_URL.protocol?.match(/https/i) + ? 443 + : PARSED_URL.port + : port + ? Number(port) + : 80, headers: {}, }; if (path) requestOptions.path = path; - if (href) requestOptions.href = href; + // if (href) requestOptions.href = href; if (headers) requestOptions.headers = headers; if (body) { requestOptions.headers["Content-Type"] = "application/json"; - requestOptions.headers["Content-Length"] = Buffer.from( - reqPayloadString || "" - ).length; + requestOptions.headers["Content-Length"] = reqPayloadString + ? Buffer.from(reqPayloadString).length + : undefined; } //////////////////////////////////////////////// @@ -59,10 +79,15 @@ function httpsRequest({ url, method, hostname, path, href, headers, body }) { //////////////////////////////////////////////// return new Promise((res, rej) => { - const httpsRequest = scheme.request( + const httpsRequest = ( + scheme?.match(/https/i) + ? https + : PARSED_URL?.protocol?.match(/https/i) + ? https + : http + ).request( /* ====== Request Options object ====== */ - // @ts-ignore - url ? url : requestOptions, + requestOptions, //////////////////////////////////////////////// //////////////////////////////////////////////// @@ -84,6 +109,11 @@ function httpsRequest({ url, method, hostname, path, href, headers, body }) { response.on("error", (error) => { console.log("HTTP response error =>", error.message); + rej(`HTTP response error =>, ${error.message}`); + }); + + response.on("close", () => { + console.log("HTTP(S) Response Closed Successfully"); }); } ); @@ -91,7 +121,8 @@ function httpsRequest({ url, method, hostname, path, href, headers, body }) { if (body) httpsRequest.write(reqPayloadString); httpsRequest.on("error", (error) => { - console.log("HTTPS request ERROR =>", error); + console.log("HTTPS request ERROR =>", error.message); + rej(`HTTP request error =>, ${error.message}`); }); httpsRequest.end(); @@ -100,7 +131,7 @@ function httpsRequest({ url, method, hostname, path, href, headers, body }) { //////////////////////////////////////////////// //////////////////////////////////////////////// }); -} +}; ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// @@ -108,5 +139,3 @@ function httpsRequest({ url, method, hostname, path, href, headers, body }) { ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// - -module.exports = httpsRequest; diff --git a/package-shared/functions/backend/parseDbResults.js b/package-shared/functions/backend/parseDbResults.js index 2d5cc7e..9959390 100644 --- a/package-shared/functions/backend/parseDbResults.js +++ b/package-shared/functions/backend/parseDbResults.js @@ -1,6 +1,6 @@ // @ts-check -const decrypt = require("./decrypt"); +const decrypt = require("../dsql/decrypt"); const defaultFieldsRegexp = require("./defaultFieldsRegexp"); /** @@ -55,7 +55,9 @@ module.exports = async function parseDbResults({ if (resultFieldSchema?.encrypted) { if (value?.match(/./)) { - result[resultFieldName] = decrypt(value); + result[resultFieldName] = decrypt({ + encryptedString: value, + }); } } } diff --git a/package-shared/functions/backend/serverError.d.ts b/package-shared/functions/backend/serverError.d.ts deleted file mode 100644 index 4715f61..0000000 --- a/package-shared/functions/backend/serverError.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -declare function _exports({ user, message, component, noMail, }: { - user?: { - id?: number | string; - first_name?: string; - last_name?: string; - email?: string; - } & any; - message: string; - component?: string; - noMail?: boolean; -}): Promise; -export = _exports; diff --git a/package-shared/functions/backend/serverError.js b/package-shared/functions/backend/serverError.js old mode 100644 new mode 100755 index 2f7302e..f542691 --- a/package-shared/functions/backend/serverError.js +++ b/package-shared/functions/backend/serverError.js @@ -6,7 +6,7 @@ * ============================================================================== */ const fs = require("fs"); -// const handleNodemailer = require("./handleNodemailer"); +const { IncomingMessage } = require("http"); /** ****************************************************************************** */ /** ****************************************************************************** */ @@ -24,6 +24,7 @@ const fs = require("fs"); * message: string, * component?: string, * noMail?: boolean, + * req?: import("next").NextApiRequest & IncomingMessage, * }} params - user id * * @returns {Promise} @@ -33,21 +34,68 @@ module.exports = async function serverError({ message, component, noMail, + req, }) { - const log = `🚀 SERVER ERROR ===========================\nUser Id: ${ - user?.id - }\nUser Name: ${user?.first_name} ${user?.last_name}\nUser Email: ${ - user?.email - }\nError Message: ${message}\nComponent: ${component}\nDate: ${Date()}\n========================================`; + const date = new Date(); - if (!fs.existsSync(`./.tmp/error.log`)) { - fs.writeFileSync(`./.tmp/error.log`, "", "utf-8"); + const reqIp = (() => { + if (!req) return null; + try { + const forwarded = req.headers["x-forwarded-for"]; + const realIp = req.headers["x-real-ip"]; + const cloudflareIp = req.headers["cf-connecting-ip"]; + + // Convert forwarded IPs to string and get the first IP if multiple exist + const forwardedIp = Array.isArray(forwarded) + ? forwarded[0] + : forwarded?.split(",")[0]; + + const clientIp = + cloudflareIp || + forwardedIp || + realIp || + req.socket.remoteAddress; + if (!clientIp) return null; + + return String(clientIp); + } catch (error) { + return null; + } + })(); + + try { + let log = `🚀 SERVER ERROR ===========================\nError Message: ${message}\nComponent: ${component}`; + + if (user?.id && user?.first_name && user?.last_name && user?.email) { + log += `\nUser Id: ${user?.id}\nUser Name: ${user?.first_name} ${user?.last_name}\nUser Email: ${user?.email}`; + } + + if (req?.url) { + log += `\nURL: ${req.url}`; + } + + if (req?.body) { + log += `\nRequest Body: ${JSON.stringify(req.body, null, 4)}`; + } + + if (reqIp) { + log += `\nIP: ${reqIp}`; + } + + log += `\nDate: ${date.toDateString()}`; + log += "\n========================================"; + + if (!fs.existsSync(`./.tmp/error.log`)) { + fs.writeFileSync(`./.tmp/error.log`, "", "utf-8"); + } + + const initialText = fs.readFileSync(`./.tmp/error.log`, "utf-8"); + + fs.writeFileSync(`./.tmp/error.log`, log); + fs.appendFileSync(`./.tmp/error.log`, `\n\n\n\n\n${initialText}`); + } catch (/** @type {any} */ error) { + console.log("Server Error Reporting Error:", error.message); } - - const initialText = fs.readFileSync(`./.tmp/error.log`, "utf-8"); - - fs.writeFileSync(`./.tmp/error.log`, log); - fs.appendFileSync(`./.tmp/error.log`, `\n\n\n\n\n${initialText}`); }; //////////////////////////////////////// diff --git a/package-shared/functions/backend/setUserSchemaData.js b/package-shared/functions/backend/setUserSchemaData.js new file mode 100755 index 0000000..53be2fc --- /dev/null +++ b/package-shared/functions/backend/setUserSchemaData.js @@ -0,0 +1,49 @@ +// @ts-check + +const serverError = require("./serverError"); +const fs = require("fs"); +const path = require("path"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * ============================================================================== + * @param {Object} params + * @param {string | number} params.userId + * @param {import("../../types").DSQL_DatabaseSchemaType[]} params.schemaData + * @returns {boolean} + */ +export default function setUserSchemaData({ userId, schemaData }) { + try { + const userSchemaFilePath = path.resolve( + process.cwd(), + `${process.env.DSQL_USER_DB_SCHEMA_PATH}/user-${userId}/main.json` + ); + fs.writeFileSync( + userSchemaFilePath, + JSON.stringify(schemaData), + "utf8" + ); + + return true; + } catch (/** @type {any} */ error) { + serverError({ + component: "/functions/backend/setUserSchemaData", + message: error.message, + }); + + return false; + } +} + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ diff --git a/package-shared/functions/backend/suSocketAuth.js b/package-shared/functions/backend/suSocketAuth.js index eb29d51..f2acdb9 100644 --- a/package-shared/functions/backend/suSocketAuth.js +++ b/package-shared/functions/backend/suSocketAuth.js @@ -1,8 +1,9 @@ // @ts-check const { IncomingMessage } = require("http"); -const decrypt = require("./decrypt"); const parseCookies = require("../../utils/backend/parseCookies"); +const decrypt = require("../dsql/decrypt"); +const getAuthCookieNames = require("./cookies/get-auth-cookie-names"); /** * @async @@ -11,14 +12,18 @@ const parseCookies = require("../../utils/backend/parseCookies"); * @returns {Promise<({ email: string, password: string, authKey: string, logged_in_status: boolean, date: number } | null)>} */ module.exports = async function (req) { + const { keyCookieName, csrfCookieName } = getAuthCookieNames(); + const suKeyName = `${keyCookieName}_su`; + const cookies = parseCookies({ request: req }); - /** ********************* Check for existence of required cookie */ - if (!cookies?.datasquirelSuAdminUserAuthKey) { + if (!cookies?.[suKeyName]) { return null; } /** ********************* Grab the payload */ - let userPayload = decrypt(cookies.datasquirelSuAdminUserAuthKey); + let userPayload = decrypt({ + encryptedString: cookies[suKeyName], + }); /** ********************* Return if no payload */ if (!userPayload) return null; diff --git a/functions/decrypt.js b/package-shared/functions/dsql/decrypt.js similarity index 62% rename from functions/decrypt.js rename to package-shared/functions/dsql/decrypt.js index 03c14c5..e6c4da7 100644 --- a/functions/decrypt.js +++ b/package-shared/functions/dsql/decrypt.js @@ -4,11 +4,10 @@ const { scryptSync, createDecipheriv } = require("crypto"); const { Buffer } = require("buffer"); /** - * * @param {object} param0 * @param {string} param0.encryptedString - * @param {string} param0.encryptionKey - * @param {string} param0.encryptionSalt + * @param {string} [param0.encryptionKey] + * @param {string} [param0.encryptionSalt] * @returns */ const decrypt = ({ encryptedString, encryptionKey, encryptionSalt }) => { @@ -17,19 +16,27 @@ const decrypt = ({ encryptedString, encryptionKey, encryptionSalt }) => { return encryptedString; } - if (!encryptionKey?.match(/.{8,}/)) { + const finalEncryptionKey = + encryptionKey || process.env.DSQL_ENCRYPTION_PASSWORD; + const finalEncryptionSalt = + encryptionSalt || process.env.DSQL_ENCRYPTION_SALT; + const finalKeyLen = process.env.DSQL_ENCRYPTION_KEY_LENGTH + ? Number(process.env.DSQL_ENCRYPTION_KEY_LENGTH) + : 24; + + if (!finalEncryptionKey?.match(/.{8,}/)) { console.log("Decrption key is invalid"); return encryptedString; } - if (!encryptionSalt?.match(/.{8,}/)) { + if (!finalEncryptionSalt?.match(/.{8,}/)) { console.log("Decrption salt is invalid"); return encryptedString; } const algorithm = "aes-192-cbc"; - let key = scryptSync(encryptionKey, encryptionSalt, 24); + let key = scryptSync(finalEncryptionKey, finalEncryptionSalt, finalKeyLen); let iv = Buffer.alloc(16, 0); // @ts-ignore const decipher = createDecipheriv(algorithm, key, iv); diff --git a/functions/encrypt.js b/package-shared/functions/dsql/encrypt.js similarity index 59% rename from functions/encrypt.js rename to package-shared/functions/dsql/encrypt.js index 9007c7b..c839b79 100644 --- a/functions/encrypt.js +++ b/package-shared/functions/dsql/encrypt.js @@ -7,8 +7,8 @@ const { Buffer } = require("buffer"); * * @param {object} param0 * @param {string} param0.data - * @param {string} param0.encryptionKey - * @param {string} param0.encryptionSalt + * @param {string} [param0.encryptionKey] + * @param {string} [param0.encryptionSalt] * @returns {string | null} */ const encrypt = ({ data, encryptionKey, encryptionSalt }) => { @@ -16,19 +16,28 @@ const encrypt = ({ data, encryptionKey, encryptionSalt }) => { console.log("Encryption string is invalid"); return data; } - if (!encryptionKey?.match(/.{8,}/)) { + + const finalEncryptionKey = + encryptionKey || process.env.DSQL_ENCRYPTION_PASSWORD; + const finalEncryptionSalt = + encryptionSalt || process.env.DSQL_ENCRYPTION_SALT; + const finalKeyLen = process.env.DSQL_ENCRYPTION_KEY_LENGTH + ? Number(process.env.DSQL_ENCRYPTION_KEY_LENGTH) + : 24; + + if (!finalEncryptionKey?.match(/.{8,}/)) { console.log("Encryption key is invalid"); return data; } - if (!encryptionSalt?.match(/.{8,}/)) { + if (!finalEncryptionSalt?.match(/.{8,}/)) { console.log("Encryption salt is invalid"); return data; } const algorithm = "aes-192-cbc"; - const password = encryptionKey; + const password = finalEncryptionKey; - let key = scryptSync(password, encryptionSalt, 24); + let key = scryptSync(password, finalEncryptionSalt, finalKeyLen); let iv = Buffer.alloc(16, 0); // @ts-ignore const cipher = createCipheriv(algorithm, key, iv); diff --git a/functions/hashPassword.d.ts b/package-shared/functions/dsql/hashPassword.d.ts similarity index 100% rename from functions/hashPassword.d.ts rename to package-shared/functions/dsql/hashPassword.d.ts diff --git a/functions/hashPassword.js b/package-shared/functions/dsql/hashPassword.js similarity index 100% rename from functions/hashPassword.js rename to package-shared/functions/dsql/hashPassword.js diff --git a/functions/sql/sql-delete-generator.d.ts b/package-shared/functions/dsql/sql/sql-delete-generator.d.ts similarity index 100% rename from functions/sql/sql-delete-generator.d.ts rename to package-shared/functions/dsql/sql/sql-delete-generator.d.ts diff --git a/functions/sql/sql-delete-generator.js b/package-shared/functions/dsql/sql/sql-delete-generator.js similarity index 100% rename from functions/sql/sql-delete-generator.js rename to package-shared/functions/dsql/sql/sql-delete-generator.js diff --git a/package-shared/functions/dsql/sql/sql-generator.d.ts b/package-shared/functions/dsql/sql/sql-generator.d.ts new file mode 100644 index 0000000..5ab8338 --- /dev/null +++ b/package-shared/functions/dsql/sql/sql-generator.d.ts @@ -0,0 +1,10 @@ +export = sqlGenerator; +declare function sqlGenerator(Param0: { + genObject?: import("../../../types").ServerQueryParam; + tableName: string; +}): + | { + string: string; + values: string[]; + } + | undefined; diff --git a/functions/sql/sql-generator.js b/package-shared/functions/dsql/sql/sql-generator.js similarity index 96% rename from functions/sql/sql-generator.js rename to package-shared/functions/dsql/sql/sql-generator.js index 8def027..a7d9379 100644 --- a/functions/sql/sql-generator.js +++ b/package-shared/functions/dsql/sql/sql-generator.js @@ -3,7 +3,7 @@ /** * # SQL Query Generator * @description Generates an SQL Query for node module `mysql` or `serverless-mysql` - * @type {import("../../package-shared/types").SqlGeneratorFn} + * @type {import("../../../types").SqlGeneratorFn} */ function sqlGenerator({ tableName, genObject }) { if (!genObject) return undefined; @@ -62,8 +62,8 @@ function sqlGenerator({ tableName, genObject }) { }); function generateJoinStr( - /** @type {import("../../package-shared/types").ServerQueryParamsJoinMatchObject} */ mtch, - /** @type {import("../../package-shared/types").ServerQueryParamsJoin} */ join + /** @type {import("../../../types").ServerQueryParamsJoinMatchObject} */ mtch, + /** @type {import("../../../types").ServerQueryParamsJoin} */ join ) { return `${ typeof mtch.source == "object" ? mtch.source.tableName : tableName diff --git a/functions/sql/sql-insert-generator.d.ts b/package-shared/functions/dsql/sql/sql-insert-generator.d.ts similarity index 100% rename from functions/sql/sql-insert-generator.d.ts rename to package-shared/functions/dsql/sql/sql-insert-generator.d.ts diff --git a/functions/sql/sql-insert-generator.js b/package-shared/functions/dsql/sql/sql-insert-generator.js similarity index 100% rename from functions/sql/sql-insert-generator.js rename to package-shared/functions/dsql/sql/sql-insert-generator.js diff --git a/engine/user/one-time-code.html b/package-shared/html/one-time-code.html similarity index 100% rename from engine/user/one-time-code.html rename to package-shared/html/one-time-code.html diff --git a/package-shared/shell/checkDb.js b/package-shared/shell/checkDb.js new file mode 100755 index 0000000..ce59d38 --- /dev/null +++ b/package-shared/shell/checkDb.js @@ -0,0 +1,57 @@ +// @ts-check + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +require("dotenv").config({ path: "./../.env" }); +const mysql = require("serverless-mysql"); +const grabDbSSL = require("../utils/backend/grabDbSSL"); + +const connection = mysql({ + config: { + host: process.env.DSQL_DB_HOST, + user: process.env.DSQL_DB_USERNAME, + password: process.env.DSQL_DB_PASSWORD, + database: process.env.DSQL_DB_NAME, + charset: "utf8mb4", + ssl: grabDbSSL(), + }, +}); + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +/** + * # Main DB Handler Function + * @async + * + * @param {object} params + * @param {string} params.query + * @param {string[] | object} [params.values] + * @param {string} [params.database] + * + * @returns {Promise} + */ +(async () => { + /** + * Switch Database + * + * @description If a database is provided, switch to it + */ + try { + const result = await connection.query( + "SELECT id,first_name,last_name FROM users LIMIT 3" + ); + console.log("Connection Query Success =>", result); + } catch (/** @type {any} */ error) { + console.log("Connection query ERROR =>", error.message); + } finally { + connection.end(); + process.exit(); + } +})(); diff --git a/package-shared/shell/createDbFromSchema.js b/package-shared/shell/createDbFromSchema.js new file mode 100755 index 0000000..05089ba --- /dev/null +++ b/package-shared/shell/createDbFromSchema.js @@ -0,0 +1,302 @@ +// @ts-check + +const path = require("path"); +const fs = require("fs"); + +require("dotenv").config({ path: "./../.env" }); + +const noDatabaseDbHandler = require("./utils/noDatabaseDbHandler"); +const varDatabaseDbHandler = require("./utils/varDatabaseDbHandler"); +const createTable = require("./utils/createTable"); +const updateTable = require("./utils/updateTable"); +const dbHandler = require("./utils/dbHandler"); +const EJSON = require("../utils/ejson"); + +const execFlag = process.argv.find((arg) => arg === "--exec"); + +/** + * Create database from Schema Function + * ============================================================================== + * @param {object} params - Single object params + * @param {number|string|null} [params.userId] - User ID or null + * @param {string} [params.targetDatabase] - User Database full name + * @param {import("../types").DSQL_DatabaseSchemaType[]} [params.dbSchemaData] + */ +async function createDbFromSchema({ userId, targetDatabase, dbSchemaData }) { + const schemaPath = userId + ? path.join( + String(process.env.DSQL_USER_DB_SCHEMA_PATH), + `/user-${userId}/main.json` + ) + : path.resolve(__dirname, "../../jsonData/dbSchemas/main.json"); + + /** @type {import("../types").DSQL_DatabaseSchemaType[] | undefined} */ + const dbSchema = + dbSchemaData || + /** @type {import("../types").DSQL_DatabaseSchemaType[] | undefined} */ ( + EJSON.parse(fs.readFileSync(schemaPath, "utf8")) + ); + + if (!dbSchema) { + console.log("Schema Not Found!"); + return; + } + + // await createDatabasesFromSchema(dbSchema); + + for (let i = 0; i < dbSchema.length; i++) { + /** @type {import("../types").DSQL_DatabaseSchemaType} */ + const database = dbSchema[i]; + const { dbFullName, tables, dbName, dbSlug, childrenDatabases } = + database; + + if (targetDatabase && dbFullName != targetDatabase) { + continue; + } + + /** @type {any} */ + const dbCheck = await noDatabaseDbHandler( + `SELECT SCHEMA_NAME AS dbFullName FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '${dbFullName}'` + ); + + if (dbCheck && dbCheck[0]?.dbFullName) { + // Database Exists + } else { + const newDatabase = await noDatabaseDbHandler( + `CREATE DATABASE IF NOT EXISTS \`${dbFullName}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_bin` + ); + } + + /** + * Select all tables + * @type {any} + * @description Select All tables in target database + */ + const allTables = await noDatabaseDbHandler( + `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='${dbFullName}'` + ); + + // let tableDropped; + + for (let tb = 0; tb < allTables.length; tb++) { + const { TABLE_NAME } = allTables[tb]; + + /** + * @description Check if TABLE_NAME is part of the tables contained + * in the user schema JSON. If it's not, the table is either deleted + * or the table name has been recently changed + */ + if ( + !tables.filter((_table) => _table.tableName === TABLE_NAME)[0] + ) { + const oldTableFilteredArray = tables.filter( + (_table) => + _table.tableNameOld && + _table.tableNameOld === TABLE_NAME + ); + + /** + * @description Check if this table has been recently renamed. Rename + * table id true. Drop table if false + */ + if (oldTableFilteredArray && oldTableFilteredArray[0]) { + console.log("Renaming Table"); + await varDatabaseDbHandler({ + queryString: `RENAME TABLE \`${oldTableFilteredArray[0].tableNameOld}\` TO \`${oldTableFilteredArray[0].tableName}\``, + database: dbFullName, + }); + } else { + console.log(`Dropping Table from ${dbFullName}`); + await varDatabaseDbHandler({ + queryString: `DROP TABLE \`${TABLE_NAME}\``, + database: dbFullName, + }); + + const deleteTableEntry = await dbHandler({ + query: `DELETE FROM user_database_tables WHERE user_id = ? AND db_slug = ? AND table_slug = ?`, + values: [userId, dbSlug, TABLE_NAME], + database: "datasquirel", + }); + } + } + } + + const recordedDbEntryArray = userId + ? await varDatabaseDbHandler({ + database: "datasquirel", + queryString: `SELECT * FROM user_databases WHERE db_full_name = ?`, + queryValuesArray: [dbFullName], + }) + : undefined; + + const recordedDbEntry = recordedDbEntryArray?.[0]; + + /** + * @description Iterate through each table and perform table actions + */ + for (let t = 0; t < tables.length; t++) { + const table = tables[t]; + + const { tableName, fields, indexes } = table; + + /** + * @description Check if table exists + * @type {any} + */ + const tableCheck = await varDatabaseDbHandler({ + queryString: ` + SELECT EXISTS ( + SELECT + TABLE_NAME + FROM + information_schema.TABLES + WHERE + TABLE_SCHEMA = ? AND + TABLE_NAME = ? + ) AS tableExists`, + queryValuesArray: [dbFullName, table.tableName], + database: dbFullName, + }); + + //////////////////////////////////////// + + if (tableCheck && tableCheck[0]?.tableExists > 0) { + /** + * @description Update table if table exists + */ + const updateExistingTable = await updateTable({ + dbFullName: dbFullName, + tableName: tableName, + tableNameFull: table.tableFullName, + tableInfoArray: fields, + userId, + dbSchema, + tableIndexes: indexes, + tableIndex: t, + childDb: database.childDatabase || undefined, + recordedDbEntry, + tableSchema: table, + }); + + if (table.childrenTables && table.childrenTables[0]) { + for (let ch = 0; ch < table.childrenTables.length; ch++) { + const childTable = table.childrenTables[ch]; + + const updateExistingChildTable = await updateTable({ + dbFullName: childTable.dbNameFull, + tableName: childTable.tableName, + tableNameFull: childTable.tableNameFull, + tableInfoArray: fields, + userId, + dbSchema, + tableIndexes: indexes, + clone: true, + childDb: database.childDatabase || undefined, + recordedDbEntry, + tableSchema: table, + }); + } + } + + //////////////////////////////////////// + } else { + //////////////////////////////////////// + + /** + * @description Create new Table if table doesnt exist + */ + const createNewTable = await createTable({ + tableName: tableName, + tableInfoArray: fields, + dbFullName: dbFullName, + dbSchema, + tableSchema: table, + recordedDbEntry, + }); + + if (indexes && indexes[0]) { + /** + * Handle DATASQUIREL Table Indexes + * =================================================== + * @description Iterate through each datasquirel schema + * table index(if available), and perform operations + */ + if (indexes && indexes[0]) { + for (let g = 0; g < indexes.length; g++) { + const { + indexType, + indexName, + indexTableFields, + alias, + } = indexes[g]; + + if (!alias?.match(/./)) continue; + + /** + * @description Check for existing Index in MYSQL db + */ + try { + /** + * @type {import("../types").DSQL_MYSQL_SHOW_INDEXES_Type[]} + * @description All indexes from MYSQL db + */ // @ts-ignore + const allExistingIndexes = + await varDatabaseDbHandler({ + queryString: `SHOW INDEXES FROM \`${tableName}\``, + database: dbFullName, + }); + + const existingKeyInDb = + allExistingIndexes.filter( + (indexObject) => + indexObject.Key_name === alias + ); + if (!existingKeyInDb[0]) + throw new Error( + "This Index Does not Exist" + ); + } catch (error) { + /** + * @description Create new index if determined that it + * doesn't exist in MYSQL db + */ + await varDatabaseDbHandler({ + queryString: `CREATE${ + indexType?.match(/fullText/i) + ? " FULLTEXT" + : "" + } INDEX \`${alias}\` ON ${tableName}(${indexTableFields + ?.map((nm) => nm.value) + .map((nm) => `\`${nm}\``) + .join(",")}) COMMENT 'schema_index'`, + database: dbFullName, + }); + } + } + } + } + } + } + + /** + * @description Check all children databases + */ + if (childrenDatabases?.[0]) { + for (let ch = 0; ch < childrenDatabases.length; ch++) { + const childDb = childrenDatabases[ch]; + const { dbFullName } = childDb; + + await createDbFromSchema({ + userId, + targetDatabase: dbFullName, + }); + } + } + } +} + +module.exports = createDbFromSchema; + +if (execFlag) { + createDbFromSchema({}); +} diff --git a/package-shared/shell/deploy.js b/package-shared/shell/deploy.js new file mode 100755 index 0000000..1a3b34b --- /dev/null +++ b/package-shared/shell/deploy.js @@ -0,0 +1,7 @@ +// @ts-check + +const fs = require("fs"); + +async function deploy() {} + +deploy(); diff --git a/package-shared/shell/encodingUpdate.js b/package-shared/shell/encodingUpdate.js new file mode 100755 index 0000000..4e87021 --- /dev/null +++ b/package-shared/shell/encodingUpdate.js @@ -0,0 +1,58 @@ +// @ts-check + +require("dotenv").config({ path: "./../.env" }); + +//////////////////////////////////////// + +const varDatabaseDbHandler = require("../functions/backend/varDatabaseDbHandler"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Grab Schema + * + * @description Grab Schema + */ +varDatabaseDbHandler({ + queryString: `SELECT user_database_tables.*,user_databases.db_full_name FROM user_database_tables JOIN user_databases ON user_database_tables.db_id=user_databases.id`, + database: "datasquirel", +}).then(async (tables) => { + for (let i = 0; i < tables.length; i++) { + const table = tables[i]; + const { + id, + user_id, + db_id, + db_full_name, + table_name, + table_slug, + table_description, + } = table; + + const tableInfo = await varDatabaseDbHandler({ + queryString: `SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='${db_full_name}' AND TABLE_NAME='${table_slug}'`, + database: db_full_name, + }); + + const updateDbCharset = await varDatabaseDbHandler({ + queryString: `ALTER DATABASE ${db_full_name} CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin;`, + database: db_full_name, + }); + + const updateEncoding = await varDatabaseDbHandler({ + queryString: `ALTER TABLE \`${table_slug}\` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin`, + database: db_full_name, + }); + } + + process.exit(); +}); + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// diff --git a/package-shared/shell/functions/jsonToBase64.js b/package-shared/shell/functions/jsonToBase64.js new file mode 100644 index 0000000..7e224c0 --- /dev/null +++ b/package-shared/shell/functions/jsonToBase64.js @@ -0,0 +1,10 @@ +// @ts-check + +const fs = require("fs"); +const path = require("path"); + +const jsonFile = path.resolve(__dirname, "../../jsonData/userPriviledges.json"); +const base64File = Buffer.from(fs.readFileSync(jsonFile, "utf8")).toString( + "base64" +); +console.log(base64File); diff --git a/package-shared/shell/grantFullPriviledges.js b/package-shared/shell/grantFullPriviledges.js new file mode 100755 index 0000000..431b407 --- /dev/null +++ b/package-shared/shell/grantFullPriviledges.js @@ -0,0 +1,79 @@ +// @ts-check + +require("dotenv").config({ path: "./../.env" }); + +const serverError = require("../functions/backend/serverError"); +const noDatabaseDbHandler = require("./utils/noDatabaseDbHandler"); +//////////////////////////////////////// + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * # Create Database From Schema + * @param {object} param0 + * @param {string | null} param0.userId + */ +async function createDbFromSchema({ userId }) { + /** + * Grab Schema + * + * @description Grab Schema + */ + try { + const defaultMariadbUserHost = process.env.DSQL_DB_HOST || "127.0.0.1"; + + const allDatabases = await noDatabaseDbHandler(`SHOW DATABASES`); + + const datasquirelUserDatabases = allDatabases.filter( + (/** @type {any} */ database) => + database.Database.match(/datasquirel_user_/) + ); + + for (let i = 0; i < datasquirelUserDatabases.length; i++) { + const datasquirelUserDatabase = datasquirelUserDatabases[i]; + const { Database } = datasquirelUserDatabase; + + const grantDbPriviledges = await noDatabaseDbHandler( + `GRANT ALL PRIVILEGES ON ${Database}.* TO '${process.env.DSQL_DB_FULL_ACCESS_USERNAME}'@'%' WITH GRANT OPTION` + ); + + const grantRead = await noDatabaseDbHandler( + `GRANT SELECT ON ${Database}.* TO '${process.env.DSQL_DB_READ_ONLY_USERNAME}'@'%'` + ); + } + + const flushPriviledged = await noDatabaseDbHandler(`FLUSH PRIVILEGES`); + } catch (/** @type {any} */ error) { + serverError({ + component: "shell/grantDbPriviledges/main-catch-error", + message: error.message, + user: { id: userId }, + }); + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + process.exit(); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// +} + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +const userArg = process.argv[process.argv.indexOf("--user")]; +const externalUser = process.argv[process.argv.indexOf("--user") + 1]; + +createDbFromSchema({ userId: userArg ? externalUser : null }); diff --git a/package-shared/shell/lessWatch.js b/package-shared/shell/lessWatch.js new file mode 100755 index 0000000..306114a --- /dev/null +++ b/package-shared/shell/lessWatch.js @@ -0,0 +1,79 @@ +const fs = require("fs"); +const { exec } = require("child_process"); + +require("dotenv").config({ path: "./../.env" }); + +const sourceFile = + process.argv.indexOf("--src") >= 0 + ? process.argv[process.argv.indexOf("--src") + 1] + : null; +const destinationFile = + process.argv.indexOf("--dst") >= 0 + ? process.argv[process.argv.indexOf("--dst") + 1] + : null; + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +console.log("Running Less compiler ..."); + +const sourceFiles = sourceFile.split(","); +const dstFiles = destinationFile.split(","); + +for (let i = 0; i < sourceFiles.length; i++) { + const srcFolder = sourceFiles[i]; + const dstFile = dstFiles[i]; + + fs.watch(srcFolder, { recursive: true }, (evtType, prev) => { + if (prev?.match(/\(/) || prev?.match(/\.js$/i)) { + return; + } + + let finalSrcPath = `${srcFolder}/main.less`; + let finalDstPath = dstFile; + + if (prev?.match(/\[/)) { + const paths = prev.split("/"); + const targetPathFull = paths[paths.length - 1]; + const targetPath = targetPathFull + .replace(/\[|\]/g, "") + .replace(/\.less/, ""); + + const destinationFileParentFolder = dstFile.replace( + /\/[^\/]+\.css$/, + "" + ); + + const targetDstFilePath = `${destinationFileParentFolder}/${targetPath}.css`; + + finalSrcPath = `${srcFolder}/${targetPathFull}`; + finalDstPath = targetDstFilePath; + } + + exec( + `lessc ${finalSrcPath} ${ + finalDstPath?.match(/\.css$/) + ? finalDstPath + : finalDstPath.replace(/\/$/, "") + "/_main.css" + }`, + (error, stdout, stderr) => { + /** @type {Error} */ + if (error) { + console.log("ERROR =>", error.message); + + if (!evtType?.match(/change/i) && prev.match(/\[/)) { + fs.unlinkSync(finalDstPath); + } + + return; + } + + console.log("Less Compilation \x1b[32msuccessful\x1b[0m!"); + } + ); + }); +} diff --git a/package-shared/shell/mariadb-users/README.md b/package-shared/shell/mariadb-users/README.md new file mode 100644 index 0000000..e82cd14 --- /dev/null +++ b/package-shared/shell/mariadb-users/README.md @@ -0,0 +1,7 @@ +# Handle Datasquirel MariaDB Users and Grants + +## Files + +### refreshUsersAndGrants.js + +This script checks MariaDB users and updates their privileges using the `mariadb_users` table in `datasquirel` database. diff --git a/package-shared/shell/mariadb-users/handleGrants.js b/package-shared/shell/mariadb-users/handleGrants.js new file mode 100755 index 0000000..271c290 --- /dev/null +++ b/package-shared/shell/mariadb-users/handleGrants.js @@ -0,0 +1,105 @@ +// @ts-check + +const noDatabaseDbHandler = require("../utils/noDatabaseDbHandler"); + +/** + * @typedef {object} GrantType + * @property {string} database - Database Name + * @property {string} table - Table Name + * @property {string[]} privileges - Privileges + */ + +/** + * Handle Grants for Users + * ================================================ + * @param {object} params - Single object params + * @param {string} params.username - Username + * @param {string} params.host - Host + * @param {GrantType[]} params.grants - Grants + * @param {string} params.userId + * + * @returns {Promise} success + */ +async function handleGrants({ username, host, grants, userId }) { + let success = false; + + console.log(`Handling Grants for User =>`, username, host); + + if (!username) { + console.log(`No username provided.`); + return success; + } + + if (!host) { + console.log( + `No Host provided. \x1b[35m\`--host\`\x1b[0m flag is required` + ); + return success; + } + + if (!grants) { + console.log(`No grants Array provided.`); + return success; + } + + try { + const existingUser = await noDatabaseDbHandler( + `SELECT * FROM mysql.user WHERE User = '${username}' AND Host = '${host}'` + ); + + const isUserExisting = Boolean(existingUser?.[0]?.User); + + if (isUserExisting) { + const userGrants = await noDatabaseDbHandler( + `SHOW GRANTS FOR '${username}'@'${host}'` + ); + + for (let i = 0; i < userGrants.length; i++) { + const grantObject = userGrants[i]; + const grant = grantObject?.[Object.keys(grantObject)[0]]; + + if (grant?.match(/GRANT .* PRIVILEGES ON .* TO/)) { + const revokeGrantText = grant + .replace(/GRANT/, "REVOKE") + .replace(/ TO /, " FROM "); + + const revokePrivilege = await noDatabaseDbHandler( + revokeGrantText + ); + } + } + + /** + * @type {GrantType[]} + */ + const grantsArray = grants; + + for (let i = 0; i < grantsArray.length; i++) { + const grantObject = grantsArray[i]; + const { database, table, privileges } = grantObject; + + const tableText = table == "*" ? "*" : `\`${table}\``; + const databaseText = + database == "*" + ? `\`${process.env.DSQL_USER_DB_PREFIX}${userId}_%\`` + : `\`${database}\``; + + const privilegesText = privileges.includes("ALL") + ? "ALL PRIVILEGES" + : privileges.join(", "); + + const grantText = `GRANT ${privilegesText} ON ${databaseText}.${tableText} TO '${username}'@'${host}'`; + + const grantPriviledge = await noDatabaseDbHandler(grantText); + } + } + + success = true; + } catch (/** @type {any} */ error) { + console.log(`Error in adding SQL user =>`, error.message); + } + + return success; +} + +module.exports = handleGrants; diff --git a/package-shared/shell/mariadb-users/refreshUsersAndGrants.js b/package-shared/shell/mariadb-users/refreshUsersAndGrants.js new file mode 100755 index 0000000..eb18bca --- /dev/null +++ b/package-shared/shell/mariadb-users/refreshUsersAndGrants.js @@ -0,0 +1,269 @@ +// @ts-check + +const path = require("path"); +require("dotenv").config({ path: path.resolve(__dirname, "../../../.env") }); + +const generator = require("generate-password"); +const noDatabaseDbHandler = require("../utils/noDatabaseDbHandler"); +const dbHandler = require("../utils/dbHandler"); +const handleGrants = require("./handleGrants"); +const encrypt = require("../../functions/dsql/encrypt"); +const decrypt = require("../../functions/dsql/decrypt"); + +const defaultMariadbUserHost = process.env.DSQL_DB_HOST || "127.0.0.1"; + +/** + * Refresh Mariadb User Grants + * =================================================== + * @param {object} params + * @param {number | string} [params.userId] + * @param {string} [params.mariadbUserHost] + * @param {string} [params.mariadbUser] + * @param {string | number} [params.sqlUserID] + */ +async function refreshUsersAndGrants({ + userId, + mariadbUserHost, + mariadbUser, + sqlUserID, +}) { + /** + * @description Users + * @type {*[] | null} + */ // @ts-ignore + const users = await dbHandler({ + query: `SELECT * FROM users`, + }); + + if (!users?.[0]) { + process.exit(); + } + + for (let i = 0; i < users.length; i++) { + const user = users[i]; + + if (!user) continue; + if (userId && user.id != userId) continue; + + try { + const { mariadb_user, mariadb_host, mariadb_pass, id } = user; + const existingUser = await noDatabaseDbHandler( + `SELECT * FROM mysql.user WHERE User = '${mariadb_user}' AND Host = '${mariadb_host}'` + ); + + const existingMariaDBUserArray = + userId && sqlUserID + ? await dbHandler({ + query: `SELECT * FROM mariadb_users WHERE id = ? AND user_id = ?`, + values: [sqlUserID, userId], + }) + : null; + + /** + * @type {import("../../types").MYSQL_mariadb_users_table_def | undefined} + */ + const activeMariadbUserObject = Array.isArray( + existingMariaDBUserArray + ) + ? existingMariaDBUserArray?.[0] + : undefined; + + const isPrimary = activeMariadbUserObject + ? String(activeMariadbUserObject.primary)?.match(/1/) + ? true + : false + : false; + + const isUserExisting = Boolean(existingUser?.[0]?.User); + + const isThisPrimaryHost = Boolean( + mariadbUserHost == defaultMariadbUserHost + ); + + const dslUsername = `dsql_user_${id}`; + const dsqlPassword = activeMariadbUserObject?.password + ? activeMariadbUserObject.password + : isUserExisting + ? mariadb_pass + : generator.generate({ + length: 16, + numbers: true, + symbols: true, + uppercase: true, + exclude: "*#.'`\"", + }); + + const encryptedPassword = activeMariadbUserObject?.password + ? activeMariadbUserObject.password + : isUserExisting + ? mariadb_pass + : encrypt({ + data: dsqlPassword, + encryptionKey: process.env.DSQL_ENCRYPTION_PASSWORD, + encryptionSalt: process.env.DSQL_ENCRYPTION_SALT, + }); + if ( + !isUserExisting && + !sqlUserID && + !isPrimary && + !mariadbUserHost && + !mariadbUser + ) { + const createNewUser = await noDatabaseDbHandler( + `CREATE USER IF NOT EXISTS '${dslUsername}'@'${defaultMariadbUserHost}' IDENTIFIED BY '${dsqlPassword}' REQUIRE SSL` + ); + + console.log("createNewUser", createNewUser); + + console.log( + `User ${user.id}: ${user.first_name} ${user.last_name} SQL credentials successfully updated.` + ); + + const updateUser = await dbHandler({ + query: `UPDATE users SET mariadb_user = ?, mariadb_host = ?, mariadb_pass = ? WHERE id = ?`, + values: [ + dslUsername, + defaultMariadbUserHost, + encryptedPassword, + user.id, + ], + }); + } + + if (isPrimary) { + const finalHost = mariadbUserHost + ? mariadbUserHost + : mariadb_host; + + const updateUser = await dbHandler({ + query: `UPDATE users SET mariadb_user = ?, mariadb_host = ?, mariadb_pass = ? WHERE id = ?`, + values: [ + dslUsername, + finalHost, + encryptedPassword, + user.id, + ], + }); + } + + ////////////////////////////////////////////// + ////////////////////////////////////////////// + ////////////////////////////////////////////// + + /** + * @description Handle mariadb_users table + */ + const existingMariadbPrimaryUser = await dbHandler({ + query: `SELECT * FROM mariadb_users WHERE user_id = ? AND \`primary\` = 1`, + values: [id], + }); + + const isPrimaryUserExisting = Boolean( + Array.isArray(existingMariadbPrimaryUser) && + existingMariadbPrimaryUser?.[0]?.user_id + ); + + /** @type {import("./handleGrants").GrantType[]} */ + const primaryUserGrants = [ + { + database: "*", + table: "*", + privileges: ["ALL"], + }, + ]; + + if (!isPrimaryUserExisting) { + const insertPrimaryMariadbUser = await dbHandler({ + query: `INSERT INTO mariadb_users (user_id, username, password, \`primary\`, grants) VALUES (?, ?, ?, ?, ?)`, + values: [ + id, + dslUsername, + encryptedPassword, + "1", + JSON.stringify(primaryUserGrants), + ], + }); + } + + ////////////////////////////////////////////// + + const existingExtraMariadbUsers = await dbHandler({ + query: `SELECT * FROM mariadb_users WHERE user_id = ? AND \`primary\` != '1'`, + values: [id], + }); + + if (Array.isArray(existingExtraMariadbUsers)) { + for (let i = 0; i < existingExtraMariadbUsers.length; i++) { + const mariadbUser = existingExtraMariadbUsers[i]; + const { + user_id, + username, + host, + password, + primary, + grants, + } = mariadbUser; + + if (mariadbUser && username != mariadbUser) continue; + if (mariadbUserHost && host != mariadbUserHost) continue; + + const decrptedPassword = decrypt({ + encryptedString: password, + encryptionKey: process.env.DSQL_ENCRYPTION_PASSWORD, + encryptionSalt: process.env.DSQL_ENCRYPTION_SALT, + }); + + const existingExtraMariadbUser = await noDatabaseDbHandler( + `SELECT * FROM mysql.user WHERE User = '${username}' AND Host = '${host}'` + ); + + const isExtraMariadbUserExisting = Boolean( + existingExtraMariadbUser?.[0]?.User + ); + + if (!isExtraMariadbUserExisting) { + await noDatabaseDbHandler( + `CREATE USER IF NOT EXISTS '${username}'@'${host}' IDENTIFIED BY '${decrptedPassword}' REQUIRE SSL` + ); + } + + const isGrantHandled = await handleGrants({ + username, + host, + grants: + grants && typeof grants == "string" + ? JSON.parse(grants) + : [], + userId: String(userId), + }); + + if (!isGrantHandled) { + console.log( + `Error in handling grants for user ${username}@${host}` + ); + } + } + } + + ////////////////////////////////////////////// + ////////////////////////////////////////////// + ////////////////////////////////////////////// + } catch (/** @type {any} */ error) { + console.log(`Error in adding SQL user =>`, error.message); + } + } + + process.exit(); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// +} + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +module.exports = refreshUsersAndGrants; diff --git a/package-shared/shell/mariadb-users/resetSQLPasswords.js b/package-shared/shell/mariadb-users/resetSQLPasswords.js new file mode 100755 index 0000000..c0823c8 --- /dev/null +++ b/package-shared/shell/mariadb-users/resetSQLPasswords.js @@ -0,0 +1,105 @@ +// @ts-check + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +require("dotenv").config({ path: "../../.env" }); +const generator = require("generate-password"); +const noDatabaseDbHandler = require("../utils/noDatabaseDbHandler"); +const dbHandler = require("../utils/dbHandler"); +const encrypt = require("../../functions/dsql/encrypt"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Create database from Schema Function + * ============================================================================== + * @param {object} params - Single object params + * @param {number|string|null} params.userId - User ID or null + */ +async function resetSQLCredentialsPasswords() { + /** + * @description Users + * @type {*[] | null} + */ // @ts-ignore + const users = await dbHandler({ + query: `SELECT * FROM users`, + }); + + if (!users) { + process.exit(); + } + + for (let i = 0; i < users.length; i++) { + const user = users[i]; + + if (!user) continue; + + try { + /** + * @type {any[]} + */ // @ts-ignore + const maridbUsers = await dbHandler({ + query: `SELECT * FROM mysql.user WHERE User = 'dsql_user_${user.id}'`, + }); + + for (let j = 0; j < maridbUsers.length; j++) { + const { User, Host } = maridbUsers[j]; + + const password = generator.generate({ + length: 16, + numbers: true, + symbols: true, + uppercase: true, + exclude: "*#.'`\"", + }); + + const encryptedPassword = encrypt({ + data: password, + encryptionKey: process.env.DSQL_ENCRYPTION_PASSWORD, + encryptionSalt: process.env.DSQL_ENCRYPTION_SALT, + }); + + await noDatabaseDbHandler( + `SET PASSWORD FOR '${User}'@'${Host}' = PASSWORD('${password}')` + ); + + if (user.mariadb_user == User && user.mariadb_host == Host) { + const updateUser = await dbHandler({ + query: `UPDATE users SET mariadb_pass = ? WHERE id = ?`, + values: [encryptedPassword, user.id], + }); + } + + console.log( + `User ${user.id}: ${user.first_name} ${user.last_name} Password Updated successfully added.` + ); + } + } catch (/** @type {any} */ error) { + console.log( + `Error Updating User ${user.id} Password =>`, + error.message + ); + } + } + + process.exit(); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// +} + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +resetSQLCredentialsPasswords(); diff --git a/package-shared/shell/mariadb-users/users/create-user.js b/package-shared/shell/mariadb-users/users/create-user.js new file mode 100755 index 0000000..6b2d145 --- /dev/null +++ b/package-shared/shell/mariadb-users/users/create-user.js @@ -0,0 +1,185 @@ +// @ts-check + +const path = require("path"); +require("dotenv").config({ path: "../../../.env" }); +const fs = require("fs"); +const { execSync } = require("child_process"); +const EJSON = require("../../../utils/ejson"); +const DB_HANDLER = require("../../../utils/backend/global-db/DB_HANDLER"); +const addDbEntry = require("../../../functions/backend/db/addDbEntry"); +const addMariadbUser = require("../../../functions/backend/addMariadbUser"); +const updateDbEntry = require("../../../functions/backend/db/updateDbEntry"); +const hashPassword = require("../../../functions/dsql/hashPassword"); + +const tmpDir = process.argv[process.argv.length - 1]; + +/** + * # Create New User + */ +async function createUser() { + /** + * Validate Form + * + * @description Check if request body is valid + */ + try { + const isTmpDir = Boolean(tmpDir?.match(/\.json$/)); + const targetPath = isTmpDir + ? path.resolve(process.cwd(), tmpDir) + : path.resolve(__dirname, "./new-user.json"); + + const userObj = EJSON.parse(fs.readFileSync(targetPath, "utf-8")); + + if (typeof userObj !== "object" || Array.isArray(userObj)) + throw new Error("User Object Invalid!"); + + const ROOT_DIR = path.resolve(__dirname, "../../../"); + + /** + * Validate Form + * + * @description Check if request body is valid + */ + const first_name = userObj.first_name; + const last_name = userObj.last_name; + const email = userObj.email; + const password = userObj.password; + const username = userObj.username; + + if (!email?.match(/.*@.*\..*/)) return false; + + if ( + !first_name?.match(/^[a-zA-Z]+$/) || + !last_name?.match(/^[a-zA-Z]+$/) + ) + return false; + + if (password?.match(/ /)) return false; + + if (username?.match(/ /)) return false; + + let hashedPassword = hashPassword({ + encryptionKey: process.env.DSQL_ENCRYPTION_PASSWORD || "", + password: password, + }); + + let existingUser = await DB_HANDLER( + `SELECT * FROM users WHERE email='${email}'` + ); + + if (existingUser?.[0]) { + console.log("User Exists"); + return false; + } + + const newUser = await addDbEntry({ + dbFullName: "datasquirel", + tableName: "users", + data: { ...userObj, password: hashedPassword }, + }); + + if (!newUser?.insertId) return false; + + /** + * Add a Mariadb User for this User + */ + await addMariadbUser({ userId: newUser.insertId }); + + const STATIC_ROOT = process.env.DSQL_STATIC_SERVER_DIR; + + if (!STATIC_ROOT) { + console.log("Static File ENV not Found!"); + throw new Error("No Static Path"); + } + + /** + * Create new user folder and file + * + * @description Create new user folder and file + */ + let newUserSchemaFolderPath = `${process.env.DSQL_USER_DB_SCHEMA_PATH}/user-${newUser.insertId}`; + let newUserMediaFolderPath = path.join( + STATIC_ROOT, + `images/user-images/user-${newUser.insertId}` + ); + + fs.mkdirSync(newUserSchemaFolderPath, { recursive: true }); + fs.mkdirSync(newUserMediaFolderPath, { recursive: true }); + + fs.writeFileSync( + `${newUserSchemaFolderPath}/main.json`, + JSON.stringify([]), + "utf8" + ); + + const imageBasePath = path.join( + STATIC_ROOT, + `images/user-images/user-${newUser.insertId}` + ); + + if (!fs.existsSync(imageBasePath)) { + fs.mkdirSync(imageBasePath, { recursive: true }); + } + + let imagePath = path.join( + STATIC_ROOT, + `images/user-images/user-${newUser.insertId}/user-${newUser.insertId}-profile.jpg` + ); + + let imageThumbnailPath = path.join( + STATIC_ROOT, + `images/user-images/user-${newUser.insertId}/user-${newUser.insertId}-profile-thumbnail.jpg` + ); + + let prodImageUrl = imagePath.replace( + STATIC_ROOT, + process.env.DSQL_STATIC_HOST || "" + ); + let prodImageThumbnailUrl = imageThumbnailPath.replace( + STATIC_ROOT, + process.env.DSQL_STATIC_HOST || "" + ); + + fs.copyFileSync( + path.join(ROOT_DIR, "/public/images/user-preset.png"), + imagePath + ); + fs.copyFileSync( + path.join(ROOT_DIR, "/public/images/user-preset-thumbnail.png"), + imageThumbnailPath + ); + + execSync(`chmod 644 ${imagePath} ${imageThumbnailPath}`); + + const updateImages = await updateDbEntry({ + dbFullName: "datasquirel", + tableName: "users", + identifierColumnName: "id", + identifierValue: newUser.insertId, + data: { + image: prodImageUrl, + image_thumbnail: prodImageThumbnailUrl, + }, + }); + + if (isTmpDir) { + try { + fs.unlinkSync(path.resolve(process.cwd(), tmpDir)); + } catch (error) {} + } + + return true; + } catch (/** @type {any} */ error) { + console.log(`Error in creating user => ${error.message}`); + return false; + } +} + +createUser().then((res) => { + if (res) { + console.log("User Creation Success!!!"); + } else { + console.log("User Creation Failed!"); + } + process.exit(); +}); diff --git a/package-shared/shell/mariadb-users/users/update-user.js b/package-shared/shell/mariadb-users/users/update-user.js new file mode 100755 index 0000000..575502e --- /dev/null +++ b/package-shared/shell/mariadb-users/users/update-user.js @@ -0,0 +1,74 @@ +// @ts-check + +const path = require("path"); +require("dotenv").config({ path: "../../../.env" }); +const fs = require("fs"); +const EJSON = require("../../../utils/ejson"); +const hashPassword = require("../../../functions/dsql/hashPassword"); +const updateDbEntry = require("../../../functions/backend/db/updateDbEntry"); + +const tmpDir = process.argv[process.argv.length - 1]; + +/** + * # Create New User + */ +async function createUser() { + /** + * Validate Form + * + * @description Check if request body is valid + */ + try { + const isTmpDir = Boolean(tmpDir?.match(/\.json$/)); + const targetPath = isTmpDir + ? path.resolve(process.cwd(), tmpDir) + : path.resolve(__dirname, "./update-user.json"); + const updateUserObj = EJSON.parse(fs.readFileSync(targetPath, "utf-8")); + + if (typeof updateUserObj !== "object" || Array.isArray(updateUserObj)) + throw new Error("Update User Object Invalid!"); + + let hashedPassword = updateUserObj.password + ? hashPassword({ + encryptionKey: process.env.DSQL_ENCRYPTION_PASSWORD || "", + password: updateUserObj.password, + }) + : undefined; + + let updatePayload = { ...updateUserObj }; + if (hashedPassword) { + updatePayload["password"] = hashedPassword; + } + + /** @type {any} */ + const newUser = await updateDbEntry({ + dbFullName: "datasquirel", + tableName: "users", + data: { ...updatePayload, id: undefined }, + identifierColumnName: "id", + identifierValue: updatePayload.id, + }); + + if (!newUser?.affectedRows) return false; + + if (isTmpDir) { + try { + fs.unlinkSync(path.resolve(process.cwd(), tmpDir)); + } catch (error) {} + } + + return true; + } catch (/** @type {any} */ error) { + console.log(`Error in creating user => ${error.message}`); + return false; + } +} + +createUser().then((res) => { + if (res) { + console.log("User Update Success!!!"); + } else { + console.log("User Update Failed!"); + } + process.exit(); +}); diff --git a/package-shared/shell/mariadb-users/users/update-user.json b/package-shared/shell/mariadb-users/users/update-user.json new file mode 100644 index 0000000..49f2a0f --- /dev/null +++ b/package-shared/shell/mariadb-users/users/update-user.json @@ -0,0 +1,4 @@ +{ + "id": "1", + "verification_status": "1" +} diff --git a/package-shared/shell/readImage.js b/package-shared/shell/readImage.js new file mode 100755 index 0000000..654e0b4 --- /dev/null +++ b/package-shared/shell/readImage.js @@ -0,0 +1,24 @@ +// @ts-check + +const fs = require("fs"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Grab Schema + * + * @description Grab Schema + */ +const imageBase64 = fs.readFileSync( + "./../public/images/unique-tokens-icon.png", + "base64" +); + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// diff --git a/package-shared/shell/recoverMainJsonFromDb.js b/package-shared/shell/recoverMainJsonFromDb.js new file mode 100755 index 0000000..e812686 --- /dev/null +++ b/package-shared/shell/recoverMainJsonFromDb.js @@ -0,0 +1,120 @@ +// @ts-check + +const fs = require("fs"); +require("dotenv").config({ path: "./../.env" }); + +//////////////////////////////////////// + +const varDatabaseDbHandler = require("../functions/backend/varDatabaseDbHandler"); +const DB_HANDLER = require("../utils/backend/global-db/DB_HANDLER"); + +/** ****************************************************************************** */ + +const userId = + process.argv.indexOf("--userId") >= 0 + ? process.argv[process.argv.indexOf("--userId") + 1] + : null; + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Grab Schema + * + * @description Grab Schema + */ +async function recoverMainJsonFromDb() { + if (!userId) { + console.log("No user Id provided"); + return; + } + + const databases = await DB_HANDLER( + `SELECT * FROM user_databases WHERE user_id='${userId}'` + ); + + const dbWrite = []; + + for (let i = 0; i < databases.length; i++) { + const { id, db_name, db_slug, db_full_name, db_image, db_description } = + databases[i]; + + /** @type {any} */ + const dbObject = { + dbName: db_name, + dbSlug: db_slug, + dbFullName: db_full_name, + dbDescription: db_description, + dbImage: db_image, + tables: [], + }; + + const tables = await DB_HANDLER( + `SELECT * FROM user_database_tables WHERE user_id='${userId}' AND db_id='${id}'` + ); + + for (let j = 0; j < tables.length; j++) { + const { table_name, table_slug, table_description } = tables[j]; + + /** @type {any} */ + const tableObject = { + tableName: table_slug, + tableFullName: table_name, + fields: [], + indexes: [], + }; + + const tableFields = await varDatabaseDbHandler({ + database: db_full_name, + queryString: `SHOW COLUMNS FROM ${table_slug}`, + }); + + for (let k = 0; k < tableFields.length; k++) { + const { Field, Type, Null, Default, Key } = tableFields[k]; + + /** @type {any} */ + const fieldObject = { + fieldName: Field, + dataType: Type.toUpperCase(), + }; + + if (Default?.match(/./) && !Default?.match(/timestamp/i)) + fieldObject["defaultValue"] = Default; + if (Key?.match(/pri/i)) { + fieldObject["primaryKey"] = true; + fieldObject["autoIncrement"] = true; + } + if (Default?.match(/timestamp/i)) + fieldObject["defaultValueLiteral"] = Default; + if (Null?.match(/yes/i)) fieldObject["nullValue"] = true; + if (Null?.match(/no/i)) fieldObject["notNullValue"] = true; + + tableObject.fields.push(fieldObject); + } + + dbObject.tables.push(tableObject); + } + + dbWrite.push(dbObject); + } + + fs.writeFileSync( + `${String( + process.env.DSQL_USER_DB_SCHEMA_PATH + )}/user-${userId}/main.json`, + JSON.stringify(dbWrite, null, 4), + "utf-8" + ); + + process.exit(); +} + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +recoverMainJsonFromDb(); diff --git a/package-shared/shell/resetSQLCredentials.js b/package-shared/shell/resetSQLCredentials.js new file mode 100755 index 0000000..cfb6aaf --- /dev/null +++ b/package-shared/shell/resetSQLCredentials.js @@ -0,0 +1,103 @@ +// @ts-check + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +require("dotenv").config({ path: "./../.env" }); +const generator = require("generate-password"); +const noDatabaseDbHandler = require("./utils/noDatabaseDbHandler"); +const dbHandler = require("./utils/dbHandler"); +const encrypt = require("../functions/dsql/encrypt"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Create database from Schema Function + * ============================================================================== + * @param {object} params - Single object params + * @param {number|string|null} params.userId - User ID or null + */ +async function resetSQLCredentials() { + /** + * @description Users + * @type {*[] | null} + */ // @ts-ignore + const users = await dbHandler({ + query: `SELECT * FROM users`, + }); + + if (!users) { + process.exit(); + } + + for (let i = 0; i < users.length; i++) { + const user = users[i]; + + if (!user) continue; + + const defaultMariadbUserHost = process.env.DSQL_DB_HOST || "127.0.0.1"; + + try { + const username = `dsql_user_${user.id}`; + const password = generator.generate({ + length: 16, + numbers: true, + symbols: true, + uppercase: true, + exclude: "*#.'`\"", + }); + const encryptedPassword = encrypt({ data: password }); + + await noDatabaseDbHandler(`DROP USER IF EXISTS '${username}'@'%'`); + await noDatabaseDbHandler( + `DROP USER IF EXISTS '${username}'@'${defaultMariadbUserHost}'` + ); + + await noDatabaseDbHandler( + `CREATE USER IF NOT EXISTS '${username}'@'${defaultMariadbUserHost}' IDENTIFIED BY '${password}' REQUIRE SSL` + ); + + await noDatabaseDbHandler( + `GRANT ALL PRIVILEGES ON \`datasquirel_user_${user.id}_%\`.* TO '${username}'@'${defaultMariadbUserHost}'` + ); + + await noDatabaseDbHandler(`FLUSH PRIVILEGES`); + + const updateUser = await dbHandler({ + query: `UPDATE users SET mariadb_user = ?, mariadb_host = ?, mariadb_pass = ? WHERE id = ?`, + values: [ + username, + defaultMariadbUserHost, + encryptedPassword, + user.id, + ], + }); + + console.log( + `User ${user.id}: ${user.first_name} ${user.last_name} SQL credentials successfully added.` + ); + } catch (/** @type {any} */ error) { + console.log(`Error in adding SQL user =>`, error.message); + } + } + + process.exit(); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// +} + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +resetSQLCredentials(); diff --git a/package-shared/shell/resetSQLCredentialsPasswords.js b/package-shared/shell/resetSQLCredentialsPasswords.js new file mode 100755 index 0000000..d34300f --- /dev/null +++ b/package-shared/shell/resetSQLCredentialsPasswords.js @@ -0,0 +1,90 @@ +// @ts-check + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +require("dotenv").config({ path: "./../.env" }); +const generator = require("generate-password"); +const noDatabaseDbHandler = require("./utils/noDatabaseDbHandler"); +const dbHandler = require("./utils/dbHandler"); +const encrypt = require("../functions/dsql/encrypt"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Create database from Schema Function + * ============================================================================== + * @param {object} params - Single object params + * @param {number|string|null} params.userId - User ID or null + */ +async function resetSQLCredentialsPasswords() { + /** + * @description Users + * @type {*[] | null} + */ // @ts-ignore + const users = await dbHandler({ + query: `SELECT * FROM users`, + }); + + if (!users) { + process.exit(); + } + + for (let i = 0; i < users.length; i++) { + const user = users[i]; + + if (!user) continue; + + const defaultMariadbUserHost = process.env.DSQL_DB_HOST || "127.0.0.1"; + + try { + const username = `dsql_user_${user.id}`; + const password = generator.generate({ + length: 16, + numbers: true, + symbols: true, + uppercase: true, + exclude: "*#.'`\"", + }); + const encryptedPassword = encrypt({ data: password }); + + await noDatabaseDbHandler( + `SET PASSWORD FOR '${username}'@'${defaultMariadbUserHost}' = PASSWORD('${password}')` + ); + + const updateUser = await dbHandler({ + query: `UPDATE users SET mariadb_pass = ? WHERE id = ?`, + values: [encryptedPassword, user.id], + }); + + console.log( + `User ${user.id}: ${user.first_name} ${user.last_name} Password Updated successfully added.` + ); + } catch (/** @type {any} */ error) { + console.log( + `Error Updating User ${user.id} Password =>`, + error.message + ); + } + } + + process.exit(); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// +} + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +resetSQLCredentialsPasswords(); diff --git a/package-shared/shell/setSQLCredentials.js b/package-shared/shell/setSQLCredentials.js new file mode 100755 index 0000000..c76b6e1 --- /dev/null +++ b/package-shared/shell/setSQLCredentials.js @@ -0,0 +1,93 @@ +// @ts-check + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +require("dotenv").config({ path: "./../.env" }); +const generator = require("generate-password"); +const noDatabaseDbHandler = require("./utils/noDatabaseDbHandler"); +const dbHandler = require("./utils/dbHandler"); +const encrypt = require("../functions/dsql/encrypt"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Create database from Schema Function + * ============================================================================== + * @param {object} params - Single object params + * @param {number|string|null} params.userId - User ID or null + */ +async function setSQLCredentials() { + /** + * @description Users + * @type {*[] | null} + */ // @ts-ignore + const users = await dbHandler({ + query: `SELECT * FROM users`, + }); + + if (!users) { + process.exit(); + } + + for (let i = 0; i < users.length; i++) { + const user = users[i]; + + if (!user) continue; + if (user.mariadb_user && user.mariadb_pass) { + continue; + } + + try { + const username = `dsql_user_${user.id}`; + const password = generator.generate({ + length: 16, + numbers: true, + symbols: true, + uppercase: true, + exclude: "*#.'`\"", + }); + const encryptedPassword = encrypt({ data: password }); + + await noDatabaseDbHandler( + `CREATE USER IF NOT EXISTS '${username}'@'127.0.0.1' IDENTIFIED BY '${password}' REQUIRE SSL` + ); + + await noDatabaseDbHandler( + `GRANT ALL PRIVILEGES ON \`datasquirel\\_user\\_${user.id}\\_%\`.* TO '${username}'@'127.0.0.1'` + ); + await noDatabaseDbHandler(`FLUSH PRIVILEGES`); + + const updateUser = await dbHandler({ + query: `UPDATE users SET mariadb_user = ?, mariadb_host = '127.0.0.1' mariadb_pass = ? WHERE id = ?`, + values: [username, encryptedPassword, user.id], + }); + + console.log( + `User ${user.id}: ${user.first_name} ${user.last_name} SQL credentials successfully added.` + ); + } catch (/** @type {any} */ error) { + console.log(`Error in adding SQL user =>`, error.message); + } + } + + process.exit(); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// +} + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +setSQLCredentials(); diff --git a/package-shared/shell/tailwindWatch.js b/package-shared/shell/tailwindWatch.js new file mode 100755 index 0000000..e947252 --- /dev/null +++ b/package-shared/shell/tailwindWatch.js @@ -0,0 +1,29 @@ +// @ts-check + +const fs = require("fs"); +const { exec } = require("child_process"); + +require("dotenv").config({ path: "./../.env" }); + +const sourceFile = process.argv.indexOf("--src") >= 0 ? process.argv[process.argv.indexOf("--src") + 1] : null; +const destinationFile = process.argv.indexOf("--dst") >= 0 ? process.argv[process.argv.indexOf("--dst") + 1] : null; + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +console.log("Running Tailwind CSS compiler ..."); + +fs.watch("./../", (curr, prev) => { + exec(`npx tailwindcss -i ./tailwind/main.css -o ./styles/tailwind.css`, (error, stdout, stderr) => { + if (error) { + console.log("ERROR =>", error.message); + return; + } + + console.log("Tailwind CSS Compilation \x1b[32msuccessful\x1b[0m!"); + }); +}); diff --git a/package-shared/shell/test-external-server.js b/package-shared/shell/test-external-server.js new file mode 100755 index 0000000..c5c93eb --- /dev/null +++ b/package-shared/shell/test-external-server.js @@ -0,0 +1,58 @@ +// @ts-check + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +require("dotenv").config({ path: "./.env" }); +const grabDbSSL = require("../utils/backend/grabDbSSL"); +const mysql = require("serverless-mysql"); + +const connection = mysql({ + config: { + host: process.env.DSQL_DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASS, + // database: process.env.DSQL_DB_NAME, + charset: "utf8mb4", + ssl: grabDbSSL(), + }, +}); + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +/** + * # Main DB Handler Function + * @async + * + * @param {object} params + * @param {string} params.query + * @param {string[] | object} [params.values] + * @param {string} [params.database] + * + * @returns {Promise} + */ +(async () => { + /** + * Switch Database + * + * @description If a database is provided, switch to it + */ + try { + const result = await connection.query("SHOW DATABASES"); + + const parsedResults = JSON.parse(JSON.stringify(result)); + + console.log("parsedResults =>", parsedResults); + } catch (/** @type {any} */ error) { + console.log("Connection query ERROR =>", error.message); + } finally { + connection.end(); + process.exit(); + } +})(); diff --git a/package-shared/shell/test.js b/package-shared/shell/test.js new file mode 100755 index 0000000..51cb797 --- /dev/null +++ b/package-shared/shell/test.js @@ -0,0 +1,221 @@ +require("dotenv").config({ path: "./../.env" }); + +const dbEngine = require("@moduletrace/datasquirel/engine"); +const http = require("http"); + +const datasquirel = require("@moduletrace/datasquirel"); + +`curl http://www.dataden.tech`; + +datasquirel + .get({ + db: "test", + key: process.env.DATASQUIREL_READ_ONLY_KEY, + query: "SELECT title, slug, body FROM blog_posts", + }) + .then((response) => { + console.log(response); + }); + +// dbEngine.db +// .query({ +// dbFullName: "datasquirel", +// dbHost: process.env.DSQL_DB_HOST, +// dbPassword: process.env.DSQL_DB_PASSWORD, +// dbUsername: process.env.DSQL_DB_USERNAME, +// query: "SHOW TABLES", +// }) +// .then((res) => { +// console.log("res =>", res); +// }); + +// run({ +// key: "bc057a2cd57922e085739c89b4985e5e676b655d7cc0ba7604659cad0a08c252040120c06597a5d22959a502a44bd816", +// db: "showmerebates", +// query: "SELECT * FROM test_table", +// }).then((res) => { +// console.log("res =>", res); +// }); + +post({ + key: "3115fce7ea7772eda75f8f0e55a1414c5c018b4920f4bc99a2d4d7000bac203c15a7036fd3d7ef55ae67a002d4c757895b5c58ff82079a04ba6d42d23d4353256985090959a58a9af8e03cb277fc7895413e6f28ae11b1cc15329c7f94cdcf9a795f54d6e1d319adc287dc147143e62d", + database: "showmerebates", + query: { + action: "delete", + table: "test_table", + identifierColumnName: "id", + identifierValue: 6, + }, +}).then((res) => { + console.log("res =>", res); +}); + +async function run({ key, db, query }) { + const httpResponse = await new Promise((resolve, reject) => { + http.request( + { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: key, + }, + hostname: "localhost", + port: 7070, + path: `/api/query/get?db=${db}&query=${query + .replace(/\n|\r|\n\r/g, "") + .replace(/ {2,}/g, " ") + .replace(/ /g, "+")}`, + }, + + /** + * Callback Function + * + * @description https request callback + */ + (response) => { + var str = ""; + + response.on("data", function (chunk) { + str += chunk; + }); + + response.on("end", function () { + resolve(JSON.parse(str)); + }); + + response.on("error", (err) => { + reject(err); + }); + } + ).end(); + }); + + return httpResponse; +} + +/** + * @typedef {Object} PostReturn + * @property {boolean} success - Did the function run successfully? + * @property {(Object[]|string)} [payload=[]] - The Y Coordinate + */ + +/** + * @typedef {object} PostDataPayload + * @property {string} action - "insert" | "update" | "delete" + * @property {string} table - Table name(slug) eg "blog_posts" + * @property {string} identifierColumnName - Table identifier field name => eg. "id" OR "email" + * @property {string} identifierValue - Corresponding value of the selected field name => This + * checks identifies a the target row for "update" or "delete". Not needed for "insert" + * @property {object} data - Table insert payload object => This must have keys that match + * table fields + * @property {string?} duplicateColumnName - Duplicate column name to check for + * @property {string?} duplicateColumnValue - Duplicate column value to match. If no "update" param + * provided, function will return null + * @property {boolean?} update - Should the "insert" action update the existing entry if indeed + * the entry with "duplicateColumnValue" exists? + */ + +/** + * Post request + * ============================================================================== + * @async + * + * @param {Object} params - Single object passed + * @param {string} params.key - FULL ACCESS API Key + * @param {string} params.database - Database Name + * @param {PostDataPayload} params.query - SQL query String or Request Object + * + * @returns { Promise } - Return Object + */ +async function post({ key, query, database }) { + /** + * Make https request + * + * @description make a request to datasquirel.com + */ + const httpResponse = await new Promise((resolve, reject) => { + const reqPayloadString = JSON.stringify({ + query, + database, + }).replace(/\n|\r|\n\r/gm, ""); + + try { + JSON.parse(reqPayloadString); + } catch (error) { + console.log(error); + console.log(reqPayloadString); + + return { + success: false, + payload: null, + error: "Query object is invalid. Please Check query data values", + }; + } + + const reqPayload = reqPayloadString; + + const httpsRequest = http.request( + { + method: "POST", + headers: { + "Content-Type": "application/json", + "Content-Length": Buffer.from(reqPayload).length, + Authorization: key, + }, + hostname: "localhost", + port: 7070, + path: `/api/query/post`, + }, + + /** + * Callback Function + * + * @description https request callback + */ + (response) => { + var str = ""; + + response.on("data", function (chunk) { + str += chunk; + }); + + response.on("end", function () { + try { + resolve(JSON.parse(str)); + } catch (error) { + console.log(error.message); + console.log("Fetched Payload =>", str); + + resolve({ + success: false, + payload: null, + error: error.message, + }); + } + }); + + response.on("error", (err) => { + resolve({ + success: false, + payload: null, + error: err.message, + }); + }); + } + ); + + httpsRequest.write(reqPayload); + + httpsRequest.on("error", (error) => { + console.log("HTTPS request ERROR =>", error.message); + }); + + httpsRequest.end(); + }); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + return httpResponse; +} diff --git a/package-shared/shell/testSQLEscape.js b/package-shared/shell/testSQLEscape.js new file mode 100755 index 0000000..32b8176 --- /dev/null +++ b/package-shared/shell/testSQLEscape.js @@ -0,0 +1,102 @@ +// @ts-check + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +require("dotenv").config({ path: "./../.env" }); +const generator = require("generate-password"); +const noDatabaseDbHandler = require("./utils/noDatabaseDbHandler"); +const dbHandler = require("./utils/dbHandler"); +const encrypt = require("../functions/dsql/encrypt"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Create database from Schema Function + * ============================================================================== + * @param {object} params - Single object params + * @param {number|string|null} params.userId - User ID or null + */ +async function testSQLEscape() { + /** + * @description Users + * @type {*[] | null} + */ // @ts-ignore + const users = await dbHandler({ + query: `SELECT * FROM users`, + }); + + if (!users) { + process.exit(); + } + + for (let i = 0; i < users.length; i++) { + const user = users[i]; + + if (!user) continue; + + const defaultMariadbUserHost = process.env.DSQL_DB_HOST || "127.0.0.1"; + + try { + const username = `dsql_user_${user.id}`; + const password = generator.generate({ + length: 16, + numbers: true, + symbols: true, + uppercase: true, + exclude: "*#.'`\"", + }); + const encryptedPassword = encrypt({ data: password }); + + await noDatabaseDbHandler( + `DROP USER '${username}'@'${defaultMariadbUserHost}'` + ); + + await noDatabaseDbHandler( + `CREATE USER IF NOT EXISTS '${username}'@'${defaultMariadbUserHost}' IDENTIFIED BY '${password}' REQUIRE SSL` + ); + + await noDatabaseDbHandler( + `GRANT ALL PRIVILEGES ON \`datasquirel\\_user\\_${user.id}\\_%\`.* TO '${username}'@'${defaultMariadbUserHost}'` + ); + + await noDatabaseDbHandler(`FLUSH PRIVILEGES`); + + const updateUser = await dbHandler({ + query: `UPDATE users SET mariadb_user = ?, mariadb_host = ? mariadb_pass = ? WHERE id = ?`, + values: [ + username, + defaultMariadbUserHost, + encryptedPassword, + user.id, + ], + }); + + console.log( + `User ${user.id}: ${user.first_name} ${user.last_name} SQL credentials successfully added.` + ); + } catch (/** @type {any} */ error) { + console.log(`Error in adding SQL user =>`, error.message); + } + } + + process.exit(); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// +} + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +testSQLEscape(); diff --git a/package-shared/shell/updateChildrenTablesOnDb.js b/package-shared/shell/updateChildrenTablesOnDb.js new file mode 100755 index 0000000..eb3366b --- /dev/null +++ b/package-shared/shell/updateChildrenTablesOnDb.js @@ -0,0 +1,80 @@ +// @ts-check + +const DB_HANDLER = require("../utils/backend/global-db/DB_HANDLER"); +const fs = require("fs"); +require("dotenv").config({ path: "./../.env" }); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +async function updateChildrenTablesOnDb() { + /** + * Grab Schema + * + * @description Grab Schema + */ + try { + const rootDir = String(process.env.DSQL_USER_DB_SCHEMA_PATH); + const userFolders = fs.readdirSync(rootDir); + + for (let i = 0; i < userFolders.length; i++) { + const folder = userFolders[i]; + const userId = folder.replace(/user-/, ""); + const databases = JSON.parse( + fs.readFileSync(`${rootDir}/${folder}/main.json`, "utf-8") + ); + + for (let j = 0; j < databases.length; j++) { + const db = databases[j]; + const dbTables = db.tables; + for (let k = 0; k < dbTables.length; k++) { + const table = dbTables[k]; + + if (table?.childTable) { + const originTableName = table.childTableName; + const originDbName = table.childTableDbFullName; + + const WHERE_CLAUSE = `WHERE user_id='${userId}' AND db_slug='${db.dbSlug}' AND table_slug='${table.tableName}'`; + + const existingTableInDb = await DB_HANDLER( + `SELECT * FROM user_database_tables ${WHERE_CLAUSE}` + ); + + if (existingTableInDb && existingTableInDb[0]) { + const updateChildrenTablesInfo = await DB_HANDLER( + `UPDATE user_database_tables SET child_table='1',child_table_parent_database='${originDbName}',child_table_parent_table='${originTableName}' WHERE id='${existingTableInDb[0].id}'` + ); + } + } + } + } + } + } catch (error) { + console.log(error); + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + process.exit(); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// +} + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +// const userArg = process.argv[process.argv.indexOf("--user")]; +// const externalUser = process.argv[process.argv.indexOf("--user") + 1]; + +updateChildrenTablesOnDb(); diff --git a/package-shared/shell/updateDateTimestamps.js b/package-shared/shell/updateDateTimestamps.js new file mode 100755 index 0000000..6729cf7 --- /dev/null +++ b/package-shared/shell/updateDateTimestamps.js @@ -0,0 +1,60 @@ +// @ts-check + +require("dotenv").config({ path: "./../.env" }); + +//////////////////////////////////////// + +const varDatabaseDbHandler = require("../functions/backend/varDatabaseDbHandler"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Grab Schema + * + * @description Grab Schema + */ +varDatabaseDbHandler({ + queryString: `SELECT user_database_tables.*,user_databases.db_full_name FROM user_database_tables JOIN user_databases ON user_database_tables.db_id=user_databases.id`, + database: "datasquirel", +}).then(async (tables) => { + for (let i = 0; i < tables.length; i++) { + const table = tables[i]; + const { + id, + user_id, + db_id, + db_full_name, + table_name, + table_slug, + table_description, + } = table; + + const tableInfo = await varDatabaseDbHandler({ + queryString: `SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='${db_full_name}' AND TABLE_NAME='${table_slug}'`, + database: db_full_name, + }); + + const updateCreationDateTimestamp = await varDatabaseDbHandler({ + queryString: `ALTER TABLE \`${table_slug}\` MODIFY COLUMN date_created_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP`, + database: db_full_name, + }); + + const updateDateTimestamp = await varDatabaseDbHandler({ + queryString: `ALTER TABLE \`${table_slug}\` MODIFY COLUMN date_updated_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`, + database: db_full_name, + }); + + console.log("Date Updated Column updated"); + } + + process.exit(); +}); + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// diff --git a/package-shared/shell/updateDbSlugsForTableRecords.js b/package-shared/shell/updateDbSlugsForTableRecords.js new file mode 100755 index 0000000..e1d0074 --- /dev/null +++ b/package-shared/shell/updateDbSlugsForTableRecords.js @@ -0,0 +1,56 @@ +// @ts-check + +require("dotenv").config({ path: "./../.env" }); + +const serverError = require("../functions/backend/serverError"); +const varDatabaseDbHandler = require("./utils/varDatabaseDbHandler"); +const DB_HANDLER = require("../utils/backend/global-db/DB_HANDLER"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Grab Schema + * + * @description Grab Schema + */ +varDatabaseDbHandler({ + queryString: `SELECT DISTINCT db_id FROM user_database_tables`, + database: "datasquirel", +}).then(async (tables) => { + // console.log(tables); + // process.exit(); + + for (let i = 0; i < tables.length; i++) { + const table = tables[i]; + + try { + const { db_id } = table; + + const dbSlug = await DB_HANDLER( + `SELECT db_slug FROM user_databases WHERE id='${db_id}'` + ); + + const updateTableSlug = await DB_HANDLER( + `UPDATE user_database_tables SET db_slug='${dbSlug[0].db_slug}' WHERE db_id='${db_id}'` + ); + } catch (/** @type {any} */ error) { + serverError({ + component: + "shell/updateDbSlugsForTableRecords/main-catch-error", + message: error.message, + user: {}, + }); + } + } + + process.exit(); +}); + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// diff --git a/package-shared/shell/updateSSLUsers.js b/package-shared/shell/updateSSLUsers.js new file mode 100755 index 0000000..01a7b76 --- /dev/null +++ b/package-shared/shell/updateSSLUsers.js @@ -0,0 +1,70 @@ +// @ts-check + +require("dotenv").config({ path: "./../.env" }); +const grabDbSSL = require("../utils/backend/grabDbSSL"); +const mysql = require("serverless-mysql"); + +const connection = mysql({ + config: { + host: process.env.DSQL_DB_HOST, + user: process.env.DSQL_DB_USERNAME, + password: process.env.DSQL_DB_PASSWORD, + database: process.env.DSQL_DB_NAME, + charset: "utf8mb4", + ssl: grabDbSSL(), + }, +}); + +/** + * # Main DB Handler Function + * @async + * + * @param {object} params + * @param {string} params.query + * @param {string[] | object} [params.values] + * @param {string} [params.database] + * + * @returns {Promise} + */ +(async () => { + /** + * Switch Database + * + * @description If a database is provided, switch to it + */ + try { + const result = await connection.query( + "SELECT user,host,ssl_type FROM mysql.user" + ); + const parsedResults = JSON.parse(JSON.stringify(result)); + + for (let i = 0; i < parsedResults.length; i++) { + const user = parsedResults[i]; + + if ( + user.User !== process.env.DSQL_DB_READ_ONLY_USERNAME || + user.User !== process.env.DSQL_DB_FULL_ACCESS_USERNAME || + !user.User?.match(/dsql_user_.*/i) + ) { + continue; + } + + const { User, Host, ssl_type } = user; + + if (ssl_type === "ANY") { + continue; + } + + const addUserSSL = await connection.query( + `ALTER USER '${User}'@'${Host}' REQUIRE SSL` + ); + + console.log(`addUserSSL => ${User}@${Host}`, addUserSSL); + } + } catch (/** @type {any} */ error) { + console.log("Connection query ERROR =>", error.message); + } finally { + connection.end(); + process.exit(); + } +})(); diff --git a/package-shared/shell/utils/camelJoinedtoCamelSpace.js b/package-shared/shell/utils/camelJoinedtoCamelSpace.js new file mode 100755 index 0000000..db7413a --- /dev/null +++ b/package-shared/shell/utils/camelJoinedtoCamelSpace.js @@ -0,0 +1,59 @@ +// @ts-check + +/** + * Convert Camel Joined Text to Camel Spaced Text + * ============================================================================== + * @description this function takes a camel cased text without spaces, and returns + * a camel-case-spaced text + * + * @param {string} text - text string without spaces + * + * @returns {string | null} + */ +module.exports = function camelJoinedtoCamelSpace(text) { + if (!text?.match(/./)) { + return ""; + } + + if (text?.match(/ /)) { + return text; + } + + if (text) { + let textArray = text.split(""); + + let capIndexes = []; + + for (let i = 0; i < textArray.length; i++) { + const char = textArray[i]; + + if (i === 0) continue; + if (char.match(/[A-Z]/)) { + capIndexes.push(i); + } + } + + let textChunks = [ + `${textArray[0].toUpperCase()}${text.substring(1, capIndexes[0])}`, + ]; + + for (let j = 0; j < capIndexes.length; j++) { + const capIndex = capIndexes[j]; + if (capIndex === 0) continue; + + const startIndex = capIndex + 1; + const endIndex = capIndexes[j + 1]; + + textChunks.push( + `${textArray[capIndex].toUpperCase()}${text.substring( + startIndex, + endIndex + )}` + ); + } + + return textChunks.join(" "); + } else { + return null; + } +}; diff --git a/engine/engine/utils/createTable.js b/package-shared/shell/utils/createTable.js old mode 100644 new mode 100755 similarity index 56% rename from engine/engine/utils/createTable.js rename to package-shared/shell/utils/createTable.js index 80d6db6..c43a14d --- a/engine/engine/utils/createTable.js +++ b/package-shared/shell/utils/createTable.js @@ -1,7 +1,9 @@ // @ts-check +const varDatabaseDbHandler = require("./varDatabaseDbHandler"); const generateColumnDescription = require("./generateColumnDescription"); const supplementTable = require("./supplementTable"); +const dbHandler = require("./dbHandler"); /** ****************************************************************************** */ /** ****************************************************************************** */ @@ -12,20 +14,24 @@ const supplementTable = require("./supplementTable"); /** * - * @param {object} param0 - * @param {string} param0.dbFullName - * @param {string} param0.tableName - * @param {any[]} param0.tableInfoArray - * @param {(params: import("./varDatabaseDbHandler").VarDbHandlerParam)=>any} param0.varDatabaseDbHandler - * @param {import("../../../package-shared/types").DSQL_DatabaseSchemaType} [param0.dbSchema] + * @param {object} params + * @param {string} params.dbFullName + * @param {string} params.tableName + * @param {any[]} params.tableInfoArray + * @param {import("../../types").DSQL_DatabaseSchemaType[]} [params.dbSchema] + * @param {import("../../types").DSQL_TableSchemaType} [params.tableSchema] + * @param {any} [params.recordedDbEntry] + * @param {boolean} [params.clone] - Is this a newly cloned table? * @returns */ module.exports = async function createTable({ dbFullName, tableName, tableInfoArray, - varDatabaseDbHandler, dbSchema, + clone, + tableSchema, + recordedDbEntry, }) { /** * Format tableInfoArray @@ -43,6 +49,50 @@ module.exports = async function createTable({ createTableQueryArray.push(`CREATE TABLE IF NOT EXISTS \`${tableName}\` (`); + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + try { + if (!recordedDbEntry) { + throw new Error("Recorded Db entry not found!"); + } + + const existingTable = await varDatabaseDbHandler({ + database: "datasquirel", + queryString: `SELECT * FROM user_database_tables WHERE db_id = ? AND table_slug = ?`, + queryValuesArray: [recordedDbEntry.id, tableSchema?.tableName], + }); + + /** @type {import("../../types").MYSQL_user_database_tables_table_def} */ + const table = existingTable?.[0]; + + if (!table?.id) { + const newTableEntry = await dbHandler({ + query: `INSERT INTO user_database_tables SET ?`, + values: { + user_id: recordedDbEntry.user_id, + db_id: recordedDbEntry.id, + db_slug: recordedDbEntry.db_slug, + table_name: tableSchema?.tableFullName, + table_slug: tableSchema?.tableName, + child_table: tableSchema?.childTable ? "1" : null, + child_table_parent_database: + tableSchema?.childTableDbFullName || null, + child_table_parent_table: + tableSchema?.childTableName || null, + date_created: Date(), + date_created_code: Date.now(), + date_updated: Date(), + date_updated_code: Date.now(), + }, + database: "datasquirel", + }); + } + } catch (error) {} + + //////////////////////////////////////// + //////////////////////////////////////// //////////////////////////////////////// let primaryKeySet = false; @@ -52,7 +102,31 @@ module.exports = async function createTable({ for (let i = 0; i < finalTable.length; i++) { const column = finalTable[i]; - const { fieldName, foreignKey } = column; + const { + fieldName, + dataType, + nullValue, + primaryKey, + autoIncrement, + defaultValue, + defaultValueLiteral, + foreignKey, + updatedField, + onUpdate, + onUpdateLiteral, + onDelete, + onDeleteLiteral, + defaultField, + encrypted, + json, + newTempField, + notNullValue, + originName, + plainText, + pattern, + patternFlags, + richText, + } = column; if (foreignKey) { foreignKeys.push({ @@ -70,12 +144,6 @@ module.exports = async function createTable({ //////////////////////////////////////// - if (fieldName?.match(/updated_timestamp/i)) { - fieldEntryText += " ON UPDATE CURRENT_TIMESTAMP"; - } - - //////////////////////////////////////// - const comma = (() => { if (foreignKeys[0]) return ","; if (i === finalTable.length - 1) return ""; diff --git a/package-shared/shell/utils/dbHandler.js b/package-shared/shell/utils/dbHandler.js new file mode 100755 index 0000000..7c014c6 --- /dev/null +++ b/package-shared/shell/utils/dbHandler.js @@ -0,0 +1,118 @@ +// @ts-check + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +const fs = require("fs"); +const path = require("path"); + +const mysql = require("serverless-mysql"); +const grabDbSSL = require("../../utils/backend/grabDbSSL"); + +let connection = mysql({ + config: { + host: process.env.DSQL_DB_HOST, + user: process.env.DSQL_DB_USERNAME, + password: process.env.DSQL_DB_PASSWORD, + database: process.env.DSQL_DB_NAME, + charset: "utf8mb4", + ssl: grabDbSSL(), + }, +}); + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +/** + * # Main DB Handler Function + * @async + * + * @param {object} params + * @param {string} params.query + * @param {string[] | object} [params.values] + * @param {string} [params.database] + * + * @returns {Promise} + */ +module.exports = async function dbHandler({ query, values, database }) { + /** + * Switch Database + * + * @description If a database is provided, switch to it + */ + let isDbCorrect = true; + + if (database) { + connection = mysql({ + config: { + host: process.env.DSQL_DB_HOST, + user: process.env.DSQL_DB_USERNAME, + password: process.env.DSQL_DB_PASSWORD, + database: database, + charset: "utf8mb4", + ssl: grabDbSSL(), + }, + }); + } + + if (!isDbCorrect) { + console.log( + "Shell Db Handler ERROR in switching Database! Operation Failed!" + ); + return null; + } + + /** + * Declare variables + * + * @description Declare "results" variable + */ + let results; + + /** + * Fetch from db + * + * @description Fetch data from db if no cache + */ + try { + if (query && values) { + results = await connection.query(query, values); + } else { + results = await connection.query(query); + } + + /** ********************* Clean up */ + await connection.end(); + } catch (/** @type {any} */ error) { + if (process.env.FIRST_RUN) { + return null; + } + + console.log("ERROR in dbHandler =>", error.message); + console.log(error); + console.log(connection.config()); + + fs.appendFileSync( + path.resolve(__dirname, "../.tmp/dbErrorLogs.txt"), + JSON.stringify(error, null, 4) + "\n" + Date() + "\n\n\n", + "utf8" + ); + results = null; + } + + /** + * Return results + * + * @description Return results add to cache if "req" param is passed + */ + if (results) { + return JSON.parse(JSON.stringify(results)); + } else { + return null; + } +}; diff --git a/package-shared/shell/utils/generateColumnDescription.js b/package-shared/shell/utils/generateColumnDescription.js new file mode 100755 index 0000000..dc5a7a8 --- /dev/null +++ b/package-shared/shell/utils/generateColumnDescription.js @@ -0,0 +1,108 @@ +// @ts-check + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Generate SQL text for Field + * ============================================================================== + * @param {object} params - Single object params + * @param {import("../../types").DSQL_FieldSchemaType} params.columnData - Field object + * @param {boolean} [params.primaryKeySet] - Table Name(slug) + * + * @returns {{ fieldEntryText: string, newPrimaryKeySet: boolean }} + */ +module.exports = function generateColumnDescription({ + columnData, + primaryKeySet, +}) { + /** + * Format tableInfoArray + * + * @description Format tableInfoArray + */ + const { + fieldName, + dataType, + nullValue, + primaryKey, + autoIncrement, + defaultValue, + defaultValueLiteral, + foreignKey, + updatedField, + onUpdate, + onUpdateLiteral, + onDelete, + onDeleteLiteral, + defaultField, + encrypted, + json, + newTempField, + notNullValue, + originName, + plainText, + pattern, + patternFlags, + richText, + } = columnData; + + let fieldEntryText = ""; + + fieldEntryText += `\`${fieldName}\` ${dataType}`; + + //////////////////////////////////////// + + // if (String(fieldEntryText).match(/ UUID$/)) { + // fieldEntryText += ` DEFAULT UUID()`; + // } else + if (nullValue) { + fieldEntryText += " DEFAULT NULL"; + } else if (defaultValueLiteral) { + fieldEntryText += ` DEFAULT ${defaultValueLiteral}`; + } else if (defaultValue) { + if (String(defaultValue).match(/uuid\(\)/i)) { + fieldEntryText += ` DEFAULT UUID()`; + } else { + fieldEntryText += ` DEFAULT '${defaultValue}'`; + } + } else if (notNullValue) { + fieldEntryText += ` NOT NULL`; + } + + //////////////////////////////////////// + + if (onUpdateLiteral) { + fieldEntryText += ` ON UPDATE ${onUpdateLiteral}`; + } + + //////////////////////////////////////// + + if (primaryKey && !primaryKeySet) { + fieldEntryText += " PRIMARY KEY"; + primaryKeySet = true; + } + + //////////////////////////////////////// + + if (autoIncrement) { + fieldEntryText += " AUTO_INCREMENT"; + primaryKeySet = true; + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + return { fieldEntryText, newPrimaryKeySet: primaryKeySet || false }; +}; + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ diff --git a/package-shared/shell/utils/noDatabaseDbHandler.js b/package-shared/shell/utils/noDatabaseDbHandler.js new file mode 100755 index 0000000..073d0f1 --- /dev/null +++ b/package-shared/shell/utils/noDatabaseDbHandler.js @@ -0,0 +1,45 @@ +// @ts-check + +const dbHandler = require("./dbHandler"); + +/** + * Create database from Schema Function + * ============================================================================== + * @param {string} queryString - Query String + * @returns {Promise} + */ +module.exports = async function noDatabaseDbHandler(queryString) { + /** + * Declare variables + * + * @description Declare "results" variable + */ + let results; + + /** + * Fetch from db + * + * @description Fetch data from db if no cache + */ + try { + /** ********************* Run Query */ + results = await dbHandler({ query: queryString }); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + } catch (/** @type {any} */ error) { + console.log("ERROR in noDatabaseDbHandler =>", error.message); + } + + /** + * Return results + * + * @description Return results add to cache if "req" param is passed + */ + if (results) { + return results; + } else { + return null; + } +}; diff --git a/package-shared/shell/utils/slugToCamelTitle.js b/package-shared/shell/utils/slugToCamelTitle.js new file mode 100755 index 0000000..576731c --- /dev/null +++ b/package-shared/shell/utils/slugToCamelTitle.js @@ -0,0 +1,18 @@ +// @ts-check + +module.exports = function slugToCamelTitle(/** @type {String} */ text) { + if (text) { + let addArray = text.split("-").filter((item) => item !== ""); + let camelArray = addArray.map((item) => { + return ( + item.substr(0, 1).toUpperCase() + item.substr(1).toLowerCase() + ); + }); + + let parsedAddress = camelArray.join(" "); + + return parsedAddress; + } else { + return null; + } +}; diff --git a/engine/engine/utils/supplementTable.js b/package-shared/shell/utils/supplementTable.js old mode 100644 new mode 100755 similarity index 89% rename from engine/engine/utils/supplementTable.js rename to package-shared/shell/utils/supplementTable.js index 2d238e4..1c0a3a6 --- a/engine/engine/utils/supplementTable.js +++ b/package-shared/shell/utils/supplementTable.js @@ -10,7 +10,7 @@ /** * * @param {object} param0 - * @param {import("../../../package-shared/types").DSQL_FieldSchemaType[]} param0.tableInfoArray + * @param {import("../../types").DSQL_FieldSchemaType[]} param0.tableInfoArray * @returns */ module.exports = function supplementTable({ tableInfoArray }) { @@ -20,7 +20,7 @@ module.exports = function supplementTable({ tableInfoArray }) { * @description Format tableInfoArray */ let finalTableArray = tableInfoArray; - const defaultFields = require("../data/defaultFields.json"); + const defaultFields = require("../../../package-shared/data/defaultFields.json"); //////////////////////////////////////// diff --git a/engine/engine/utils/updateTable.js b/package-shared/shell/utils/updateTable.js old mode 100644 new mode 100755 similarity index 60% rename from engine/engine/utils/updateTable.js rename to package-shared/shell/utils/updateTable.js index f07de4b..12fd783 --- a/engine/engine/utils/updateTable.js +++ b/package-shared/shell/utils/updateTable.js @@ -8,15 +8,13 @@ //////////////////////////////////////////////////////////////////////////////// const fs = require("fs"); -const path = require("path"); - -const defaultFieldsRegexp = - /^id$|^date_created$|^date_created_code$|^date_created_timestamp$|^date_updated$|^date_updated_code$|^date_updated_timestamp$/; - -const generateColumnDescription = require("./generateColumnDescription"); const varDatabaseDbHandler = require("./varDatabaseDbHandler"); -const schemaPath = path.resolve(process.cwd(), "dsql.schema.json"); +const defaultFieldsRegexp = + /^id$|^uuid$|^date_created$|^date_created_code$|^date_created_timestamp$|^date_updated$|^date_updated_code$|^date_updated_timestamp$/; + +const generateColumnDescription = require("./generateColumnDescription"); +const dbHandler = require("./dbHandler"); //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -31,22 +29,30 @@ const schemaPath = path.resolve(process.cwd(), "dsql.schema.json"); * @param {object} params - Single object params * @param {string} params.dbFullName - Database full name => "datasquirel_user_4394_db_name" * @param {string} params.tableName - Table Name(slug) - * @param {import("../../../package-shared/types").DSQL_FieldSchemaType[]} params.tableInfoArray - Table Info Array - * @param {import("../../../package-shared/types").DSQL_DatabaseSchemaType[]} params.dbSchema - Single post - * @param {import("../../../package-shared/types").DSQL_IndexSchemaType[]} [params.tableIndexes] - Table Indexes + * @param {import("../../types").DSQL_TableSchemaType} params.tableSchema - Table Name(slug) + * @param {string} [params.tableNameFull] - Table Name(slug) + * @param {import("../../types").DSQL_FieldSchemaType[]} params.tableInfoArray - Table Info Array + * @param {number | string | null} [params.userId] - User ID + * @param {import("../../types").DSQL_DatabaseSchemaType[]} params.dbSchema - Single post + * @param {import("../../types").DSQL_IndexSchemaType[]} [params.tableIndexes] - Table Indexes * @param {boolean} [params.clone] - Is this a newly cloned table? * @param {number} [params.tableIndex] - The number index of the table in the dbSchema array - * - * @returns {Promise} + * @param {boolean} [params.childDb] - The number index of the table in the dbSchema array + * @param {any} [params.recordedDbEntry] - The database object as recorded in `user_databases` table */ module.exports = async function updateTable({ dbFullName, tableName, tableInfoArray, + userId, dbSchema, tableIndexes, + tableSchema, clone, + childDb, tableIndex, + tableNameFull, + recordedDbEntry, }) { /** * Initialize @@ -87,19 +93,63 @@ module.exports = async function updateTable({ //////////////////////////////////////// //////////////////////////////////////// + if (childDb) { + try { + if (!recordedDbEntry) { + throw new Error("Recorded Db entry not found!"); + } + + const existingTable = await varDatabaseDbHandler({ + database: "datasquirel", + queryString: `SELECT * FROM user_database_tables WHERE db_id = ? AND table_slug = ?`, + queryValuesArray: [recordedDbEntry.id, tableName], + }); + + /** @type {import("../../types").MYSQL_user_database_tables_table_def} */ + const table = existingTable?.[0]; + + if (!table?.id) { + const newTableEntry = await dbHandler({ + query: `INSERT INTO user_database_tables SET ?`, + values: { + user_id: recordedDbEntry.user_id, + db_id: recordedDbEntry.id, + db_slug: recordedDbEntry.db_slug, + table_name: tableNameFull, + table_slug: tableName, + child_table: tableSchema?.childTable ? "1" : null, + child_table_parent_database: + tableSchema?.childTableDbFullName || null, + child_table_parent_table: + tableSchema.childTableName || null, + date_created: Date(), + date_created_code: Date.now(), + date_updated: Date(), + date_updated_code: Date.now(), + }, + database: "datasquirel", + }); + } + } catch (error) {} + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + /** - * @type {import("../../../package-shared/types").DSQL_MYSQL_SHOW_INDEXES_Type[]} + * @type {import("../../types").DSQL_MYSQL_SHOW_INDEXES_Type[]} * @description All indexes from MYSQL db - */ + */ // @ts-ignore const allExistingIndexes = await varDatabaseDbHandler({ queryString: `SHOW INDEXES FROM \`${tableName}\``, database: dbFullName, }); /** - * @type {import("../../../package-shared/types").DSQL_MYSQL_SHOW_COLUMNS_Type[]} + * @type {import("../../types").DSQL_MYSQL_SHOW_COLUMNS_Type[]} * @description All columns from MYSQL db - */ + */ // @ts-ignore const allExistingColumns = await varDatabaseDbHandler({ queryString: `SHOW COLUMNS FROM \`${tableName}\``, database: dbFullName, @@ -120,107 +170,103 @@ module.exports = async function updateTable({ /** * @description Iterate through every existing column */ - if (allExistingColumns) - for (let e = 0; e < allExistingColumns.length; e++) { - const { Field } = allExistingColumns[e]; + for (let e = 0; e < allExistingColumns.length; e++) { + const { Field } = allExistingColumns[e]; - if (Field.match(defaultFieldsRegexp)) continue; + if (Field.match(defaultFieldsRegexp)) continue; + /** + * @description This finds out whether the fieldName corresponds with the MSQL Field name + * if the fildName doesn't match any MYSQL Field name, the field is deleted. + */ + let existingEntry = upToDateTableFieldsArray.filter( + (column) => + column.fieldName === Field || column.originName === Field + ); + + if (existingEntry && existingEntry[0]) { /** - * @description This finds out whether the fieldName corresponds with the MSQL Field name - * if the fildName doesn't match any MYSQL Field name, the field is deleted. + * @description Check if Field name has been updated */ - let existingEntry = upToDateTableFieldsArray.filter( - (column) => - column.fieldName === Field || - column.originName === Field - ); + if ( + existingEntry[0].updatedField && + existingEntry[0].fieldName + ) { + updatedColumnsArray.push(existingEntry[0].fieldName); + + const renameColumn = await varDatabaseDbHandler({ + queryString: `ALTER TABLE ${tableName} RENAME COLUMN \`${existingEntry[0].originName}\` TO \`${existingEntry[0].fieldName}\``, + database: dbFullName, + }); + + console.log( + `Column Renamed from "${existingEntry[0].originName}" to "${existingEntry[0].fieldName}"` + ); - if (existingEntry && existingEntry[0]) { /** - * @description Check if Field name has been updated + * Update Db Schema + * =================================================== + * @description Update Db Schema after renaming column */ - if (existingEntry[0].updatedField) { - updatedColumnsArray.push( - String(existingEntry[0].fieldName) + try { + const userSchemaData = dbSchema; + + const targetDbIndex = userSchemaData.findIndex( + (db) => db.dbFullName === dbFullName + ); + const targetTableIndex = userSchemaData[ + targetDbIndex + ].tables.findIndex( + (table) => table.tableName === tableName + ); + const targetFieldIndex = userSchemaData[ + targetDbIndex + ].tables[targetTableIndex].fields.findIndex( + (field) => + field.fieldName === existingEntry[0].fieldName ); - const renameColumn = await varDatabaseDbHandler({ - queryString: `ALTER TABLE ${tableName} RENAME COLUMN \`${existingEntry[0].originName}\` TO \`${existingEntry[0].fieldName}\``, - database: dbFullName, - }); - - console.log( - `Column Renamed from "${existingEntry[0].originName}" to "${existingEntry[0].fieldName}"` - ); + delete userSchemaData[targetDbIndex].tables[ + targetTableIndex + ].fields[targetFieldIndex]["originName"]; + delete userSchemaData[targetDbIndex].tables[ + targetTableIndex + ].fields[targetFieldIndex]["updatedField"]; /** - * Update Db Schema - * =================================================== - * @description Update Db Schema after renaming column + * @description Set New Table Fields Array */ - try { - const userSchemaData = dbSchema; - - const targetDbIndex = userSchemaData.findIndex( - (db) => db.dbFullName === dbFullName - ); - const targetTableIndex = userSchemaData[ - targetDbIndex - ].tables.findIndex( - (table) => table.tableName === tableName - ); - const targetFieldIndex = userSchemaData[ - targetDbIndex - ].tables[targetTableIndex].fields.findIndex( - (field) => - field.fieldName === - existingEntry[0].fieldName - ); - - delete userSchemaData[targetDbIndex].tables[ + upToDateTableFieldsArray = + userSchemaData[targetDbIndex].tables[ targetTableIndex - ].fields[targetFieldIndex]["originName"]; - delete userSchemaData[targetDbIndex].tables[ - targetTableIndex - ].fields[targetFieldIndex]["updatedField"]; + ].fields; - /** - * @description Set New Table Fields Array - */ - upToDateTableFieldsArray = - userSchemaData[targetDbIndex].tables[ - targetTableIndex - ].fields; - - fs.writeFileSync( - schemaPath, - JSON.stringify(userSchemaData), - "utf8" - ); - } catch (/** @type {*} */ error) { - console.log( - "Error in updating Table =>", - error.message - ); - } - - //////////////////////////////////////// + fs.writeFileSync( + `${String( + process.env.DSQL_USER_DB_SCHEMA_PATH + )}/user-${userId}/main.json`, + JSON.stringify(userSchemaData), + "utf8" + ); + } catch (/** @type {any} */ error) { + console.log("Update table error =>", error.message); } //////////////////////////////////////// - - continue; - - //////////////////////////////////////// - } else { - // console.log("Column Deleted =>", Field); - await varDatabaseDbHandler({ - queryString: `ALTER TABLE ${tableName} DROP COLUMN \`${Field}\``, - database: dbFullName, - }); } + + //////////////////////////////////////// + + continue; + + //////////////////////////////////////// + } else { + await varDatabaseDbHandler({ + queryString: `ALTER TABLE ${tableName} DROP COLUMN \`${Field}\``, + database: dbFullName, + }); } + } //////////////////////////////////////// //////////////////////////////////////// @@ -232,38 +278,34 @@ module.exports = async function updateTable({ * @description Iterate through each table index(if available) * and perform operations */ - if (allExistingIndexes) - for (let f = 0; f < allExistingIndexes.length; f++) { - const { Key_name, Index_comment } = allExistingIndexes[f]; + for (let f = 0; f < allExistingIndexes.length; f++) { + const { Key_name, Index_comment } = allExistingIndexes[f]; - /** - * @description Check if this index was specifically created - * by datasquirel - */ - if (Index_comment?.match(/schema_index/)) { - try { - const existingKeyInSchema = tableIndexes - ? tableIndexes.filter( - (indexObject) => - indexObject.alias === Key_name - ) - : null; - if (!existingKeyInSchema?.[0]) - throw new Error( - `This Index(${Key_name}) Has been Deleted!` - ); - } catch (error) { - /** - * @description Drop Index: This happens when the MYSQL index is not - * present in the datasquirel DB schema - */ - await varDatabaseDbHandler({ - queryString: `ALTER TABLE ${tableName} DROP INDEX \`${Key_name}\``, - database: dbFullName, - }); - } + /** + * @description Check if this index was specifically created + * by datasquirel + */ + if (Index_comment?.match(/schema_index/)) { + try { + const existingKeyInSchema = tableIndexes?.filter( + (indexObject) => indexObject.alias === Key_name + ); + if (!existingKeyInSchema?.[0]) + throw new Error( + `This Index(${Key_name}) Has been Deleted!` + ); + } catch (error) { + /** + * @description Drop Index: This happens when the MYSQL index is not + * present in the datasquirel DB schema + */ + await varDatabaseDbHandler({ + queryString: `ALTER TABLE ${tableName} DROP INDEX \`${Key_name}\``, + database: dbFullName, + }); } } + } /** * Handle DATASQUIREL Table Indexes @@ -282,11 +324,10 @@ module.exports = async function updateTable({ * @description Check for existing Index in MYSQL db */ try { - const existingKeyInDb = allExistingIndexes?.filter( - (/** @type {any} */ indexObject) => - indexObject.Key_name === alias + const existingKeyInDb = allExistingIndexes.filter( + (indexObject) => indexObject.Key_name === alias ); - if (!existingKeyInDb?.[0]) + if (!existingKeyInDb[0]) throw new Error("This Index Does not Exist"); } catch (error) { /** @@ -319,14 +360,14 @@ module.exports = async function updateTable({ /** * @description All MSQL Foreign Keys - * @type {*} - */ + * @type {import("../../types").DSQL_MYSQL_FOREIGN_KEYS_Type[] | null} + */ // @ts-ignore const allForeignKeys = await varDatabaseDbHandler({ queryString: `SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_SCHEMA = '${dbFullName}' AND TABLE_NAME='${tableName}' AND CONSTRAINT_TYPE='FOREIGN KEY'`, database: dbFullName, }); - if (allForeignKeys) + if (allForeignKeys) { for (let c = 0; c < allForeignKeys.length; c++) { const { CONSTRAINT_NAME } = allForeignKeys[c]; @@ -344,6 +385,7 @@ module.exports = async function updateTable({ database: dbFullName, }); } + } //////////////////////////////////////// //////////////////////////////////////// @@ -389,6 +431,7 @@ module.exports = async function updateTable({ //////////////////////////////////////// + /** @type {any} */ let existingColumnIndex; /** @@ -419,9 +462,7 @@ module.exports = async function updateTable({ const { Field, Type, Null, Key, Default, Extra } = existingColumn[0]; - let isColumnReordered = existingColumnIndex - ? i < existingColumnIndex - : false; + let isColumnReordered = i < existingColumnIndex; if ( Field === fieldName && @@ -431,17 +472,19 @@ module.exports = async function updateTable({ updateText += `MODIFY COLUMN ${fieldEntryText}`; // continue; } else { - updateText += `MODIFY COLUMN ${fieldEntryText}${ - isColumnReordered - ? prevColumn?.fieldName - ? " AFTER `" + prevColumn.fieldName + "`" - : " AFTER `id`" - : "" - }`; - // if (userId) { - // } else { - // updateText += `MODIFY COLUMN ${fieldEntryText}`; - // } + if (userId) { + updateText += `MODIFY COLUMN ${fieldEntryText}${ + isColumnReordered + ? prevColumn?.fieldName + ? " AFTER `" + prevColumn.fieldName + "`" + : nextColumn?.fieldName + ? " BEFORE `" + nextColumn.fieldName + "`" + : "" + : "" + }`; + } else { + updateText += `MODIFY COLUMN ${fieldEntryText}`; + } } } else if (prevColumn && prevColumn.fieldName) { /** @@ -449,12 +492,12 @@ module.exports = async function updateTable({ * previous column exists */ updateText += `ADD COLUMN ${fieldEntryText} AFTER \`${prevColumn.fieldName}\``; - } else if (!prevColumn && nextColumn && nextColumn.fieldName) { + } else if (nextColumn && nextColumn.fieldName) { /** - * @description Add new Column before next column, if + * @description Add new Column BEFORE next column, if * next column exists */ - updateText += `ADD COLUMN ${fieldEntryText} AFTER \`id\``; + updateText += `ADD COLUMN ${fieldEntryText} BEFORE \`${nextColumn.fieldName}\``; } else { /** * @description Append new column to the end of existing columns @@ -536,8 +579,8 @@ module.exports = async function updateTable({ //////////////////////////////////////// //////////////////////////////////////// //////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log('Error in "updateTable" function =>', error.message); + } catch (/** @type {any} */ error) { + console.log('Error in "updateTable" shell function =>', error.message); return "Error in Updating Table"; } diff --git a/package-shared/shell/utils/varDatabaseDbHandler.js b/package-shared/shell/utils/varDatabaseDbHandler.js new file mode 100755 index 0000000..807fbdb --- /dev/null +++ b/package-shared/shell/utils/varDatabaseDbHandler.js @@ -0,0 +1,71 @@ +// @ts-check + +const fs = require("fs"); +const dbHandler = require("./dbHandler"); + +/** + * DB handler for specific database + * ============================================================================== + * @async + * @param {object} params - Single object params + * @param {string} params.queryString - SQL string + * @param {string[]} [params.queryValuesArray] - Values Array + * @param {string} [params.database] - Database name + * @param {import("../../types").DSQL_TableSchemaType} [params.tableSchema] - Table schema + * @returns {Promise} + */ +module.exports = async function varDatabaseDbHandler({ + queryString, + queryValuesArray, + database, + tableSchema, +}) { + /** + * Declare variables + * + * @description Declare "results" variable + */ + let results; + + /** + * Fetch from db + * + * @description Fetch data from db if no cache + */ + try { + if ( + queryString && + queryValuesArray && + Array.isArray(queryValuesArray) && + queryValuesArray[0] + ) { + results = await dbHandler({ + query: queryString, + values: queryValuesArray, + database, + }); + } else { + results = await dbHandler({ + query: queryString, + database, + }); + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + } catch (/** @type {any} */ error) { + console.log("Shell Vardb Error =>", error.message); + } + + /** + * Return results + * + * @description Return results add to cache if "req" param is passed + */ + return results; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// +}; diff --git a/package-shared/types/index.d.ts b/package-shared/types/index.d.ts index 565ec5e..8f454bf 100644 --- a/package-shared/types/index.d.ts +++ b/package-shared/types/index.d.ts @@ -173,6 +173,7 @@ export interface PackageUserLoginRequestBody { token?: boolean; social?: boolean; dbSchema?: DSQL_DatabaseSchemaType; + skipPassword?: boolean; } export interface PackageUserLoginLocalBody { @@ -184,6 +185,7 @@ export interface PackageUserLoginLocalBody { token?: boolean; social?: boolean; dbSchema?: DSQL_DatabaseSchemaType; + skipPassword?: boolean; } type Request = IncomingMessage; @@ -212,7 +214,7 @@ export interface SerializeQueryParams { // @ts-check -export interface DATASQUIREL_LoggedInUser { +export type DATASQUIREL_LoggedInUser = { id?: number; first_name: string; last_name: string; @@ -220,7 +222,6 @@ export interface DATASQUIREL_LoggedInUser { phone?: string; user_type?: string; username?: string; - password: string; image?: string; image_thumbnail?: string; address?: string; @@ -237,7 +238,7 @@ export interface DATASQUIREL_LoggedInUser { is_admin?: number; admin_level?: number; admin_permissions?: string; - uuid: string; + uuid?: string; temp_login_code?: string; date_created?: string; date_created_code?: number; @@ -249,7 +250,9 @@ export interface DATASQUIREL_LoggedInUser { logged_in_status?: boolean; date?: number; more_data?: any; -} +} & { + [key: string]: any; +}; export interface AuthenticatedUser { success: boolean; @@ -307,7 +310,7 @@ export interface GetUserFunctionReturn { image: string; image_thumbnail: string; verification_status: [number]; - }; + } | null; } export interface ReauthUserFunctionReturn { @@ -348,6 +351,9 @@ export type GetSchemaAPIParam = GetSchemaRequestQuery & export interface PostReturn { success: boolean; payload?: Object[] | string | PostInsertReturn; + msg?: string; + error?: any; + schema?: DSQL_TableSchemaType; } export interface PostDataPayload { @@ -1251,3 +1257,122 @@ export type MariadbRemoteServerUserObject = { password: string; host: string; }; + +export type APILoginFunctionParams = { + encryptionKey: string; + email: string; + username?: string; + password?: string; + database: string; + additionalFields?: string[]; + email_login?: boolean; + email_login_code?: string; + email_login_field?: string; + token?: boolean; + skipPassword?: boolean; + social?: boolean; +}; +export type APILoginFunctionReturn = { + success: boolean; + msg?: string; + payload?: DATASQUIREL_LoggedInUser | null; + userId?: number | string; +}; +export type APILoginFunction = ( + params: APILoginFunctionParams +) => Promise; + +export type APICreateUserFunctionParams = { + encryptionKey: string; + payload: any; + database: string; + userId?: string | number; +}; + +export type APICreateUserFunction = ( + params: APICreateUserFunctionParams +) => Promise; + +/** + * API Get User Function + */ +export type APIGetUserFunctionParams = { + fields: string[]; + dbFullName: string; + userId: string | number; +}; + +export type APIGetUserFunction = ( + params: APIGetUserFunctionParams +) => Promise; + +/** + * API Google Login Function + */ +export type APIGoogleLoginFunctionParams = { + clientId: string; + token: string; + database: string; + userId: string | number; + additionalFields?: { [key: string]: any }; + res: any; +}; + +export type APIGoogleLoginFunctionReturn = { + dsqlUserId?: number | string; +} & HandleSocialDbFunctionReturn; + +export type APIGoogleLoginFunction = ( + params: APIGoogleLoginFunctionParams +) => Promise; + +/** + * Handle Social DB Function + */ +export type HandleSocialDbFunctionParams = { + database?: string; + social_id: string | number; + email: string; + social_platform: string; + payload: any; + res?: ServerResponse; + invitation?: any; + supEmail?: string; + additionalFields?: object; +}; + +export type HandleSocialDbFunctionReturn = { + success: boolean; + user?: null; + msg?: string; + social_id?: string | number; + social_platform?: string; + payload?: any; + alert?: boolean; + newUser?: any; + error?: any; +} | null; + +/** + * Handle Social User Auth on Datasquirel Database + * ============================================================================== + * + * @description This function handles all social login logic after the social user + * has been authenticated and userpayload is present. The payload MUST contain the + * specified fields because this funciton will create a new user if the authenticated + * user does not exist. + * + * @param {HandleSocialDbFunctionParams} params - function parameters inside an object + * + * @returns {Promise} - Response object + */ +export type HandleSocialDbFunction = ( + params: HandleSocialDbFunctionParams +) => Promise; + +export type ApiReauthUserReturn = { + success: boolean; + payload?: { [key: string]: any } | null; + msg?: string; + userId?: string | number; +}; diff --git a/engine/engine/utils/camelJoinedtoCamelSpace.js b/package-shared/utils/camelJoinedtoCamelSpace.js similarity index 100% rename from engine/engine/utils/camelJoinedtoCamelSpace.js rename to package-shared/utils/camelJoinedtoCamelSpace.js diff --git a/engine/engine/utils/endConnection.js b/package-shared/utils/endConnection.js similarity index 100% rename from engine/engine/utils/endConnection.js rename to package-shared/utils/endConnection.js diff --git a/engine/engine/utils/generateColumnDescription.js b/package-shared/utils/generateColumnDescription.js similarity index 93% rename from engine/engine/utils/generateColumnDescription.js rename to package-shared/utils/generateColumnDescription.js index 1f28112..97b7455 100644 --- a/engine/engine/utils/generateColumnDescription.js +++ b/package-shared/utils/generateColumnDescription.js @@ -11,7 +11,7 @@ * Generate SQL text for Field * ============================================================================== * @param {object} params - Single object params - * @param {import("../../../package-shared/types").DSQL_FieldSchemaType} params.columnData - Field object + * @param {import("../types").DSQL_FieldSchemaType} params.columnData - Field object * @param {boolean} [params.primaryKeySet] - Table Name(slug) * * @returns {{fieldEntryText: string, newPrimaryKeySet: boolean}} diff --git a/engine/engine/utils/slugToCamelTitle.js b/package-shared/utils/slugToCamelTitle.js similarity index 100% rename from engine/engine/utils/slugToCamelTitle.js rename to package-shared/utils/slugToCamelTitle.js diff --git a/package.json b/package.json index 38741ac..9f7d748 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@moduletrace/datasquirel", - "version": "2.7.4", + "version": "2.7.5", "description": "Cloud-based SQL data management tool", "main": "index.js", "bin": { @@ -31,19 +31,22 @@ "homepage": "https://datasquirel.com/", "dependencies": { "@types/ace": "^0.0.52", - "@types/react": "^18.3.12", + "@types/lodash": "^4.17.13", + "@types/mysql": "^2.15.21", + "@types/next": "^9.0.0", + "@types/node": "^22.7.5", + "@types/react": "^18.2.21", + "@types/react-dom": "^19.0.0", "@types/tinymce": "^4.6.9", "dotenv": "^16.3.1", "generate-password": "^1.7.1", + "google-auth-library": "^9.15.0", "lodash": "^4.17.21", "mysql": "^2.18.1", "nodemailer": "^6.9.14", + "react": "^19.0.0", + "react-dom": "^19.0.0", "sanitize-html": "^2.13.1", "serverless-mysql": "^1.5.5" - }, - "devDependencies": { - "@types/lodash": "^4.17.13", - "@types/mysql": "^2.15.21", - "@types/node": "^22.7.5" } } diff --git a/tsconfig.json b/tsconfig.json index 04af5b7..614bd65 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -25,7 +25,7 @@ }, "include": [ "engine", - "functions", + "package-shared/functions/dsql", "types", "users", "utils", diff --git a/users/add-user.js b/users/add-user.js index ea2a129..7c6baf9 100644 --- a/users/add-user.js +++ b/users/add-user.js @@ -1,15 +1,13 @@ // @ts-check -const https = require("https"); -const http = require("http"); const path = require("path"); const fs = require("fs"); -const localAddUser = require("../engine/user/add-user"); const grabHostNames = require("../package-shared/utils/grab-host-names"); +const apiCreateUser = require("../package-shared/functions/api/users/api-create-user"); /** * Add User to Database - * ============================================================================== + * ============================================ * @async * * @param {object} param - Single object passed @@ -18,7 +16,9 @@ const grabHostNames = require("../package-shared/utils/grab-host-names"); * @param {import("../package-shared/types").UserDataPayload} param.payload - User Data Payload * @param {string} param.encryptionKey * @param {string} [param.encryptionSalt] - * @param {boolean} [param.user_id] - User ID + * @param {string | number} [param.user_id] + * @param {string | number} param.apiUserId + * @param {boolean} [param.useLocal] * * @returns { Promise } */ @@ -27,23 +27,16 @@ async function addUser({ payload, database, encryptionKey, - encryptionSalt, user_id, + useLocal, + apiUserId, }) { /** * Check for local DB settings * * @description Look for local db settings in `.env` file and by pass the http request if available */ - const { - DSQL_HOST, - DSQL_USER, - DSQL_PASS, - DSQL_DB_NAME, - DSQL_KEY, - DSQL_REF_DB_NAME, - DSQL_FULL_SYNC, - } = process.env; + const { DSQL_HOST, DSQL_USER, DSQL_PASS, DSQL_DB_NAME } = process.env; const grabedHostNames = grabHostNames(); const { host, port, scheme } = grabedHostNames; @@ -52,7 +45,8 @@ async function addUser({ DSQL_HOST?.match(/./) && DSQL_USER?.match(/./) && DSQL_PASS?.match(/./) && - DSQL_DB_NAME?.match(/./) + DSQL_DB_NAME?.match(/./) && + useLocal ) { /** @type {import("../package-shared/types").DSQL_DatabaseSchemaType | undefined} */ let dbSchema; @@ -66,11 +60,11 @@ async function addUser({ } catch (error) {} if (dbSchema) { - return await localAddUser({ - dbSchema: dbSchema, - payload: payload, + return await apiCreateUser({ + database: DSQL_DB_NAME, encryptionKey, - encryptionSalt, + payload, + userId: apiUserId, }); } } @@ -130,15 +124,7 @@ async function addUser({ httpsRequest.end(); }); - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - return httpResponse; } -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - module.exports = addUser; diff --git a/users/get-token.js b/users/get-token.js index 00f0f62..1a86fc4 100644 --- a/users/get-token.js +++ b/users/get-token.js @@ -6,7 +6,7 @@ * ============================================================================== */ const http = require("http"); -const decrypt = require("../functions/decrypt"); +const decrypt = require("../package-shared/functions/dsql/decrypt"); const parseCookies = require("../utils/functions/parseCookies"); /** ****************************************************************************** */ diff --git a/users/get-user.d.ts b/users/get-user.d.ts deleted file mode 100644 index 393da65..0000000 --- a/users/get-user.d.ts +++ /dev/null @@ -1,27 +0,0 @@ -export = getUser; -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** - * ============================================================================== - * Main Function - * ============================================================================== - * @async - * - * @param {object} params - Single Param object containing params - * @param {String} params.key - API Key - * @param {String} params.database - Target Database - * @param {number} params.userId - user id - * @param {string[]} [params.fields] - fields to select - * - * @returns { Promise} - */ -declare function getUser({ key, userId, database, fields }: { - key: string; - database: string; - userId: number; - fields?: string[]; -}): Promise; diff --git a/users/get-user.js b/users/get-user.js index ade7e99..28dcb50 100644 --- a/users/get-user.js +++ b/users/get-user.js @@ -9,8 +9,8 @@ const path = require("path"); const fs = require("fs"); const https = require("https"); const http = require("http"); -const getLocalUser = require("../engine/user/get-user"); const grabHostNames = require("../package-shared/utils/grab-host-names"); +const apiGetUser = require("../package-shared/functions/api/users/api-get-user"); /** ****************************************************************************** */ /** ****************************************************************************** */ @@ -31,10 +31,11 @@ const grabHostNames = require("../package-shared/utils/grab-host-names"); * @param {number} params.userId - user id * @param {string[]} [params.fields] - fields to select * @param {boolean} [params.user_id] - User ID + * @param {boolean} [params.useLocal] - Whether to use a remote database instead of API * * @returns { Promise} */ -async function getUser({ key, userId, database, fields, user_id }) { +async function getUser({ key, userId, database, fields, user_id, useLocal }) { /** * Initialize */ @@ -72,21 +73,14 @@ async function getUser({ key, userId, database, fields, user_id }) { * * @description Look for local db settings in `.env` file and by pass the http request if available */ - const { - DSQL_HOST, - DSQL_USER, - DSQL_PASS, - DSQL_DB_NAME, - DSQL_KEY, - DSQL_REF_DB_NAME, - DSQL_FULL_SYNC, - } = process.env; + const { DSQL_HOST, DSQL_USER, DSQL_PASS, DSQL_DB_NAME } = process.env; if ( DSQL_HOST?.match(/./) && DSQL_USER?.match(/./) && DSQL_PASS?.match(/./) && - DSQL_DB_NAME?.match(/./) + DSQL_DB_NAME?.match(/./) && + useLocal ) { /** @type {import("../package-shared/types").DSQL_DatabaseSchemaType | undefined} */ let dbSchema; @@ -100,10 +94,10 @@ async function getUser({ key, userId, database, fields, user_id }) { } catch (error) {} if (dbSchema) { - return await getLocalUser({ + return await apiGetUser({ userId, fields: [...new Set(updatedFields)], - dbSchema, + dbFullName: DSQL_DB_NAME, }); } } diff --git a/users/login-user.js b/users/login-user.js index 9f70108..29cd514 100644 --- a/users/login-user.js +++ b/users/login-user.js @@ -9,16 +9,9 @@ const http = require("http"); const https = require("https"); const fs = require("fs"); const path = require("path"); -const encrypt = require("../functions/encrypt"); -const loginLocalUser = require("../engine/user/login-user"); +const encrypt = require("../package-shared/functions/dsql/encrypt"); const grabHostNames = require("../package-shared/utils/grab-host-names"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ +const apiLoginUser = require("../package-shared/functions/api/users/api-login"); /** * Login A user @@ -42,6 +35,8 @@ const grabHostNames = require("../package-shared/utils/grab-host-names"); * @param {string} [params.temp_code_field] - Database table field name for temporary code * @param {boolean} [params.token] - Send access key as part of response body? * @param {boolean} [params.user_id] - User ID + * @param {boolean} [params.skipPassword] + * @param {boolean} [params.useLocal] * * @returns { Promise} */ @@ -58,6 +53,8 @@ async function loginUser({ temp_code_field, token, user_id, + skipPassword, + useLocal, }) { const grabedHostNames = grabHostNames(); const { host, port, scheme } = grabedHostNames; @@ -69,6 +66,19 @@ async function loginUser({ : defaultTempLoginFieldName : undefined; + /** + * Check required fields + * + * @description Check required fields + */ + if (!payload.email) { + return { + success: false, + payload: null, + msg: "Email Required", + }; + } + /** * Check Encryption Keys * @@ -112,21 +122,14 @@ async function loginUser({ * * @description Look for local db settings in `.env` file and by pass the http request if available */ - const { - DSQL_HOST, - DSQL_USER, - DSQL_PASS, - DSQL_DB_NAME, - DSQL_KEY, - DSQL_REF_DB_NAME, - DSQL_FULL_SYNC, - } = process.env; + const { DSQL_HOST, DSQL_USER, DSQL_PASS, DSQL_DB_NAME } = process.env; if ( DSQL_HOST?.match(/./) && DSQL_USER?.match(/./) && DSQL_PASS?.match(/./) && - DSQL_DB_NAME?.match(/./) + DSQL_DB_NAME?.match(/./) && + useLocal ) { /** @type {import("../package-shared/types").DSQL_DatabaseSchemaType | undefined} */ let dbSchema; @@ -140,10 +143,14 @@ async function loginUser({ } catch (error) {} if (dbSchema) { - httpResponse = await loginLocalUser({ - payload, + httpResponse = await apiLoginUser({ + database: process.env.DSQL_DB_NAME || "", + email: payload.email, + username: payload.username, + password: payload.password, + skipPassword, + encryptionKey, additionalFields, - dbSchema, email_login, email_login_code, email_login_field: emailLoginTempCodeFieldName, @@ -169,6 +176,7 @@ async function loginUser({ email_login_code, email_login_field: emailLoginTempCodeFieldName, token, + skipPassword: skipPassword, }; const reqPayloadJSON = JSON.stringify(reqPayload); @@ -218,10 +226,6 @@ async function loginUser({ }); } - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - /** * Make https request * @@ -250,15 +254,7 @@ async function loginUser({ ]); } - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - return httpResponse; } -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - module.exports = loginUser; diff --git a/users/reauth-user.js b/users/reauth-user.js index 3d3ff84..6ef7d8c 100644 --- a/users/reauth-user.js +++ b/users/reauth-user.js @@ -9,11 +9,11 @@ const http = require("http"); const https = require("https"); const fs = require("fs"); const path = require("path"); -const encrypt = require("../functions/encrypt"); +const encrypt = require("../package-shared/functions/dsql/encrypt"); const userAuth = require("./user-auth"); -const localReauthUser = require("../engine/user/reauth-user"); const grabHostNames = require("../package-shared/utils/grab-host-names"); +const apiReauthUser = require("../package-shared/functions/api/users/api-reauth-user"); /** ****************************************************************************** */ /** ****************************************************************************** */ @@ -117,10 +117,10 @@ async function reauthUser({ } catch (error) {} if (dbSchema) { - httpResponse = await localReauthUser({ + httpResponse = await apiReauthUser({ existingUser: existingUser.payload, additionalFields, - dbSchema, + database: DSQL_DB_NAME, }); } } else { diff --git a/users/send-email-code.js b/users/send-email-code.js index 6e7049c..035d610 100644 --- a/users/send-email-code.js +++ b/users/send-email-code.js @@ -9,10 +9,8 @@ const http = require("http"); const https = require("https"); const fs = require("fs"); const path = require("path"); -const encrypt = require("../functions/encrypt"); -const loginLocalUser = require("../engine/user/login-user"); -const localSendEmailCode = require("../engine/user/send-email-code"); const grabHostNames = require("../package-shared/utils/grab-host-names"); +const apiSendEmailCode = require("../package-shared/functions/api/users/api-send-email-code"); /** ****************************************************************************** */ /** ****************************************************************************** */ @@ -65,6 +63,11 @@ async function sendEmailCode({ ? temp_code_field : defaultTempLoginFieldName; + const emailHtml = fs.readFileSync( + path.resolve(__dirname, "../package-shared/html/one-time-code.html"), + "utf-8" + ); + /** * Check Encryption Keys * @@ -128,14 +131,15 @@ async function sendEmailCode({ } catch (error) {} if (dbSchema) { - httpResponse = await localSendEmailCode({ + httpResponse = await apiSendEmailCode({ + database: DSQL_DB_NAME, email, - dbSchema, email_login_field: emailLoginTempCodeFieldName, + html: emailHtml, mail_domain, mail_password, - mail_username, mail_port, + mail_username, sender, }); } @@ -157,13 +161,7 @@ async function sendEmailCode({ mail_username, mail_port, sender, - html: fs.readFileSync( - path.resolve( - __dirname, - "../engine/user/one-time-code.html" - ), - "utf-8" - ), + html: emailHtml, }); const httpsRequest = scheme.request( diff --git a/users/social/github-auth.js b/users/social/github-auth.js index 7f7fffb..9b9fd74 100644 --- a/users/social/github-auth.js +++ b/users/social/github-auth.js @@ -9,9 +9,9 @@ const http = require("http"); const https = require("https"); const fs = require("fs"); const path = require("path"); -const encrypt = require("../../functions/encrypt"); -const localGithubAuth = require("../../engine/user/social/github-auth"); +const encrypt = require("../../package-shared/functions/dsql/encrypt"); const grabHostNames = require("../../package-shared/utils/grab-host-names"); +const apiGithubLogin = require("../../package-shared/functions/api/users/social/api-github-login"); /** ****************************************************************************** */ /** ****************************************************************************** */ @@ -168,14 +168,14 @@ async function githubAuth({ } catch (error) {} if (dbSchema) { - httpResponse = await localGithubAuth({ - dbSchema: dbSchema, + httpResponse = await apiGithubLogin({ code, email: email || undefined, clientId, clientSecret, additionalFields, res: response, + database: DSQL_DB_NAME, }); } } else { diff --git a/users/social/google-auth.js b/users/social/google-auth.js index 8fee0c6..e3104b1 100644 --- a/users/social/google-auth.js +++ b/users/social/google-auth.js @@ -9,9 +9,9 @@ const http = require("http"); const https = require("https"); const fs = require("fs"); const path = require("path"); -const encrypt = require("../../functions/encrypt"); -const localGoogleAuth = require("../../engine/user/social/google-auth"); +const encrypt = require("../../package-shared/functions/dsql/encrypt"); const grabHostNames = require("../../package-shared/utils/grab-host-names"); +const apiGoogleLogin = require("../../package-shared/functions/api/users/social/api-google-login"); /** ****************************************************************************** */ /** ****************************************************************************** */ @@ -44,6 +44,8 @@ const grabHostNames = require("../../package-shared/utils/grab-host-names"); * @param {string} params.encryptionSalt - Encryption salt * @param {object} [params.additionalFields] - Additional Fields to be added to the user object * @param {boolean} [params.user_id] - User ID + * @param {string | number} [params.apiUserID] - Required for Local + * @param {boolean} [params.useLocal] - Whether to use a remote database instead of API * * @returns { Promise } */ @@ -57,6 +59,8 @@ async function googleAuth({ encryptionSalt, additionalFields, user_id, + apiUserID, + useLocal, }) { const grabedHostNames = grabHostNames(); const { host, port, scheme } = grabedHostNames; @@ -136,21 +140,14 @@ async function googleAuth({ * * @description Look for local db settings in `.env` file and by pass the http request if available */ - const { - DSQL_HOST, - DSQL_USER, - DSQL_PASS, - DSQL_DB_NAME, - DSQL_KEY, - DSQL_REF_DB_NAME, - DSQL_FULL_SYNC, - } = process.env; + const { DSQL_HOST, DSQL_USER, DSQL_PASS, DSQL_DB_NAME } = process.env; if ( DSQL_HOST?.match(/./) && DSQL_USER?.match(/./) && DSQL_PASS?.match(/./) && - DSQL_DB_NAME?.match(/./) + DSQL_DB_NAME?.match(/./) && + useLocal ) { /** @type {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined | undefined} */ let dbSchema; @@ -163,13 +160,14 @@ async function googleAuth({ dbSchema = JSON.parse(fs.readFileSync(localDbSchemaPath, "utf8")); } catch (error) {} - if (dbSchema) { - httpResponse = await localGoogleAuth({ - dbSchema: dbSchema, + if (dbSchema && apiUserID) { + httpResponse = await apiGoogleLogin({ token, clientId, additionalFields, - response: response, + res: response, + database: DSQL_DB_NAME, + userId: apiUserID, }); } } else { diff --git a/users/update-user.js b/users/update-user.js index b522d6b..7262384 100644 --- a/users/update-user.js +++ b/users/update-user.js @@ -4,8 +4,8 @@ const http = require("http"); const https = require("https"); const path = require("path"); const fs = require("fs"); -const localUpdateUser = require("../engine/user/update-user"); const grabHostNames = require("../package-shared/utils/grab-host-names"); +const apiUpdateUser = require("../package-shared/functions/api/users/api-update-user"); /** * # Update User @@ -56,9 +56,9 @@ async function updateUser({ key, payload, database, user_id }) { } catch (error) {} if (dbSchema) { - return await localUpdateUser({ - dbSchema: dbSchema, + return await apiUpdateUser({ payload: payload, + dbFullName: DSQL_DB_NAME, }); } } diff --git a/users/user-auth.js b/users/user-auth.js index 29597d1..360d227 100644 --- a/users/user-auth.js +++ b/users/user-auth.js @@ -6,7 +6,7 @@ * ============================================================================== */ const http = require("http"); -const decrypt = require("../functions/decrypt"); +const decrypt = require("../package-shared/functions/dsql/decrypt"); const parseCookies = require("../utils/functions/parseCookies"); /** ****************************************************************************** */ diff --git a/users/validate-token.js b/users/validate-token.js index 27fc63e..300c67e 100644 --- a/users/validate-token.js +++ b/users/validate-token.js @@ -6,7 +6,7 @@ * ============================================================================== */ const http = require("http"); -const decrypt = require("../functions/decrypt"); +const decrypt = require("../package-shared/functions/dsql/decrypt"); /** ****************************************************************************** */ /** ****************************************************************************** */ diff --git a/utils/get.js b/utils/get.js index 392024a..1c15bbf 100644 --- a/utils/get.js +++ b/utils/get.js @@ -1,12 +1,11 @@ // @ts-check -const http = require("node:http"); const https = require("node:https"); const path = require("path"); const fs = require("fs"); -const localGet = require("../engine/query/get"); const serializeQuery = require("./functions/serialize-query"); const grabHostNames = require("../package-shared/utils/grab-host-names"); +const apiGet = require("../package-shared/functions/api/query/get"); /** * Make a get request to Datasquirel API @@ -62,13 +61,12 @@ async function get({ dbSchema = JSON.parse(fs.readFileSync(localDbSchemaPath, "utf8")); } catch (error) {} - return await localGet({ - dbSchema: dbSchema, - options: { - query: query, - queryValues: queryValues, - tableName: tableName, - }, + return await apiGet({ + dbFullName: DSQL_DB_NAME, + query, + queryValues, + tableName, + dbSchema, }); } diff --git a/utils/post.js b/utils/post.js index f48daee..8fbaab8 100644 --- a/utils/post.js +++ b/utils/post.js @@ -2,8 +2,8 @@ const path = require("path"); const fs = require("fs"); -const localPost = require("../engine/query/post"); const grabHostNames = require("../package-shared/utils/grab-host-names"); +const apiPost = require("../package-shared/functions/api/query/post"); /** * # Make a post request to Datasquirel API @@ -58,13 +58,12 @@ async function post({ dbSchema = JSON.parse(fs.readFileSync(localDbSchemaPath, "utf8")); } catch (error) {} - return await localPost({ - dbSchema: dbSchema, - options: { - query: query, - queryValues: queryValues, - tableName: tableName, - }, + return await apiPost({ + dbFullName: DSQL_DB_NAME, + query, + dbSchema, + queryValues, + tableName, }); }