Implement denylists
All checks were successful
All checks were successful
This commit is contained in:
@@ -17,16 +17,19 @@ pub use create_user::*;
|
||||
pub use drop_db::*;
|
||||
pub use drop_user::*;
|
||||
pub use edit_privs::*;
|
||||
use futures_util::SinkExt;
|
||||
use itertools::Itertools;
|
||||
pub use lock_user::*;
|
||||
pub use passwd_user::*;
|
||||
pub use show_db::*;
|
||||
pub use show_privs::*;
|
||||
pub use show_user::*;
|
||||
use tokio_stream::StreamExt;
|
||||
pub use unlock_user::*;
|
||||
|
||||
use clap::Subcommand;
|
||||
|
||||
use crate::core::protocol::{ClientToServerMessageStream, Response};
|
||||
use crate::core::protocol::{ClientToServerMessageStream, Request, Response};
|
||||
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
#[command(subcommand_required = true)]
|
||||
@@ -183,3 +186,23 @@ pub fn erroneous_server_response(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn print_authorization_owner_hint(
|
||||
server_connection: &mut ClientToServerMessageStream,
|
||||
) -> anyhow::Result<()> {
|
||||
server_connection
|
||||
.send(Request::ListValidNamePrefixes)
|
||||
.await?;
|
||||
|
||||
let response = match server_connection.next().await {
|
||||
Some(Ok(Response::ListValidNamePrefixes(prefixes))) => prefixes,
|
||||
response => return erroneous_server_response(response),
|
||||
};
|
||||
|
||||
println!(
|
||||
"Note: You are allowed to manage databases and users with the following prefixes:\n{}",
|
||||
response.into_iter().map(|p| format!(" - {}", p)).join("\n")
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -3,11 +3,12 @@ use futures_util::SinkExt;
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
use crate::{
|
||||
client::commands::erroneous_server_response,
|
||||
client::commands::{erroneous_server_response, print_authorization_owner_hint},
|
||||
core::{
|
||||
protocol::{
|
||||
ClientToServerMessageStream, Request, Response, print_create_databases_output_status,
|
||||
print_create_databases_output_status_json,
|
||||
ClientToServerMessageStream, CreateDatabaseError, Request, Response,
|
||||
print_create_databases_output_status, print_create_databases_output_status_json,
|
||||
request_validation::ValidationError,
|
||||
},
|
||||
types::MySQLDatabase,
|
||||
},
|
||||
@@ -40,13 +41,24 @@ pub async fn create_databases(
|
||||
response => return erroneous_server_response(response),
|
||||
};
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
if args.json {
|
||||
print_create_databases_output_status_json(&result);
|
||||
} else {
|
||||
print_create_databases_output_status(&result);
|
||||
|
||||
if result.iter().any(|(_, res)| {
|
||||
matches!(
|
||||
res,
|
||||
Err(CreateDatabaseError::ValidationError(
|
||||
ValidationError::AuthorizationError(_)
|
||||
))
|
||||
)
|
||||
}) {
|
||||
print_authorization_owner_hint(&mut server_connection).await?
|
||||
}
|
||||
}
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -4,11 +4,15 @@ use futures_util::SinkExt;
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
use crate::{
|
||||
client::commands::{erroneous_server_response, read_password_from_stdin_with_double_check},
|
||||
client::commands::{
|
||||
erroneous_server_response, print_authorization_owner_hint,
|
||||
read_password_from_stdin_with_double_check,
|
||||
},
|
||||
core::{
|
||||
protocol::{
|
||||
ClientToServerMessageStream, Request, Response, print_create_users_output_status,
|
||||
print_create_users_output_status_json, print_set_password_output_status,
|
||||
ClientToServerMessageStream, CreateUserError, Request, Response,
|
||||
print_create_users_output_status, print_create_users_output_status_json,
|
||||
print_set_password_output_status, request_validation::ValidationError,
|
||||
},
|
||||
types::MySQLUser,
|
||||
},
|
||||
@@ -55,6 +59,17 @@ pub async fn create_users(
|
||||
} else {
|
||||
print_create_users_output_status(&result);
|
||||
|
||||
if result.iter().any(|(_, res)| {
|
||||
matches!(
|
||||
res,
|
||||
Err(CreateUserError::ValidationError(
|
||||
ValidationError::AuthorizationError(_)
|
||||
))
|
||||
)
|
||||
}) {
|
||||
print_authorization_owner_hint(&mut server_connection).await?
|
||||
}
|
||||
|
||||
let successfully_created_users = result
|
||||
.iter()
|
||||
.filter_map(|(username, result)| result.as_ref().ok().map(|_| username))
|
||||
|
||||
@@ -5,12 +5,13 @@ use futures_util::SinkExt;
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
use crate::{
|
||||
client::commands::erroneous_server_response,
|
||||
client::commands::{erroneous_server_response, print_authorization_owner_hint},
|
||||
core::{
|
||||
completion::mysql_database_completer,
|
||||
protocol::{
|
||||
ClientToServerMessageStream, Request, Response, print_drop_databases_output_status,
|
||||
print_drop_databases_output_status_json,
|
||||
ClientToServerMessageStream, DropDatabaseError, Request, Response,
|
||||
print_drop_databases_output_status, print_drop_databases_output_status_json,
|
||||
request_validation::ValidationError,
|
||||
},
|
||||
types::MySQLDatabase,
|
||||
},
|
||||
@@ -66,13 +67,24 @@ pub async fn drop_databases(
|
||||
response => return erroneous_server_response(response),
|
||||
};
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
if args.json {
|
||||
print_drop_databases_output_status_json(&result);
|
||||
} else {
|
||||
print_drop_databases_output_status(&result);
|
||||
|
||||
if result.iter().any(|(_, res)| {
|
||||
matches!(
|
||||
res,
|
||||
Err(DropDatabaseError::ValidationError(
|
||||
ValidationError::AuthorizationError(_)
|
||||
))
|
||||
)
|
||||
}) {
|
||||
print_authorization_owner_hint(&mut server_connection).await?
|
||||
}
|
||||
};
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -5,12 +5,13 @@ use futures_util::SinkExt;
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
use crate::{
|
||||
client::commands::erroneous_server_response,
|
||||
client::commands::{erroneous_server_response, print_authorization_owner_hint},
|
||||
core::{
|
||||
completion::mysql_user_completer,
|
||||
protocol::{
|
||||
ClientToServerMessageStream, Request, Response, print_drop_users_output_status,
|
||||
print_drop_users_output_status_json,
|
||||
ClientToServerMessageStream, DropUserError, Request, Response,
|
||||
print_drop_users_output_status, print_drop_users_output_status_json,
|
||||
request_validation::ValidationError,
|
||||
},
|
||||
types::MySQLUser,
|
||||
},
|
||||
@@ -70,13 +71,24 @@ pub async fn drop_users(
|
||||
response => return erroneous_server_response(response),
|
||||
};
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
if args.json {
|
||||
print_drop_users_output_status_json(&result);
|
||||
} else {
|
||||
print_drop_users_output_status(&result);
|
||||
|
||||
if result.iter().any(|(_, res)| {
|
||||
matches!(
|
||||
res,
|
||||
Err(DropUserError::ValidationError(
|
||||
ValidationError::AuthorizationError(_)
|
||||
))
|
||||
)
|
||||
}) {
|
||||
print_authorization_owner_hint(&mut server_connection).await?
|
||||
}
|
||||
}
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use nix::unistd::{User, getuid};
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
use crate::{
|
||||
client::commands::erroneous_server_response,
|
||||
client::commands::{erroneous_server_response, print_authorization_owner_hint},
|
||||
core::{
|
||||
completion::{mysql_database_completer, mysql_user_completer},
|
||||
database_privileges::{
|
||||
@@ -19,8 +19,8 @@ use crate::{
|
||||
parse_privilege_data_from_editor_content, reduce_privilege_diffs,
|
||||
},
|
||||
protocol::{
|
||||
ClientToServerMessageStream, Request, Response,
|
||||
print_modify_database_privileges_output_status,
|
||||
ClientToServerMessageStream, ModifyDatabasePrivilegesError, Request, Response,
|
||||
print_modify_database_privileges_output_status, request_validation::ValidationError,
|
||||
},
|
||||
types::{MySQLDatabase, MySQLUser},
|
||||
},
|
||||
@@ -219,6 +219,8 @@ pub async fn edit_database_privileges(
|
||||
diff_privileges(&existing_privilege_rows, &privileges_to_change)
|
||||
};
|
||||
|
||||
// TODO: validate authorization before existence
|
||||
|
||||
let user_existence_map = users_exist(&mut server_connection, &diffs).await?;
|
||||
let database_existence_map = databases_exist(&mut server_connection, &diffs).await?;
|
||||
|
||||
@@ -274,6 +276,19 @@ pub async fn edit_database_privileges(
|
||||
|
||||
print_modify_database_privileges_output_status(&result);
|
||||
|
||||
if result.iter().any(|(_, res)| {
|
||||
matches!(
|
||||
res,
|
||||
Err(ModifyDatabasePrivilegesError::UserValidationError(
|
||||
ValidationError::AuthorizationError(_)
|
||||
) | ModifyDatabasePrivilegesError::DatabaseValidationError(
|
||||
ValidationError::AuthorizationError(_)
|
||||
))
|
||||
)
|
||||
}) {
|
||||
print_authorization_owner_hint(&mut server_connection).await?
|
||||
}
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -4,12 +4,13 @@ use futures_util::SinkExt;
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
use crate::{
|
||||
client::commands::erroneous_server_response,
|
||||
client::commands::{erroneous_server_response, print_authorization_owner_hint},
|
||||
core::{
|
||||
completion::mysql_user_completer,
|
||||
protocol::{
|
||||
ClientToServerMessageStream, Request, Response, print_lock_users_output_status,
|
||||
print_lock_users_output_status_json,
|
||||
ClientToServerMessageStream, LockUserError, Request, Response,
|
||||
print_lock_users_output_status, print_lock_users_output_status_json,
|
||||
request_validation::ValidationError,
|
||||
},
|
||||
types::MySQLUser,
|
||||
},
|
||||
@@ -47,13 +48,24 @@ pub async fn lock_users(
|
||||
response => return erroneous_server_response(response),
|
||||
};
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
if args.json {
|
||||
print_lock_users_output_status_json(&result);
|
||||
} else {
|
||||
print_lock_users_output_status(&result);
|
||||
|
||||
if result.iter().any(|(_, res)| {
|
||||
matches!(
|
||||
res,
|
||||
Err(LockUserError::ValidationError(
|
||||
ValidationError::AuthorizationError(_)
|
||||
))
|
||||
)
|
||||
}) {
|
||||
print_authorization_owner_hint(&mut server_connection).await?
|
||||
}
|
||||
}
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@ use futures_util::SinkExt;
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
use crate::{
|
||||
client::commands::erroneous_server_response,
|
||||
client::commands::{erroneous_server_response, print_authorization_owner_hint},
|
||||
core::{
|
||||
completion::mysql_user_completer,
|
||||
protocol::{
|
||||
ClientToServerMessageStream, ListUsersError, Request, Response,
|
||||
print_set_password_output_status,
|
||||
ClientToServerMessageStream, ListUsersError, Request, Response, SetPasswordError,
|
||||
print_set_password_output_status, request_validation::ValidationError,
|
||||
},
|
||||
types::MySQLUser,
|
||||
},
|
||||
@@ -103,9 +103,18 @@ pub async fn passwd_user(
|
||||
response => return erroneous_server_response(response),
|
||||
};
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
print_set_password_output_status(&result, &args.username);
|
||||
|
||||
if matches!(
|
||||
result,
|
||||
Err(SetPasswordError::ValidationError(
|
||||
ValidationError::AuthorizationError(_)
|
||||
))
|
||||
) {
|
||||
print_authorization_owner_hint(&mut server_connection).await?
|
||||
}
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -4,12 +4,13 @@ use futures_util::SinkExt;
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
use crate::{
|
||||
client::commands::erroneous_server_response,
|
||||
client::commands::{erroneous_server_response, print_authorization_owner_hint},
|
||||
core::{
|
||||
completion::mysql_database_completer,
|
||||
protocol::{
|
||||
ClientToServerMessageStream, Request, Response, print_list_databases_output_status,
|
||||
print_list_databases_output_status_json,
|
||||
ClientToServerMessageStream, ListDatabasesError, Request, Response,
|
||||
print_list_databases_output_status, print_list_databases_output_status_json,
|
||||
request_validation::ValidationError,
|
||||
},
|
||||
types::MySQLDatabase,
|
||||
},
|
||||
@@ -60,14 +61,25 @@ pub async fn show_databases(
|
||||
response => return erroneous_server_response(response),
|
||||
};
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
if args.json {
|
||||
print_list_databases_output_status_json(&databases);
|
||||
} else {
|
||||
print_list_databases_output_status(&databases);
|
||||
|
||||
if databases.iter().any(|(_, res)| {
|
||||
matches!(
|
||||
res,
|
||||
Err(ListDatabasesError::ValidationError(
|
||||
ValidationError::AuthorizationError(_)
|
||||
))
|
||||
)
|
||||
}) {
|
||||
print_authorization_owner_hint(&mut server_connection).await?
|
||||
}
|
||||
}
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
if args.fail && databases.values().any(|res| res.is_err()) {
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
@@ -5,12 +5,13 @@ use itertools::Itertools;
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
use crate::{
|
||||
client::commands::erroneous_server_response,
|
||||
client::commands::{erroneous_server_response, print_authorization_owner_hint},
|
||||
core::{
|
||||
completion::mysql_database_completer,
|
||||
protocol::{
|
||||
ClientToServerMessageStream, Request, Response, print_list_privileges_output_status,
|
||||
print_list_privileges_output_status_json,
|
||||
ClientToServerMessageStream, GetDatabasesPrivilegeDataError, Request, Response,
|
||||
print_list_privileges_output_status, print_list_privileges_output_status_json,
|
||||
request_validation::ValidationError,
|
||||
},
|
||||
types::MySQLDatabase,
|
||||
},
|
||||
@@ -68,14 +69,25 @@ pub async fn show_database_privileges(
|
||||
response => return erroneous_server_response(response),
|
||||
};
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
if args.json {
|
||||
print_list_privileges_output_status_json(&privilege_data);
|
||||
} else {
|
||||
print_list_privileges_output_status(&privilege_data, args.long);
|
||||
|
||||
if privilege_data.iter().any(|(_, res)| {
|
||||
matches!(
|
||||
res,
|
||||
Err(GetDatabasesPrivilegeDataError::ValidationError(
|
||||
ValidationError::AuthorizationError(_)
|
||||
))
|
||||
)
|
||||
}) {
|
||||
print_authorization_owner_hint(&mut server_connection).await?
|
||||
}
|
||||
}
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
if args.fail && privilege_data.values().any(|res| res.is_err()) {
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
@@ -4,12 +4,13 @@ use futures_util::SinkExt;
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
use crate::{
|
||||
client::commands::erroneous_server_response,
|
||||
client::commands::{erroneous_server_response, print_authorization_owner_hint},
|
||||
core::{
|
||||
completion::mysql_user_completer,
|
||||
protocol::{
|
||||
ClientToServerMessageStream, Request, Response, print_list_users_output_status,
|
||||
print_list_users_output_status_json,
|
||||
ClientToServerMessageStream, ListUsersError, Request, Response,
|
||||
print_list_users_output_status, print_list_users_output_status_json,
|
||||
request_validation::ValidationError,
|
||||
},
|
||||
types::MySQLUser,
|
||||
},
|
||||
@@ -63,14 +64,25 @@ pub async fn show_users(
|
||||
response => return erroneous_server_response(response),
|
||||
};
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
if args.json {
|
||||
print_list_users_output_status_json(&users);
|
||||
} else {
|
||||
print_list_users_output_status(&users);
|
||||
|
||||
if users.iter().any(|(_, res)| {
|
||||
matches!(
|
||||
res,
|
||||
Err(ListUsersError::ValidationError(
|
||||
ValidationError::AuthorizationError(_)
|
||||
))
|
||||
)
|
||||
}) {
|
||||
print_authorization_owner_hint(&mut server_connection).await?
|
||||
}
|
||||
}
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
if args.fail && users.values().any(|result| result.is_err()) {
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
@@ -4,12 +4,13 @@ use futures_util::SinkExt;
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
use crate::{
|
||||
client::commands::erroneous_server_response,
|
||||
client::commands::{erroneous_server_response, print_authorization_owner_hint},
|
||||
core::{
|
||||
completion::mysql_user_completer,
|
||||
protocol::{
|
||||
ClientToServerMessageStream, Request, Response, print_unlock_users_output_status,
|
||||
print_unlock_users_output_status_json,
|
||||
ClientToServerMessageStream, Request, Response, UnlockUserError,
|
||||
print_unlock_users_output_status, print_unlock_users_output_status_json,
|
||||
request_validation::ValidationError,
|
||||
},
|
||||
types::MySQLUser,
|
||||
},
|
||||
@@ -47,13 +48,24 @@ pub async fn unlock_users(
|
||||
response => return erroneous_server_response(response),
|
||||
};
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
if args.json {
|
||||
print_unlock_users_output_status_json(&result);
|
||||
} else {
|
||||
print_unlock_users_output_status(&result);
|
||||
|
||||
if result.iter().any(|(_, res)| {
|
||||
matches!(
|
||||
res,
|
||||
Err(UnlockUserError::ValidationError(
|
||||
ValidationError::AuthorizationError(_)
|
||||
))
|
||||
)
|
||||
}) {
|
||||
print_authorization_owner_hint(&mut server_connection).await?
|
||||
}
|
||||
}
|
||||
|
||||
server_connection.send(Request::Exit).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user