Misc 3 #57

Merged
oysteikt merged 4 commits from misc into main 2024-08-18 00:20:39 +02:00
2 changed files with 56 additions and 6 deletions
Showing only changes of commit 168f832aec - Show all commits

View File

@ -290,14 +290,14 @@ async fn show_users(
"User", "User",
"Password is set", "Password is set",
"Locked", "Locked",
// "Databases where user has privileges" "Databases where user has privileges"
]); ]);
for user in users { for user in users {
table.add_row(row![ table.add_row(row![
user.user, user.user,
user.has_password, user.has_password,
user.is_locked, user.is_locked,
// user.databases.join("\n") user.databases.join("\n")
]); ]);
} }
table.printstd(); table.printstd();

View File

@ -1,4 +1,6 @@
use itertools::Itertools;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use indoc::formatdoc;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -20,6 +22,8 @@ use crate::{
}, },
}; };
use super::database_privilege_operations::DATABASE_PRIVILEGE_FIELDS;
// NOTE: this function is unsafe because it does no input validation. // NOTE: this function is unsafe because it does no input validation.
async fn unsafe_user_exists( async fn unsafe_user_exists(
db_user: &str, db_user: &str,
@ -309,6 +313,9 @@ pub struct DatabaseUser {
#[sqlx(rename = "is_locked")] #[sqlx(rename = "is_locked")]
pub is_locked: bool, pub is_locked: bool,
#[sqlx(skip)]
pub databases: Vec<String>,
} }
const DB_USER_SELECT_STATEMENT: &str = r#" const DB_USER_SELECT_STATEMENT: &str = r#"
@ -344,13 +351,17 @@ pub async fn list_database_users(
continue; continue;
} }
let result = sqlx::query_as::<_, DatabaseUser>( let mut result = sqlx::query_as::<_, DatabaseUser>(
&(DB_USER_SELECT_STATEMENT.to_string() + "WHERE `mysql`.`user`.`User` = ?"), &(DB_USER_SELECT_STATEMENT.to_string() + "WHERE `mysql`.`user`.`User` = ?"),
) )
.bind(&db_user) .bind(&db_user)
.fetch_optional(&mut *connection) .fetch_optional(&mut *connection)
.await; .await;
if let Ok(Some(user)) = result.as_mut() {
append_databases_where_user_has_privileges(user, &mut *connection).await;
}
match result { match result {
Ok(Some(user)) => results.insert(db_user, Ok(user)), Ok(Some(user)) => results.insert(db_user, Ok(user)),
Ok(None) => results.insert(db_user, Err(ListUsersError::UserDoesNotExist)), Ok(None) => results.insert(db_user, Err(ListUsersError::UserDoesNotExist)),
@ -365,11 +376,50 @@ pub async fn list_all_database_users_for_unix_user(
unix_user: &UnixUser, unix_user: &UnixUser,
connection: &mut MySqlConnection, connection: &mut MySqlConnection,
) -> ListAllUsersOutput { ) -> ListAllUsersOutput {
sqlx::query_as::<_, DatabaseUser>( let mut result = sqlx::query_as::<_, DatabaseUser>(
&(DB_USER_SELECT_STATEMENT.to_string() + "WHERE `mysql`.`user`.`User` REGEXP ?"), &(DB_USER_SELECT_STATEMENT.to_string() + "WHERE `mysql`.`user`.`User` REGEXP ?"),
) )
.bind(create_user_group_matching_regex(unix_user)) .bind(create_user_group_matching_regex(unix_user))
.fetch_all(connection) .fetch_all(&mut *connection)
.await .await
.map_err(|err| ListAllUsersError::MySqlError(err.to_string())) .map_err(|err| ListAllUsersError::MySqlError(err.to_string()));
if let Ok(users) = result.as_mut() {
for user in users {
append_databases_where_user_has_privileges(user, &mut *connection).await;
}
}
result
}
pub async fn append_databases_where_user_has_privileges(
database_user: &mut DatabaseUser,
connection: &mut MySqlConnection,
) {
let database_list = sqlx::query(
formatdoc!(
r#"
SELECT `db` AS `database`
FROM `db`
WHERE `user` = ? AND ({})
"#,
DATABASE_PRIVILEGE_FIELDS
.iter()
.map(|field| format!("`{}` = 'Y'", field))
.join(" OR "),
)
.as_str(),
)
.bind(database_user.user.clone())
.fetch_all(&mut *connection)
.await;
database_user.databases = database_list
.map(|rows| {
rows.into_iter()
.map(|row| row.get::<String, _>("database"))
.collect()
})
.unwrap_or_default();
} }