// @ts-check //////////////////////////////////////// //////////////////////////////////////// //////////////////////////////////////// require("dotenv").config({ path: "../../.env" }); const generator = require("generate-password"); const noDatabaseDbHandler = require("../utils/noDatabaseDbHandler"); const dbHandler = require("../utils/dbHandler"); const encrypt = require("../../package-shared/functions/backend/encrypt"); const decrypt = require("../../package-shared/functions/backend/decrypt"); const { execSync } = require("child_process"); const handleGrants = require("./handleGrants"); /** ****************************************************************************** */ /** ****************************************************************************** */ /** ****************************************************************************** */ /** ****************************************************************************** */ /** ****************************************************************************** */ /** ****************************************************************************** */ const userIdFlagIndex = process.argv.findIndex((arg) => arg == "--userId"); const userId = userIdFlagIndex > 0 ? process.argv[userIdFlagIndex + 1] : null; ////////////////////////////////////////////// ////////////////////////////////////////////// const mariadbUserHostFlagIndex = process.argv.findIndex( (arg) => arg == "--host" ); const mariadbUserHostArg = mariadbUserHostFlagIndex > 0 ? process.argv[mariadbUserHostFlagIndex + 1] : null; ////////////////////////////////////////////// ////////////////////////////////////////////// const mariadbUserFlagIndex = process.argv.findIndex( (arg) => arg == "--username" ); const mariadbUserArg = mariadbUserFlagIndex > 0 ? process.argv[mariadbUserFlagIndex + 1] : null; const sqlUserIDFlagIndex = process.argv.findIndex( (arg) => arg == "--sql-user-id" ); const sqlUserIDArg = sqlUserIDFlagIndex > 0 ? process.argv[sqlUserIDFlagIndex + 1] : null; ////////////////////////////////////////////// ////////////////////////////////////////////// const defaultMariadbUserHost = process.env.DSQL_DB_HOST || "127.0.0.1"; /** * Create database from Schema Function * ============================================================================== * @param {object} params - Single object params * @param {number|string|null} params.userId - User ID or null */ async function refreshUsersAndGrants() { /** * @description Users * @type {*[] | null} */ // @ts-ignore const users = await dbHandler({ query: `SELECT * FROM users`, }); if (!users?.[0]) { process.exit(); } for (let i = 0; i < users.length; i++) { const user = users[i]; if (!user) continue; if (userId && user.id != userId) continue; try { const { mariadb_user, mariadb_host, mariadb_pass, id } = user; const existingUser = await noDatabaseDbHandler( `SELECT * FROM mysql.user WHERE User = '${mariadb_user}' AND Host = '${mariadb_host}'` ); const existingMariaDBUserArray = userId && sqlUserIDArg ? await dbHandler({ query: `SELECT * FROM mariadb_users WHERE id = ? AND user_id = ?`, values: [sqlUserIDArg, userId], }) : null; /** * @type {import("../../package-shared/types").MYSQL_mariadb_users_table_def | undefined} */ const activeMariadbUserObject = Array.isArray( existingMariaDBUserArray ) ? existingMariaDBUserArray?.[0] : undefined; const isPrimary = activeMariadbUserObject ? String(activeMariadbUserObject.primary)?.match(/1/) ? true : false : false; const isUserExisting = Boolean(existingUser?.[0]?.User); const isThisPrimaryHost = Boolean( mariadbUserHostArg == defaultMariadbUserHost ); const dslUsername = `dsql_user_${id}`; const dsqlPassword = activeMariadbUserObject?.password ? activeMariadbUserObject.password : isUserExisting ? mariadb_pass : generator.generate({ length: 16, numbers: true, symbols: true, uppercase: true, exclude: "*#.'`\"", }); const encryptedPassword = activeMariadbUserObject?.password ? activeMariadbUserObject.password : isUserExisting ? mariadb_pass : encrypt(dsqlPassword); if ( !isUserExisting && !sqlUserIDArg && !isPrimary && !mariadbUserHostArg && !mariadbUserArg ) { await noDatabaseDbHandler( `CREATE USER IF NOT EXISTS '${dslUsername}'@'${defaultMariadbUserHost}' IDENTIFIED BY '${dsqlPassword}' REQUIRE SSL` ); console.log( `User ${user.id}: ${user.first_name} ${user.last_name} SQL credentials successfully updated.` ); const updateUser = await dbHandler({ query: `UPDATE users SET mariadb_user = ?, mariadb_host = ?, mariadb_pass = ? WHERE id = ?`, values: [ dslUsername, defaultMariadbUserHost, encryptedPassword, user.id, ], }); } if (isPrimary) { const finalHost = mariadbUserHostArg ? mariadbUserHostArg : mariadb_host; const updateUser = await dbHandler({ query: `UPDATE users SET mariadb_user = ?, mariadb_host = ?, mariadb_pass = ? WHERE id = ?`, values: [ dslUsername, finalHost, encryptedPassword, user.id, ], }); } ////////////////////////////////////////////// ////////////////////////////////////////////// ////////////////////////////////////////////// /** * @description Handle mariadb_users table */ const existingMariadbPrimaryUser = await dbHandler({ query: `SELECT * FROM mariadb_users WHERE user_id = ? AND \`primary\` = 1`, values: [id], }); const isPrimaryUserExisting = Boolean( Array.isArray(existingMariadbPrimaryUser) && existingMariadbPrimaryUser?.[0]?.user_id ); /** @type {import("./handleGrants").GrantType[]} */ const primaryUserGrants = [ { database: "*", table: "*", privileges: ["ALL"], }, ]; if (!isPrimaryUserExisting) { const insertPrimaryMariadbUser = await dbHandler({ query: `INSERT INTO mariadb_users (user_id, username, password, \`primary\`, grants) VALUES (?, ?, ?, ?, ?)`, values: [ id, dslUsername, encryptedPassword, "1", JSON.stringify(primaryUserGrants), ], }); } ////////////////////////////////////////////// const existingExtraMariadbUsers = await dbHandler({ query: `SELECT * FROM mariadb_users WHERE user_id = ? AND \`primary\` != '1'`, values: [id], }); if (Array.isArray(existingExtraMariadbUsers)) { for (let i = 0; i < existingExtraMariadbUsers.length; i++) { const mariadbUser = existingExtraMariadbUsers[i]; const { user_id, username, host, password, primary, grants, } = mariadbUser; if (mariadbUserArg && username != mariadbUserArg) continue; if (mariadbUserHostArg && host != mariadbUserHostArg) continue; const decrptedPassword = decrypt(password); const existingExtraMariadbUser = await noDatabaseDbHandler( `SELECT * FROM mysql.user WHERE User = '${username}' AND Host = '${host}'` ); const isExtraMariadbUserExisting = Boolean( existingExtraMariadbUser?.[0]?.User ); if (!isExtraMariadbUserExisting) { await noDatabaseDbHandler( `CREATE USER IF NOT EXISTS '${username}'@'${host}' IDENTIFIED BY '${decrptedPassword}' REQUIRE SSL` ); } const isGrantHandled = await handleGrants({ username, host, grants: grants && typeof grants == "string" ? JSON.parse(grants) : [], }); if (!isGrantHandled) { console.log( `Error in handling grants for user ${username}@${host}` ); } } } ////////////////////////////////////////////// ////////////////////////////////////////////// ////////////////////////////////////////////// } catch (/** @type {any} */ error) { console.log(`Error in adding SQL user =>`, error.message); } } process.exit(); //////////////////////////////////////// //////////////////////////////////////// //////////////////////////////////////// } /** ****************************************************************************** */ /** ****************************************************************************** */ /** ****************************************************************************** */ /** ****************************************************************************** */ /** ****************************************************************************** */ refreshUsersAndGrants();