import path from "path"; require("dotenv").config({ path: path.resolve(__dirname, "../../../.env") }); import generator from "generate-password"; import noDatabaseDbHandler from "../utils/noDatabaseDbHandler"; import dbHandler from "../utils/dbHandler"; import handleGrants, { GrantType } from "./handleGrants"; import encrypt from "../../functions/dsql/encrypt"; import decrypt from "../../functions/dsql/decrypt"; import { MYSQL_mariadb_users_table_def } from "../../types"; const defaultMariadbUserHost = process.env.DSQL_DB_HOST || "127.0.0.1"; type Param = { userId?: number | string; mariadbUserHost?: string; mariadbUsername?: string; sqlUserID?: string | number; }; /** * # Refresh Mariadb User Grants */ export default async function refreshUsersAndGrants({ userId, mariadbUserHost, mariadbUsername, sqlUserID, }: Param) { const mariadbUsers = (await dbHandler({ query: `SELECT * FROM mariadb_users`, })) as any[] | null; if (!mariadbUsers?.[0]) { return; } const isRootUser = userId ? userId == Number(process.env.DSQL_SU_USER_ID) : false; for (let i = 0; i < mariadbUsers.length; i++) { const mariadbUser = mariadbUsers[i]; if (!mariadbUser) continue; if (userId && mariadbUser.user_id != userId) continue; try { const { mariadb_user, mariadb_host, mariadb_pass, user_id } = mariadbUser; const existingUser = await noDatabaseDbHandler( `SELECT * FROM mysql.user WHERE User = '${mariadb_user}' AND Host = '${mariadb_host}'` ); const existingMariaDBUserArray = userId && sqlUserID ? await dbHandler({ query: `SELECT * FROM mariadb_users WHERE id = ? AND user_id = ?`, values: [sqlUserID, userId], }) : null; const activeMariadbUserObject: | import("../../types").MYSQL_mariadb_users_table_def | undefined = Array.isArray(existingMariaDBUserArray) ? existingMariaDBUserArray?.[0] : undefined; const isPrimary = activeMariadbUserObject ? String(activeMariadbUserObject.primary)?.match(/1/) ? true : false : false; const isUserExisting = Boolean(existingUser?.[0]?.User); const isThisPrimaryHost = Boolean( mariadbUserHost == defaultMariadbUserHost ); const dslUsername = isRootUser ? mariadbUsername : `dsql_user_${user_id}`; const dsqlPassword = activeMariadbUserObject?.password ? activeMariadbUserObject.password : isUserExisting ? mariadb_pass : generator.generate({ length: 16, numbers: true, symbols: true, uppercase: true, exclude: "*#.'`\"", }); const encryptedPassword = activeMariadbUserObject?.password ? activeMariadbUserObject.password : isUserExisting ? mariadb_pass : encrypt({ data: dsqlPassword, encryptionKey: process.env.DSQL_ENCRYPTION_PASSWORD, encryptionSalt: process.env.DSQL_ENCRYPTION_SALT, }); if ( !isUserExisting && !sqlUserID && !isPrimary && !mariadbUserHost && !mariadbUsername ) { const createNewUser = await noDatabaseDbHandler( `CREATE USER IF NOT EXISTS '${dslUsername}'@'${defaultMariadbUserHost}' IDENTIFIED BY '${dsqlPassword}'` ); console.log("createNewUser", createNewUser); console.log( `User ${mariadbUser.id}: ${mariadbUser.first_name} ${mariadbUser.last_name} SQL credentials successfully updated.` ); const updateUser = await dbHandler({ query: `UPDATE users SET mariadb_user = ?, mariadb_host = ?, mariadb_pass = ? WHERE id = ?`, values: [ dslUsername, defaultMariadbUserHost, encryptedPassword, mariadbUser.id, ], }); } else if (!isUserExisting && mariadbUserHost) { const createNewUser = await noDatabaseDbHandler( `CREATE USER IF NOT EXISTS '${dslUsername}'@'${mariadbUserHost}' IDENTIFIED BY '${dsqlPassword}'` ); } if (isPrimary) { const finalHost = mariadbUserHost ? mariadbUserHost : mariadb_host; const updateUser = await dbHandler({ query: `UPDATE users SET mariadb_user = ?, mariadb_host = ?, mariadb_pass = ? WHERE id = ?`, values: [ dslUsername, finalHost, encryptedPassword, mariadbUser.id, ], }); } ////////////////////////////////////////////// ////////////////////////////////////////////// ////////////////////////////////////////////// /** * @description Handle mariadb_users table */ const existingMariadbPrimaryUser = await dbHandler({ query: `SELECT * FROM mariadb_users WHERE user_id = ? AND \`primary\` = 1`, values: [user_id], }); const isPrimaryUserExisting = Boolean( Array.isArray(existingMariadbPrimaryUser) && existingMariadbPrimaryUser?.[0]?.user_id ); const primaryUserGrants: GrantType[] = [ { database: "*", table: "*", privileges: ["ALL"], }, ]; if (!isPrimaryUserExisting) { const insertPrimaryMariadbUser = await dbHandler({ query: `INSERT INTO mariadb_users (user_id, username, password, \`primary\`, grants) VALUES (?, ?, ?, ?, ?)`, values: [ user_id, dslUsername, encryptedPassword, "1", JSON.stringify(primaryUserGrants), ], }); } ////////////////////////////////////////////// const existingExtraMariadbUsers = await dbHandler({ query: `SELECT * FROM mariadb_users WHERE user_id = ? AND \`primary\` != '1'`, values: [user_id], }); if (Array.isArray(existingExtraMariadbUsers)) { for (let i = 0; i < existingExtraMariadbUsers.length; i++) { const _mariadbUser = existingExtraMariadbUsers[ i ] as MYSQL_mariadb_users_table_def; if ( _mariadbUser && _mariadbUser.username != mariadbUsername ) continue; if (mariadbUserHost && _mariadbUser.host != mariadbUserHost) continue; const decrptedPassword = decrypt({ encryptedString: _mariadbUser.password || "", encryptionKey: process.env.DSQL_ENCRYPTION_PASSWORD, encryptionSalt: process.env.DSQL_ENCRYPTION_SALT, }); const existingExtraMariadbUser = await noDatabaseDbHandler( `SELECT * FROM mysql.user WHERE User='${_mariadbUser.username}' AND Host='${_mariadbUser.host}'` ); const isExtraMariadbUserExisting = Boolean( existingExtraMariadbUser?.[0]?.User ); if (!isExtraMariadbUserExisting) { await noDatabaseDbHandler( `CREATE USER IF NOT EXISTS '${_mariadbUser.username}'@'${_mariadbUser.host}' IDENTIFIED BY '${decrptedPassword}'` ); } const isGrantHandled = await handleGrants({ username: _mariadbUser.username, host: _mariadbUser.host, grants: _mariadbUser.grants && typeof _mariadbUser.grants == "string" ? JSON.parse(_mariadbUser.grants) : [], userId: String(userId), }); if (!isGrantHandled) { console.log( `Error in handling grants for user ${_mariadbUser.username}@${_mariadbUser.host}` ); } } } } catch (error: any) { console.log(`Error in adding SQL user =>`, error.message); } } }