Misc 7 #81
@ -17,8 +17,8 @@ use crate::{
|
||||
protocol::{
|
||||
print_create_databases_output_status, print_create_databases_output_status_json,
|
||||
print_drop_databases_output_status, print_drop_databases_output_status_json,
|
||||
print_modify_database_privileges_output_status, ClientToServerMessageStream, Request,
|
||||
Response,
|
||||
print_modify_database_privileges_output_status, ClientToServerMessageStream,
|
||||
MySQLDatabase, Request, Response,
|
||||
},
|
||||
},
|
||||
server::sql::database_privilege_operations::{DatabasePrivilegeRow, DATABASE_PRIVILEGE_FIELDS},
|
||||
@ -105,7 +105,7 @@ pub enum DatabaseCommand {
|
||||
pub struct DatabaseCreateArgs {
|
||||
/// The name of the database(s) to create
|
||||
#[arg(num_args = 1..)]
|
||||
name: Vec<String>,
|
||||
name: Vec<MySQLDatabase>,
|
||||
|
||||
/// Print the information as JSON
|
||||
#[arg(short, long)]
|
||||
@ -116,7 +116,7 @@ pub struct DatabaseCreateArgs {
|
||||
pub struct DatabaseDropArgs {
|
||||
/// The name of the database(s) to drop
|
||||
#[arg(num_args = 1..)]
|
||||
name: Vec<String>,
|
||||
name: Vec<MySQLDatabase>,
|
||||
|
||||
/// Print the information as JSON
|
||||
#[arg(short, long)]
|
||||
@ -127,7 +127,7 @@ pub struct DatabaseDropArgs {
|
||||
pub struct DatabaseShowArgs {
|
||||
/// The name of the database(s) to show
|
||||
#[arg(num_args = 0..)]
|
||||
name: Vec<String>,
|
||||
name: Vec<MySQLDatabase>,
|
||||
|
||||
/// Print the information as JSON
|
||||
#[arg(short, long)]
|
||||
@ -138,7 +138,7 @@ pub struct DatabaseShowArgs {
|
||||
pub struct DatabaseShowPrivsArgs {
|
||||
/// The name of the database(s) to show
|
||||
#[arg(num_args = 0..)]
|
||||
name: Vec<String>,
|
||||
name: Vec<MySQLDatabase>,
|
||||
|
||||
/// Print the information as JSON
|
||||
#[arg(short, long)]
|
||||
@ -148,7 +148,7 @@ pub struct DatabaseShowPrivsArgs {
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
pub struct DatabaseEditPrivsArgs {
|
||||
/// The name of the database to edit privileges for
|
||||
pub name: Option<String>,
|
||||
pub name: Option<MySQLDatabase>,
|
||||
|
||||
#[arg(short, long, value_name = "[DATABASE:]USER:PRIVILEGES", num_args = 0..)]
|
||||
pub privs: Vec<String>,
|
||||
@ -191,7 +191,7 @@ async fn create_databases(
|
||||
anyhow::bail!("No database names provided");
|
||||
}
|
||||
|
||||
let message = Request::CreateDatabases(args.name.clone());
|
||||
let message = Request::CreateDatabases(args.name.to_owned());
|
||||
server_connection.send(message).await?;
|
||||
|
||||
let result = match server_connection.next().await {
|
||||
@ -218,7 +218,7 @@ async fn drop_databases(
|
||||
anyhow::bail!("No database names provided");
|
||||
}
|
||||
|
||||
let message = Request::DropDatabases(args.name.clone());
|
||||
let message = Request::DropDatabases(args.name.to_owned());
|
||||
server_connection.send(message).await?;
|
||||
|
||||
let result = match server_connection.next().await {
|
||||
@ -244,7 +244,7 @@ async fn show_databases(
|
||||
let message = if args.name.is_empty() {
|
||||
Request::ListDatabases(None)
|
||||
} else {
|
||||
Request::ListDatabases(Some(args.name.clone()))
|
||||
Request::ListDatabases(Some(args.name.to_owned()))
|
||||
};
|
||||
|
||||
server_connection.send(message).await?;
|
||||
@ -301,7 +301,7 @@ async fn show_database_privileges(
|
||||
let message = if args.name.is_empty() {
|
||||
Request::ListPrivileges(None)
|
||||
} else {
|
||||
Request::ListPrivileges(Some(args.name.clone()))
|
||||
Request::ListPrivileges(Some(args.name.to_owned()))
|
||||
};
|
||||
server_connection.send(message).await?;
|
||||
|
||||
@ -373,7 +373,7 @@ pub async fn edit_database_privileges(
|
||||
args: DatabaseEditPrivsArgs,
|
||||
mut server_connection: ClientToServerMessageStream,
|
||||
) -> anyhow::Result<()> {
|
||||
let message = Request::ListPrivileges(args.name.clone().map(|name| vec![name]));
|
||||
let message = Request::ListPrivileges(args.name.to_owned().map(|name| vec![name]));
|
||||
|
||||
server_connection.send(message).await?;
|
||||
|
||||
@ -405,7 +405,7 @@ pub async fn edit_database_privileges(
|
||||
let privileges_to_change = if !args.privs.is_empty() {
|
||||
parse_privilege_tables_from_args(&args)?
|
||||
} else {
|
||||
edit_privileges_with_editor(&privilege_data, args.name.as_deref())?
|
||||
edit_privileges_with_editor(&privilege_data, args.name.as_ref())?
|
||||
};
|
||||
|
||||
let diffs = diff_privileges(&privilege_data, &privileges_to_change);
|
||||
@ -471,7 +471,7 @@ fn parse_privilege_tables_from_args(
|
||||
|
||||
fn edit_privileges_with_editor(
|
||||
privilege_data: &[DatabasePrivilegeRow],
|
||||
database_name: Option<&str>,
|
||||
database_name: Option<&MySQLDatabase>,
|
||||
) -> anyhow::Result<Vec<DatabasePrivilegeRow>> {
|
||||
let unix_user = User::from_uid(getuid())
|
||||
.context("Failed to look up your UNIX username")
|
||||
|
@ -1,4 +1,11 @@
|
||||
use crate::core::protocol::{MySQLDatabase, MySQLUser};
|
||||
|
||||
#[inline]
|
||||
pub fn trim_to_32_chars(name: &str) -> String {
|
||||
name.chars().take(32).collect()
|
||||
pub fn trim_db_name_to_32_chars(db_name: &MySQLDatabase) -> MySQLDatabase {
|
||||
db_name.chars().take(32).collect::<String>().into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn trim_user_name_to_32_chars(user_name: &MySQLUser) -> MySQLUser {
|
||||
user_name.chars().take(32).collect::<String>().into()
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use crate::{
|
||||
common::erroneous_server_response,
|
||||
database_command,
|
||||
mysql_admutils_compatibility::{
|
||||
common::trim_to_32_chars,
|
||||
common::trim_db_name_to_32_chars,
|
||||
error_messages::{
|
||||
format_show_database_error_message, handle_create_database_error,
|
||||
handle_drop_database_error,
|
||||
@ -20,7 +20,7 @@ use crate::{
|
||||
bootstrap::bootstrap_server_connection_and_drop_privileges,
|
||||
protocol::{
|
||||
create_client_to_server_message_stream, ClientToServerMessageStream,
|
||||
GetDatabasesPrivilegeDataError, Request, Response,
|
||||
GetDatabasesPrivilegeDataError, MySQLDatabase, Request, Response,
|
||||
},
|
||||
},
|
||||
server::sql::database_privilege_operations::DatabasePrivilegeRow,
|
||||
@ -120,27 +120,27 @@ pub enum Command {
|
||||
pub struct CreateArgs {
|
||||
/// The name of the DATABASE(s) to create.
|
||||
#[arg(num_args = 1..)]
|
||||
name: Vec<String>,
|
||||
name: Vec<MySQLDatabase>,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
pub struct DatabaseDropArgs {
|
||||
/// The name of the DATABASE(s) to drop.
|
||||
#[arg(num_args = 1..)]
|
||||
name: Vec<String>,
|
||||
name: Vec<MySQLDatabase>,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
pub struct DatabaseShowArgs {
|
||||
/// The name of the DATABASE(s) to show.
|
||||
#[arg(num_args = 0..)]
|
||||
name: Vec<String>,
|
||||
name: Vec<MySQLDatabase>,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
pub struct EditPermArgs {
|
||||
/// The name of the DATABASE to edit permissions for.
|
||||
pub database: String,
|
||||
pub database: MySQLDatabase,
|
||||
}
|
||||
|
||||
pub fn main() -> anyhow::Result<()> {
|
||||
@ -202,11 +202,7 @@ async fn create_databases(
|
||||
args: CreateArgs,
|
||||
mut server_connection: ClientToServerMessageStream,
|
||||
) -> anyhow::Result<()> {
|
||||
let database_names = args
|
||||
.name
|
||||
.iter()
|
||||
.map(|name| trim_to_32_chars(name))
|
||||
.collect();
|
||||
let database_names = args.name.iter().map(trim_db_name_to_32_chars).collect();
|
||||
|
||||
let message = Request::CreateDatabases(database_names);
|
||||
server_connection.send(message).await?;
|
||||
@ -232,11 +228,7 @@ async fn drop_databases(
|
||||
args: DatabaseDropArgs,
|
||||
mut server_connection: ClientToServerMessageStream,
|
||||
) -> anyhow::Result<()> {
|
||||
let database_names = args
|
||||
.name
|
||||
.iter()
|
||||
.map(|name| trim_to_32_chars(name))
|
||||
.collect();
|
||||
let database_names = args.name.iter().map(trim_db_name_to_32_chars).collect();
|
||||
|
||||
let message = Request::DropDatabases(database_names);
|
||||
server_connection.send(message).await?;
|
||||
@ -262,11 +254,8 @@ async fn show_databases(
|
||||
args: DatabaseShowArgs,
|
||||
mut server_connection: ClientToServerMessageStream,
|
||||
) -> anyhow::Result<()> {
|
||||
let database_names: Vec<String> = args
|
||||
.name
|
||||
.iter()
|
||||
.map(|name| trim_to_32_chars(name))
|
||||
.collect();
|
||||
let database_names: Vec<MySQLDatabase> =
|
||||
args.name.iter().map(trim_db_name_to_32_chars).collect();
|
||||
|
||||
let message = if database_names.is_empty() {
|
||||
let message = Request::ListDatabases(None);
|
||||
@ -291,14 +280,16 @@ async fn show_databases(
|
||||
|
||||
// NOTE: mysql-dbadm show has a quirk where valid database names
|
||||
// for non-existent databases will report with no users.
|
||||
let results: Vec<Result<(String, Vec<DatabasePrivilegeRow>), String>> = match response {
|
||||
let results: Vec<Result<(MySQLDatabase, Vec<DatabasePrivilegeRow>), String>> = match response {
|
||||
Some(Ok(Response::ListPrivileges(result))) => result
|
||||
.into_iter()
|
||||
.map(|(name, rows)| match rows.map(|rows| (name.clone(), rows)) {
|
||||
Ok(rows) => Ok(rows),
|
||||
Err(GetDatabasesPrivilegeDataError::DatabaseDoesNotExist) => Ok((name, vec![])),
|
||||
Err(err) => Err(format_show_database_error_message(err, &name)),
|
||||
})
|
||||
.map(
|
||||
|(name, rows)| match rows.map(|rows| (name.to_owned(), rows)) {
|
||||
Ok(rows) => Ok(rows),
|
||||
Err(GetDatabasesPrivilegeDataError::DatabaseDoesNotExist) => Ok((name, vec![])),
|
||||
Err(err) => Err(format_show_database_error_message(err, &name)),
|
||||
},
|
||||
)
|
||||
.collect(),
|
||||
response => return erroneous_server_response(response),
|
||||
};
|
||||
|
@ -9,7 +9,7 @@ use crate::{
|
||||
cli::{
|
||||
common::erroneous_server_response,
|
||||
mysql_admutils_compatibility::{
|
||||
common::trim_to_32_chars,
|
||||
common::trim_user_name_to_32_chars,
|
||||
error_messages::{
|
||||
handle_create_user_error, handle_drop_user_error, handle_list_users_error,
|
||||
},
|
||||
@ -19,7 +19,8 @@ use crate::{
|
||||
core::{
|
||||
bootstrap::bootstrap_server_connection_and_drop_privileges,
|
||||
protocol::{
|
||||
create_client_to_server_message_stream, ClientToServerMessageStream, Request, Response,
|
||||
create_client_to_server_message_stream, ClientToServerMessageStream, MySQLUser,
|
||||
Request, Response,
|
||||
},
|
||||
},
|
||||
server::sql::user_operations::DatabaseUser,
|
||||
@ -83,28 +84,28 @@ pub enum Command {
|
||||
pub struct CreateArgs {
|
||||
/// The name of the USER(s) to create.
|
||||
#[arg(num_args = 1..)]
|
||||
name: Vec<String>,
|
||||
name: Vec<MySQLUser>,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
pub struct DeleteArgs {
|
||||
/// The name of the USER(s) to delete.
|
||||
#[arg(num_args = 1..)]
|
||||
name: Vec<String>,
|
||||
name: Vec<MySQLUser>,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
pub struct PasswdArgs {
|
||||
/// The name of the USER(s) to change the password for.
|
||||
#[arg(num_args = 1..)]
|
||||
name: Vec<String>,
|
||||
name: Vec<MySQLUser>,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
pub struct ShowArgs {
|
||||
/// The name of the USER(s) to show.
|
||||
#[arg(num_args = 0..)]
|
||||
name: Vec<String>,
|
||||
name: Vec<MySQLUser>,
|
||||
}
|
||||
|
||||
pub fn main() -> anyhow::Result<()> {
|
||||
@ -152,13 +153,9 @@ async fn create_user(
|
||||
args: CreateArgs,
|
||||
mut server_connection: ClientToServerMessageStream,
|
||||
) -> anyhow::Result<()> {
|
||||
let usernames = args
|
||||
.name
|
||||
.iter()
|
||||
.map(|name| trim_to_32_chars(name))
|
||||
.collect();
|
||||
let db_users = args.name.iter().map(trim_user_name_to_32_chars).collect();
|
||||
|
||||
let message = Request::CreateUsers(usernames);
|
||||
let message = Request::CreateUsers(db_users);
|
||||
server_connection.send(message).await?;
|
||||
|
||||
let result = match server_connection.next().await {
|
||||
@ -182,13 +179,9 @@ async fn drop_users(
|
||||
args: DeleteArgs,
|
||||
mut server_connection: ClientToServerMessageStream,
|
||||
) -> anyhow::Result<()> {
|
||||
let usernames = args
|
||||
.name
|
||||
.iter()
|
||||
.map(|name| trim_to_32_chars(name))
|
||||
.collect();
|
||||
let db_users = args.name.iter().map(trim_user_name_to_32_chars).collect();
|
||||
|
||||
let message = Request::DropUsers(usernames);
|
||||
let message = Request::DropUsers(db_users);
|
||||
server_connection.send(message).await?;
|
||||
|
||||
let result = match server_connection.next().await {
|
||||
@ -212,13 +205,9 @@ async fn passwd_users(
|
||||
args: PasswdArgs,
|
||||
mut server_connection: ClientToServerMessageStream,
|
||||
) -> anyhow::Result<()> {
|
||||
let usernames = args
|
||||
.name
|
||||
.iter()
|
||||
.map(|name| trim_to_32_chars(name))
|
||||
.collect();
|
||||
let db_users = args.name.iter().map(trim_user_name_to_32_chars).collect();
|
||||
|
||||
let message = Request::ListUsers(Some(usernames));
|
||||
let message = Request::ListUsers(Some(db_users));
|
||||
server_connection.send(message).await?;
|
||||
|
||||
let response = match server_connection.next().await {
|
||||
@ -243,11 +232,11 @@ async fn passwd_users(
|
||||
|
||||
for user in users {
|
||||
let password = read_password_from_stdin_with_double_check(&user.user)?;
|
||||
let message = Request::PasswdUser(user.user.clone(), password);
|
||||
let message = Request::PasswdUser(user.user.to_owned(), password);
|
||||
server_connection.send(message).await?;
|
||||
match server_connection.next().await {
|
||||
Some(Ok(Response::PasswdUser(result))) => match result {
|
||||
Ok(()) => println!("Password updated for user '{}'.", user.user),
|
||||
Ok(()) => println!("Password updated for user '{}'.", &user.user),
|
||||
Err(_) => eprintln!(
|
||||
"{}: Failed to update password for user '{}'.",
|
||||
argv0, user.user,
|
||||
@ -266,16 +255,12 @@ async fn show_users(
|
||||
args: ShowArgs,
|
||||
mut server_connection: ClientToServerMessageStream,
|
||||
) -> anyhow::Result<()> {
|
||||
let usernames: Vec<_> = args
|
||||
.name
|
||||
.iter()
|
||||
.map(|name| trim_to_32_chars(name))
|
||||
.collect();
|
||||
let db_users: Vec<_> = args.name.iter().map(trim_user_name_to_32_chars).collect();
|
||||
|
||||
let message = if usernames.is_empty() {
|
||||
let message = if db_users.is_empty() {
|
||||
Request::ListUsers(None)
|
||||
} else {
|
||||
Request::ListUsers(Some(usernames))
|
||||
Request::ListUsers(Some(db_users))
|
||||
};
|
||||
server_connection.send(message).await?;
|
||||
|
||||
|
@ -8,8 +8,8 @@ use crate::core::protocol::{
|
||||
print_drop_users_output_status, print_drop_users_output_status_json,
|
||||
print_lock_users_output_status, print_lock_users_output_status_json,
|
||||
print_set_password_output_status, print_unlock_users_output_status,
|
||||
print_unlock_users_output_status_json, ClientToServerMessageStream, ListUsersError, Request,
|
||||
Response,
|
||||
print_unlock_users_output_status_json, ClientToServerMessageStream, ListUsersError, MySQLUser,
|
||||
Request, Response,
|
||||
};
|
||||
|
||||
use super::common::erroneous_server_response;
|
||||
@ -53,7 +53,7 @@ pub enum UserCommand {
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
pub struct UserCreateArgs {
|
||||
#[arg(num_args = 1..)]
|
||||
username: Vec<String>,
|
||||
username: Vec<MySQLUser>,
|
||||
|
||||
/// Do not ask for a password, leave it unset
|
||||
#[clap(long)]
|
||||
@ -69,7 +69,7 @@ pub struct UserCreateArgs {
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
pub struct UserDeleteArgs {
|
||||
#[arg(num_args = 1..)]
|
||||
username: Vec<String>,
|
||||
username: Vec<MySQLUser>,
|
||||
|
||||
/// Print the information as JSON
|
||||
#[arg(short, long)]
|
||||
@ -78,7 +78,7 @@ pub struct UserDeleteArgs {
|
||||
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
pub struct UserPasswdArgs {
|
||||
username: String,
|
||||
username: MySQLUser,
|
||||
|
||||
#[clap(short, long)]
|
||||
password_file: Option<String>,
|
||||
@ -91,7 +91,7 @@ pub struct UserPasswdArgs {
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
pub struct UserShowArgs {
|
||||
#[arg(num_args = 0..)]
|
||||
username: Vec<String>,
|
||||
username: Vec<MySQLUser>,
|
||||
|
||||
/// Print the information as JSON
|
||||
#[arg(short, long)]
|
||||
@ -101,7 +101,7 @@ pub struct UserShowArgs {
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
pub struct UserLockArgs {
|
||||
#[arg(num_args = 1..)]
|
||||
username: Vec<String>,
|
||||
username: Vec<MySQLUser>,
|
||||
|
||||
/// Print the information as JSON
|
||||
#[arg(short, long)]
|
||||
@ -111,7 +111,7 @@ pub struct UserLockArgs {
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
pub struct UserUnlockArgs {
|
||||
#[arg(num_args = 1..)]
|
||||
username: Vec<String>,
|
||||
username: Vec<MySQLUser>,
|
||||
|
||||
/// Print the information as JSON
|
||||
#[arg(short, long)]
|
||||
@ -140,7 +140,7 @@ async fn create_users(
|
||||
anyhow::bail!("No usernames provided");
|
||||
}
|
||||
|
||||
let message = Request::CreateUsers(args.username.clone());
|
||||
let message = Request::CreateUsers(args.username.to_owned());
|
||||
if let Err(err) = server_connection.send(message).await {
|
||||
server_connection.close().await.ok();
|
||||
anyhow::bail!(anyhow::Error::from(err).context("Failed to communicate with server"));
|
||||
@ -172,7 +172,7 @@ async fn create_users(
|
||||
.interact()?
|
||||
{
|
||||
let password = read_password_from_stdin_with_double_check(username)?;
|
||||
let message = Request::PasswdUser(username.clone(), password);
|
||||
let message = Request::PasswdUser(username.to_owned(), password);
|
||||
|
||||
if let Err(err) = server_connection.send(message).await {
|
||||
server_connection.close().await.ok();
|
||||
@ -204,7 +204,7 @@ async fn drop_users(
|
||||
anyhow::bail!("No usernames provided");
|
||||
}
|
||||
|
||||
let message = Request::DropUsers(args.username.clone());
|
||||
let message = Request::DropUsers(args.username.to_owned());
|
||||
|
||||
if let Err(err) = server_connection.send(message).await {
|
||||
server_connection.close().await.ok();
|
||||
@ -227,7 +227,7 @@ async fn drop_users(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_password_from_stdin_with_double_check(username: &str) -> anyhow::Result<String> {
|
||||
pub fn read_password_from_stdin_with_double_check(username: &MySQLUser) -> anyhow::Result<String> {
|
||||
Password::new()
|
||||
.with_prompt(format!("New MySQL password for user '{}'", username))
|
||||
.with_confirmation(
|
||||
@ -243,7 +243,7 @@ async fn passwd_user(
|
||||
mut server_connection: ClientToServerMessageStream,
|
||||
) -> anyhow::Result<()> {
|
||||
// TODO: create a "user" exists check" command
|
||||
let message = Request::ListUsers(Some(vec![args.username.clone()]));
|
||||
let message = Request::ListUsers(Some(vec![args.username.to_owned()]));
|
||||
if let Err(err) = server_connection.send(message).await {
|
||||
server_connection.close().await.ok();
|
||||
anyhow::bail!(err);
|
||||
@ -273,7 +273,7 @@ async fn passwd_user(
|
||||
read_password_from_stdin_with_double_check(&args.username)?
|
||||
};
|
||||
|
||||
let message = Request::PasswdUser(args.username.clone(), password);
|
||||
let message = Request::PasswdUser(args.username.to_owned(), password);
|
||||
|
||||
if let Err(err) = server_connection.send(message).await {
|
||||
server_connection.close().await.ok();
|
||||
@ -299,7 +299,7 @@ async fn show_users(
|
||||
let message = if args.username.is_empty() {
|
||||
Request::ListUsers(None)
|
||||
} else {
|
||||
Request::ListUsers(Some(args.username.clone()))
|
||||
Request::ListUsers(Some(args.username.to_owned()))
|
||||
};
|
||||
|
||||
if let Err(err) = server_connection.send(message).await {
|
||||
@ -370,7 +370,7 @@ async fn lock_users(
|
||||
anyhow::bail!("No usernames provided");
|
||||
}
|
||||
|
||||
let message = Request::LockUsers(args.username.clone());
|
||||
let message = Request::LockUsers(args.username.to_owned());
|
||||
|
||||
if let Err(err) = server_connection.send(message).await {
|
||||
server_connection.close().await.ok();
|
||||
@ -401,7 +401,7 @@ async fn unlock_users(
|
||||
anyhow::bail!("No usernames provided");
|
||||
}
|
||||
|
||||
let message = Request::UnlockUsers(args.username.clone());
|
||||
let message = Request::UnlockUsers(args.username.to_owned());
|
||||
|
||||
if let Err(err) = server_connection.send(message).await {
|
||||
server_connection.close().await.ok();
|
||||
|
@ -54,7 +54,7 @@ impl UnixUser {
|
||||
|
||||
Ok(UnixUser {
|
||||
username: libc_user.name,
|
||||
groups: groups.iter().map(|g| g.name.clone()).collect(),
|
||||
groups: groups.iter().map(|g| g.name.to_owned()).collect(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,10 @@ use std::{
|
||||
collections::{BTreeSet, HashMap},
|
||||
};
|
||||
|
||||
use super::common::{rev_yn, yn};
|
||||
use super::{
|
||||
common::{rev_yn, yn},
|
||||
protocol::{MySQLDatabase, MySQLUser},
|
||||
};
|
||||
use crate::server::sql::database_privilege_operations::{
|
||||
DatabasePrivilegeRow, DATABASE_PRIVILEGE_FIELDS,
|
||||
};
|
||||
@ -35,8 +38,8 @@ pub fn diff(row1: &DatabasePrivilegeRow, row2: &DatabasePrivilegeRow) -> Databas
|
||||
debug_assert!(row1.db == row2.db && row1.user == row2.user);
|
||||
|
||||
DatabasePrivilegeRowDiff {
|
||||
db: row1.db.clone(),
|
||||
user: row1.user.clone(),
|
||||
db: row1.db.to_owned(),
|
||||
user: row1.user.to_owned(),
|
||||
diff: DATABASE_PRIVILEGE_FIELDS
|
||||
.into_iter()
|
||||
.skip(2)
|
||||
@ -70,8 +73,8 @@ pub fn parse_privilege_table_cli_arg(arg: &str) -> anyhow::Result<DatabasePrivil
|
||||
anyhow::bail!("Username cannot be empty.");
|
||||
}
|
||||
|
||||
let db = parts[0].to_string();
|
||||
let user = parts[1].to_string();
|
||||
let db = parts[0].into();
|
||||
let user = parts[1].into();
|
||||
let privs = parts[2].to_string();
|
||||
|
||||
let mut result = DatabasePrivilegeRow {
|
||||
@ -165,11 +168,11 @@ const EDITOR_COMMENT: &str = r#"
|
||||
pub fn generate_editor_content_from_privilege_data(
|
||||
privilege_data: &[DatabasePrivilegeRow],
|
||||
unix_user: &str,
|
||||
database_name: Option<&str>,
|
||||
database_name: Option<&MySQLDatabase>,
|
||||
) -> String {
|
||||
let example_user = format!("{}_user", unix_user);
|
||||
let example_db = database_name
|
||||
.unwrap_or(&format!("{}_db", unix_user))
|
||||
.unwrap_or(&format!("{}_db", unix_user).into())
|
||||
.to_string();
|
||||
|
||||
// NOTE: `.max()`` fails when the iterator is empty.
|
||||
@ -206,8 +209,8 @@ pub fn generate_editor_content_from_privilege_data(
|
||||
|
||||
let example_line = format_privileges_line_for_editor(
|
||||
&DatabasePrivilegeRow {
|
||||
db: example_db,
|
||||
user: example_user,
|
||||
db: example_db.into(),
|
||||
user: example_user.into(),
|
||||
select_priv: true,
|
||||
insert_priv: true,
|
||||
update_priv: true,
|
||||
@ -298,8 +301,8 @@ fn parse_privilege_row_from_editor(row: &str) -> PrivilegeRowParseResult {
|
||||
}
|
||||
|
||||
let row = DatabasePrivilegeRow {
|
||||
db: (*parts.first().unwrap()).to_owned(),
|
||||
user: (*parts.get(1).unwrap()).to_owned(),
|
||||
db: (*parts.first().unwrap()).into(),
|
||||
user: (*parts.get(1).unwrap()).into(),
|
||||
select_priv: match parse_privilege_cell_from_editor(
|
||||
parts.get(2).unwrap(),
|
||||
DATABASE_PRIVILEGE_FIELDS[2],
|
||||
@ -423,8 +426,8 @@ pub fn parse_privilege_data_from_editor_content(
|
||||
/// The `User` and `Database` are the same for both instances.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)]
|
||||
pub struct DatabasePrivilegeRowDiff {
|
||||
pub db: String,
|
||||
pub user: String,
|
||||
pub db: MySQLDatabase,
|
||||
pub user: MySQLUser,
|
||||
pub diff: BTreeSet<DatabasePrivilegeChange>,
|
||||
}
|
||||
|
||||
@ -454,7 +457,7 @@ pub enum DatabasePrivilegesDiff {
|
||||
}
|
||||
|
||||
impl DatabasePrivilegesDiff {
|
||||
pub fn get_database_name(&self) -> &str {
|
||||
pub fn get_database_name(&self) -> &MySQLDatabase {
|
||||
match self {
|
||||
DatabasePrivilegesDiff::New(p) => &p.db,
|
||||
DatabasePrivilegesDiff::Modified(p) => &p.db,
|
||||
@ -462,7 +465,7 @@ impl DatabasePrivilegesDiff {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_user_name(&self) -> &str {
|
||||
pub fn get_user_name(&self) -> &MySQLUser {
|
||||
match self {
|
||||
DatabasePrivilegesDiff::New(p) => &p.user,
|
||||
DatabasePrivilegesDiff::Modified(p) => &p.user,
|
||||
@ -478,34 +481,36 @@ pub fn diff_privileges(
|
||||
from: &[DatabasePrivilegeRow],
|
||||
to: &[DatabasePrivilegeRow],
|
||||
) -> BTreeSet<DatabasePrivilegesDiff> {
|
||||
let from_lookup_table: HashMap<(String, String), DatabasePrivilegeRow> = HashMap::from_iter(
|
||||
from.iter()
|
||||
.cloned()
|
||||
.map(|p| ((p.db.clone(), p.user.clone()), p)),
|
||||
);
|
||||
let from_lookup_table: HashMap<(MySQLDatabase, MySQLUser), DatabasePrivilegeRow> =
|
||||
HashMap::from_iter(
|
||||
from.iter()
|
||||
.cloned()
|
||||
.map(|p| ((p.db.to_owned(), p.user.to_owned()), p)),
|
||||
);
|
||||
|
||||
let to_lookup_table: HashMap<(String, String), DatabasePrivilegeRow> = HashMap::from_iter(
|
||||
to.iter()
|
||||
.cloned()
|
||||
.map(|p| ((p.db.clone(), p.user.clone()), p)),
|
||||
);
|
||||
let to_lookup_table: HashMap<(MySQLDatabase, MySQLUser), DatabasePrivilegeRow> =
|
||||
HashMap::from_iter(
|
||||
to.iter()
|
||||
.cloned()
|
||||
.map(|p| ((p.db.to_owned(), p.user.to_owned()), p)),
|
||||
);
|
||||
|
||||
let mut result = BTreeSet::new();
|
||||
|
||||
for p in to {
|
||||
if let Some(old_p) = from_lookup_table.get(&(p.db.clone(), p.user.clone())) {
|
||||
if let Some(old_p) = from_lookup_table.get(&(p.db.to_owned(), p.user.to_owned())) {
|
||||
let diff = diff(old_p, p);
|
||||
if !diff.diff.is_empty() {
|
||||
result.insert(DatabasePrivilegesDiff::Modified(diff));
|
||||
}
|
||||
} else {
|
||||
result.insert(DatabasePrivilegesDiff::New(p.clone()));
|
||||
result.insert(DatabasePrivilegesDiff::New(p.to_owned()));
|
||||
}
|
||||
}
|
||||
|
||||
for p in from {
|
||||
if !to_lookup_table.contains_key(&(p.db.clone(), p.user.clone())) {
|
||||
result.insert(DatabasePrivilegesDiff::Deleted(p.clone()));
|
||||
if !to_lookup_table.contains_key(&(p.db.to_owned(), p.user.to_owned())) {
|
||||
result.insert(DatabasePrivilegesDiff::Deleted(p.to_owned()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -593,8 +598,8 @@ mod tests {
|
||||
assert_eq!(
|
||||
result.ok(),
|
||||
Some(DatabasePrivilegeRow {
|
||||
db: "db".to_owned(),
|
||||
user: "user".to_owned(),
|
||||
db: "db".into(),
|
||||
user: "user".into(),
|
||||
select_priv: true,
|
||||
insert_priv: true,
|
||||
update_priv: true,
|
||||
@ -613,8 +618,8 @@ mod tests {
|
||||
assert_eq!(
|
||||
result.ok(),
|
||||
Some(DatabasePrivilegeRow {
|
||||
db: "db".to_owned(),
|
||||
user: "user".to_owned(),
|
||||
db: "db".into(),
|
||||
user: "user".into(),
|
||||
select_priv: false,
|
||||
insert_priv: false,
|
||||
update_priv: false,
|
||||
@ -633,8 +638,8 @@ mod tests {
|
||||
assert_eq!(
|
||||
result.ok(),
|
||||
Some(DatabasePrivilegeRow {
|
||||
db: "db".to_owned(),
|
||||
user: "user".to_owned(),
|
||||
db: "db".into(),
|
||||
user: "user".into(),
|
||||
select_priv: true,
|
||||
insert_priv: true,
|
||||
update_priv: true,
|
||||
@ -668,8 +673,8 @@ mod tests {
|
||||
#[test]
|
||||
fn test_diff_privileges() {
|
||||
let row_to_be_modified = DatabasePrivilegeRow {
|
||||
db: "db".to_owned(),
|
||||
user: "user".to_owned(),
|
||||
db: "db".into(),
|
||||
user: "user".into(),
|
||||
select_priv: true,
|
||||
insert_priv: true,
|
||||
update_priv: true,
|
||||
@ -683,20 +688,20 @@ mod tests {
|
||||
references_priv: false,
|
||||
};
|
||||
|
||||
let mut row_to_be_deleted = row_to_be_modified.clone();
|
||||
let mut row_to_be_deleted = row_to_be_modified.to_owned();
|
||||
"user2".clone_into(&mut row_to_be_deleted.user);
|
||||
|
||||
let from = vec![row_to_be_modified.clone(), row_to_be_deleted.clone()];
|
||||
let from = vec![row_to_be_modified.to_owned(), row_to_be_deleted.to_owned()];
|
||||
|
||||
let mut modified_row = row_to_be_modified.clone();
|
||||
let mut modified_row = row_to_be_modified.to_owned();
|
||||
modified_row.select_priv = false;
|
||||
modified_row.insert_priv = false;
|
||||
modified_row.index_priv = true;
|
||||
|
||||
let mut new_row = row_to_be_modified.clone();
|
||||
let mut new_row = row_to_be_modified.to_owned();
|
||||
"user3".clone_into(&mut new_row.user);
|
||||
|
||||
let to = vec![modified_row.clone(), new_row.clone()];
|
||||
let to = vec![modified_row.to_owned(), new_row.to_owned()];
|
||||
|
||||
let diffs = diff_privileges(&from, &to);
|
||||
|
||||
@ -705,8 +710,8 @@ mod tests {
|
||||
BTreeSet::from_iter(vec![
|
||||
DatabasePrivilegesDiff::Deleted(row_to_be_deleted),
|
||||
DatabasePrivilegesDiff::Modified(DatabasePrivilegeRowDiff {
|
||||
db: "db".to_owned(),
|
||||
user: "user".to_owned(),
|
||||
db: "db".into(),
|
||||
user: "user".into(),
|
||||
diff: BTreeSet::from_iter(vec![
|
||||
DatabasePrivilegeChange::YesToNo("select_priv".to_owned()),
|
||||
DatabasePrivilegeChange::YesToNo("insert_priv".to_owned()),
|
||||
@ -722,8 +727,8 @@ mod tests {
|
||||
fn ensure_generated_and_parsed_editor_content_is_equal() {
|
||||
let permissions = vec![
|
||||
DatabasePrivilegeRow {
|
||||
db: "db".to_owned(),
|
||||
user: "user".to_owned(),
|
||||
db: "db".into(),
|
||||
user: "user".into(),
|
||||
select_priv: true,
|
||||
insert_priv: true,
|
||||
update_priv: true,
|
||||
@ -737,8 +742,8 @@ mod tests {
|
||||
references_priv: true,
|
||||
},
|
||||
DatabasePrivilegeRow {
|
||||
db: "db2".to_owned(),
|
||||
user: "user2".to_owned(),
|
||||
db: "db".into(),
|
||||
user: "user".into(),
|
||||
select_priv: false,
|
||||
insert_priv: false,
|
||||
update_priv: false,
|
||||
|
@ -1,4 +1,9 @@
|
||||
use std::collections::BTreeSet;
|
||||
use std::{
|
||||
collections::BTreeSet,
|
||||
fmt::{Display, Formatter},
|
||||
ops::{Deref, DerefMut},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::net::UnixStream;
|
||||
@ -31,21 +36,107 @@ pub fn create_client_to_server_message_stream(socket: UnixStream) -> ClientToSer
|
||||
tokio_serde::Framed::new(length_delimited, Bincode::default())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||
pub struct MySQLUser(String);
|
||||
|
||||
impl FromStr for MySQLUser {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(MySQLUser(s.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for MySQLUser {
|
||||
type Target = String;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for MySQLUser {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for MySQLUser {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for MySQLUser {
|
||||
fn from(s: &str) -> Self {
|
||||
MySQLUser(s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for MySQLUser {
|
||||
fn from(s: String) -> Self {
|
||||
MySQLUser(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||
pub struct MySQLDatabase(String);
|
||||
|
||||
impl FromStr for MySQLDatabase {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(MySQLDatabase(s.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for MySQLDatabase {
|
||||
type Target = String;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for MySQLDatabase {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for MySQLDatabase {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for MySQLDatabase {
|
||||
fn from(s: &str) -> Self {
|
||||
MySQLDatabase(s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for MySQLDatabase {
|
||||
fn from(s: String) -> Self {
|
||||
MySQLDatabase(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Request {
|
||||
CreateDatabases(Vec<String>),
|
||||
DropDatabases(Vec<String>),
|
||||
ListDatabases(Option<Vec<String>>),
|
||||
ListPrivileges(Option<Vec<String>>),
|
||||
CreateDatabases(Vec<MySQLDatabase>),
|
||||
DropDatabases(Vec<MySQLDatabase>),
|
||||
ListDatabases(Option<Vec<MySQLDatabase>>),
|
||||
ListPrivileges(Option<Vec<MySQLDatabase>>),
|
||||
ModifyPrivileges(BTreeSet<DatabasePrivilegesDiff>),
|
||||
|
||||
CreateUsers(Vec<String>),
|
||||
DropUsers(Vec<String>),
|
||||
PasswdUser(String, String),
|
||||
ListUsers(Option<Vec<String>>),
|
||||
LockUsers(Vec<String>),
|
||||
UnlockUsers(Vec<String>),
|
||||
CreateUsers(Vec<MySQLUser>),
|
||||
DropUsers(Vec<MySQLUser>),
|
||||
PasswdUser(MySQLUser, String),
|
||||
ListUsers(Option<Vec<MySQLUser>>),
|
||||
LockUsers(Vec<MySQLUser>),
|
||||
UnlockUsers(Vec<MySQLUser>),
|
||||
|
||||
// Commit,
|
||||
Exit,
|
||||
|
@ -13,6 +13,8 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
use super::{MySQLDatabase, MySQLUser};
|
||||
|
||||
/// This enum is used to differentiate between database and user operations.
|
||||
/// Their output are very similar, but there are slight differences in the words used.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
@ -22,17 +24,17 @@ pub enum DbOrUser {
|
||||
}
|
||||
|
||||
impl DbOrUser {
|
||||
pub fn lowercased(&self) -> String {
|
||||
pub fn lowercased(&self) -> &'static str {
|
||||
match self {
|
||||
DbOrUser::Database => "database".to_string(),
|
||||
DbOrUser::User => "user".to_string(),
|
||||
DbOrUser::Database => "database",
|
||||
DbOrUser::User => "user",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn capitalized(&self) -> String {
|
||||
pub fn capitalized(&self) -> &'static str {
|
||||
match self {
|
||||
DbOrUser::Database => "Database".to_string(),
|
||||
DbOrUser::User => "User".to_string(),
|
||||
DbOrUser::Database => "Database",
|
||||
DbOrUser::User => "User",
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -73,6 +75,11 @@ impl OwnerValidationError {
|
||||
pub fn to_error_message(self, name: &str, db_or_user: DbOrUser) -> String {
|
||||
let user = UnixUser::from_enviroment();
|
||||
|
||||
let UnixUser { username, groups } = user.unwrap_or(UnixUser {
|
||||
username: "???".to_string(),
|
||||
groups: vec![],
|
||||
});
|
||||
|
||||
match self {
|
||||
OwnerValidationError::NoMatch => format!(
|
||||
indoc! {r#"
|
||||
@ -88,11 +95,8 @@ impl OwnerValidationError {
|
||||
name,
|
||||
db_or_user.lowercased(),
|
||||
db_or_user.lowercased(),
|
||||
user.as_ref()
|
||||
.map(|u| u.username.clone())
|
||||
.unwrap_or("???".to_string()),
|
||||
user.map(|u| u.groups)
|
||||
.unwrap_or_default()
|
||||
username,
|
||||
groups
|
||||
.iter()
|
||||
.map(|g| format!(" - {}", g))
|
||||
.sorted()
|
||||
@ -118,7 +122,7 @@ pub enum OwnerValidationError {
|
||||
StringEmpty,
|
||||
}
|
||||
|
||||
pub type CreateDatabasesOutput = BTreeMap<String, Result<(), CreateDatabaseError>>;
|
||||
pub type CreateDatabasesOutput = BTreeMap<MySQLDatabase, Result<(), CreateDatabaseError>>;
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum CreateDatabaseError {
|
||||
SanitizationError(NameValidationError),
|
||||
@ -146,9 +150,9 @@ pub fn print_create_databases_output_status_json(output: &CreateDatabasesOutput)
|
||||
let value = output
|
||||
.iter()
|
||||
.map(|(name, result)| match result {
|
||||
Ok(()) => (name.to_owned(), json!({ "status": "success" })),
|
||||
Ok(()) => (name.to_string(), json!({ "status": "success" })),
|
||||
Err(err) => (
|
||||
name.clone(),
|
||||
name.to_string(),
|
||||
json!({
|
||||
"status": "error",
|
||||
"error": err.to_error_message(name),
|
||||
@ -164,7 +168,7 @@ pub fn print_create_databases_output_status_json(output: &CreateDatabasesOutput)
|
||||
}
|
||||
|
||||
impl CreateDatabaseError {
|
||||
pub fn to_error_message(&self, database_name: &str) -> String {
|
||||
pub fn to_error_message(&self, database_name: &MySQLDatabase) -> String {
|
||||
match self {
|
||||
CreateDatabaseError::SanitizationError(err) => {
|
||||
err.to_error_message(database_name, DbOrUser::Database)
|
||||
@ -182,7 +186,7 @@ impl CreateDatabaseError {
|
||||
}
|
||||
}
|
||||
|
||||
pub type DropDatabasesOutput = BTreeMap<String, Result<(), DropDatabaseError>>;
|
||||
pub type DropDatabasesOutput = BTreeMap<MySQLDatabase, Result<(), DropDatabaseError>>;
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum DropDatabaseError {
|
||||
SanitizationError(NameValidationError),
|
||||
@ -195,7 +199,10 @@ pub fn print_drop_databases_output_status(output: &DropDatabasesOutput) {
|
||||
for (database_name, result) in output {
|
||||
match result {
|
||||
Ok(()) => {
|
||||
println!("Database '{}' dropped successfully.", database_name);
|
||||
println!(
|
||||
"Database '{}' dropped successfully.",
|
||||
database_name.as_str()
|
||||
);
|
||||
}
|
||||
Err(err) => {
|
||||
println!("{}", err.to_error_message(database_name));
|
||||
@ -210,9 +217,9 @@ pub fn print_drop_databases_output_status_json(output: &DropDatabasesOutput) {
|
||||
let value = output
|
||||
.iter()
|
||||
.map(|(name, result)| match result {
|
||||
Ok(()) => (name.to_owned(), json!({ "status": "success" })),
|
||||
Ok(()) => (name.to_string(), json!({ "status": "success" })),
|
||||
Err(err) => (
|
||||
name.clone(),
|
||||
name.to_string(),
|
||||
json!({
|
||||
"status": "error",
|
||||
"error": err.to_error_message(name),
|
||||
@ -228,7 +235,7 @@ pub fn print_drop_databases_output_status_json(output: &DropDatabasesOutput) {
|
||||
}
|
||||
|
||||
impl DropDatabaseError {
|
||||
pub fn to_error_message(&self, database_name: &str) -> String {
|
||||
pub fn to_error_message(&self, database_name: &MySQLDatabase) -> String {
|
||||
match self {
|
||||
DropDatabaseError::SanitizationError(err) => {
|
||||
err.to_error_message(database_name, DbOrUser::Database)
|
||||
@ -246,7 +253,7 @@ impl DropDatabaseError {
|
||||
}
|
||||
}
|
||||
|
||||
pub type ListDatabasesOutput = BTreeMap<String, Result<DatabaseRow, ListDatabasesError>>;
|
||||
pub type ListDatabasesOutput = BTreeMap<MySQLDatabase, Result<DatabaseRow, ListDatabasesError>>;
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ListDatabasesError {
|
||||
SanitizationError(NameValidationError),
|
||||
@ -256,7 +263,7 @@ pub enum ListDatabasesError {
|
||||
}
|
||||
|
||||
impl ListDatabasesError {
|
||||
pub fn to_error_message(&self, database_name: &str) -> String {
|
||||
pub fn to_error_message(&self, database_name: &MySQLDatabase) -> String {
|
||||
match self {
|
||||
ListDatabasesError::SanitizationError(err) => {
|
||||
err.to_error_message(database_name, DbOrUser::Database)
|
||||
@ -293,7 +300,7 @@ impl ListAllDatabasesError {
|
||||
// no need to index by database name.
|
||||
|
||||
pub type GetDatabasesPrivilegeData =
|
||||
BTreeMap<String, Result<Vec<DatabasePrivilegeRow>, GetDatabasesPrivilegeDataError>>;
|
||||
BTreeMap<MySQLDatabase, Result<Vec<DatabasePrivilegeRow>, GetDatabasesPrivilegeDataError>>;
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum GetDatabasesPrivilegeDataError {
|
||||
SanitizationError(NameValidationError),
|
||||
@ -303,7 +310,7 @@ pub enum GetDatabasesPrivilegeDataError {
|
||||
}
|
||||
|
||||
impl GetDatabasesPrivilegeDataError {
|
||||
pub fn to_error_message(&self, database_name: &str) -> String {
|
||||
pub fn to_error_message(&self, database_name: &MySQLDatabase) -> String {
|
||||
match self {
|
||||
GetDatabasesPrivilegeDataError::SanitizationError(err) => {
|
||||
err.to_error_message(database_name, DbOrUser::Database)
|
||||
@ -337,7 +344,7 @@ impl GetAllDatabasesPrivilegeDataError {
|
||||
}
|
||||
|
||||
pub type ModifyDatabasePrivilegesOutput =
|
||||
BTreeMap<(String, String), Result<(), ModifyDatabasePrivilegesError>>;
|
||||
BTreeMap<(MySQLDatabase, MySQLUser), Result<(), ModifyDatabasePrivilegesError>>;
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ModifyDatabasePrivilegesError {
|
||||
DatabaseSanitizationError(NameValidationError),
|
||||
@ -352,8 +359,8 @@ pub enum ModifyDatabasePrivilegesError {
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum DiffDoesNotApplyError {
|
||||
RowAlreadyExists(String, String),
|
||||
RowDoesNotExist(String, String),
|
||||
RowAlreadyExists(MySQLDatabase, MySQLUser),
|
||||
RowDoesNotExist(MySQLDatabase, MySQLUser),
|
||||
RowPrivilegeChangeDoesNotApply(DatabasePrivilegeRowDiff, DatabasePrivilegeRow),
|
||||
}
|
||||
|
||||
@ -376,7 +383,7 @@ pub fn print_modify_database_privileges_output_status(output: &ModifyDatabasePri
|
||||
}
|
||||
|
||||
impl ModifyDatabasePrivilegesError {
|
||||
pub fn to_error_message(&self, database_name: &str, username: &str) -> String {
|
||||
pub fn to_error_message(&self, database_name: &MySQLDatabase, username: &MySQLUser) -> String {
|
||||
match self {
|
||||
ModifyDatabasePrivilegesError::DatabaseSanitizationError(err) => {
|
||||
err.to_error_message(database_name, DbOrUser::Database)
|
||||
@ -431,7 +438,7 @@ impl DiffDoesNotApplyError {
|
||||
}
|
||||
}
|
||||
|
||||
pub type CreateUsersOutput = BTreeMap<String, Result<(), CreateUserError>>;
|
||||
pub type CreateUsersOutput = BTreeMap<MySQLUser, Result<(), CreateUserError>>;
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum CreateUserError {
|
||||
SanitizationError(NameValidationError),
|
||||
@ -459,9 +466,9 @@ pub fn print_create_users_output_status_json(output: &CreateUsersOutput) {
|
||||
let value = output
|
||||
.iter()
|
||||
.map(|(name, result)| match result {
|
||||
Ok(()) => (name.to_owned(), json!({ "status": "success" })),
|
||||
Ok(()) => (name.to_string(), json!({ "status": "success" })),
|
||||
Err(err) => (
|
||||
name.clone(),
|
||||
name.to_string(),
|
||||
json!({
|
||||
"status": "error",
|
||||
"error": err.to_error_message(name),
|
||||
@ -477,7 +484,7 @@ pub fn print_create_users_output_status_json(output: &CreateUsersOutput) {
|
||||
}
|
||||
|
||||
impl CreateUserError {
|
||||
pub fn to_error_message(&self, username: &str) -> String {
|
||||
pub fn to_error_message(&self, username: &MySQLUser) -> String {
|
||||
match self {
|
||||
CreateUserError::SanitizationError(err) => {
|
||||
err.to_error_message(username, DbOrUser::User)
|
||||
@ -493,7 +500,7 @@ impl CreateUserError {
|
||||
}
|
||||
}
|
||||
|
||||
pub type DropUsersOutput = BTreeMap<String, Result<(), DropUserError>>;
|
||||
pub type DropUsersOutput = BTreeMap<MySQLUser, Result<(), DropUserError>>;
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum DropUserError {
|
||||
SanitizationError(NameValidationError),
|
||||
@ -521,9 +528,9 @@ pub fn print_drop_users_output_status_json(output: &DropUsersOutput) {
|
||||
let value = output
|
||||
.iter()
|
||||
.map(|(name, result)| match result {
|
||||
Ok(()) => (name.to_owned(), json!({ "status": "success" })),
|
||||
Ok(()) => (name.to_string(), json!({ "status": "success" })),
|
||||
Err(err) => (
|
||||
name.clone(),
|
||||
name.to_string(),
|
||||
json!({
|
||||
"status": "error",
|
||||
"error": err.to_error_message(name),
|
||||
@ -539,7 +546,7 @@ pub fn print_drop_users_output_status_json(output: &DropUsersOutput) {
|
||||
}
|
||||
|
||||
impl DropUserError {
|
||||
pub fn to_error_message(&self, username: &str) -> String {
|
||||
pub fn to_error_message(&self, username: &MySQLUser) -> String {
|
||||
match self {
|
||||
DropUserError::SanitizationError(err) => err.to_error_message(username, DbOrUser::User),
|
||||
DropUserError::OwnershipError(err) => err.to_error_message(username, DbOrUser::User),
|
||||
@ -562,7 +569,7 @@ pub enum SetPasswordError {
|
||||
MySqlError(String),
|
||||
}
|
||||
|
||||
pub fn print_set_password_output_status(output: &SetPasswordOutput, username: &str) {
|
||||
pub fn print_set_password_output_status(output: &SetPasswordOutput, username: &MySQLUser) {
|
||||
match output {
|
||||
Ok(()) => {
|
||||
println!("Password for user '{}' set successfully.", username);
|
||||
@ -575,7 +582,7 @@ pub fn print_set_password_output_status(output: &SetPasswordOutput, username: &s
|
||||
}
|
||||
|
||||
impl SetPasswordError {
|
||||
pub fn to_error_message(&self, username: &str) -> String {
|
||||
pub fn to_error_message(&self, username: &MySQLUser) -> String {
|
||||
match self {
|
||||
SetPasswordError::SanitizationError(err) => {
|
||||
err.to_error_message(username, DbOrUser::User)
|
||||
@ -591,7 +598,7 @@ impl SetPasswordError {
|
||||
}
|
||||
}
|
||||
|
||||
pub type LockUsersOutput = BTreeMap<String, Result<(), LockUserError>>;
|
||||
pub type LockUsersOutput = BTreeMap<MySQLUser, Result<(), LockUserError>>;
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum LockUserError {
|
||||
SanitizationError(NameValidationError),
|
||||
@ -620,9 +627,9 @@ pub fn print_lock_users_output_status_json(output: &LockUsersOutput) {
|
||||
let value = output
|
||||
.iter()
|
||||
.map(|(name, result)| match result {
|
||||
Ok(()) => (name.to_owned(), json!({ "status": "success" })),
|
||||
Ok(()) => (name.to_string(), json!({ "status": "success" })),
|
||||
Err(err) => (
|
||||
name.clone(),
|
||||
name.to_string(),
|
||||
json!({
|
||||
"status": "error",
|
||||
"error": err.to_error_message(name),
|
||||
@ -638,7 +645,7 @@ pub fn print_lock_users_output_status_json(output: &LockUsersOutput) {
|
||||
}
|
||||
|
||||
impl LockUserError {
|
||||
pub fn to_error_message(&self, username: &str) -> String {
|
||||
pub fn to_error_message(&self, username: &MySQLUser) -> String {
|
||||
match self {
|
||||
LockUserError::SanitizationError(err) => err.to_error_message(username, DbOrUser::User),
|
||||
LockUserError::OwnershipError(err) => err.to_error_message(username, DbOrUser::User),
|
||||
@ -655,7 +662,7 @@ impl LockUserError {
|
||||
}
|
||||
}
|
||||
|
||||
pub type UnlockUsersOutput = BTreeMap<String, Result<(), UnlockUserError>>;
|
||||
pub type UnlockUsersOutput = BTreeMap<MySQLUser, Result<(), UnlockUserError>>;
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum UnlockUserError {
|
||||
SanitizationError(NameValidationError),
|
||||
@ -684,9 +691,9 @@ pub fn print_unlock_users_output_status_json(output: &UnlockUsersOutput) {
|
||||
let value = output
|
||||
.iter()
|
||||
.map(|(name, result)| match result {
|
||||
Ok(()) => (name.to_owned(), json!({ "status": "success" })),
|
||||
Ok(()) => (name.to_string(), json!({ "status": "success" })),
|
||||
Err(err) => (
|
||||
name.clone(),
|
||||
name.to_string(),
|
||||
json!({
|
||||
"status": "error",
|
||||
"error": err.to_error_message(name),
|
||||
@ -702,7 +709,7 @@ pub fn print_unlock_users_output_status_json(output: &UnlockUsersOutput) {
|
||||
}
|
||||
|
||||
impl UnlockUserError {
|
||||
pub fn to_error_message(&self, username: &str) -> String {
|
||||
pub fn to_error_message(&self, username: &MySQLUser) -> String {
|
||||
match self {
|
||||
UnlockUserError::SanitizationError(err) => {
|
||||
err.to_error_message(username, DbOrUser::User)
|
||||
@ -721,7 +728,7 @@ impl UnlockUserError {
|
||||
}
|
||||
}
|
||||
|
||||
pub type ListUsersOutput = BTreeMap<String, Result<DatabaseUser, ListUsersError>>;
|
||||
pub type ListUsersOutput = BTreeMap<MySQLUser, Result<DatabaseUser, ListUsersError>>;
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ListUsersError {
|
||||
SanitizationError(NameValidationError),
|
||||
@ -731,7 +738,7 @@ pub enum ListUsersError {
|
||||
}
|
||||
|
||||
impl ListUsersError {
|
||||
pub fn to_error_message(&self, username: &str) -> String {
|
||||
pub fn to_error_message(&self, username: &MySQLUser) -> String {
|
||||
match self {
|
||||
ListUsersError::SanitizationError(err) => {
|
||||
err.to_error_message(username, DbOrUser::User)
|
||||
|
@ -153,10 +153,10 @@ fn handle_server_command(args: &Args) -> anyhow::Result<Option<()>> {
|
||||
match args.command {
|
||||
Command::Server(ref command) => {
|
||||
tokio_start_server(
|
||||
args.server_socket_path.clone(),
|
||||
args.config.clone(),
|
||||
args.verbose.clone(),
|
||||
command.clone(),
|
||||
args.server_socket_path.to_owned(),
|
||||
args.config.to_owned(),
|
||||
args.verbose.to_owned(),
|
||||
command.to_owned(),
|
||||
)?;
|
||||
Ok(Some(()))
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ pub fn read_config_from_path(config_path: Option<PathBuf>) -> anyhow::Result<Ser
|
||||
}
|
||||
|
||||
fn log_config(config: &MysqlConfig) {
|
||||
let mut display_config = config.clone();
|
||||
let mut display_config = config.to_owned();
|
||||
display_config.password = display_config
|
||||
.password
|
||||
.as_ref()
|
||||
|
@ -24,7 +24,7 @@ pub fn validate_ownership_by_unix_user(
|
||||
name: &str,
|
||||
user: &UnixUser,
|
||||
) -> Result<(), OwnerValidationError> {
|
||||
let prefixes = std::iter::once(user.username.clone())
|
||||
let prefixes = std::iter::once(user.username.to_owned())
|
||||
.chain(user.groups.iter().cloned())
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
|
@ -5,6 +5,7 @@ use sqlx::MySqlConnection;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::core::protocol::MySQLDatabase;
|
||||
use crate::{
|
||||
core::{
|
||||
common::UnixUser,
|
||||
@ -42,7 +43,7 @@ pub(super) async fn unsafe_database_exists(
|
||||
}
|
||||
|
||||
pub async fn create_databases(
|
||||
database_names: Vec<String>,
|
||||
database_names: Vec<MySQLDatabase>,
|
||||
unix_user: &UnixUser,
|
||||
connection: &mut MySqlConnection,
|
||||
) -> CreateDatabasesOutput {
|
||||
@ -51,7 +52,7 @@ pub async fn create_databases(
|
||||
for database_name in database_names {
|
||||
if let Err(err) = validate_name(&database_name) {
|
||||
results.insert(
|
||||
database_name.clone(),
|
||||
database_name.to_owned(),
|
||||
Err(CreateDatabaseError::SanitizationError(err)),
|
||||
);
|
||||
continue;
|
||||
@ -59,7 +60,7 @@ pub async fn create_databases(
|
||||
|
||||
if let Err(err) = validate_ownership_by_unix_user(&database_name, unix_user) {
|
||||
results.insert(
|
||||
database_name.clone(),
|
||||
database_name.to_owned(),
|
||||
Err(CreateDatabaseError::OwnershipError(err)),
|
||||
);
|
||||
continue;
|
||||
@ -68,14 +69,14 @@ pub async fn create_databases(
|
||||
match unsafe_database_exists(&database_name, &mut *connection).await {
|
||||
Ok(true) => {
|
||||
results.insert(
|
||||
database_name.clone(),
|
||||
database_name.to_owned(),
|
||||
Err(CreateDatabaseError::DatabaseAlreadyExists),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
Err(err) => {
|
||||
results.insert(
|
||||
database_name.clone(),
|
||||
database_name.to_owned(),
|
||||
Err(CreateDatabaseError::MySqlError(err.to_string())),
|
||||
);
|
||||
continue;
|
||||
@ -101,7 +102,7 @@ pub async fn create_databases(
|
||||
}
|
||||
|
||||
pub async fn drop_databases(
|
||||
database_names: Vec<String>,
|
||||
database_names: Vec<MySQLDatabase>,
|
||||
unix_user: &UnixUser,
|
||||
connection: &mut MySqlConnection,
|
||||
) -> DropDatabasesOutput {
|
||||
@ -110,7 +111,7 @@ pub async fn drop_databases(
|
||||
for database_name in database_names {
|
||||
if let Err(err) = validate_name(&database_name) {
|
||||
results.insert(
|
||||
database_name.clone(),
|
||||
database_name.to_owned(),
|
||||
Err(DropDatabaseError::SanitizationError(err)),
|
||||
);
|
||||
continue;
|
||||
@ -118,7 +119,7 @@ pub async fn drop_databases(
|
||||
|
||||
if let Err(err) = validate_ownership_by_unix_user(&database_name, unix_user) {
|
||||
results.insert(
|
||||
database_name.clone(),
|
||||
database_name.to_owned(),
|
||||
Err(DropDatabaseError::OwnershipError(err)),
|
||||
);
|
||||
continue;
|
||||
@ -127,14 +128,14 @@ pub async fn drop_databases(
|
||||
match unsafe_database_exists(&database_name, &mut *connection).await {
|
||||
Ok(false) => {
|
||||
results.insert(
|
||||
database_name.clone(),
|
||||
database_name.to_owned(),
|
||||
Err(DropDatabaseError::DatabaseDoesNotExist),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
Err(err) => {
|
||||
results.insert(
|
||||
database_name.clone(),
|
||||
database_name.to_owned(),
|
||||
Err(DropDatabaseError::MySqlError(err.to_string())),
|
||||
);
|
||||
continue;
|
||||
@ -159,13 +160,21 @@ pub async fn drop_databases(
|
||||
results
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, FromRow)]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct DatabaseRow {
|
||||
pub database: String,
|
||||
pub database: MySQLDatabase,
|
||||
}
|
||||
|
||||
impl FromRow<'_, sqlx::mysql::MySqlRow> for DatabaseRow {
|
||||
fn from_row(row: &sqlx::mysql::MySqlRow) -> Result<Self, sqlx::Error> {
|
||||
Ok(DatabaseRow {
|
||||
database: row.try_get::<String, _>("database")?.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn list_databases(
|
||||
database_names: Vec<String>,
|
||||
database_names: Vec<MySQLDatabase>,
|
||||
unix_user: &UnixUser,
|
||||
connection: &mut MySqlConnection,
|
||||
) -> ListDatabasesOutput {
|
||||
@ -174,7 +183,7 @@ pub async fn list_databases(
|
||||
for database_name in database_names {
|
||||
if let Err(err) = validate_name(&database_name) {
|
||||
results.insert(
|
||||
database_name.clone(),
|
||||
database_name.to_owned(),
|
||||
Err(ListDatabasesError::SanitizationError(err)),
|
||||
);
|
||||
continue;
|
||||
@ -182,7 +191,7 @@ pub async fn list_databases(
|
||||
|
||||
if let Err(err) = validate_ownership_by_unix_user(&database_name, unix_user) {
|
||||
results.insert(
|
||||
database_name.clone(),
|
||||
database_name.to_owned(),
|
||||
Err(ListDatabasesError::OwnershipError(err)),
|
||||
);
|
||||
continue;
|
||||
@ -195,7 +204,7 @@ pub async fn list_databases(
|
||||
WHERE `SCHEMA_NAME` = ?
|
||||
"#,
|
||||
)
|
||||
.bind(&database_name)
|
||||
.bind(database_name.to_string())
|
||||
.fetch_optional(&mut *connection)
|
||||
.await
|
||||
.map_err(|err| ListDatabasesError::MySqlError(err.to_string()))
|
||||
|
@ -28,7 +28,8 @@ use crate::{
|
||||
protocol::{
|
||||
DiffDoesNotApplyError, GetAllDatabasesPrivilegeData, GetAllDatabasesPrivilegeDataError,
|
||||
GetDatabasesPrivilegeData, GetDatabasesPrivilegeDataError,
|
||||
ModifyDatabasePrivilegesError, ModifyDatabasePrivilegesOutput,
|
||||
ModifyDatabasePrivilegesError, ModifyDatabasePrivilegesOutput, MySQLDatabase,
|
||||
MySQLUser,
|
||||
},
|
||||
},
|
||||
server::{
|
||||
@ -63,8 +64,8 @@ pub const DATABASE_PRIVILEGE_FIELDS: [&str; 13] = [
|
||||
/// This struct represents the set of privileges for a single user on a single database.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)]
|
||||
pub struct DatabasePrivilegeRow {
|
||||
pub db: String,
|
||||
pub user: String,
|
||||
pub db: MySQLDatabase,
|
||||
pub user: MySQLUser,
|
||||
pub select_priv: bool,
|
||||
pub insert_priv: bool,
|
||||
pub update_priv: bool,
|
||||
@ -115,8 +116,8 @@ fn get_mysql_row_priv_field(row: &MySqlRow, position: usize) -> Result<bool, sql
|
||||
impl FromRow<'_, MySqlRow> for DatabasePrivilegeRow {
|
||||
fn from_row(row: &MySqlRow) -> Result<Self, sqlx::Error> {
|
||||
Ok(Self {
|
||||
db: try_get_with_binary_fallback(row, "Db")?,
|
||||
user: try_get_with_binary_fallback(row, "User")?,
|
||||
db: try_get_with_binary_fallback(row, "Db")?.into(),
|
||||
user: try_get_with_binary_fallback(row, "User")?.into(),
|
||||
select_priv: get_mysql_row_priv_field(row, 2)?,
|
||||
insert_priv: get_mysql_row_priv_field(row, 3)?,
|
||||
update_priv: get_mysql_row_priv_field(row, 4)?,
|
||||
@ -163,8 +164,8 @@ async fn unsafe_get_database_privileges(
|
||||
// NOTE: this function is unsafe because it does no input validation.
|
||||
/// Get all users + privileges for a single database-user pair.
|
||||
pub async fn unsafe_get_database_privileges_for_db_user_pair(
|
||||
database_name: &str,
|
||||
user_name: &str,
|
||||
database_name: &MySQLDatabase,
|
||||
user_name: &MySQLUser,
|
||||
connection: &mut MySqlConnection,
|
||||
) -> Result<Option<DatabasePrivilegeRow>, sqlx::Error> {
|
||||
let result = sqlx::query_as::<_, DatabasePrivilegeRow>(&format!(
|
||||
@ -174,8 +175,8 @@ pub async fn unsafe_get_database_privileges_for_db_user_pair(
|
||||
.map(|field| quote_identifier(field))
|
||||
.join(","),
|
||||
))
|
||||
.bind(database_name)
|
||||
.bind(user_name)
|
||||
.bind(database_name.as_str())
|
||||
.bind(user_name.as_str())
|
||||
.fetch_optional(connection)
|
||||
.await;
|
||||
|
||||
@ -192,7 +193,7 @@ pub async fn unsafe_get_database_privileges_for_db_user_pair(
|
||||
}
|
||||
|
||||
pub async fn get_databases_privilege_data(
|
||||
database_names: Vec<String>,
|
||||
database_names: Vec<MySQLDatabase>,
|
||||
unix_user: &UnixUser,
|
||||
connection: &mut MySqlConnection,
|
||||
) -> GetDatabasesPrivilegeData {
|
||||
@ -201,7 +202,7 @@ pub async fn get_databases_privilege_data(
|
||||
for database_name in database_names.iter() {
|
||||
if let Err(err) = validate_name(database_name) {
|
||||
results.insert(
|
||||
database_name.clone(),
|
||||
database_name.to_owned(),
|
||||
Err(GetDatabasesPrivilegeDataError::SanitizationError(err)),
|
||||
);
|
||||
continue;
|
||||
@ -209,7 +210,7 @@ pub async fn get_databases_privilege_data(
|
||||
|
||||
if let Err(err) = validate_ownership_by_unix_user(database_name, unix_user) {
|
||||
results.insert(
|
||||
database_name.clone(),
|
||||
database_name.to_owned(),
|
||||
Err(GetDatabasesPrivilegeDataError::OwnershipError(err)),
|
||||
);
|
||||
continue;
|
||||
@ -220,7 +221,7 @@ pub async fn get_databases_privilege_data(
|
||||
.unwrap()
|
||||
{
|
||||
results.insert(
|
||||
database_name.clone(),
|
||||
database_name.to_owned(),
|
||||
Err(GetDatabasesPrivilegeDataError::DatabaseDoesNotExist),
|
||||
);
|
||||
continue;
|
||||
@ -230,7 +231,7 @@ pub async fn get_databases_privilege_data(
|
||||
.await
|
||||
.map_err(|e| GetDatabasesPrivilegeDataError::MySqlError(e.to_string()));
|
||||
|
||||
results.insert(database_name.clone(), result);
|
||||
results.insert(database_name.to_owned(), result);
|
||||
}
|
||||
|
||||
debug_assert!(database_names.len() == results.len());
|
||||
@ -364,8 +365,8 @@ async fn validate_diff(
|
||||
if privilege_row.is_some() {
|
||||
Err(ModifyDatabasePrivilegesError::DiffDoesNotApply(
|
||||
DiffDoesNotApplyError::RowAlreadyExists(
|
||||
diff.get_user_name().to_string(),
|
||||
diff.get_database_name().to_string(),
|
||||
diff.get_database_name().to_owned(),
|
||||
diff.get_user_name().to_owned(),
|
||||
),
|
||||
))
|
||||
} else {
|
||||
@ -375,8 +376,8 @@ async fn validate_diff(
|
||||
DatabasePrivilegesDiff::Modified(_) if privilege_row.is_none() => {
|
||||
Err(ModifyDatabasePrivilegesError::DiffDoesNotApply(
|
||||
DiffDoesNotApplyError::RowDoesNotExist(
|
||||
diff.get_user_name().to_string(),
|
||||
diff.get_database_name().to_string(),
|
||||
diff.get_database_name().to_owned(),
|
||||
diff.get_user_name().to_owned(),
|
||||
),
|
||||
))
|
||||
}
|
||||
@ -390,7 +391,7 @@ async fn validate_diff(
|
||||
|
||||
if error_exists {
|
||||
Err(ModifyDatabasePrivilegesError::DiffDoesNotApply(
|
||||
DiffDoesNotApplyError::RowPrivilegeChangeDoesNotApply(row_diff.clone(), row),
|
||||
DiffDoesNotApplyError::RowPrivilegeChangeDoesNotApply(row_diff.to_owned(), row),
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
@ -400,8 +401,8 @@ async fn validate_diff(
|
||||
if privilege_row.is_none() {
|
||||
Err(ModifyDatabasePrivilegesError::DiffDoesNotApply(
|
||||
DiffDoesNotApplyError::RowDoesNotExist(
|
||||
diff.get_user_name().to_string(),
|
||||
diff.get_database_name().to_string(),
|
||||
diff.get_database_name().to_owned(),
|
||||
diff.get_user_name().to_owned(),
|
||||
),
|
||||
))
|
||||
} else {
|
||||
@ -419,12 +420,12 @@ pub async fn apply_privilege_diffs(
|
||||
unix_user: &UnixUser,
|
||||
connection: &mut MySqlConnection,
|
||||
) -> ModifyDatabasePrivilegesOutput {
|
||||
let mut results: BTreeMap<(String, String), _> = BTreeMap::new();
|
||||
let mut results: BTreeMap<(MySQLDatabase, MySQLUser), _> = BTreeMap::new();
|
||||
|
||||
for diff in database_privilege_diffs {
|
||||
let key = (
|
||||
diff.get_database_name().to_string(),
|
||||
diff.get_user_name().to_string(),
|
||||
diff.get_database_name().to_owned(),
|
||||
diff.get_user_name().to_owned(),
|
||||
);
|
||||
if let Err(err) = validate_name(diff.get_database_name()) {
|
||||
results.insert(
|
||||
|
@ -7,18 +7,17 @@ use serde::{Deserialize, Serialize};
|
||||
use sqlx::prelude::*;
|
||||
use sqlx::MySqlConnection;
|
||||
|
||||
use crate::server::common::try_get_with_binary_fallback;
|
||||
use crate::{
|
||||
core::{
|
||||
common::UnixUser,
|
||||
protocol::{
|
||||
CreateUserError, CreateUsersOutput, DropUserError, DropUsersOutput, ListAllUsersError,
|
||||
ListAllUsersOutput, ListUsersError, ListUsersOutput, LockUserError, LockUsersOutput,
|
||||
SetPasswordError, SetPasswordOutput, UnlockUserError, UnlockUsersOutput,
|
||||
MySQLUser, SetPasswordError, SetPasswordOutput, UnlockUserError, UnlockUsersOutput,
|
||||
},
|
||||
},
|
||||
server::{
|
||||
common::create_user_group_matching_regex,
|
||||
common::{create_user_group_matching_regex, try_get_with_binary_fallback},
|
||||
input_sanitization::{quote_literal, validate_name, validate_ownership_by_unix_user},
|
||||
},
|
||||
};
|
||||
@ -52,7 +51,7 @@ async fn unsafe_user_exists(
|
||||
}
|
||||
|
||||
pub async fn create_database_users(
|
||||
db_users: Vec<String>,
|
||||
db_users: Vec<MySQLUser>,
|
||||
unix_user: &UnixUser,
|
||||
connection: &mut MySqlConnection,
|
||||
) -> CreateUsersOutput {
|
||||
@ -98,7 +97,7 @@ pub async fn create_database_users(
|
||||
}
|
||||
|
||||
pub async fn drop_database_users(
|
||||
db_users: Vec<String>,
|
||||
db_users: Vec<MySQLUser>,
|
||||
unix_user: &UnixUser,
|
||||
connection: &mut MySqlConnection,
|
||||
) -> DropUsersOutput {
|
||||
@ -144,7 +143,7 @@ pub async fn drop_database_users(
|
||||
}
|
||||
|
||||
pub async fn set_password_for_database_user(
|
||||
db_user: &str,
|
||||
db_user: &MySQLUser,
|
||||
password: &str,
|
||||
unix_user: &UnixUser,
|
||||
connection: &mut MySqlConnection,
|
||||
@ -219,7 +218,7 @@ async fn database_user_is_locked_unsafe(
|
||||
}
|
||||
|
||||
pub async fn lock_database_users(
|
||||
db_users: Vec<String>,
|
||||
db_users: Vec<MySQLUser>,
|
||||
unix_user: &UnixUser,
|
||||
connection: &mut MySqlConnection,
|
||||
) -> LockUsersOutput {
|
||||
@ -279,7 +278,7 @@ pub async fn lock_database_users(
|
||||
}
|
||||
|
||||
pub async fn unlock_database_users(
|
||||
db_users: Vec<String>,
|
||||
db_users: Vec<MySQLUser>,
|
||||
unix_user: &UnixUser,
|
||||
connection: &mut MySqlConnection,
|
||||
) -> UnlockUsersOutput {
|
||||
@ -342,7 +341,7 @@ pub async fn unlock_database_users(
|
||||
/// This can be extended if we need more information in the future.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct DatabaseUser {
|
||||
pub user: String,
|
||||
pub user: MySQLUser,
|
||||
#[serde(skip)]
|
||||
pub host: String,
|
||||
pub has_password: bool,
|
||||
@ -353,7 +352,7 @@ pub struct DatabaseUser {
|
||||
impl FromRow<'_, sqlx::mysql::MySqlRow> for DatabaseUser {
|
||||
fn from_row(row: &sqlx::mysql::MySqlRow) -> Result<Self, sqlx::Error> {
|
||||
Ok(Self {
|
||||
user: try_get_with_binary_fallback(row, "User")?,
|
||||
user: try_get_with_binary_fallback(row, "User")?.into(),
|
||||
host: try_get_with_binary_fallback(row, "Host")?,
|
||||
has_password: row.try_get("has_password")?,
|
||||
is_locked: row.try_get("is_locked")?,
|
||||
@ -378,7 +377,7 @@ JOIN `global_priv` ON
|
||||
"#;
|
||||
|
||||
pub async fn list_database_users(
|
||||
db_users: Vec<String>,
|
||||
db_users: Vec<MySQLUser>,
|
||||
unix_user: &UnixUser,
|
||||
connection: &mut MySqlConnection,
|
||||
) -> ListUsersOutput {
|
||||
@ -398,7 +397,7 @@ pub async fn list_database_users(
|
||||
let mut result = sqlx::query_as::<_, DatabaseUser>(
|
||||
&(DB_USER_SELECT_STATEMENT.to_string() + "WHERE `mysql`.`user`.`User` = ?"),
|
||||
)
|
||||
.bind(&db_user)
|
||||
.bind(db_user.as_str())
|
||||
.fetch_optional(&mut *connection)
|
||||
.await;
|
||||
|
||||
@ -463,7 +462,7 @@ pub async fn append_databases_where_user_has_privileges(
|
||||
)
|
||||
.as_str(),
|
||||
)
|
||||
.bind(db_user.user.clone())
|
||||
.bind(db_user.user.as_str())
|
||||
.fetch_all(&mut *connection)
|
||||
.await;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user