Compare commits

...

25 Commits

Author SHA1 Message Date
Benjamin Toby
54b7981be4 Update Query algo 2024-11-06 10:30:00 +01:00
Benjamin Toby
6c78cae127 Add Remote API 2024-11-06 07:37:42 +01:00
Benjamin Toby
190598aa3f Updates 2024-11-06 07:26:23 +01:00
Benjamin Toby
d81f38809b Update types 2024-10-24 08:08:22 +01:00
Benjamin Toby
1b6504ab93 Update types 2024-10-23 07:08:06 +01:00
Benjamin Toby
fdb1501588 Update types 2024-10-23 06:55:53 +01:00
Benjamin Toby
adf599009c Update types 2024-10-22 18:32:02 +01:00
Benjamin Toby
c801ddfdd9 Updates 2024-10-22 18:29:50 +01:00
Benjamin Toby
b03d90026c Testing 2024-10-22 18:26:38 +01:00
Benjamin Toby
c2328116da Updates 2024-10-22 18:17:59 +01:00
Benjamin Toby
d774e8d35d Update types 2024-10-21 08:05:18 +01:00
Benjamin Toby
fabf2945d7 Update types 2024-10-19 17:59:05 +01:00
Benjamin Toby
0690b5f081 Update types 2024-10-19 17:52:12 +01:00
Benjamin Toby
d6e89b4ed8 Update version 2024-10-19 17:50:52 +01:00
Benjamin Toby
2804f85236 Update types 2024-10-19 17:50:33 +01:00
Benjamin Toby
4462ba315d Update types: Remove '@/' references 2024-10-19 17:45:42 +01:00
Benjamin Toby
bf1d7f5fcd Update Types and Bugfixes 2024-10-18 07:02:16 +01:00
Benjamin Toby
30f607ce8d Update Types 2024-10-18 06:48:45 +01:00
Benjamin Toby
bf903d3524 Update Types 2024-10-18 06:45:25 +01:00
Benjamin Toby
2f93b6a311 Update Types 2024-10-18 06:02:12 +01:00
Benjamin Toby
33283e7d0f Refactor get query serialization 2024-10-18 05:49:04 +01:00
Benjamin Toby
e2d2d00487 Update version 2024-10-18 05:20:53 +01:00
Benjamin Toby
4bbb4da274 Update types 2024-10-18 05:20:28 +01:00
Benjamin Toby
59c6f6dd40 Update types 2024-10-18 05:15:04 +01:00
Benjamin Toby
5d395fe3b5 Update package.json 2024-10-14 13:44:31 +01:00
85 changed files with 4790 additions and 813 deletions

2
.gitignore vendored
View File

@ -141,3 +141,5 @@ test/
# NPM # NPM
# .npmrc # .npmrc
/dump

4
.npmrc
View File

@ -1,4 +1,4 @@
# registry=https://git.tben.me/api/packages/Moduletrace/npm/ # registry=https://git.tben.me/api/packages/Moduletrace/npm/
# registry=https://git.tben.me/api/packages/Moduletrace/npm/ registry=https://git.tben.me/api/packages/Moduletrace/npm/
# //git.tben.me/api/packages/Moduletrace/npm/:_authToken=${GITBEN_NPM_TOKEN} //git.tben.me/api/packages/Moduletrace/npm/:_authToken=${GITBEN_NPM_TOKEN}

View File

@ -116,3 +116,29 @@ const postData = await datasquirel.uploadImage({
}, },
}); });
``` ```
### Local Querying
You can query directly from an SQL database if you provide these environment variables in your `.env` file:
```conf
DSQL_DB_HOST=
DSQL_DB_PORT=
DSQL_DB_USERNAME=
DSQL_DB_PASSWORD=
DSQL_DB_NAME=
DSQL_SSL_DIR=
```
The ssl directory **_must_** contain a file named `ca-cert.pem`. `DSQL_DB_PORT` defaults to **3306** if not provided.
### Remote Querying
You can query from a self hosted installation of datasquirel. Just add these environment variables:
```conf
DSQL_API_REMOTE_HOST=
DSQL_API_REMOTE_HOST_PORT=
```
If these aren't provided it defaults to `datasquirel.com`.

View File

@ -1,22 +1,10 @@
/**
* ==============================================================================
* Imports
* ==============================================================================
*/
import imageInputFileToBase64 from "./imageInputFileToBase64"; import imageInputFileToBase64 from "./imageInputFileToBase64";
import imageInputToBase64 from "./imageInputToBase64"; import imageInputToBase64 from "./imageInputToBase64";
/** ****************************************************************************** */
/** ****************************************************************************** */
/** ****************************************************************************** */
/** ****************************************************************************** */
/** ****************************************************************************** */
/** ****************************************************************************** */
/** /**
* ============================================================================== * ==========================
* Media Functions Object * Media Functions Object
* ============================================================================== * ==========================
*/ */
const media = { const media = {
imageInputToBase64: imageInputToBase64, imageInputToBase64: imageInputToBase64,
@ -24,9 +12,9 @@ const media = {
}; };
/** /**
* ============================================================================== * ==========================
* Media Functions Object * Media Functions Object
* ============================================================================== * ==========================
*/ */
const auth = { const auth = {
imageInputToBase64: imageInputToBase64, imageInputToBase64: imageInputToBase64,
@ -34,16 +22,12 @@ const auth = {
}; };
/** /**
* ============================================================================== * ==========================
* Main Export * Main Export
* ============================================================================== * ==========================
*/ */
const datasquirelClient = { const datasquirelClient = {
media: media, media: media,
}; };
export default datasquirelClient; export default datasquirelClient;
/** ********************************************** */
/** ********************************************** */
/** ********************************************** */

View File

@ -68,6 +68,7 @@ async function run() {
process.exit(); process.exit();
} }
/** @type {import("../package-shared/types").DSQL_DatabaseSchemaType} */ // @ts-ignore
let fetchedDbSchemaObject = dbSchemaDataResponse.payload; let fetchedDbSchemaObject = dbSchemaDataResponse.payload;
if (DSQL_DB_NAME) fetchedDbSchemaObject.dbFullName = DSQL_DB_NAME; if (DSQL_DB_NAME) fetchedDbSchemaObject.dbFullName = DSQL_DB_NAME;

View File

@ -22,7 +22,7 @@ const updateApiSchemaFromLocalDb = require("../query/update-api-schema-from-loca
* ============================================================================== * ==============================================================================
* *
* @param {object} params - Single object passed * @param {object} params - Single object passed
* @param {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined} params.dbSchema - Database Schema Object * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} params.dbSchema - Database Schema Object
* *
* @returns {Promise<*>} new user auth object payload * @returns {Promise<*>} new user auth object payload
*/ */
@ -33,7 +33,7 @@ module.exports = async function addUsersTableToDb({ dbSchema }) {
* @description Initialize * @description Initialize
*/ */
const database = process.env.DSQL_DB_NAME || ""; const database = process.env.DSQL_DB_NAME || "";
/** @type {import("@/package-shared/types/database-schema.td").DSQL_TableSchemaType} */ /** @type {import("../../package-shared/types").DSQL_TableSchemaType} */
const userPreset = require("./data/presets/users.json"); const userPreset = require("./data/presets/users.json");
try { try {

View File

@ -27,7 +27,7 @@ const updateTable = require("./utils/updateTable");
* runs the "dsql create" command. `NOTE`: there must be a "dsql.schema.json" file * 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 * in the root of the project for this function to work
* *
* @param {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined} dbSchema - An array of database schema objects * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} dbSchema - An array of database schema objects
*/ */
async function createDbFromSchema(dbSchema) { async function createDbFromSchema(dbSchema) {
try { try {
@ -42,7 +42,7 @@ async function createDbFromSchema(dbSchema) {
} }
for (let i = 0; i < dbSchema.length; i++) { for (let i = 0; i < dbSchema.length; i++) {
/** @type {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined} */ /** @type {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} */
const database = dbSchema[i]; const database = dbSchema[i];
if (!database) { if (!database) {
@ -262,11 +262,11 @@ async function createDbFromSchema(dbSchema) {
*/ */
await varDatabaseDbHandler({ await varDatabaseDbHandler({
queryString: `CREATE${ queryString: `CREATE${
indexType.match(/fullText/i) indexType?.match(/fullText/i)
? " FULLTEXT" ? " FULLTEXT"
: "" : ""
} INDEX \`${alias}\` ON ${tableName}(${indexTableFields } INDEX \`${alias}\` ON ${tableName}(${indexTableFields
.map((nm) => nm.value) ?.map((nm) => nm.value)
.map((nm) => `\`${nm}\``) .map((nm) => `\`${nm}\``)
.join( .join(
"," ","

View File

@ -17,7 +17,7 @@ const supplementTable = require("./supplementTable");
* @param {string} param0.tableName * @param {string} param0.tableName
* @param {any[]} param0.tableInfoArray * @param {any[]} param0.tableInfoArray
* @param {(params: import("./varDatabaseDbHandler").VarDbHandlerParam)=>any} param0.varDatabaseDbHandler * @param {(params: import("./varDatabaseDbHandler").VarDbHandlerParam)=>any} param0.varDatabaseDbHandler
* @param {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType} [param0.dbSchema] * @param {import("../../../package-shared/types").DSQL_DatabaseSchemaType} [param0.dbSchema]
* @returns * @returns
*/ */
module.exports = async function createTable({ module.exports = async function createTable({

View File

@ -65,7 +65,7 @@ const connection = mysql.createConnection({
* @param {object} params - Single Param object containing params * @param {object} params - Single Param object containing params
* @param {string} params.query - Query String * @param {string} params.query - Query String
* @param {(string | number)[]} [params.values] - Values * @param {(string | number)[]} [params.values] - Values
* @param {import("../../../package-shared/types/database-schema.td").DSQL_DatabaseSchemaType} [params.dbSchema] - Database Schema * @param {import("../../../package-shared/types").DSQL_DatabaseSchemaType} [params.dbSchema] - Database Schema
* @param {string} [params.database] - Target Database * @param {string} [params.database] - Target Database
* @param {string} [params.tableName] - Target Table Name * @param {string} [params.tableName] - Target Table Name
* *

View File

@ -11,7 +11,7 @@
* Generate SQL text for Field * Generate SQL text for Field
* ============================================================================== * ==============================================================================
* @param {object} params - Single object params * @param {object} params - Single object params
* @param {import("@/package-shared/types/database-schema.td").DSQL_FieldSchemaType} params.columnData - Field object * @param {import("../../../package-shared/types").DSQL_FieldSchemaType} params.columnData - Field object
* @param {boolean} [params.primaryKeySet] - Table Name(slug) * @param {boolean} [params.primaryKeySet] - Table Name(slug)
* *
* @returns {{fieldEntryText: string, newPrimaryKeySet: boolean}} * @returns {{fieldEntryText: string, newPrimaryKeySet: boolean}}

View File

@ -14,7 +14,7 @@ const defaultFieldsRegexp = require("./defaultFieldsRegexp");
* @param {object} params - Single object params * @param {object} params - Single object params
* @param {*[]} params.unparsedResults - Array of data objects containing Fields(keys) * @param {*[]} params.unparsedResults - Array of data objects containing Fields(keys)
* and corresponding values of the fields(values) * and corresponding values of the fields(values)
* @param {import("../../../package-shared/types/database-schema.td").DSQL_TableSchemaType} [params.tableSchema] - Table schema * @param {import("../../../package-shared/types").DSQL_TableSchemaType} [params.tableSchema] - Table schema
* @returns {Promise<object[]|null>} * @returns {Promise<object[]|null>}
*/ */
module.exports = async function parseDbResults({ module.exports = async function parseDbResults({

View File

@ -10,7 +10,7 @@
/** /**
* *
* @param {object} param0 * @param {object} param0
* @param {import("@/package-shared/types/database-schema.td").DSQL_FieldSchemaType[]} param0.tableInfoArray * @param {import("../../../package-shared/types").DSQL_FieldSchemaType[]} param0.tableInfoArray
* @returns * @returns
*/ */
module.exports = function supplementTable({ tableInfoArray }) { module.exports = function supplementTable({ tableInfoArray }) {

View File

@ -31,9 +31,9 @@ const schemaPath = path.resolve(process.cwd(), "dsql.schema.json");
* @param {object} params - Single object params * @param {object} params - Single object params
* @param {string} params.dbFullName - Database full name => "datasquirel_user_4394_db_name" * @param {string} params.dbFullName - Database full name => "datasquirel_user_4394_db_name"
* @param {string} params.tableName - Table Name(slug) * @param {string} params.tableName - Table Name(slug)
* @param {import("@/package-shared/types/database-schema.td").DSQL_FieldSchemaType[]} params.tableInfoArray - Table Info Array * @param {import("../../../package-shared/types").DSQL_FieldSchemaType[]} params.tableInfoArray - Table Info Array
* @param {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType[]} params.dbSchema - Single post * @param {import("../../../package-shared/types").DSQL_DatabaseSchemaType[]} params.dbSchema - Single post
* @param {import("@/package-shared/types/database-schema.td").DSQL_IndexSchemaType[]} [params.tableIndexes] - Table Indexes * @param {import("../../../package-shared/types").DSQL_IndexSchemaType[]} [params.tableIndexes] - Table Indexes
* @param {boolean} [params.clone] - Is this a newly cloned table? * @param {boolean} [params.clone] - Is this a newly cloned table?
* @param {number} [params.tableIndex] - The number index of the table in the dbSchema array * @param {number} [params.tableIndex] - The number index of the table in the dbSchema array
* *
@ -88,7 +88,7 @@ module.exports = async function updateTable({
//////////////////////////////////////// ////////////////////////////////////////
/** /**
* @type {DSQL_MYSQL_SHOW_INDEXES_Type[]} * @type {import("../../../package-shared/types").DSQL_MYSQL_SHOW_INDEXES_Type[]}
* @description All indexes from MYSQL db * @description All indexes from MYSQL db
*/ */
const allExistingIndexes = await varDatabaseDbHandler({ const allExistingIndexes = await varDatabaseDbHandler({
@ -97,7 +97,7 @@ module.exports = async function updateTable({
}); });
/** /**
* @type {DSQL_MYSQL_SHOW_COLUMNS_Type[]} * @type {import("../../../package-shared/types").DSQL_MYSQL_SHOW_COLUMNS_Type[]}
* @description All columns from MYSQL db * @description All columns from MYSQL db
*/ */
const allExistingColumns = await varDatabaseDbHandler({ const allExistingColumns = await varDatabaseDbHandler({
@ -141,7 +141,9 @@ module.exports = async function updateTable({
* @description Check if Field name has been updated * @description Check if Field name has been updated
*/ */
if (existingEntry[0].updatedField) { if (existingEntry[0].updatedField) {
updatedColumnsArray.push(existingEntry[0].fieldName); updatedColumnsArray.push(
String(existingEntry[0].fieldName)
);
const renameColumn = await varDatabaseDbHandler({ const renameColumn = await varDatabaseDbHandler({
queryString: `ALTER TABLE ${tableName} RENAME COLUMN \`${existingEntry[0].originName}\` TO \`${existingEntry[0].fieldName}\``, queryString: `ALTER TABLE ${tableName} RENAME COLUMN \`${existingEntry[0].originName}\` TO \`${existingEntry[0].fieldName}\``,
@ -293,9 +295,9 @@ module.exports = async function updateTable({
*/ */
await varDatabaseDbHandler({ await varDatabaseDbHandler({
queryString: `CREATE${ queryString: `CREATE${
indexType.match(/fullText/i) ? " FULLTEXT" : "" indexType?.match(/fullText/i) ? " FULLTEXT" : ""
} INDEX \`${alias}\` ON ${tableName}(${indexTableFields } INDEX \`${alias}\` ON ${tableName}(${indexTableFields
.map((nm) => nm.value) ?.map((nm) => nm.value)
.map((nm) => `\`${nm}\``) .map((nm) => `\`${nm}\``)
.join(",")}) COMMENT 'schema_index'`, .join(",")}) COMMENT 'schema_index'`,
database: dbFullName, database: dbFullName,
@ -375,7 +377,7 @@ module.exports = async function updateTable({
/** /**
* @description Skip default fields * @description Skip default fields
*/ */
if (fieldName.match(/^id$|^date_/)) continue; if (fieldName?.match(/^id$|^date_/)) continue;
/** /**
* @description Skip columns that have been updated recently * @description Skip columns that have been updated recently
*/ */
@ -424,7 +426,7 @@ module.exports = async function updateTable({
if ( if (
Field === fieldName && Field === fieldName &&
!isColumnReordered && !isColumnReordered &&
dataType.toUpperCase() === Type.toUpperCase() dataType?.toUpperCase() === Type.toUpperCase()
) { ) {
updateText += `MODIFY COLUMN ${fieldEntryText}`; updateText += `MODIFY COLUMN ${fieldEntryText}`;
// continue; // continue;

View File

@ -24,7 +24,7 @@ const dbHandler = require("./dbHandler");
* @property {string} queryString - SQL string * @property {string} queryString - SQL string
* @property {string[]} [queryValuesArray] - Values Array * @property {string[]} [queryValuesArray] - Values Array
* @property {string} database - Database name * @property {string} database - Database name
* @property {import("@/package-shared/types/database-schema.td").DSQL_TableSchemaType} [tableSchema] - Table schema * @property {import("../../../package-shared/types").DSQL_TableSchemaType} [tableSchema] - Table schema
*/ */
/** /**

View File

@ -3,9 +3,9 @@
* No imports found for this Module * No imports found for this Module
==== MODULE TRACE END ==== */ ==== MODULE TRACE END ==== */
// @ts-check const runQuery = require("../../package-shared/functions/backend/db/runQuery");
const runQuery = require("./utils/runQuery"); // @ts-check
/** /**
* @typedef {Object} LocalGetReturn * @typedef {Object} LocalGetReturn
@ -29,7 +29,7 @@ const runQuery = require("./utils/runQuery");
* *
* @param {Object} params - Single object passed * @param {Object} params - Single object passed
* @param {LocalQueryObject} params.options - SQL Query * @param {LocalQueryObject} params.options - SQL Query
* @param {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined} [params.dbSchema] - Name of the table to query * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} [params.dbSchema] - Name of the table to query
* *
* @returns { Promise<LocalGetReturn> } - Return Object * @returns { Promise<LocalGetReturn> } - Return Object
*/ */
@ -39,7 +39,6 @@ async function localGet({ options, dbSchema }) {
/** @type {string | undefined | any } */ /** @type {string | undefined | any } */
const tableName = options?.tableName ? options.tableName : undefined; const tableName = options?.tableName ? options.tableName : undefined;
const dbFullName = process.env.DSQL_DB_NAME || ""; const dbFullName = process.env.DSQL_DB_NAME || "";
/** /**
@ -71,6 +70,7 @@ async function localGet({ options, dbSchema }) {
queryValuesArray: queryValues, queryValuesArray: queryValues,
dbSchema, dbSchema,
tableName, tableName,
local: true,
}); });
if (error) throw error; if (error) throw error;

View File

@ -1,21 +1,6 @@
// @ts-check // @ts-check
const runQuery = require("./utils/runQuery"); const runQuery = require("../../package-shared/functions/backend/db/runQuery");
/**
* @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
*/
/**
* @typedef {Object} LocalPostQueryObject
* @property {string | import("../../utils/post").PostDataPayload} query - Table Name
* @property {string} [tableName] - Table Name
* @property {string[]} [queryValues] - GET request results
*/
/** /**
* Make a get request to Datasquirel API * Make a get request to Datasquirel API
@ -23,10 +8,10 @@ const runQuery = require("./utils/runQuery");
* @async * @async
* *
* @param {Object} params - Single object passed * @param {Object} params - Single object passed
* @param {LocalPostQueryObject} params.options - SQL Query * @param {import("../../package-shared/types").LocalPostQueryObject} params.options - SQL Query
* @param {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined} [params.dbSchema] - Name of the table to query * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} [params.dbSchema] - Name of the table to query
* *
* @returns { Promise<LocalPostReturn> } - Return Object * @returns { Promise<import("../../package-shared/types").LocalPostReturn> } - Return Object
*/ */
async function localPost({ options, dbSchema }) { async function localPost({ options, dbSchema }) {
try { try {
@ -67,6 +52,7 @@ async function localPost({ options, dbSchema }) {
dbSchema: dbSchema, dbSchema: dbSchema,
queryValuesArray: queryValues, queryValuesArray: queryValues,
tableName, tableName,
local: true,
}); });
if (error) throw error; if (error) throw error;
@ -83,7 +69,6 @@ async function localPost({ options, dbSchema }) {
return { return {
success: false, success: false,
payload: null,
error: error.message, error: error.message,
}; };
} }
@ -95,7 +80,6 @@ async function localPost({ options, dbSchema }) {
return { return {
success: false, success: false,
payload: null,
msg: "Something went wrong!", msg: "Something went wrong!",
}; };

View File

@ -1,184 +0,0 @@
// @ts-check
/**
* Imports: Handle imports
*/
const encrypt = require("../../../functions/encrypt");
const dbHandler = require("../../engine/utils/dbHandler");
const updateDb = require("./updateDbEntry");
const updateDbEntry = require("./updateDbEntry");
/**
* Add a db Entry Function
* ==============================================================================
* @description Description
* @async
*
* @param {object} params - An object containing the function parameters.
* "Read only" or "Full Access"? Defaults to "Read Only"
* @param {string} params.dbFullName - Database full name
* @param {string} params.tableName - Table name
* @param {*} params.data - Data to add
* @param {import("@/package-shared/types/database-schema.td").DSQL_TableSchemaType} [params.tableSchema] - Table schema
* @param {string} [params.duplicateColumnName] - Duplicate column name
* @param {string} [params.duplicateColumnValue] - Duplicate column value
* @param {boolean} [params.update] - Update this row if it exists
* @param {string} params.encryptionKey - Update this row if it exists
* @param {string} params.encryptionSalt - Update this row if it exists
*
* @returns {Promise<*>}
*/
async function addDbEntry({
dbFullName,
tableName,
data,
tableSchema,
duplicateColumnName,
duplicateColumnValue,
update,
encryptionKey,
encryptionSalt,
}) {
/**
* Initialize variables
*/
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
/**
* Handle function logic
*/
if (duplicateColumnName && typeof duplicateColumnName === "string") {
const duplicateValue = await dbHandler({
database: dbFullName,
query: `SELECT * FROM \`${tableName}\` WHERE \`${duplicateColumnName}\`=?`,
values: [duplicateColumnValue || ""],
});
if (duplicateValue && duplicateValue[0] && !update) {
return null;
} else if (duplicateValue && duplicateValue[0] && update) {
return await updateDbEntry({
dbFullName,
tableName,
data,
tableSchema,
identifierColumnName: duplicateColumnName,
identifierValue: duplicateColumnValue || "",
encryptionKey,
encryptionSalt,
});
}
}
/**
* Declare variables
*
* @description Declare "results" variable
*/
const dataKeys = Object.keys(data);
let insertKeysArray = [];
let insertValuesArray = [];
for (let i = 0; i < dataKeys.length; i++) {
try {
const dataKey = dataKeys[i];
let value = data[dataKey];
const targetFieldSchemaArray = tableSchema
? tableSchema?.fields?.filter(
(field) => field.fieldName == dataKey
)
: null;
const targetFieldSchema =
targetFieldSchemaArray && targetFieldSchemaArray[0]
? targetFieldSchemaArray[0]
: null;
if (!value) continue;
if (targetFieldSchema?.encrypted) {
value = encrypt({ data: value, encryptionKey, encryptionSalt });
console.log("DSQL: Encrypted value =>", value);
}
if (targetFieldSchema?.pattern) {
const pattern = new RegExp(
targetFieldSchema.pattern,
targetFieldSchema.patternFlags || ""
);
if (!value?.toString()?.match(pattern)) {
console.log("DSQL: Pattern not matched =>", value);
value = "";
}
}
if (typeof value === "string" && !value.match(/./i)) {
value = {
toSqlString: function () {
return "NULL";
},
};
}
insertKeysArray.push("`" + dataKey + "`");
if (typeof value === "object") {
value = JSON.stringify(value);
}
insertValuesArray.push(value);
} catch (/** @type {*} */ error) {
console.log("DSQL: Error in parsing data keys =>", error.message);
continue;
}
}
////////////////////////////////////////
insertKeysArray.push("`date_created`");
insertValuesArray.push(Date());
insertKeysArray.push("`date_created_code`");
insertValuesArray.push(Date.now());
////////////////////////////////////////
insertKeysArray.push("`date_updated`");
insertValuesArray.push(Date());
insertKeysArray.push("`date_updated_code`");
insertValuesArray.push(Date.now());
////////////////////////////////////////
const query = `INSERT INTO \`${tableName}\` (${insertKeysArray.join(
","
)}) VALUES (${insertValuesArray.map(() => "?").join(",")})`;
const queryValuesArray = insertValuesArray;
const newInsert = await dbHandler({
database: dbFullName,
query: query,
values: queryValuesArray,
});
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
/**
* Return statement
*/
return newInsert;
}
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
module.exports = addDbEntry;

View File

@ -1,18 +1,9 @@
// @ts-check // @ts-check
const hashPassword = require("../../functions/hashPassword"); const hashPassword = require("../../functions/hashPassword");
const addDbEntry = require("../../package-shared/functions/backend/db/addDbEntry");
const addUsersTableToDb = require("../engine/addUsersTableToDb"); const addUsersTableToDb = require("../engine/addUsersTableToDb");
const varDatabaseDbHandler = require("../engine/utils/varDatabaseDbHandler"); const varDatabaseDbHandler = require("../engine/utils/varDatabaseDbHandler");
const addDbEntry = require("../query/utils/addDbEntry");
const runQuery = require("../query/utils/runQuery");
/**
* @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 * Make a get request to Datasquirel API
@ -20,12 +11,12 @@ const runQuery = require("../query/utils/runQuery");
* @async * @async
* *
* @param {Object} params - Single object passed * @param {Object} params - Single object passed
* @param {import("@/types/user.td").UserDataPayload} params.payload - SQL Query * @param {import("../../package-shared/types").UserDataPayload} params.payload - SQL Query
* @param {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined} params.dbSchema - Name of the table to query * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} params.dbSchema - Name of the table to query
* @param {string} [params.encryptionKey] * @param {string} [params.encryptionKey]
* @param {string} [params.encryptionSalt] * @param {string} [params.encryptionSalt]
* *
* @returns { Promise<LocalPostReturn> } - Return Object * @returns { Promise<import("../../package-shared/types").AddUserFunctionReturn> } - Return Object
*/ */
async function localAddUser({ async function localAddUser({
payload, payload,
@ -50,7 +41,7 @@ async function localAddUser({
if (!payload?.password) { if (!payload?.password) {
return { return {
success: false, success: false,
payload: `Password is required to create an account`, msg: `Password is required to create an account`,
}; };
} }
@ -79,7 +70,7 @@ async function localAddUser({
if (!fields) { if (!fields) {
return { return {
success: false, success: false,
payload: "Could not create users table", msg: "Could not create users table",
}; };
} }
@ -100,7 +91,7 @@ async function localAddUser({
if (invalidField) { if (invalidField) {
return { return {
success: false, success: false,
payload: `${invalidField} is not a valid field!`, msg: `${invalidField} is not a valid field!`,
}; };
} }
@ -126,7 +117,7 @@ async function localAddUser({
if (existingUser && existingUser[0]) { if (existingUser && existingUser[0]) {
return { return {
success: false, success: false,
payload: "User Already Exists", msg: "User Already Exists",
}; };
} }
@ -157,7 +148,7 @@ async function localAddUser({
} else { } else {
return { return {
success: false, success: false,
payload: "Could not create user", msg: "Could not create user",
}; };
} }
@ -168,7 +159,6 @@ async function localAddUser({
return { return {
success: false, success: false,
payload: null,
msg: "Something went wrong!", msg: "Something went wrong!",
}; };

View File

@ -7,7 +7,7 @@ const varDatabaseDbHandler = require("../engine/utils/varDatabaseDbHandler");
* @param {object} param0 * @param {object} param0
* @param {number} param0.userId * @param {number} param0.userId
* @param {string[]} param0.fields * @param {string[]} param0.fields
* @param {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined} [param0.dbSchema] * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} [param0.dbSchema]
* @returns * @returns
*/ */
async function getLocalUser({ userId, fields, dbSchema }) { async function getLocalUser({ userId, fields, dbSchema }) {

View File

@ -5,7 +5,7 @@ const varDatabaseDbHandler = require("../engine/utils/varDatabaseDbHandler");
/** /**
* *
* @param {PackageUserLoginLocalBody} param0 * @param {import("../../package-shared/types").PackageUserLoginLocalBody} param0
* @returns * @returns
*/ */
async function loginLocalUser({ async function loginLocalUser({

View File

@ -7,7 +7,7 @@ const varDatabaseDbHandler = require("../engine/utils/varDatabaseDbHandler");
* @param {object} param0 * @param {object} param0
* @param {*} param0.existingUser * @param {*} param0.existingUser
* @param {string[]} [param0.additionalFields] * @param {string[]} [param0.additionalFields]
* @param {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined} [param0.dbSchema] * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} [param0.dbSchema]
* @returns * @returns
*/ */
async function localReauthUser({ existingUser, additionalFields, dbSchema }) { async function localReauthUser({ existingUser, additionalFields, dbSchema }) {

View File

@ -10,7 +10,7 @@ const path = require("path");
* *
* @param {object} param0 * @param {object} param0
* @param {string} param0.email * @param {string} param0.email
* @param {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined} [param0.dbSchema] * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} [param0.dbSchema]
* @param {string} param0.email_login_field * @param {string} param0.email_login_field
* @param {string} [param0.mail_domain] * @param {string} [param0.mail_domain]
* @param {string} [param0.mail_username] * @param {string} [param0.mail_username]
@ -77,15 +77,6 @@ async function localSendEmailCode({
msg: "No user found", 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) { if (foundUser && foundUser[0] && email_login_field) {
const tempCode = generateCode(); const tempCode = generateCode();
@ -150,4 +141,13 @@ async function localSendEmailCode({
} }
} }
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; module.exports = localSendEmailCode;

View File

@ -36,7 +36,7 @@ const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || "";
* @param {string} params.clientId * @param {string} params.clientId
* @param {string} params.clientSecret * @param {string} params.clientSecret
* @param {object} [params.additionalFields] * @param {object} [params.additionalFields]
* @param {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType} params.dbSchema * @param {import("../../../package-shared/types").DSQL_DatabaseSchemaType} params.dbSchema
*/ */
async function localGithubAuth({ async function localGithubAuth({
res, res,

View File

@ -44,7 +44,7 @@ const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || "";
* @param {string} params.clientId - Google client id * @param {string} params.clientId - Google client id
* @param {http.ServerResponse} params.response - HTTPS response object * @param {http.ServerResponse} params.response - HTTPS response object
* @param {object} [params.additionalFields] - Additional Fields to be added to the user object * @param {object} [params.additionalFields] - Additional Fields to be added to the user object
* @param {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType} [params.dbSchema] - Database Schema * @param {import("../../../package-shared/types").DSQL_DatabaseSchemaType} [params.dbSchema] - Database Schema
* *
* @returns { Promise<FunctionReturn> } * @returns { Promise<FunctionReturn> }
*/ */

View File

@ -8,8 +8,8 @@
const fs = require("fs"); const fs = require("fs");
const http = require("http"); const http = require("http");
const varDatabaseDbHandler = require("../../../engine/utils/varDatabaseDbHandler"); const varDatabaseDbHandler = require("../../../engine/utils/varDatabaseDbHandler");
const addDbEntry = require("../../../query/utils/addDbEntry");
const encrypt = require("../../../../functions/encrypt"); const encrypt = require("../../../../functions/encrypt");
const addDbEntry = require("../../../../package-shared/functions/backend/db/addDbEntry");
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
@ -74,7 +74,7 @@ const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || "";
* res: http.ServerResponse, * res: http.ServerResponse,
* supEmail?: string | null, * supEmail?: string | null,
* additionalFields?: object, * additionalFields?: object,
* dbSchema: import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined * dbSchema: import("../../../../package-shared/types").DSQL_DatabaseSchemaType | undefined
* }} params - function parameters inside an object * }} params - function parameters inside an object
* *
* @returns {Promise<FunctionReturn>} - Response object * @returns {Promise<FunctionReturn>} - Response object

View File

@ -1,6 +1,6 @@
// @ts-check // @ts-check
const updateDbEntry = require("../query/utils/updateDbEntry"); const updateDbEntry = require("../../package-shared/functions/backend/db/updateDbEntry");
/** /**
* @typedef {Object} LocalPostReturn * @typedef {Object} LocalPostReturn
@ -17,7 +17,7 @@ const updateDbEntry = require("../query/utils/updateDbEntry");
* *
* @param {Object} params - Single object passed * @param {Object} params - Single object passed
* @param {*} params.payload - SQL Query * @param {*} params.payload - SQL Query
* @param {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined} params.dbSchema - Name of the table to query * @param {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined} params.dbSchema - Name of the table to query
* *
* @returns { Promise<LocalPostReturn> } - Return Object * @returns { Promise<LocalPostReturn> } - Return Object
*/ */

View File

@ -31,6 +31,7 @@ const decrypt = ({ encryptedString, encryptionKey, encryptionSalt }) => {
let key = scryptSync(encryptionKey, encryptionSalt, 24); let key = scryptSync(encryptionKey, encryptionSalt, 24);
let iv = Buffer.alloc(16, 0); let iv = Buffer.alloc(16, 0);
// @ts-ignore
const decipher = createDecipheriv(algorithm, key, iv); const decipher = createDecipheriv(algorithm, key, iv);
try { try {

View File

@ -30,6 +30,7 @@ const encrypt = ({ data, encryptionKey, encryptionSalt }) => {
let key = scryptSync(password, encryptionSalt, 24); let key = scryptSync(password, encryptionSalt, 24);
let iv = Buffer.alloc(16, 0); let iv = Buffer.alloc(16, 0);
// @ts-ignore
const cipher = createCipheriv(algorithm, key, iv); const cipher = createCipheriv(algorithm, key, iv);
try { try {

300
package-lock.json generated
View File

@ -1,32 +1,62 @@
{ {
"name": "datasquirel", "name": "datasquirel",
"version": "2.0.0", "version": "2.3.5",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "datasquirel", "name": "datasquirel",
"version": "2.0.0", "version": "2.3.5",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@types/ace": "^0.0.52",
"@types/react": "^18.3.12",
"@types/tinymce": "^4.6.9",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"generate-password": "^1.7.1",
"lodash": "^4.17.21",
"mysql": "^2.18.1", "mysql": "^2.18.1",
"nodemailer": "^6.9.14" "nodemailer": "^6.9.14",
"sanitize-html": "^2.13.1",
"serverless-mysql": "^1.5.5"
}, },
"bin": { "bin": {
"dsql-dump": "engine/dump.js", "dsql-dump": "engine/dump.js",
"dsql-watch": "engine/dsql.js" "dsql-watch": "engine/dsql.js"
}, },
"devDependencies": { "devDependencies": {
"@types/lodash": "^4.17.13",
"@types/mysql": "^2.15.21", "@types/mysql": "^2.15.21",
"@types/node": "^22.7.5" "@types/node": "^22.7.5"
} }
}, },
"node_modules/@types/ace": {
"version": "0.0.52",
"resolved": "https://registry.npmjs.org/@types/ace/-/ace-0.0.52.tgz",
"integrity": "sha512-YPF9S7fzpuyrxru+sG/rrTpZkC6gpHBPF14W3x70kqVOD+ks6jkYLapk4yceh36xej7K4HYxcyz9ZDQ2lTvwgQ==",
"license": "MIT"
},
"node_modules/@types/jquery": {
"version": "3.5.32",
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.32.tgz",
"integrity": "sha512-b9Xbf4CkMqS02YH8zACqN1xzdxc3cO735Qe5AbSUFmyOiaWAbcpqh9Wna+Uk0vgACvoQHpWDg2rGdHkYPLmCiQ==",
"license": "MIT",
"dependencies": {
"@types/sizzle": "*"
}
},
"node_modules/@types/lodash": {
"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": { "node_modules/@types/mysql": {
"version": "2.15.21", "version": "2.15.21",
"resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.21.tgz", "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.21.tgz",
"integrity": "sha512-NPotx5CVful7yB+qZbWtXL2fA4e7aEHkihHLjklc6ID8aq7bhguHgeIoC1EmSNTAuCgI6ZXrjt2ZSaXnYX0EUg==", "integrity": "sha512-NPotx5CVful7yB+qZbWtXL2fA4e7aEHkihHLjklc6ID8aq7bhguHgeIoC1EmSNTAuCgI6ZXrjt2ZSaXnYX0EUg==",
"dev": true, "devOptional": true,
"dependencies": { "dependencies": {
"@types/node": "*" "@types/node": "*"
} }
@ -35,12 +65,43 @@
"version": "22.7.5", "version": "22.7.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz",
"integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==",
"dev": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"undici-types": "~6.19.2" "undici-types": "~6.19.2"
} }
}, },
"node_modules/@types/prop-types": {
"version": "15.7.13",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
"integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==",
"license": "MIT"
},
"node_modules/@types/react": {
"version": "18.3.12",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz",
"integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==",
"license": "MIT",
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
}
},
"node_modules/@types/sizzle": {
"version": "2.3.9",
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.9.tgz",
"integrity": "sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w==",
"license": "MIT"
},
"node_modules/@types/tinymce": {
"version": "4.6.9",
"resolved": "https://registry.npmjs.org/@types/tinymce/-/tinymce-4.6.9.tgz",
"integrity": "sha512-pDxBUlV4v1jgJ97SlnVOSyf3KUy3OQ3s5Ddpfh1L9M5lXlBmX7TJ2OLSozx1WBxp91acHvYPWDwz2U/kMM1oxQ==",
"license": "MIT",
"dependencies": {
"@types/jquery": "*"
}
},
"node_modules/bignumber.js": { "node_modules/bignumber.js": {
"version": "9.0.0", "version": "9.0.0",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
@ -54,6 +115,76 @@
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
}, },
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"license": "MIT"
},
"node_modules/deepmerge": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"license": "MIT",
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
"entities": "^4.2.0"
},
"funding": {
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
}
},
"node_modules/domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
],
"license": "BSD-2-Clause"
},
"node_modules/domhandler": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"license": "BSD-2-Clause",
"dependencies": {
"domelementtype": "^2.3.0"
},
"engines": {
"node": ">= 4"
},
"funding": {
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
"node_modules/domutils": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
"license": "BSD-2-Clause",
"dependencies": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3"
},
"funding": {
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
"node_modules/dotenv": { "node_modules/dotenv": {
"version": "16.3.1", "version": "16.3.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz",
@ -65,16 +196,80 @@
"url": "https://github.com/motdotla/dotenv?sponsor=1" "url": "https://github.com/motdotla/dotenv?sponsor=1"
} }
}, },
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"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/htmlparser2": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
"funding": [
"https://github.com/fb55/htmlparser2?sponsor=1",
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
],
"license": "MIT",
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3",
"domutils": "^3.0.1",
"entities": "^4.4.0"
}
},
"node_modules/inherits": { "node_modules/inherits": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
}, },
"node_modules/is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/isarray": { "node_modules/isarray": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
}, },
"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/mysql": { "node_modules/mysql": {
"version": "2.18.1", "version": "2.18.1",
"resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz",
@ -89,6 +284,24 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/nanoid": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/nodemailer": { "node_modules/nodemailer": {
"version": "6.9.14", "version": "6.9.14",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.14.tgz", "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.14.tgz",
@ -98,6 +311,46 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/parse-srcset": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz",
"integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==",
"license": "MIT"
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"license": "ISC"
},
"node_modules/postcss": {
"version": "8.4.47",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
"integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
"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.7",
"picocolors": "^1.1.0",
"source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/process-nextick-args": { "node_modules/process-nextick-args": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@ -122,6 +375,41 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
}, },
"node_modules/sanitize-html": {
"version": "2.13.1",
"resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.13.1.tgz",
"integrity": "sha512-ZXtKq89oue4RP7abL9wp/9URJcqQNABB5GGJ2acW1sdO8JTVl92f4ygD7Yc9Ze09VAZhnt2zegeU0tbNsdcLYg==",
"license": "MIT",
"dependencies": {
"deepmerge": "^4.2.2",
"escape-string-regexp": "^4.0.0",
"htmlparser2": "^8.0.0",
"is-plain-object": "^5.0.0",
"parse-srcset": "^1.0.2",
"postcss": "^8.3.11"
}
},
"node_modules/serverless-mysql": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/serverless-mysql/-/serverless-mysql-1.5.5.tgz",
"integrity": "sha512-QwaCtswn3GKCnqyVA0whwDFMIw91iKTeTvf6F++HoGiunfyvfJ2MdU8d3MKMQdKGNOXIvmUlLq/JVjxuPQxkrw==",
"license": "MIT",
"dependencies": {
"mysql": "^2.18.1"
},
"optionalDependencies": {
"@types/mysql": "^2.15.6"
}
},
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/sqlstring": { "node_modules/sqlstring": {
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz",
@ -142,7 +430,7 @@
"version": "6.19.8", "version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"dev": true, "devOptional": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/util-deprecate": { "node_modules/util-deprecate": {

View File

@ -1,3 +1,7 @@
# Shared resources # Shared resources
This directory contains data (mostly type definitions) shared by both the datasquirel NPM package and the datasquirel web app This directory contains data (mostly type definitions) shared by both the datasquirel NPM package and the datasquirel web app
## Functions
## Types

View File

@ -0,0 +1,66 @@
// @ts-check
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");
/**
* # Add Mariadb User
*
* @description this function adds a Mariadb user to the database server
*
* @param {object} params - parameters object *
* @param {number | string} params.userId - invited user object
*
* @returns {Promise<any>} new user auth object payload
*/
module.exports = async function addMariadbUser({ userId }) {
try {
const defaultMariadbUserHost = process.env.DSQL_DB_HOST || "127.0.0.1";
const username = `dsql_user_${userId}`;
const password = generator.generate({
length: 16,
numbers: true,
symbols: true,
uppercase: true,
exclude: "*#.'`\"",
});
const encryptedPassword = encrypt(password);
await NO_DB_HANDLER(
`CREATE USER IF NOT EXISTS '${username}'@'127.0.0.1' IDENTIFIED BY '${password}' REQUIRE SSL`
);
const updateUser = await DB_HANDLER(
`UPDATE users SET mariadb_user = ?, mariadb_host = '127.0.0.1', mariadb_pass = ? WHERE id = ?`,
[username, encryptedPassword, userId]
);
const addMariadbUser = await addDbEntry({
tableName: "mariadb_users",
data: {
user_id: userId,
username,
host: defaultMariadbUserHost,
password: encryptedPassword,
primary: "1",
grants: '[{"database":"*","table":"*","privileges":["ALL"]}]',
},
dbContext: "Master",
});
console.log(`User ${userId} SQL credentials successfully added.`);
} catch (/** @type {any} */ error) {
console.log(
`Error in adding SQL user in 'addMariadbUser' function =>`,
error.message
);
}
};
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////

View File

@ -0,0 +1,43 @@
// @ts-check
const fs = require("fs");
const decrypt = require("./decrypt");
/** @type {import("../../types").CheckApiCredentialsFn} */
const grabApiCred = ({ key, database, table }) => {
try {
const allowedKeysPath = process.env.DSQL_API_KEYS_PATH;
if (!allowedKeysPath)
throw new Error(
"process.env.DSQL_API_KEYS_PATH variable not found"
);
const ApiJSON = decrypt(key);
/** @type {import("../../types").ApiKeyObject} */
const ApiObject = JSON.parse(ApiJSON || "");
const isApiKeyValid = fs.existsSync(
`${allowedKeysPath}/${ApiObject.sign}`
);
if (!isApiKeyValid) return null;
if (!ApiObject.target_database) return ApiObject;
if (!database && ApiObject.target_database) return null;
const isDatabaseAllowed = ApiObject.target_database
?.split(",")
.includes(String(database));
if (isDatabaseAllowed && !ApiObject.target_table) return ApiObject;
if (isDatabaseAllowed && !table && ApiObject.target_table) return null;
const isTableAllowed = ApiObject.target_table
?.split(",")
.includes(String(table));
if (isTableAllowed) return ApiObject;
return null;
} catch (/** @type {any} */ error) {
console.log(`api-cred ERROR: ${error.message}`);
return null;
}
};
module.exports = grabApiCred;

View File

@ -0,0 +1,163 @@
// @ts-check
const fs = require("fs");
const DB_HANDLER = require("../../../utils/backend/global-db/DB_HANDLER");
/** ****************************************************************************** */
/** ****************************************************************************** */
/** ****************************************************************************** */
/** ****************************************************************************** */
/** ****************************************************************************** */
/** ****************************************************************************** */
/**
* Add Database Entry
* ==============================================================================
* @param {object} params - foundUser if any
* @param {string} params.tableName - Table Name
* @param {any} params.data - Data to be added
* @param {string} [params.duplicateColumnName] - Duplicate Column Name
* @param {string | number} [params.duplicateColumnValue] - Duplicate Column Value
*/
module.exports = async function addDbEntry({
tableName,
data,
duplicateColumnName,
duplicateColumnValue,
}) {
/**
* Check Duplicate if specified
*
* @description Check Duplicate if specified
*/
if (duplicateColumnName) {
let duplicateEntry = await DB_HANDLER(
`SELECT ${duplicateColumnName} FROM ${tableName} WHERE ${duplicateColumnName}='${duplicateColumnValue}'`
);
if (duplicateEntry && duplicateEntry[0]) return null;
}
/**
* Declare variables
*
* @description Declare "results" variable
*/
const dataKeys = Object.keys(data);
let insertKeysArray = [];
let insertValuesArray = [];
for (let i = 0; i < dataKeys.length; i++) {
const dataKey = dataKeys[i];
let dataValue = data[dataKey];
// const correspondingColumnObject = dbColumns.filter((col) => col.Field === dataKey);
// const { Field, Type, Null, Key, Default, Extra } = correspondingColumnObject;
if (!dataValue) continue;
insertKeysArray.push("`" + dataKey + "`");
if (typeof dataValue === "object") {
dataValue = JSON.stringify(data[dataKey]);
}
// let parsedDataValue = dataValue.toString().replace(/\'/g, "\\'");
insertValuesArray.push(dataValue);
}
////////////////////////////////////////
// @ts-ignore
let existingDateCreatedColumn = await DB_HANDLER(
`SHOW COLUMNS FROM \`${tableName}\` WHERE Field = 'date_created'`
);
if (!existingDateCreatedColumn || !existingDateCreatedColumn[0]) {
// @ts-ignore
await DB_HANDLER(
`ALTER TABLE ${tableName} ADD COLUMN date_created VARCHAR(255) NOT NULL`
);
}
insertKeysArray.push("date_created");
insertValuesArray.push(Date());
////////////////////////////////////////
// @ts-ignore
let existingDateCreatedCodeColumn = await DB_HANDLER(
`SHOW COLUMNS FROM ${tableName} WHERE Field = 'date_created_code'`
);
if (!existingDateCreatedCodeColumn || !existingDateCreatedCodeColumn[0]) {
// @ts-ignore
await DB_HANDLER(
`ALTER TABLE ${tableName} ADD COLUMN date_created_code BIGINT NOT NULL`
);
}
insertKeysArray.push("date_created_code");
insertValuesArray.push(Date.now());
////////////////////////////////////////
// @ts-ignore
let existingDateCodeColumn = await DB_HANDLER(
`SHOW COLUMNS FROM ${tableName} WHERE Field = 'date_code'`
);
if (existingDateCodeColumn && existingDateCodeColumn[0]) {
insertKeysArray.push("date_code");
insertValuesArray.push(Date.now());
}
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
// @ts-ignore
let existingDateUpdatedColumn = await DB_HANDLER(
`SHOW COLUMNS FROM ${tableName} WHERE Field = 'date_updated'`
);
if (!existingDateUpdatedColumn || !existingDateUpdatedColumn[0]) {
// @ts-ignore
await DB_HANDLER(
`ALTER TABLE ${tableName} ADD COLUMN date_updated VARCHAR(255) NOT NULL`
);
}
insertKeysArray.push("date_updated");
insertValuesArray.push(Date());
////////////////////////////////////////
// @ts-ignore
let existingDateUpdatedCodeColumn = await DB_HANDLER(
`SHOW COLUMNS FROM ${tableName} WHERE Field = 'date_updated_code'`
);
if (!existingDateUpdatedCodeColumn || !existingDateUpdatedCodeColumn[0]) {
// @ts-ignore
await DB_HANDLER(
`ALTER TABLE ${tableName} ADD COLUMN date_updated_code BIGINT NOT NULL`
);
}
insertKeysArray.push("date_updated_code");
insertValuesArray.push(Date.now());
////////////////////////////////////////
const query = `INSERT INTO ${tableName} (${insertKeysArray.join(
","
)}) VALUES (${insertValuesArray.map((val) => "?").join(",")})`;
const queryValuesArray = insertValuesArray;
// @ts-ignore
const newInsert = await DB_HANDLER(query, queryValuesArray);
////////////////////////////////////////
return newInsert;
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
};

View File

@ -0,0 +1,232 @@
// @ts-check
/**
* Imports: Handle imports
*/
const encrypt = require("../encrypt");
const sanitizeHtml = require("sanitize-html");
const sanitizeHtmlOptions = require("../html/sanitizeHtmlOptions");
const updateDb = require("./updateDbEntry");
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");
/**
* Add a db Entry Function
* ==============================================================================
* @description Description
* @async
*
* @param {object} params - An object containing the function parameters.
* @param {("Master" | "Dsql User")} [params.dbContext] - What is the database context? "Master"
* or "Dsql User". Defaults to "Master"
* @param {("Read Only" | "Full Access")} [params.paradigm] - What is the paradigm for "Dsql User"?
* "Read only" or "Full Access"? Defaults to "Read Only"
* @param {string} [params.dbFullName] - Database full name
* @param {string} params.tableName - Table name
* @param {any} params.data - Data to add
* @param {import("../../../types").DSQL_TableSchemaType} [params.tableSchema] - Table schema
* @param {string} [params.duplicateColumnName] - Duplicate column name
* @param {string} [params.duplicateColumnValue] - Duplicate column value
* @param {boolean} [params.update] - Update this row if it exists
* @param {string} [params.encryptionKey] - Update this row if it exists
* @param {string} [params.encryptionSalt] - Update this row if it exists
*
* @returns {Promise<any>}
*/
async function addDbEntry({
dbContext,
paradigm,
dbFullName,
tableName,
data,
tableSchema,
duplicateColumnName,
duplicateColumnValue,
update,
encryptionKey,
encryptionSalt,
}) {
/**
* Initialize variables
*/
const isMaster = dbContext?.match(/dsql.user/i)
? false
: dbFullName && !dbFullName.match(/^datasquirel$/)
? false
: true;
/** @type { any } */
const dbHandler = isMaster ? DB_HANDLER : DSQL_USER_DB_HANDLER;
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
if (data?.["date_created_timestamp"]) delete data["date_created_timestamp"];
if (data?.["date_updated_timestamp"]) delete data["date_updated_timestamp"];
if (data?.["date_updated"]) delete data["date_updated"];
if (data?.["date_updated_code"]) delete data["date_updated_code"];
if (data?.["date_created"]) delete data["date_created"];
if (data?.["date_created_code"]) delete data["date_created_code"];
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
/**
* Handle function logic
*/
if (duplicateColumnName && typeof duplicateColumnName === "string") {
const duplicateValue = isMaster
? await dbHandler(
`SELECT * FROM \`${tableName}\` WHERE \`${duplicateColumnName}\`=?`,
[duplicateColumnValue]
)
: await dbHandler({
paradigm: "Read Only",
database: dbFullName,
queryString: `SELECT * FROM \`${tableName}\` WHERE \`${duplicateColumnName}\`=?`,
queryValues: [duplicateColumnValue],
});
if (duplicateValue?.[0] && !update) {
return null;
} else if (duplicateValue && duplicateValue[0] && update) {
return await updateDbEntry({
dbContext,
paradigm,
dbFullName,
tableName,
data,
tableSchema,
encryptionKey,
encryptionSalt,
identifierColumnName: duplicateColumnName,
identifierValue: duplicateColumnValue || "",
});
}
}
/**
* Declare variables
*
* @description Declare "results" variable
*/
const dataKeys = Object.keys(data);
let insertKeysArray = [];
let insertValuesArray = [];
for (let i = 0; i < dataKeys.length; i++) {
try {
const dataKey = dataKeys[i];
// @ts-ignore
let value = data?.[dataKey];
const targetFieldSchemaArray = tableSchema
? tableSchema?.fields?.filter(
(field) => field.fieldName == dataKey
)
: null;
const targetFieldSchema =
targetFieldSchemaArray && targetFieldSchemaArray[0]
? targetFieldSchemaArray[0]
: null;
if (value == null || value == undefined) continue;
if (targetFieldSchema?.encrypted) {
value = encrypt(value, encryptionKey, encryptionSalt);
console.log("DSQL: Encrypted value =>", value);
}
if (targetFieldSchema?.richText) {
value = sanitizeHtml(value, sanitizeHtmlOptions);
}
if (targetFieldSchema?.pattern) {
const pattern = new RegExp(
targetFieldSchema.pattern,
targetFieldSchema.patternFlags || ""
);
if (!pattern.test(value)) {
console.log("DSQL: Pattern not matched =>", value);
value = "";
}
}
insertKeysArray.push("`" + dataKey + "`");
if (typeof value === "object") {
value = JSON.stringify(value);
}
if (typeof value == "number") {
insertValuesArray.push(String(value));
} else {
insertValuesArray.push(value);
}
} catch (/** @type {any} */ error) {
console.log("DSQL: Error in parsing data keys =>", error.message);
continue;
}
}
////////////////////////////////////////
if (!data?.["date_created"]) {
insertKeysArray.push("`date_created`");
insertValuesArray.push(Date());
}
if (!data?.["date_created_code"]) {
insertKeysArray.push("`date_created_code`");
insertValuesArray.push(Date.now());
}
////////////////////////////////////////
if (!data?.["date_updated"]) {
insertKeysArray.push("`date_updated`");
insertValuesArray.push(Date());
}
if (!data?.["date_updated_code"]) {
insertKeysArray.push("`date_updated_code`");
insertValuesArray.push(Date.now());
}
////////////////////////////////////////
const query = `INSERT INTO \`${tableName}\` (${insertKeysArray.join(
","
)}) VALUES (${insertValuesArray.map(() => "?").join(",")})`;
const queryValuesArray = insertValuesArray;
const newInsert = isMaster
? await dbHandler(query, queryValuesArray)
: await dbHandler({
paradigm,
database: dbFullName,
queryString: query,
queryValues: queryValuesArray,
});
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
/**
* Return statement
*/
return newInsert;
}
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
module.exports = addDbEntry;

View File

@ -1,6 +1,7 @@
// @ts-check // @ts-check
const dbHandler = require("../../engine/utils/dbHandler"); const DB_HANDLER = require("../../../utils/backend/global-db/DB_HANDLER");
const DSQL_USER_DB_HANDLER = require("../../../utils/backend/global-db/DSQL_USER_DB_HANDLER");
/** /**
* Imports: Handle imports * Imports: Handle imports
@ -19,7 +20,7 @@ const dbHandler = require("../../engine/utils/dbHandler");
* "Read only" or "Full Access"? Defaults to "Read Only" * "Read only" or "Full Access"? Defaults to "Read Only"
* @param {string} params.dbFullName - Database full name * @param {string} params.dbFullName - Database full name
* @param {string} params.tableName - Table name * @param {string} params.tableName - Table name
* @param {import("@/package-shared/types/database-schema.td").DSQL_TableSchemaType} [params.tableSchema] - Table schema * @param {import("../../../types").DSQL_TableSchemaType} [params.tableSchema] - Table schema
* @param {string} params.identifierColumnName - Update row identifier column name * @param {string} params.identifierColumnName - Update row identifier column name
* @param {string|number} params.identifierValue - Update row identifier column value * @param {string|number} params.identifierValue - Update row identifier column value
* *
@ -37,6 +38,14 @@ async function deleteDbEntry({
/** /**
* Check if data is valid * Check if data is valid
*/ */
const isMaster = dbContext?.match(/dsql.user/i)
? false
: dbFullName && !dbFullName.match(/^datasquirel$/)
? false
: true;
/** @type { (a1:any, a2?:any) => any } */
const dbHandler = isMaster ? DB_HANDLER : DSQL_USER_DB_HANDLER;
//////////////////////////////////////// ////////////////////////////////////////
//////////////////////////////////////// ////////////////////////////////////////
@ -49,10 +58,13 @@ async function deleteDbEntry({
*/ */
const query = `DELETE FROM ${tableName} WHERE \`${identifierColumnName}\`=?`; const query = `DELETE FROM ${tableName} WHERE \`${identifierColumnName}\`=?`;
const deletedEntry = await dbHandler({ const deletedEntry = isMaster
query: query, ? await dbHandler(query, [identifierValue])
: await dbHandler({
paradigm,
queryString: query,
database: dbFullName, database: dbFullName,
values: [identifierValue], queryValues: [identifierValue],
}); });
//////////////////////////////////////// ////////////////////////////////////////

View File

@ -0,0 +1,41 @@
// @ts-check
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/**
* Sanitize SQL function
* ==============================================================================
* @description this function takes in a text(or number) and returns a sanitized
* text, usually without spaces
*
* @param {string|number} text - Text or number or object
*
* @returns {string}
*/
function pathTraversalCheck(text) {
/**
* Initial Checks
*
* @description Initial Checks
*/
return text.toString().replace(/\//g, "");
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
module.exports = pathTraversalCheck;

View File

@ -1,21 +1,25 @@
/** # MODULE TRACE /** # MODULE TRACE
====================================================================== ======================================================================
* Detected 4 files that call this module. The files are listed below: * Detected 3 files that call this module. The files are listed below:
====================================================================== ======================================================================
* `require` Statement Found in [get.js](d:\GitHub\dsql\engine\query\get.js) * `import` Statement Found in [get.js] => file:///d:\GitHub\datasquirel\pages\api\query\get.js
* `require` Statement Found in [post.js](d:\GitHub\dsql\engine\query\post.js) * `import` Statement Found in [post.js] => file:///d:\GitHub\datasquirel\pages\api\query\post.js
* `require` Statement Found in [add-user.js](d:\GitHub\dsql\engine\user\add-user.js) * `import` Statement Found in [add-user.js] => file:///d:\GitHub\datasquirel\pages\api\user\add-user.js
* `require` Statement Found in [update-user.js](d:\GitHub\dsql\engine\user\update-user.js)
==== MODULE TRACE END ==== */ ==== MODULE TRACE END ==== */
// @ts-check // @ts-check
const fs = require("fs"); const fs = require("fs");
const fullAccessDbHandler = require("../fullAccessDbHandler");
const varReadOnlyDatabaseDbHandler = require("../varReadOnlyDatabaseDbHandler");
const serverError = require("../serverError");
const addDbEntry = require("./addDbEntry"); const addDbEntry = require("./addDbEntry");
const updateDbEntry = require("./updateDbEntry"); const updateDbEntry = require("./updateDbEntry");
const deleteDbEntry = require("./deleteDbEntry"); const deleteDbEntry = require("./deleteDbEntry");
const varDatabaseDbHandler = require("../../engine/utils/varDatabaseDbHandler"); const DB_HANDLER = require("../../../utils/backend/global-db/DB_HANDLER");
const parseDbResults = require("../parseDbResults");
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
@ -29,13 +33,14 @@ const varDatabaseDbHandler = require("../../engine/utils/varDatabaseDbHandler");
* ============================================================================== * ==============================================================================
* @param {object} params - An object containing the function parameters. * @param {object} params - An object containing the function parameters.
* @param {string} params.dbFullName - Database full name. Eg. "datasquire_user_2_test" * @param {string} params.dbFullName - Database full name. Eg. "datasquire_user_2_test"
* @param {*} params.query - Query string or object * @param {string | any} params.query - Query string or object
* @param {boolean} [params.readOnly] - Is this operation read only? * @param {boolean} [params.readOnly] - Is this operation read only?
* @param {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType} [params.dbSchema] - Database schema * @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.queryValuesArray] - An optional array of query values if "?" is used in the query string
* @param {string} [params.tableName] - Table Name * @param {string} [params.tableName] - Table Name
* *
* @return {Promise<{result: *, error?: *}>} * @return {Promise<any>}
*/ */
async function runQuery({ async function runQuery({
dbFullName, dbFullName,
@ -44,16 +49,20 @@ async function runQuery({
dbSchema, dbSchema,
queryValuesArray, queryValuesArray,
tableName, tableName,
local,
}) { }) {
/** /**
* Declare variables * Declare variables
* *
* @description Declare "results" variable * @description Declare "results" variable
*/ */
const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || "";
const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || "";
let result, error, tableSchema; /** @type {any} */
let result;
/** @type {any} */
let error;
/** @type {import("../../../types").DSQL_TableSchemaType | undefined} */
let tableSchema;
if (dbSchema) { if (dbSchema) {
try { try {
@ -68,7 +77,9 @@ async function runQuery({
tableSchema = dbSchema.tables.filter( tableSchema = dbSchema.tables.filter(
(tb) => tb?.tableName === table (tb) => tb?.tableName === table
)[0]; )[0];
} catch (_err) {} } catch (_err) {
// console.log("ERROR getting tableSchema: ", _err.message);
}
} }
/** /**
@ -78,12 +89,29 @@ async function runQuery({
*/ */
try { try {
if (typeof query === "string") { if (typeof query === "string") {
result = await varDatabaseDbHandler({ if (local) {
const rawResults = await DB_HANDLER(query, queryValuesArray);
result = tableSchema
? parseDbResults({
unparsedResults: rawResults,
tableSchema,
})
: rawResults;
} else if (readOnly) {
result = await varReadOnlyDatabaseDbHandler({
queryString: query, queryString: query,
queryValuesArray, queryValuesArray,
database: dbFullName, database: dbFullName,
tableSchema, tableSchema,
}); });
} else {
result = await fullAccessDbHandler({
queryString: query,
queryValuesArray,
database: dbFullName,
tableSchema,
});
}
} else if (typeof query === "object") { } else if (typeof query === "object") {
/** /**
* Declare variables * Declare variables
@ -104,6 +132,8 @@ async function runQuery({
switch (action.toLowerCase()) { switch (action.toLowerCase()) {
case "insert": case "insert":
result = await addDbEntry({ result = await addDbEntry({
dbContext: local ? "Master" : "Dsql User",
paradigm: "Full Access",
dbFullName: dbFullName, dbFullName: dbFullName,
tableName: table, tableName: table,
data: data, data: data,
@ -111,8 +141,6 @@ async function runQuery({
duplicateColumnName, duplicateColumnName,
duplicateColumnValue, duplicateColumnValue,
tableSchema, tableSchema,
encryptionKey,
encryptionSalt,
}); });
if (!result?.insertId) { if (!result?.insertId) {
@ -123,7 +151,7 @@ async function runQuery({
case "update": case "update":
result = await updateDbEntry({ result = await updateDbEntry({
dbContext: "Dsql User", dbContext: local ? "Master" : "Dsql User",
paradigm: "Full Access", paradigm: "Full Access",
dbFullName: dbFullName, dbFullName: dbFullName,
tableName: table, tableName: table,
@ -131,15 +159,13 @@ async function runQuery({
identifierColumnName, identifierColumnName,
identifierValue, identifierValue,
tableSchema, tableSchema,
encryptionKey,
encryptionSalt,
}); });
break; break;
case "delete": case "delete":
result = await deleteDbEntry({ result = await deleteDbEntry({
dbContext: "Dsql User", dbContext: local ? "Master" : "Dsql User",
paradigm: "Full Access", paradigm: "Full Access",
dbFullName: dbFullName, dbFullName: dbFullName,
tableName: table, tableName: table,
@ -151,12 +177,7 @@ async function runQuery({
break; break;
default: default:
console.log("Unhandled Query"); result = null;
console.log("Query Recieved =>", query);
result = {
result: null,
error: "Unhandled Query",
};
break; break;
} }
} }
@ -164,14 +185,12 @@ async function runQuery({
//////////////////////////////////////// ////////////////////////////////////////
//////////////////////////////////////// ////////////////////////////////////////
//////////////////////////////////////// ////////////////////////////////////////
} catch (/** @type {*} */ error) { } catch (/** @type {any} */ error) {
console.log("Error in Running Query =>", error.message); serverError({
console.log("Query Recieved =>", query); component: "functions/backend/runQuery",
message: error.message,
result = { });
result: null, result = null;
error: "Error in running Query => " + error.message,
};
error = error.message; error = error.message;
} }

View File

@ -0,0 +1,207 @@
// @ts-check
const _ = require("lodash");
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/**
* Sanitize SQL function
* ==============================================================================
* @description this function takes in a text(or number) and returns a sanitized
* text, usually without spaces
*
* @param {any} text - Text or number or object
* @param {boolean} [spaces] - Allow spaces
* @param {RegExp?} [regex] - Regular expression, removes any match
*
* @returns {any}
*/
function sanitizeSql(text, spaces, regex) {
/**
* Initial Checks
*
* @description Initial Checks
*/
if (!text) return "";
if (typeof text == "number" || typeof text == "boolean") return text;
if (typeof text == "string" && !text?.toString()?.match(/./)) return "";
if (typeof text == "object" && !Array.isArray(text)) {
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
const newObject = sanitizeObjects(text, spaces);
return newObject;
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
} else if (typeof text == "object" && Array.isArray(text)) {
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
const newArray = sanitizeArrays(text, spaces);
return newArray;
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
}
// if (text?.toString()?.match(/\'|\"/)) {
// console.log("TEXT containing commas =>", text);
// return "";
// }
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
/**
* Declare variables
*
* @description Declare "results" variable
*/
let finalText = text;
if (regex) {
finalText = text.toString().replace(regex, "");
}
if (spaces) {
} else {
finalText = text
.toString()
.replace(/\n|\r|\n\r|\r\n/g, "")
.replace(/ /g, "");
}
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
const escapeRegex =
/select |insert |drop |delete |alter |create |exec | union | or | like | concat|LOAD_FILE|ASCII| COLLATE | HAVING | information_schema|DECLARE |\#|WAITFOR |delay |BENCHMARK |\/\*.*\*\//gi;
finalText = finalText
.replace(/(?<!\\)\'/g, "\\'")
.replace(/(?<!\\)\`/g, "\\`")
// .replace(/(?<!\\)\"/g, '\\"')
.replace(/\/\*\*\//g, "")
.replace(escapeRegex, "\\$&");
// const injectionRegexp = /select .* from|\*|delete from|drop database|drop table|update .* set/i;
// if (text?.toString()?.match(injectionRegexp)) {
// console.log("ATTEMPTED INJECTION =>", text);
// return "";
// }
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
return finalText;
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/**
* Sanitize Objects Function
* ==============================================================================
* @description Sanitize objects in the form { key: "value" }
*
* @param {any} object - Database Full Name
* @param {boolean} [spaces] - Allow spaces
*
* @returns {object}
*/
function sanitizeObjects(object, spaces) {
/** @type {any} */
let objectUpdated = { ...object };
const keys = Object.keys(objectUpdated);
keys.forEach((key) => {
const value = objectUpdated[key];
if (!value) {
delete objectUpdated[key];
return;
}
if (typeof value == "string" || typeof value == "number") {
objectUpdated[key] = sanitizeSql(value, spaces);
} else if (typeof value == "object" && !Array.isArray(value)) {
objectUpdated[key] = sanitizeObjects(value, spaces);
} else if (typeof value == "object" && Array.isArray(value)) {
objectUpdated[key] = sanitizeArrays(value, spaces);
}
});
return objectUpdated;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/**
* Sanitize Objects Function
* ==============================================================================
* @description Sanitize objects in the form { key: "value" }
*
* @param {any[]} array - Database Full Name
* @param {boolean} [spaces] - Allow spaces
*
* @returns {string[]|number[]|object[]}
*/
function sanitizeArrays(array, spaces) {
let arrayUpdated = _.cloneDeep(array);
arrayUpdated.forEach((item, index) => {
const value = item;
if (!value) {
arrayUpdated.splice(index, 1);
return;
}
if (typeof item == "string" || typeof item == "number") {
arrayUpdated[index] = sanitizeSql(value, spaces);
} else if (typeof item == "object" && !Array.isArray(value)) {
arrayUpdated[index] = sanitizeObjects(value, spaces);
} else if (typeof item == "object" && Array.isArray(value)) {
arrayUpdated[index] = sanitizeArrays(item, spaces);
}
});
return arrayUpdated;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
module.exports = sanitizeSql;

View File

@ -1,11 +1,13 @@
// @ts-check // @ts-check
const encrypt = require("../../../functions/encrypt");
const dbHandler = require("../../engine/utils/dbHandler");
/** /**
* Imports: Handle imports * 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");
/** /**
* Update DB Function * Update DB Function
@ -18,14 +20,14 @@ const dbHandler = require("../../engine/utils/dbHandler");
* or "Dsql User". Defaults to "Master" * or "Dsql User". Defaults to "Master"
* @param {("Read Only" | "Full Access")} [params.paradigm] - What is the paradigm for "Dsql User"? * @param {("Read Only" | "Full Access")} [params.paradigm] - What is the paradigm for "Dsql User"?
* "Read only" or "Full Access"? Defaults to "Read Only" * "Read only" or "Full Access"? Defaults to "Read Only"
* @param {string} params.dbFullName - Database full name * @param {string} [params.dbFullName] - Database full name
* @param {string} params.tableName - Table name * @param {string} params.tableName - Table name
* @param {*} params.data - Data to add * @param {string} [params.encryptionKey]
* @param {import("@/package-shared/types/database-schema.td").DSQL_TableSchemaType} [params.tableSchema] - Table schema * @param {string} [params.encryptionSalt]
* @param {any} params.data - Data to add
* @param {import("../../../types").DSQL_TableSchemaType} [params.tableSchema] - Table schema
* @param {string} params.identifierColumnName - Update row identifier column name * @param {string} params.identifierColumnName - Update row identifier column name
* @param {string | number} params.identifierValue - Update row identifier column value * @param {string | number} params.identifierValue - Update row identifier column value
* @param {string} params.encryptionKey - Encryption key
* @param {string} params.encryptionSalt - Encryption salt
* *
* @returns {Promise<object|null>} * @returns {Promise<object|null>}
*/ */
@ -46,6 +48,15 @@ async function updateDbEntry({
*/ */
if (!data || !Object.keys(data).length) return null; if (!data || !Object.keys(data).length) return null;
const isMaster = dbContext?.match(/dsql.user/i)
? false
: dbFullName && !dbFullName.match(/^datasquirel$/)
? false
: true;
/** @type {(a1:any, a2?:any)=> any } */
const dbHandler = isMaster ? DB_HANDLER : DSQL_USER_DB_HANDLER;
//////////////////////////////////////// ////////////////////////////////////////
//////////////////////////////////////// ////////////////////////////////////////
//////////////////////////////////////// ////////////////////////////////////////
@ -60,14 +71,10 @@ async function updateDbEntry({
let updateKeyValueArray = []; let updateKeyValueArray = [];
let updateValues = []; let updateValues = [];
/**
* Declare variables
*
* @description Declare "results" variable
*/
for (let i = 0; i < dataKeys.length; i++) { for (let i = 0; i < dataKeys.length; i++) {
try { try {
const dataKey = dataKeys[i]; const dataKey = dataKeys[i];
// @ts-ignore
let value = data[dataKey]; let value = data[dataKey];
const targetFieldSchemaArray = tableSchema const targetFieldSchemaArray = tableSchema
@ -80,22 +87,31 @@ async function updateDbEntry({
? targetFieldSchemaArray[0] ? targetFieldSchemaArray[0]
: null; : null;
if (typeof value == "undefined") continue; if (value == null || value == undefined) continue;
if (
typeof value !== "string" && if (targetFieldSchema?.richText) {
typeof value !== "number" && value = sanitizeHtml(value, sanitizeHtmlOptions);
!value }
)
continue;
if (targetFieldSchema?.encrypted) { if (targetFieldSchema?.encrypted) {
value = encrypt({ data: value, encryptionKey, encryptionSalt }); value = encrypt(value, encryptionKey, encryptionSalt);
} }
if (typeof value === "object") { if (typeof value === "object") {
value = JSON.stringify(value); value = JSON.stringify(value);
} }
if (targetFieldSchema?.pattern) {
const pattern = new RegExp(
targetFieldSchema.pattern,
targetFieldSchema.patternFlags || ""
);
if (!pattern.test(value)) {
console.log("DSQL: Pattern not matched =>", value);
value = "";
}
}
if (typeof value === "string" && value.match(/^null$/i)) { if (typeof value === "string" && value.match(/^null$/i)) {
value = { value = {
toSqlString: function () { toSqlString: function () {
@ -104,17 +120,6 @@ async function updateDbEntry({
}; };
} }
if (targetFieldSchema?.pattern) {
const pattern = new RegExp(
targetFieldSchema.pattern,
targetFieldSchema.patternFlags || ""
);
if (!value?.toString()?.match(pattern)) {
console.log("DSQL: Pattern not matched =>", value);
value = "";
}
}
if (typeof value === "string" && !value.match(/./i)) { if (typeof value === "string" && !value.match(/./i)) {
value = { value = {
toSqlString: function () { toSqlString: function () {
@ -123,14 +128,17 @@ async function updateDbEntry({
}; };
} }
if (!value && typeof value == "number" && value != 0) continue;
updateKeyValueArray.push(`\`${dataKey}\`=?`); updateKeyValueArray.push(`\`${dataKey}\`=?`);
if (typeof value == "number") {
updateValues.push(String(value));
} else {
updateValues.push(value); updateValues.push(value);
}
//////////////////////////////////////// ////////////////////////////////////////
//////////////////////////////////////// ////////////////////////////////////////
} catch (/** @type {*} */ error) { } catch (/** @type {any} */ error) {
//////////////////////////////////////// ////////////////////////////////////////
//////////////////////////////////////// ////////////////////////////////////////
@ -157,10 +165,13 @@ async function updateDbEntry({
updateValues.push(identifierValue); updateValues.push(identifierValue);
const updatedEntry = await dbHandler({ const updatedEntry = isMaster
? await dbHandler(query, updateValues)
: await dbHandler({
paradigm,
database: dbFullName, database: dbFullName,
query: query, queryString: query,
values: updateValues, queryValues: updateValues,
}); });
//////////////////////////////////////// ////////////////////////////////////////

View File

@ -0,0 +1,91 @@
// @ts-check
const fs = require("fs");
const serverError = require("./serverError");
const mysql = require("serverless-mysql");
const path = require("path");
const SSL_DIR =
process.env.DSQL_SSL_DIR || path.resolve(__dirname, "../../../ssl");
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: {
ca: fs.readFileSync(`${SSL_DIR}/ca-cert.pem`),
},
},
});
/**
* Main DB Handler Function
* ==============================================================================
* @async
*
* @param {any} args
* @returns {Promise<object|null>}
*/
module.exports = async function dbHandler(...args) {
process.env.NODE_ENV?.match(/dev/) &&
fs.appendFileSync(
"./.tmp/sqlQuery.sql",
args[0] + "\n" + Date() + "\n\n\n",
"utf8"
);
/**
* 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) => {
// @ts-ignore
connection.query(...args, (error, result, fields) => {
if (error) {
resolve({ error: error.message });
} else {
resolve(result);
}
});
});
await connection.end();
} catch (/** @type {any} */ error) {
fs.appendFileSync(
"./.tmp/dbErrorLogs.txt",
JSON.stringify(error, null, 4) + "\n" + Date() + "\n\n\n",
"utf8"
);
results = null;
serverError({
component: "dbHandler",
message: error.message,
});
}
/**
* Return results
*
* @description Return results add to cache if "req" param is passed
*/
if (results) {
return JSON.parse(JSON.stringify(results));
} else {
return null;
}
};

View File

@ -0,0 +1,29 @@
// @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;

View File

@ -0,0 +1,15 @@
// @ts-check
/**
* Regular expression to match default fields
*
* @description Regular expression to match default fields
*/
const defaultFieldsRegexp =
/^id$|^uuid$|^date_created$|^date_created_code$|^date_created_timestamp$|^date_updated$|^date_updated_code$|^date_updated_timestamp$/;
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
module.exports = defaultFieldsRegexp;

View File

@ -0,0 +1,43 @@
// @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;

View File

@ -0,0 +1,78 @@
// @ts-check
const DSQL_USER_DB_HANDLER = require("../../utils/backend/global-db/DSQL_USER_DB_HANDLER");
const parseDbResults = require("./parseDbResults");
const serverError = require("./serverError");
/**
*
* @param {object} param0
* @param {string} param0.queryString
* @param {string} param0.database
* @param {boolean} [param0.local]
* @param {import("../../types").DSQL_TableSchemaType | null} [param0.tableSchema]
* @param {string[]} [param0.queryValuesArray]
* @returns
*/
module.exports = async function fullAccessDbHandler({
queryString,
database,
tableSchema,
queryValuesArray,
local,
}) {
/**
* Declare variables
*
* @description Declare "results" variable
*/
let results;
/**
* Fetch from db
*
* @description Fetch data from db if no cache
*/
try {
/** ********************* Run Query */
results = await DSQL_USER_DB_HANDLER({
paradigm: "Full Access",
database,
queryString,
queryValues: queryValuesArray,
});
////////////////////////////////////////
} catch (/** @type {any} */ error) {
////////////////////////////////////////
serverError({
component: "fullAccessDbHandler",
message: error.message,
});
/**
* Return error
*/
return error.message;
}
/**
* Return results
*
* @description Return results add to cache if "req" param is passed
*/
if (results && tableSchema) {
const unparsedResults = results;
const parsedResults = await parseDbResults({
unparsedResults: unparsedResults,
tableSchema: tableSchema,
});
return parsedResults;
} else if (results) {
return results;
} else {
return null;
}
};

View File

@ -0,0 +1,12 @@
// @ts-check
const sanitizeHtmlOptions = {
allowedTags: ["b", "i", "em", "strong", "a", "p", "span", "ul", "ol", "li", "h1", "h2", "h3", "h4", "h5", "h6", "img", "div", "button", "pre", "code", "br"],
allowedAttributes: {
a: ["href"],
img: ["src", "alt", "width", "height", "class", "style"],
"*": ["style", "class"],
},
};
module.exports = sanitizeHtmlOptions;

View File

@ -0,0 +1,59 @@
// @ts-check
const fs = require("fs");
const serverError = require("./serverError");
const NO_DB_HANDLER = require("../../../package-shared/utils/backend/global-db/NO_DB_HANDLER");
/**
* Create database from Schema Function
* ==============================================================================
* @param {string} queryString - Query String
* @returns {Promise<any>}
*/
module.exports = async function noDatabaseDbHandler(queryString) {
process.env.NODE_ENV?.match(/dev/) &&
fs.appendFileSync(
"./.tmp/sqlQuery.sql",
queryString + "\n" + Date() + "\n\n\n",
"utf8"
);
/**
* Declare variables
*
* @description Declare "results" variable
*/
let results;
/**
* Fetch from db
*
* @description Fetch data from db if no cache
*/
try {
/** ********************* Run Query */
results = await NO_DB_HANDLER(queryString);
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
} catch (/** @type {any} */ error) {
serverError({
component: "noDatabaseDbHandler",
message: error.message,
});
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;
}
};

View File

@ -0,0 +1,76 @@
// @ts-check
const decrypt = require("./decrypt");
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 {any[]} params.unparsedResults - Array of data objects containing Fields(keys)
* and corresponding values of the fields(values)
* @param {import("../../types").DSQL_TableSchemaType} [params.tableSchema] - Table schema
* @returns {Promise<object[]|null>}
*/
module.exports = async function parseDbResults({
unparsedResults,
tableSchema,
}) {
/**
* Declare variables
*
* @description Declare "results" variable
*/
let parsedResults = [];
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) {
if (value?.match(/./)) {
result[resultFieldName] = decrypt(value);
}
}
}
parsedResults.push(result);
}
/**
* Declare variables
*
* @description Declare "results" variable
*/
return parsedResults;
} catch (/** @type {any} */ error) {
console.log("ERROR in parseDbResults Function =>", error.message);
return unparsedResults;
}
};

View File

@ -0,0 +1,31 @@
// @ts-check
const { createHmac } = require("crypto");
//
/**
* # Password Hash function
* @param {string} password
* @returns
*/
function hashPassword(password) {
const hmac = createHmac(
"sha512",
process.env.DSQL_ENCRYPTION_PASSWORD || ""
);
hmac.update(password);
let hashed = hmac.digest("base64");
return hashed;
}
exports.hashPassword = hashPassword;
// export const comparePasswords = async (password) => {
// const hmac = createHmac("sha512", process.env.DSQL_ENCRYPTION_PASSWORD);
// hmac.update(password);
// let hashed = hmac.digest("base64");
// let dbPass = await global.DB_HANDLER(`SELECT * FROM users WHERE password = '${hashed}'`);
// console.log(dbPass);
// return dbPass;
// };

View File

@ -0,0 +1,55 @@
// @ts-check
/**
* ==============================================================================
* Imports
* ==============================================================================
*/
const fs = require("fs");
// const handleNodemailer = require("./handleNodemailer");
/** ****************************************************************************** */
/** ****************************************************************************** */
/** ****************************************************************************** */
/** ****************************************************************************** */
/** ****************************************************************************** */
/** ****************************************************************************** */
/**
* ==============================================================================
* Main Function
* ==============================================================================
* @param {{
* user?: { id?: number | string, first_name?: string, last_name?: string, email?: string } & *,
* message: string,
* component?: string,
* noMail?: boolean,
* }} params - user id
*
* @returns {Promise<void>}
*/
module.exports = async function serverError({
user,
message,
component,
noMail,
}) {
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========================================`;
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}`);
};
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////

View File

@ -0,0 +1,38 @@
// @ts-check
const { IncomingMessage } = require("http");
const decrypt = require("./decrypt");
const parseCookies = require("../../../utils/functions/parseCookies");
/**
* @async
* @param {IncomingMessage} req - https request object
*
* @returns {Promise<({ email: string, password: string, authKey: string, logged_in_status: boolean, date: number } | null)>}
*/
module.exports = async function (req) {
const cookies = parseCookies({ request: req });
/** ********************* Check for existence of required cookie */
if (!cookies?.datasquirelSuAdminUserAuthKey) {
return null;
}
/** ********************* Grab the payload */
let userPayload = decrypt(cookies.datasquirelSuAdminUserAuthKey);
/** ********************* Return if no payload */
if (!userPayload) return null;
/** ********************* Parse the payload */
let userObject = JSON.parse(userPayload);
if (userObject.password !== process.env.DSQL_USER_KEY) return null;
if (userObject.authKey !== process.env.DSQL_SPECIAL_KEY) return null;
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
/** ********************* return user object */
return userObject;
};

View File

@ -0,0 +1,116 @@
// @ts-check
const fs = require("fs");
const parseDbResults = require("./parseDbResults");
const serverError = require("./serverError");
const DB_HANDLER = require("../../utils/backend/global-db/DB_HANDLER");
const DSQL_USER_DB_HANDLER = require("../../utils/backend/global-db/DSQL_USER_DB_HANDLER");
/**
* DB handler for specific database
* ==============================================================================
* @async
* @param {object} params - Single object params
* @param {string} params.queryString - SQL string
* @param {*[]} [params.queryValuesArray] - Values Array
* @param {string} [params.database] - Database name
* @param {import("../../types").DSQL_TableSchemaType} [params.tableSchema] - Table schema
* @returns {Promise<any>}
*/
module.exports = async function varDatabaseDbHandler({
queryString,
queryValuesArray,
database,
tableSchema,
}) {
/**
* Declare variables
*
* @description Declare "results" variable
*/
const isMaster = database?.match(/^datasquirel$/) ? true : false;
/** @type {any} */
const FINAL_DB_HANDLER = isMaster ? DB_HANDLER : DSQL_USER_DB_HANDLER;
let results;
/**
* Fetch from db
*
* @description Fetch data from db if no cache
*/
try {
if (
queryString &&
queryValuesArray &&
Array.isArray(queryValuesArray) &&
queryValuesArray[0]
) {
results = isMaster
? await FINAL_DB_HANDLER(queryString, queryValuesArray)
: await FINAL_DB_HANDLER({
paradigm: "Full Access",
database,
queryString,
queryValues: queryValuesArray,
});
} else {
results = isMaster
? await FINAL_DB_HANDLER(queryString)
: await FINAL_DB_HANDLER({
paradigm: "Full Access",
database,
queryString,
});
}
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
} catch (/** @type {any} */ error) {
serverError({
component: "varDatabaseDbHandler/lines-29-32",
message: error.message,
});
}
/**
* Return results
*
* @description Return results add to cache if "req" param is passed
*/
if (results && tableSchema) {
try {
const unparsedResults = results;
const parsedResults = await parseDbResults({
unparsedResults: unparsedResults,
tableSchema: tableSchema,
});
return parsedResults;
} catch (/** @type {any} */ error) {
console.log(
"\x1b[31mvarDatabaseDbHandler ERROR\x1b[0m =>",
database,
error
);
serverError({
component: "varDatabaseDbHandler/lines-52-53",
message: error.message,
});
return null;
}
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
} else if (results) {
return results;
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
} else {
return null;
}
};

View File

@ -0,0 +1,74 @@
// @ts-check
const fs = require("fs");
const serverError = require("./serverError");
const parseDbResults = require("./parseDbResults");
const DSQL_USER_DB_HANDLER = require("../../utils/backend/global-db/DSQL_USER_DB_HANDLER");
/**
*
* @param {object} param0
* @param {string} param0.queryString
* @param {string} param0.database
* @param {string[]} [param0.queryValuesArray]
* @param {import("../../types").DSQL_TableSchemaType} [param0.tableSchema]
* @returns
*/
module.exports = async function varReadOnlyDatabaseDbHandler({
queryString,
database,
queryValuesArray,
tableSchema,
}) {
/**
* Declare variables
*
* @description Declare "results" variable
*/
let results;
/**
* Fetch from db
*
* @description Fetch data from db if no cache
*/
try {
results = await DSQL_USER_DB_HANDLER({
paradigm: "Read Only",
database,
queryString,
queryValues: queryValuesArray,
});
////////////////////////////////////////
} catch (/** @type {any} */ error) {
////////////////////////////////////////
serverError({
component: "varReadOnlyDatabaseDbHandler",
message: error.message,
noMail: true,
});
/**
* Return error
*/
return error.message;
}
/**
* Return results
*
* @description Return results add to cache if "req" param is passed
*/
if (results) {
const unparsedResults = results;
const parsedResults = await parseDbResults({
unparsedResults: unparsedResults,
tableSchema: tableSchema,
});
return parsedResults;
} else {
return null;
}
};

View File

@ -1,95 +0,0 @@
/**
* @typedef {string} DSQL_DatabaseFullName - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database"
*/
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/**
* @typedef {object} DSQL_DatabaseSchemaType
* @property {string} dbName - Database Full name with spaces => "New Database"
* @property {string} dbSlug - Database Slug => "new_database"
* @property {string} dbFullName - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database"
* @property {string} [dbDescription] - Database brief description
* @property {string} [dbImage] - Database image - Defaults to "/images/default.png"
* @property {DSQL_TableSchemaType[]} tables - List of database tables
* @property {{ dbFullName: string }[]} [childrenDatabases] - List of children databases for current database which is parent
* @property {boolean} [childDatabase] - If current database is a child of a different parent database
* @property {string} [childDatabaseDbFullName] - Parent database full name => "datasquirel_user_7_new_database"
*/
////////////////////////////////////////
/**
* @typedef {object} DSQL_TableSchemaType
* @property {string} tableName - Table slug (blog_posts)
* @property {string} tableFullName - Table full name with spaces => "Blog Posts"
* @property {string} [tableDescription] - Brief description of table
* @property {DSQL_FieldSchemaType[]} fields - List of table Fields
* @property {DSQL_IndexSchemaType[]} [indexes] - List of table indexes, if available
* @property {DSQL_ChildrenTablesType[]} [childrenTables] - List of children tables
* @property {boolean} [childTable] -If current table is a child clone
* @property {string} [childTableName] - Table slug of parent table => "blog_posts"
* @property {string} [childTableDbFullName] - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database"
* @property {string} [tableNameOld] - Old table name, incase of renaming table
*/
/**
* @typedef {object} DSQL_ChildrenTablesType
* @property {string} dbNameFull - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database"
* @property {string} tableName - Table slug => "blog_posts"
*/
////////////////////////////////////////
/**
* @typedef {object} DSQL_FieldSchemaType
* @property {string} fieldName - Field Name(slug) => "long_description"
* @property {string} [originName] - Field origin name(optional)
* @property {boolean} [updatedField] - Has this field been renamed?
* @property {string} dataType - Field Data type => "BIGIN" | "LONGTEXT" | "VARCHAR(***)" | ...
* @property {boolean} [nullValue] - Is this a null value or not?
* @property {boolean} [notNullValue] - Is this NOT a null value?
* @property {boolean} [primaryKey] - Is this the primary key for table?
* @property {boolean} [encrypted] - Is this field value encrypted?
* @property {boolean} [autoIncrement] - Does this table primary key increment automatically?
* @property {string|number} [defaultValue] - Value of field by default
* @property {string} [defaultValueLiteral] - SQL key word which generates value automatically => "CURRENT_TIMESTAMP"
* @property {DSQL_ForeignKeyType} [foreignKey] - Field foreign key reference object
* @property {boolean} [richText] - Rich text field
* @property {string | RegExp} [pattern] - Field pattern for validation. Can be a string or a regular expression. Example: "^[a-zA-Z0-9_]*$"
* @property {string} [patternFlags] - Field pattern flags for validation. Example: "i"
*/
/**
* @typedef {object} DSQL_ForeignKeyType
* @property {string} foreignKeyName - Unique Name of foreign key
* @property {string} destinationTableName - Reference table name(slug) => "blog_posts"
* @property {string} destinationTableColumnName - Reference column name(slug) => "id"
* @property {string} destinationTableColumnType - Reference table field type => "BIGINT" | "VARCHAR(***)" | ...
* @property {boolean} [cascadeDelete] - Does the reference table entry delete when this key is deleted?
* @property {boolean} [cascadeUpdate] - Does the reference table entry update when this key is updated?
*/
////////////////////////////////////////
/**
* @typedef {object} DSQL_IndexSchemaType
* @property {string} indexName - Unique Name of index => "blog_text_index"
* @property {string} indexType - "regular" or "fullText"
* @property {DSQL_IndexTableFieldType[]} indexTableFields - List of Index table fields
* @property {string} [alias] - List of Index table fields
*/
/**
* @typedef {object} DSQL_IndexTableFieldType
* @property {string} value - Table Field Name
* @property {string} dataType - Table Field data type "VARCHAR(***)" | "BIGINT" | ...
*/
////////////////////////////////////////
exports.DSQL_TableSchemaType = DSQL_TableSchemaType;

1098
package-shared/types/index.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +0,0 @@
// @ts-check
/**
* @typedef {object} PackageUserLoginRequestBody
* @property {string} encryptionKey
* @property {any} payload
* @property {string} database
* @property {string[]} [additionalFields]
* @property {boolean} [email_login]
* @property {string} [email_login_code]
* @property {string} [email_login_field]
* @property {boolean} [token]
* @property {boolean} [social]
* @property {import("./database-schema.td").DSQL_DatabaseSchemaType} [dbSchema]
*/
/**
* @typedef {object} PackageUserLoginLocalBody
* @property {any} payload
* @property {string[]} [additionalFields]
* @property {boolean} [email_login]
* @property {string} [email_login_code]
* @property {string} [email_login_field]
* @property {boolean} [token]
* @property {boolean} [social]
* @property {import("./database-schema.td").DSQL_DatabaseSchemaType} [dbSchema]
*/

View File

@ -0,0 +1,51 @@
// @ts-check
const fs = require("fs");
const path = require("path");
const mysql = require("serverless-mysql");
const SSL_DIR =
process.env.DSQL_SSL_DIR || path.resolve(__dirname, "../../../../ssl");
const MASTER = 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,
port: process.env.DSQL_DB_PORT
? Number(process.env.DSQL_DB_PORT)
: undefined,
charset: "utf8mb4",
ssl: {
ca: fs.readFileSync(`${SSL_DIR}/ca-cert.pem`),
},
},
});
/**
* DSQL user read-only DB handler
* @param {object} params
* @param {string} params.paradigm
* @param {string} params.database
* @param {string} params.queryString
* @param {string[]} [params.queryValues]
*/ // @ts-ignore
async function DB_HANDLER(...args) {
try {
const results = await MASTER.query(...args);
/** ********************* Clean up */
await MASTER.end();
return JSON.parse(JSON.stringify(results));
} catch (/** @type {any} */ error) {
console.log("DB Error =>", error);
return {
success: false,
error: error.message,
};
}
}
module.exports = DB_HANDLER;

View File

@ -0,0 +1,130 @@
// @ts-check
const fs = require("fs");
const path = require("path");
const mysql = require("serverless-mysql");
const SSL_DIR =
process.env.DSQL_SSL_DIR || path.resolve(__dirname, "../../../../ssl");
let DSQL_USER = mysql({
config: {
host: process.env.DSQL_DB_HOST,
user: process.env.DSQL_DB_READ_ONLY_USERNAME,
password: process.env.DSQL_DB_READ_ONLY_PASSWORD,
charset: "utf8mb4",
ssl: {
ca: fs.readFileSync(`${SSL_DIR}/ca-cert.pem`),
},
},
});
/**
* DSQL user read-only DB handler
* @param {object} params
* @param {"Full Access" | "FA" | "Read Only"} params.paradigm
* @param {string} params.database
* @param {string} params.queryString
* @param {string[]} [params.queryValues]
*/
function DSQL_USER_DB_HANDLER({
paradigm,
database,
queryString,
queryValues,
}) {
try {
return new Promise((resolve, reject) => {
const fullAccess = paradigm?.match(/full.access|^fa$/i)
? true
: false;
try {
if (fullAccess) {
DSQL_USER = mysql({
config: {
host: process.env.DSQL_DB_HOST,
user: process.env.DSQL_DB_FULL_ACCESS_USERNAME,
password: process.env.DSQL_DB_FULL_ACCESS_PASSWORD,
database: database,
ssl: {
ca: fs.readFileSync(`${SSL_DIR}/ca-cert.pem`),
},
},
});
} else {
DSQL_USER = mysql({
config: {
host: process.env.DSQL_DB_HOST,
user: process.env.DSQL_DB_READ_ONLY_USERNAME,
password: process.env.DSQL_DB_READ_ONLY_PASSWORD,
database: database,
ssl: {
ca: fs.readFileSync(`${SSL_DIR}/ca-cert.pem`),
},
},
});
}
/**
* ### Run query Function
* @param {any} results
*/
function runQuery(results) {
DSQL_USER.end();
resolve(JSON.parse(JSON.stringify(results)));
}
/**
* ### Query Error
* @param {any} err
*/
function queryError(err) {
DSQL_USER.end();
resolve({
error: err.message,
queryStringGenerated: queryString,
queryValuesGenerated: queryValues,
sql: err.sql,
});
}
if (
queryValues &&
Array.isArray(queryValues) &&
queryValues[0]
) {
DSQL_USER.query(queryString, queryValues)
.then(runQuery)
.catch(queryError);
} else {
DSQL_USER.query(queryString)
.then(runQuery)
.catch(queryError);
}
////////////////////////////////////////
} catch (/** @type {any} */ error) {
////////////////////////////////////////
fs.appendFileSync(
"./.tmp/dbErrorLogs.txt",
error.message + "\n" + Date() + "\n\n\n",
"utf8"
);
resolve({
error: error.message,
});
}
});
} catch (/** @type {any} */ error) {
return {
success: false,
error: error.message,
};
}
}
module.exports = DSQL_USER_DB_HANDLER;

View File

@ -0,0 +1,64 @@
// @ts-check
const fs = require("fs");
const path = require("path");
// const mysql = require("mysql");
// const NO_DB = mysql.createConnection({
// host: process.env.DSQL_DB_HOST,
// user: process.env.DSQL_DB_USERNAME,
// password: process.env.DSQL_DB_PASSWORD,
// charset: "utf8mb4",
// });
const mysql = require("serverless-mysql");
const SSL_DIR =
process.env.DSQL_SSL_DIR || path.resolve(__dirname, "../../../../ssl");
let NO_DB = mysql({
config: {
host: process.env.DSQL_DB_HOST,
user: process.env.DSQL_DB_USERNAME,
password: process.env.DSQL_DB_PASSWORD,
charset: "utf8mb4",
ssl: {
ca: fs.readFileSync(`${SSL_DIR}/ca-cert.pem`),
},
},
});
/**
* DSQL user read-only DB handler
* @param {object} params
* @param {string} params.paradigm
* @param {string} params.database
* @param {string} params.queryString
* @param {string[]} [params.queryValues]
*/ // @ts-ignore
function NO_DB_HANDLER(...args) {
try {
return new Promise((resolve, reject) => {
NO_DB.query(...args)
.then((results) => {
NO_DB.end();
resolve(JSON.parse(JSON.stringify(results)));
})
.catch((err) => {
NO_DB.end();
resolve({
error: err.message,
sql: err.sql,
});
});
});
} catch (/** @type {any} */ error) {
return {
success: false,
error: error.message,
};
}
}
module.exports = NO_DB_HANDLER;

View File

@ -0,0 +1,55 @@
// @ts-check
const fs = require("fs");
const path = require("path");
const mysql = require("serverless-mysql");
const SSL_DIR =
process.env.DSQL_SSL_DIR || path.resolve(__dirname, "../../../../ssl");
let NO_DB = mysql({
config: {
host: process.env.DSQL_DB_HOST,
user: process.env.DSQL_DB_USERNAME,
password: process.env.DSQL_DB_PASSWORD,
charset: "utf8mb4",
ssl: {
ca: fs.readFileSync(`${SSL_DIR}/ca-cert.pem`),
},
},
});
/**
* DSQL user read-only DB handler
* @param {object} params
* @param {string} params.paradigm
* @param {string} params.database
* @param {string} params.queryString
* @param {string[]} [params.queryValues]
*/ // @ts-ignore
function ROOT_DB_HANDLER(...args) {
try {
return new Promise((resolve, reject) => {
NO_DB.query(...args)
.then((results) => {
NO_DB.end();
resolve(JSON.parse(JSON.stringify(results)));
})
.catch((err) => {
NO_DB.end();
resolve({
error: err.message,
sql: err.sql,
});
});
});
} catch (/** @type {any} */ error) {
return {
success: false,
error: error.message,
};
}
}
module.exports = ROOT_DB_HANDLER;

View File

@ -0,0 +1,49 @@
// @ts-check
const fs = require("fs");
const DSQL_USER_DB_HANDLER = require("./DSQL_USER_DB_HANDLER");
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
process.addListener("exit", async (code) => {
console.log("PROCESS EXITING ...");
});
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
/**
* Global function
* ================================================
* @description this sets all require global variables. This only runs once.
*/
module.exports = function globalFunction() {
/**
* Main Db Handler
*/
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
/**
* Main Db Handler
*/
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
/**
* DSQL user read-only DB handler
* @param {object} params
* @param {string} params.paradigm
* @param {string} params.database
* @param {string} params.queryString
* @param {string[]} [params.queryValues]
*/
DSQL_USER_DB_HANDLER;
};

View File

@ -0,0 +1,38 @@
/**
*
* @param {string | null | number} string
* @param {(this: any, key: string, value: any) => any} [reviver]
* @returns {{ [key: string]: any } | { [key: string]: any }[] | undefined}
*/
function parse(string, reviver) {
if (!string) return undefined;
if (typeof string == "object") return string;
if (typeof string !== "string") return undefined;
try {
return JSON.parse(string, reviver);
} catch (error) {
return undefined;
}
}
/**
*
* @param {any} value
* @param {(this: any, key: string, value: any) => any} [replacer]
* @param { string | number } [space]
* @returns {string | undefined}
*/
function stringify(value, replacer, space) {
try {
return JSON.stringify(value, replacer, space);
} catch (error) {
return undefined;
}
}
const EJSON = {
parse,
stringify,
};
module.exports = EJSON;

View File

@ -1,6 +1,6 @@
{ {
"name": "datasquirel", "name": "datasquirel",
"version": "2.1.1", "version": "2.3.7",
"description": "Cloud-based SQL data management tool", "description": "Cloud-based SQL data management tool",
"main": "index.js", "main": "index.js",
"bin": { "bin": {
@ -9,7 +9,7 @@
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://git.tben.me/Moduletrace/datasquirel.git" "url": "git+https://github.com/BenjaminToby/dsql.git"
}, },
"keywords": [ "keywords": [
"SQL", "SQL",
@ -22,15 +22,23 @@
"author": "Benjamin Toby", "author": "Benjamin Toby",
"license": "ISC", "license": "ISC",
"bugs": { "bugs": {
"url": "https://git.tben.me/Moduletrace/datasquirel/issues" "url": "https://github.com/BenjaminToby/dsql/issues"
}, },
"homepage": "https://datasquirel.com/", "homepage": "https://datasquirel.com/",
"dependencies": { "dependencies": {
"@types/ace": "^0.0.52",
"@types/react": "^18.3.12",
"@types/tinymce": "^4.6.9",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"generate-password": "^1.7.1",
"lodash": "^4.17.21",
"mysql": "^2.18.1", "mysql": "^2.18.1",
"nodemailer": "^6.9.14" "nodemailer": "^6.9.14",
"sanitize-html": "^2.13.1",
"serverless-mysql": "^1.5.5"
}, },
"devDependencies": { "devDependencies": {
"@types/lodash": "^4.17.13",
"@types/mysql": "^2.15.21", "@types/mysql": "^2.15.21",
"@types/node": "^22.7.5" "@types/node": "^22.7.5"
} }

View File

@ -2,22 +2,21 @@
"compilerOptions": { "compilerOptions": {
"target": "ES2015", "target": "ES2015",
"module": "commonjs", "module": "commonjs",
"paths": {
"@/*": ["./*"]
},
"maxNodeModuleJsDepth": 10, "maxNodeModuleJsDepth": 10,
"esModuleInterop": true, "esModuleInterop": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"strict": true, "strict": true,
"skipLibCheck": true, // "skipLibCheck": true,
"lib": ["dom", "dom.iterable", "esnext"], "lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true, "allowJs": true,
"noEmit": true,
"incremental": true, "incremental": true,
"resolveJsonModule": true, "resolveJsonModule": true,
"isolatedModules": true, "isolatedModules": true,
"jsx": "preserve", "jsx": "preserve",
"moduleResolution": "node", "moduleResolution": "node",
"emitDeclarationOnly": true,
"declaration": true,
"outDir": "./dump/tsc",
"plugins": [ "plugins": [
{ {
"name": "next" "name": "next"
@ -30,7 +29,7 @@
"types", "types",
"users", "users",
"utils", "utils",
"package-shared/types" "package-shared"
], ],
"exclude": ["node_modules", "dump"] "exclude": ["node_modules", "dump"]
} }

View File

View File

@ -1,20 +0,0 @@
const http = require("http");
/**
* @typedef {http.IncomingMessage} Request
*/
/**
* @typedef {http.ServerResponse} Response
*/
/**
* @typedef {{
* imageBase64: string,
* imageBase64Full: string,
* imageName: string,
* imageSize: number,
* }} ImageInputFileToBase64FunctionReturn
*/
module.exports = { Request, Response, ImageInputFileToBase64FunctionReturn };

View File

@ -1,48 +0,0 @@
/**
* @typedef {object} DSQL_MYSQL_SHOW_INDEXES_Type
* @property {string} Key_name - MYSQL Index Name
* @property {string} Table - Table Name(slug)
* @property {string} Column_name
* @property {string} Collation
* @property {string} Index_type - "FULL_TEXT" | ...
* @property {string} Cardinality
* @property {string} Index_comment
* @property {string} Comment
*/
////////////////////////////////////////
/**
* @typedef {object} DSQL_MYSQL_SHOW_COLUMNS_Type
* @property {string} Field - Field Name as represented in MSQL database
* @property {string} Type - varchar(***) | tinyint | bigint | ...
* @property {string} Null
* @property {string} Key
* @property {string} Default
* @property {string} Extra
*/
////////////////////////////////////////
/**
* @typedef {object} DSQL_MYSQL_FOREIGN_KEYS_Type
* @property {string} CONSTRAINT_NAME - Constraint Name => "PRIMARY" | "MUL" | null | ...
* @property {string} CONSTRAINT_SCHEMA - Database name
* @property {string} TABLE_NAME - Table name
*/
////////////////////////////////////////
/**
* @typedef {object} DSQL_MYSQL_user_databases_Type
* @property {number} user_id - User Id
* @property {string} db_full_name - Database full name => eg. (dataasquirel_user_2_new_database)
* @property {string} db_name - Database name with spaces => eg. (New Database)
* @property {string} db_slug - Database slug => eg. (new_database)
* @property {string} db_image - Database image path
* @property {string} db_description - Database description
* @property {number} active_clone - is Database active clone => 0 or 1
* @property {string} active_clone_parent_db - Database parent db full name => eg. "datasquirel_user_7_wexculture"
*/
////////////////////////////////////////

View File

@ -1,129 +0,0 @@
/**
* @typedef {object} DATASQUIREL_LoggedInUser
* @property {number} [id]
* @property {string} first_name
* @property {string} last_name
* @property {string} email
* @property {string} [phone]
* @property {string} [user_type]
* @property {string} [username]
* @property {string} password
* @property {string} [image]
* @property {string} [image_thumbnail]
* @property {string} [address]
* @property {string} [city]
* @property {string} [state]
* @property {string} [country]
* @property {string} [zip_code]
* @property {number} [social_login]
* @property {string?} [social_platform]
* @property {string?} [social_id]
* @property {string} [more_user_data]
* @property {number} [verification_status]
* @property {number?} [loan_officer_id]
* @property {number} [is_admin]
* @property {number} [admin_level]
* @property {string} [admin_permissions]
* @property {string?} uuid
* @property {string?} [temp_login_code]
* @property {string?} [date_created]
* @property {number?} [date_created_code]
* @property {string?} [date_created_timestamp]
* @property {string?} [date_updated]
* @property {number?} [date_updated_code]
* @property {string?} [date_updated_timestamp]
* @property {string} [csrf_k] - CSRF key
* @property {boolean} [logged_in_status]
* @property {number} [date]
* @property {any} [more_data]
*/
/**
* @typedef {object} AuthenticatedUser
* @property {boolean} success - Did the function run successfully?
* @property {import("../types/user.td").DATASQUIREL_LoggedInUser | null} payload - Payload of the response
* @property {string} [msg] - An optional message
* @property {number} [userId] - An optional message
*/
/**
* @typedef {object} SuccessUserObject
* @property {number} id
* @property {string} first_name
* @property {string} last_name
* @property {string} email
*/
/**
* @typedef {object} AddUserFunctionReturn
* @property {boolean} success - Did the function run successfully?
* @property {SuccessUserObject | null} [payload] - Payload
* @property {string} [msg]
* @property {any} [sqlResult]
*/
/**
* @typedef {object} GoogleIdentityPromptNotification
* @property {function(): string} getMomentType - Notification moment type
* @property {function(): string} getDismissedReason - Notification get Dismissed Reason
* @property {function(): string} getNotDisplayedReason - Notification get Not Displayed Reason
* @property {function(): string} getSkippedReason - Notification get Skipped Reason
* @property {function(): boolean} isDismissedMoment - Notification is Dismissed Moment
* @property {function(): boolean} isDisplayMoment - Notification is Display Moment
* @property {function(): boolean} isDisplayed - Notification is Displayed
* @property {function(): boolean} isNotDisplayed - Notification is Not Displayed
* @property {function(): boolean} isSkippedMoment - Notification is Skipped Moment
*/
/**
* @typedef {object} UserDataPayload
* @property {string} first_name - First Name *Required
* @property {string} last_name - Last Name *Required
* @property {string} email - Email *Required
* @property {string} password - Password *Required
* @property {string?} username - Username (Optional)
*/
/**
* @typedef {object} GetUserFunctionReturn
* @property {boolean} success - Did the function run successfully?
* @property {{
* id: number,
* first_name: string,
* last_name: string,
* username: string,
* email: string,
* phone: string,
* social_id: [string],
* image: string,
* image_thumbnail: string,
* verification_status: [number=0],
* }} payload - Payload
*/
/**
* @typedef {object} ReauthUserFunctionReturn
* @property {boolean} success - Did the function run successfully?
* @property {import("../types/user.td").DATASQUIREL_LoggedInUser | null} payload - Payload
* @property {string} [msg] - Response Message
* @property {number} [userId] - user ID
* @property {string} [token] - new Token
*/
/**
* @typedef {object} UpdateUserFunctionReturn
* @property {boolean} success - Did the function run successfully?
* @property {(Object[]|string)} [payload=[]] - Payload
*/
module.exports = {
DATASQUIREL_LoggedInUser,
AuthenticatedUser,
AddUserFunctionReturn,
SuccessUserObject,
GoogleIdentityPromptNotification,
UserDataPayload,
GetUserFunctionReturn,
ReauthUserFunctionReturn,
UpdateUserFunctionReturn,
};

View File

@ -26,11 +26,11 @@ const localAddUser = require("../engine/user/add-user");
* @param {object} props - Single object passed * @param {object} props - Single object passed
* @param {string} props.key - FULL ACCESS API Key * @param {string} props.key - FULL ACCESS API Key
* @param {string} props.database - Database Name * @param {string} props.database - Database Name
* @param {import("../types/user.td").UserDataPayload} props.payload - User Data Payload * @param {import("../package-shared/types").UserDataPayload} props.payload - User Data Payload
* @param {string} props.encryptionKey * @param {string} props.encryptionKey
* @param {string} [props.encryptionSalt] * @param {string} [props.encryptionSalt]
* *
* @returns { Promise<import("../types/user.td").AddUserFunctionReturn> } * @returns { Promise<import("../package-shared/types").AddUserFunctionReturn> }
*/ */
async function addUser({ async function addUser({
key, key,
@ -64,7 +64,7 @@ async function addUser({
DSQL_PASS?.match(/./) && DSQL_PASS?.match(/./) &&
DSQL_DB_NAME?.match(/./) DSQL_DB_NAME?.match(/./)
) { ) {
/** @type {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined} */ /** @type {import("../package-shared/types").DSQL_DatabaseSchemaType | undefined} */
let dbSchema; let dbSchema;
try { try {

View File

@ -83,7 +83,7 @@ async function getUser({ key, userId, database, fields }) {
DSQL_PASS?.match(/./) && DSQL_PASS?.match(/./) &&
DSQL_DB_NAME?.match(/./) DSQL_DB_NAME?.match(/./)
) { ) {
/** @type {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined} */ /** @type {DSQL_DatabaseSchemaType | undefined} */
let dbSchema; let dbSchema;
try { try {

View File

@ -41,7 +41,7 @@ const loginLocalUser = require("../engine/user/login-user");
* @param {string} [params.temp_code_field] - Database table field name for temporary code * @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.token] - Send access key as part of response body?
* *
* @returns { Promise<import("../types/user.td").AuthenticatedUser>} * @returns { Promise<import("../package-shared/types").AuthenticatedUser>}
*/ */
async function loginUser({ async function loginUser({
key, key,
@ -126,7 +126,7 @@ async function loginUser({
DSQL_PASS?.match(/./) && DSQL_PASS?.match(/./) &&
DSQL_DB_NAME?.match(/./) DSQL_DB_NAME?.match(/./)
) { ) {
/** @type {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined} */ /** @type {import("../package-shared/types").DSQL_DatabaseSchemaType | undefined} */
let dbSchema; let dbSchema;
try { try {
@ -154,10 +154,10 @@ async function loginUser({
* *
* @description make a request to datasquirel.com * @description make a request to datasquirel.com
* *
* @type {{ success: boolean, payload: import("../types/user.td").DATASQUIREL_LoggedInUser | null, userId?: number, msg?: string }} * @type {{ success: boolean, payload: import("../package-shared/types").DATASQUIREL_LoggedInUser | null, userId?: number, msg?: string }}
*/ */
httpResponse = await new Promise((resolve, reject) => { httpResponse = await new Promise((resolve, reject) => {
/** @type {PackageUserLoginRequestBody} */ /** @type {import("../package-shared/types").PackageUserLoginRequestBody} */
const reqPayload = { const reqPayload = {
encryptionKey, encryptionKey,
payload, payload,

View File

@ -38,7 +38,7 @@ const localReauthUser = require("../engine/user/reauth-user");
* @param {string[]} [params.additionalFields] - Additional Fields to be added to the user object * @param {string[]} [params.additionalFields] - Additional Fields to be added to the user object
* @param {string} [params.token] - access token to use instead of getting from cookie header * @param {string} [params.token] - access token to use instead of getting from cookie header
* *
* @returns { Promise<import("../types/user.td").ReauthUserFunctionReturn> } * @returns { Promise<import("../package-shared/types").ReauthUserFunctionReturn> }
*/ */
async function reauthUser({ async function reauthUser({
key, key,
@ -103,7 +103,7 @@ async function reauthUser({
DSQL_PASS?.match(/./) && DSQL_PASS?.match(/./) &&
DSQL_DB_NAME?.match(/./) DSQL_DB_NAME?.match(/./)
) { ) {
/** @type {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined} */ /** @type {import("../package-shared/types").DSQL_DatabaseSchemaType | undefined} */
let dbSchema; let dbSchema;
try { try {

View File

@ -114,7 +114,7 @@ async function sendEmailCode({
DSQL_PASS?.match(/./) && DSQL_PASS?.match(/./) &&
DSQL_DB_NAME?.match(/./) DSQL_DB_NAME?.match(/./)
) { ) {
/** @type {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined} */ /** @type {import("../package-shared/types").DSQL_DatabaseSchemaType | undefined} */
let dbSchema; let dbSchema;
try { try {
@ -143,7 +143,7 @@ async function sendEmailCode({
* *
* @description make a request to datasquirel.com * @description make a request to datasquirel.com
* *
* @type {{ success: boolean, payload: import("../types/user.td").DATASQUIREL_LoggedInUser | null, userId?: number, msg?: string }} * @type {{ success: boolean, payload: import("../package-shared/types").DATASQUIREL_LoggedInUser | null, userId?: number, msg?: string }}
*/ */
httpResponse = await new Promise((resolve, reject) => { httpResponse = await new Promise((resolve, reject) => {
const reqPayload = JSON.stringify({ const reqPayload = JSON.stringify({

View File

@ -154,7 +154,7 @@ async function githubAuth({
DSQL_PASS?.match(/./) && DSQL_PASS?.match(/./) &&
DSQL_DB_NAME?.match(/./) DSQL_DB_NAME?.match(/./)
) { ) {
/** @type {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined | undefined} */ /** @type {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined | undefined} */
let dbSchema; let dbSchema;
try { try {

View File

@ -150,7 +150,7 @@ async function googleAuth({
DSQL_PASS?.match(/./) && DSQL_PASS?.match(/./) &&
DSQL_DB_NAME?.match(/./) DSQL_DB_NAME?.match(/./)
) { ) {
/** @type {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined | undefined} */ /** @type {import("../../package-shared/types").DSQL_DatabaseSchemaType | undefined | undefined} */
let dbSchema; let dbSchema;
try { try {
@ -179,7 +179,7 @@ async function googleAuth({
* Make https request * Make https request
* *
* @description make a request to datasquirel.com * @description make a request to datasquirel.com
* @type {{ success: boolean, user: import("../../types/user.td").DATASQUIREL_LoggedInUser | null, msg?: string, dsqlUserId?: number } | null } - Https response object * @type {{ success: boolean, user: import("../../package-shared/types").DATASQUIREL_LoggedInUser | null, msg?: string, dsqlUserId?: number } | null } - Https response object
*/ */
httpResponse = await new Promise((resolve, reject) => { httpResponse = await new Promise((resolve, reject) => {
const reqPayload = JSON.stringify({ const reqPayload = JSON.stringify({

View File

@ -27,9 +27,9 @@ const localUpdateUser = require("../engine/user/update-user");
* @param {object} params - API Key * @param {object} params - API Key
* @param {String} params.key - API Key * @param {String} params.key - API Key
* @param {String} params.database - Target Database * @param {String} params.database - Target Database
* @param {{ id: number } & Object.<string, *>} params.payload - User Object: ID is required * @param {{ id: number } & Object.<string, any>} params.payload - User Object: ID is required
* *
* @returns { Promise<import("../types/user.td").UpdateUserFunctionReturn>} * @returns { Promise<import("../package-shared/types").UpdateUserFunctionReturn>}
*/ */
async function updateUser({ key, payload, database }) { async function updateUser({ key, payload, database }) {
/** /**
@ -57,7 +57,7 @@ async function updateUser({ key, payload, database }) {
DSQL_PASS?.match(/./) && DSQL_PASS?.match(/./) &&
DSQL_DB_NAME?.match(/./) DSQL_DB_NAME?.match(/./)
) { ) {
/** @type {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined} */ /** @type {import("../package-shared/types").DSQL_DatabaseSchemaType | undefined} */
let dbSchema; let dbSchema;
try { try {

View File

@ -30,7 +30,7 @@ const parseCookies = require("../utils/functions/parseCookies");
* @param {string} params.database - Database Name * @param {string} params.database - Database Name
* @param {string} [params.token] - access token to use instead of getting from cookie header * @param {string} [params.token] - access token to use instead of getting from cookie header
* *
* @returns { import("../types/user.td").AuthenticatedUser } * @returns { import("../package-shared/types").AuthenticatedUser }
*/ */
function userAuth({ function userAuth({
request, request,

View File

@ -27,7 +27,7 @@ const decrypt = require("../functions/decrypt");
* @param {("deep" | "normal")?} [params.level] - Optional. "Deep" value indicates an extra layer of security * @param {("deep" | "normal")?} [params.level] - Optional. "Deep" value indicates an extra layer of security
* @param {string} params.database - Database Name * @param {string} params.database - Database Name
* *
* @returns { import("../types/user.td").DATASQUIREL_LoggedInUser | null} * @returns { import("../package-shared/types").DATASQUIREL_LoggedInUser | null}
*/ */
function validateToken({ token, encryptionKey, encryptionSalt }) { function validateToken({ token, encryptionKey, encryptionSalt }) {
try { try {

View File

@ -39,6 +39,12 @@ async function uploadImage({ key, url }) {
const scheme = process.env.DSQL_HTTP_SCHEME; const scheme = process.env.DSQL_HTTP_SCHEME;
const localHost = process.env.DSQL_LOCAL_HOST; const localHost = process.env.DSQL_LOCAL_HOST;
const localHostPort = process.env.DSQL_LOCAL_HOST_PORT; const localHostPort = process.env.DSQL_LOCAL_HOST_PORT;
const remoteHost = process.env.DSQL_API_REMOTE_HOST?.match(/.*\..*/)
? process.env.DSQL_API_REMOTE_HOST
: undefined;
const remoteHostPort = process.env.DSQL_API_REMOTE_HOST_PORT?.match(/./)
? process.env.DSQL_API_REMOTE_HOST_PORT
: undefined;
try { try {
/** /**
@ -59,8 +65,8 @@ async function uploadImage({ key, url }) {
"Content-Length": Buffer.from(reqPayload).length, "Content-Length": Buffer.from(reqPayload).length,
Authorization: key, Authorization: key,
}, },
port: localHostPort || 443, port: remoteHostPort || localHostPort || 443,
hostname: localHost || "datasquirel.com", hostname: remoteHost || localHost || "datasquirel.com",
path: `/api/query/delete-file`, path: `/api/query/delete-file`,
}, },

View File

@ -0,0 +1,18 @@
// @ts-check
/** @type {import("../../package-shared/types").SerializeQueryFnType} */
function serializeQuery({ query }) {
let str = "?";
const keys = Object.keys(query);
/** @type {string[]} */
const queryArr = [];
keys.forEach((key) => {
if (!key || !query[key]) return;
queryArr.push(`${key}=${query[key]}`);
});
str += queryArr.join("&");
return str;
}
module.exports = serializeQuery;

View File

@ -18,24 +18,25 @@ const https = require("https");
/** /**
* @typedef {Object} GetSchemaReturn * @typedef {Object} GetSchemaReturn
* @property {boolean} success - Did the function run successfully? * @property {boolean} success - Did the function run successfully?
* @property {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType[] | import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | null} payload - Response payload * @property {import("../package-shared/types").DSQL_DatabaseSchemaType | import("../package-shared/types").DSQL_TableSchemaType | import("../package-shared/types").DSQL_FieldSchemaType | null} payload - Response payload
*/ */
/** /**
* Make a get request to Datasquirel API * # Get Schema for Database, table, or field *
* ============================================================================== * @param {import("../package-shared/types").GetSchemaAPIParam} params
* @async
*
* @param {Object} params - Single object passed
* @param {string} params.key - `FULL ACCESS` API Key
* @param {string} [params.database] - The database schema to get
* *
* @returns { Promise<GetSchemaReturn> } - Return Object * @returns { Promise<GetSchemaReturn> } - Return Object
*/ */
async function getSchema({ key, database }) { async function getSchema({ key, database, field, table }) {
const scheme = process.env.DSQL_HTTP_SCHEME; const scheme = process.env.DSQL_HTTP_SCHEME;
const localHost = process.env.DSQL_LOCAL_HOST; const localHost = process.env.DSQL_LOCAL_HOST;
const localHostPort = process.env.DSQL_LOCAL_HOST_PORT; const localHostPort = process.env.DSQL_LOCAL_HOST_PORT;
const remoteHost = process.env.DSQL_API_REMOTE_HOST?.match(/.*\..*/)
? process.env.DSQL_API_REMOTE_HOST
: undefined;
const remoteHostPort = process.env.DSQL_API_REMOTE_HOST_PORT?.match(/./)
? process.env.DSQL_API_REMOTE_HOST_PORT
: undefined;
/** /**
* Make https request * Make https request
@ -43,6 +44,15 @@ async function getSchema({ key, database }) {
* @description make a request to datasquirel.com * @description make a request to datasquirel.com
*/ */
const httpResponse = await new Promise((resolve, reject) => { const httpResponse = await new Promise((resolve, reject) => {
/** @type {import("../package-shared/types").GetSchemaRequestQuery} */
const queryObject = { database, field, table };
let query = Object.keys(queryObject)
// @ts-ignore
.filter((k) => queryObject[k])
// @ts-ignore
.map((k) => `${k}=${queryObject[k]}`)
.join("&");
(scheme?.match(/^http$/i) ? http : https) (scheme?.match(/^http$/i) ? http : https)
.request( .request(
{ {
@ -51,11 +61,11 @@ async function getSchema({ key, database }) {
"Content-Type": "application/json", "Content-Type": "application/json",
Authorization: key, Authorization: key,
}, },
port: localHostPort || 443, port: remoteHostPort || localHostPort || 443,
hostname: localHost || "datasquirel.com", hostname: remoteHost || localHost || "datasquirel.com",
path: path:
"/api/query/get-schema" + "/api/query/get-schema" +
(database ? `?database=${database}` : ""), (query?.match(/./) ? `?${query}` : ""),
}, },
/** /**

View File

@ -10,6 +10,7 @@ const https = require("node:https");
const path = require("path"); const path = require("path");
const fs = require("fs"); const fs = require("fs");
const localGet = require("../engine/query/get"); const localGet = require("../engine/query/get");
const serializeQuery = require("./functions/serialize-query");
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
@ -18,14 +19,6 @@ const localGet = require("../engine/query/get");
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/**
* @typedef {Object} GetReturn
* @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 * Make a get request to Datasquirel API
* ============================================================================== * ==============================================================================
@ -38,35 +31,34 @@ const localGet = require("../engine/query/get");
* @param {string[]} [params.queryValues] - An array of query values if using "?" placeholders * @param {string[]} [params.queryValues] - An array of query values if using "?" placeholders
* @param {string} [params.tableName] - Name of the table to query * @param {string} [params.tableName] - Name of the table to query
* *
* @returns { Promise<GetReturn> } - Return Object * @returns { Promise<import("../package-shared/types").GetReturn> } - Return Object
*/ */
async function get({ key, db, query, queryValues, tableName }) { async function get({ key, db, query, queryValues, tableName }) {
const scheme = process.env.DSQL_HTTP_SCHEME; const scheme = process.env.DSQL_HTTP_SCHEME;
const localHost = process.env.DSQL_LOCAL_HOST; const localHost = process.env.DSQL_LOCAL_HOST;
const localHostPort = process.env.DSQL_LOCAL_HOST_PORT; const localHostPort = process.env.DSQL_LOCAL_HOST_PORT;
const remoteHost = process.env.DSQL_API_REMOTE_HOST?.match(/.*\..*/)
? process.env.DSQL_API_REMOTE_HOST
: undefined;
const remoteHostPort = process.env.DSQL_API_REMOTE_HOST_PORT?.match(/./)
? process.env.DSQL_API_REMOTE_HOST_PORT
: undefined;
/** /**
* Check for local DB settings * Check for local DB settings
* *
* @description Look for local db settings in `.env` file and by pass the http request if available * @description Look for local db settings in `.env` file and by pass the http request if available
*/ */
const { const { DSQL_DB_HOST, DSQL_DB_USERNAME, DSQL_DB_PASSWORD, DSQL_DB_NAME } =
DSQL_HOST, process.env;
DSQL_USER,
DSQL_PASS,
DSQL_DB_NAME,
DSQL_KEY,
DSQL_REF_DB_NAME,
DSQL_FULL_SYNC,
} = process.env;
if ( if (
DSQL_HOST?.match(/./) && DSQL_DB_HOST?.match(/./) &&
DSQL_USER?.match(/./) && DSQL_DB_USERNAME?.match(/./) &&
DSQL_PASS?.match(/./) && DSQL_DB_PASSWORD?.match(/./) &&
DSQL_DB_NAME?.match(/./) DSQL_DB_NAME?.match(/./)
) { ) {
/** @type {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined} */ /** @type {import("../package-shared/types").DSQL_DatabaseSchemaType | undefined} */
let dbSchema; let dbSchema;
try { try {
@ -93,16 +85,22 @@ async function get({ key, db, query, queryValues, tableName }) {
* @description make a request to datasquirel.com * @description make a request to datasquirel.com
*/ */
const httpResponse = await new Promise((resolve, reject) => { const httpResponse = await new Promise((resolve, reject) => {
let path = `/api/query/get?db=${db}&query=${query /** @type {import("../package-shared/types").GetReqQueryObject} */
const queryObject = {
db: String(db),
query: String(
query
.replace(/\n|\r|\n\r/g, "") .replace(/\n|\r|\n\r/g, "")
.replace(/ {2,}/g, " ") .replace(/ {2,}/g, " ")
.replace(/ /g, "+")}`; .replace(/ /g, "+")
),
queryValues: queryValues ? JSON.stringify(queryValues) : undefined,
tableName,
};
if (queryValues) { const queryString = serializeQuery({ query: queryObject });
path += `&queryValues=${JSON.stringify(queryValues)}${
tableName ? `&tableName=${tableName}` : "" let path = `/api/query/get${queryString}`;
}`;
}
/** @type {https.RequestOptions} */ /** @type {https.RequestOptions} */
const requestObject = { const requestObject = {
@ -111,8 +109,8 @@ async function get({ key, db, query, queryValues, tableName }) {
"Content-Type": "application/json", "Content-Type": "application/json",
Authorization: key, Authorization: key,
}, },
port: localHostPort || 443, port: remoteHostPort || localHostPort || 443,
hostname: localHost || "datasquirel.com", hostname: remoteHost || localHost || "datasquirel.com",
path: encodeURI(path), path: encodeURI(path),
}; };

View File

@ -16,28 +16,6 @@ const localPost = require("../engine/query/post");
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/**
* @typedef {Object} PostReturn
* @property {boolean} success - Did the function run successfully?
* @property {(Object[]|string)} [payload=[]] - The Y Coordinate
*/
/**
* @typedef {object} PostDataPayload
* @property {"insert" | "update" | "delete"} action - The target action to take
* @property {string} table - Table name(slug) eg "blog_posts"
* @property {object} [data] - Table insert payload object => This must have keys that match
* table fields
* @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 {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?
*/
/** /**
* Make a post request to Datasquirel API * Make a post request to Datasquirel API
* ============================================================================== * ==============================================================================
@ -46,16 +24,22 @@ const localPost = require("../engine/query/post");
* @param {Object} params - Single object passed * @param {Object} params - Single object passed
* @param {string} [params.key] - FULL ACCESS API Key * @param {string} [params.key] - FULL ACCESS API Key
* @param {string} [params.database] - Database Name * @param {string} [params.database] - Database Name
* @param {PostDataPayload | string} params.query - SQL query String or Request Object * @param {import("../package-shared/types").PostDataPayload | string} params.query - SQL query String or Request Object
* @param {any[]} [params.queryValues] - Query Values if using "?" placeholders * @param {any[]} [params.queryValues] - Query Values if using "?" placeholders
* @param {string} [params.tableName] - Name of the table to query * @param {string} [params.tableName] - Name of the table to query
* *
* @returns { Promise<PostReturn> } - Return Object * @returns { Promise<import("../package-shared/types").PostReturn> } - Return Object
*/ */
async function post({ key, query, queryValues, database, tableName }) { async function post({ key, query, queryValues, database, tableName }) {
const scheme = process.env.DSQL_HTTP_SCHEME; const scheme = process.env.DSQL_HTTP_SCHEME;
const localHost = process.env.DSQL_LOCAL_HOST; const localHost = process.env.DSQL_LOCAL_HOST;
const localHostPort = process.env.DSQL_LOCAL_HOST_PORT; const localHostPort = process.env.DSQL_LOCAL_HOST_PORT;
const remoteHost = process.env.DSQL_API_REMOTE_HOST?.match(/.*\..*/)
? process.env.DSQL_API_REMOTE_HOST
: undefined;
const remoteHostPort = process.env.DSQL_API_REMOTE_HOST_PORT?.match(/./)
? process.env.DSQL_API_REMOTE_HOST_PORT
: undefined;
/** /**
* Check for local DB settings * Check for local DB settings
@ -78,7 +62,7 @@ async function post({ key, query, queryValues, database, tableName }) {
DSQL_PASS?.match(/./) && DSQL_PASS?.match(/./) &&
DSQL_DB_NAME?.match(/./) DSQL_DB_NAME?.match(/./)
) { ) {
/** @type {import("@/package-shared/types/database-schema.td").DSQL_DatabaseSchemaType | undefined} */ /** @type {import("../package-shared/types").DSQL_DatabaseSchemaType | undefined} */
let dbSchema; let dbSchema;
try { try {
@ -135,8 +119,8 @@ async function post({ key, query, queryValues, database, tableName }) {
"Content-Length": Buffer.from(reqPayload).length, "Content-Length": Buffer.from(reqPayload).length,
Authorization: key, Authorization: key,
}, },
port: localHostPort || 443, port: remoteHostPort || localHostPort || 443,
hostname: localHost || "datasquirel.com", hostname: remoteHost || localHost || "datasquirel.com",
path: `/api/query/post`, path: `/api/query/post`,
}, },

View File

@ -46,6 +46,12 @@ async function uploadImage({ key, payload }) {
const scheme = process.env.DSQL_HTTP_SCHEME; const scheme = process.env.DSQL_HTTP_SCHEME;
const localHost = process.env.DSQL_LOCAL_HOST; const localHost = process.env.DSQL_LOCAL_HOST;
const localHostPort = process.env.DSQL_LOCAL_HOST_PORT; const localHostPort = process.env.DSQL_LOCAL_HOST_PORT;
const remoteHost = process.env.DSQL_API_REMOTE_HOST?.match(/.*\..*/)
? process.env.DSQL_API_REMOTE_HOST
: undefined;
const remoteHostPort = process.env.DSQL_API_REMOTE_HOST_PORT?.match(/./)
? process.env.DSQL_API_REMOTE_HOST_PORT
: undefined;
try { try {
/** /**
@ -66,8 +72,8 @@ async function uploadImage({ key, payload }) {
"Content-Length": Buffer.from(reqPayload).length, "Content-Length": Buffer.from(reqPayload).length,
Authorization: key, Authorization: key,
}, },
port: localHostPort || 443, port: remoteHostPort || localHostPort || 443,
hostname: localHost || "datasquirel.com", hostname: remoteHost || localHost || "datasquirel.com",
path: `/api/query/add-file`, path: `/api/query/add-file`,
}, },

View File

@ -48,6 +48,12 @@ async function uploadImage({ key, payload }) {
const scheme = process.env.DSQL_HTTP_SCHEME; const scheme = process.env.DSQL_HTTP_SCHEME;
const localHost = process.env.DSQL_LOCAL_HOST; const localHost = process.env.DSQL_LOCAL_HOST;
const localHostPort = process.env.DSQL_LOCAL_HOST_PORT; const localHostPort = process.env.DSQL_LOCAL_HOST_PORT;
const remoteHost = process.env.DSQL_API_REMOTE_HOST?.match(/.*\..*/)
? process.env.DSQL_API_REMOTE_HOST
: undefined;
const remoteHostPort = process.env.DSQL_API_REMOTE_HOST_PORT?.match(/./)
? process.env.DSQL_API_REMOTE_HOST_PORT
: undefined;
try { try {
/** /**
@ -68,8 +74,8 @@ async function uploadImage({ key, payload }) {
"Content-Length": Buffer.from(reqPayload).length, "Content-Length": Buffer.from(reqPayload).length,
Authorization: key, Authorization: key,
}, },
port: localHostPort || 443, port: remoteHostPort || localHostPort || 443,
hostname: localHost || "datasquirel.com", hostname: remoteHost || localHost || "datasquirel.com",
path: `/api/query/add-image`, path: `/api/query/add-image`,
}, },