list-db
-> show-db
This commit is contained in:
src
cli
core
server
@ -48,4 +48,4 @@ mod tests {
|
||||
assert!(!re.is_match("user"));
|
||||
assert!(!re.is_match("usersomething"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ use tokio::net::{UnixListener, UnixStream};
|
||||
use sqlx::prelude::*;
|
||||
use sqlx::MySqlConnection;
|
||||
|
||||
use crate::server::sql::database_operations::list_databases;
|
||||
use crate::{
|
||||
core::{
|
||||
common::{UnixUser, DEFAULT_SOCKET_PATH},
|
||||
@ -17,7 +18,7 @@ use crate::{
|
||||
server::{
|
||||
config::{create_mysql_connection_from_config, ServerConfig},
|
||||
sql::{
|
||||
database_operations::{create_databases, drop_databases, list_databases_for_user},
|
||||
database_operations::{create_databases, drop_databases, list_all_databases_for_user},
|
||||
database_privilege_operations::{
|
||||
apply_privilege_diffs, get_all_database_privileges, get_databases_privilege_data,
|
||||
},
|
||||
@ -183,9 +184,18 @@ pub async fn handle_requests_for_single_session_with_db_connection(
|
||||
let result = drop_databases(databases_names, unix_user, db_connection).await;
|
||||
stream.send(Response::DropDatabases(result)).await?;
|
||||
}
|
||||
Request::ListDatabases => {
|
||||
let result = list_databases_for_user(unix_user, db_connection).await;
|
||||
stream.send(Response::ListAllDatabases(result)).await?;
|
||||
Request::ListDatabases(database_names) => {
|
||||
let response = match database_names {
|
||||
Some(database_names) => {
|
||||
let result = list_databases(database_names, unix_user, db_connection).await;
|
||||
Response::ListDatabases(result)
|
||||
}
|
||||
None => {
|
||||
let result = list_all_databases_for_user(unix_user, db_connection).await;
|
||||
Response::ListAllDatabases(result)
|
||||
}
|
||||
};
|
||||
stream.send(response).await?;
|
||||
}
|
||||
Request::ListPrivileges(database_names) => {
|
||||
let response = match database_names {
|
||||
|
@ -1,9 +1,16 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use sqlx::prelude::*;
|
||||
use sqlx::MySqlConnection;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
core::{
|
||||
common::UnixUser,
|
||||
protocol::{
|
||||
CreateDatabaseError, CreateDatabasesOutput, DropDatabaseError, DropDatabasesOutput,
|
||||
ListDatabasesError,
|
||||
ListAllDatabasesError, ListAllDatabasesOutput, ListDatabasesError, ListDatabasesOutput,
|
||||
},
|
||||
},
|
||||
server::{
|
||||
@ -12,11 +19,6 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
use sqlx::prelude::*;
|
||||
|
||||
use sqlx::MySqlConnection;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
// NOTE: this function is unsafe because it does no input validation.
|
||||
pub(super) async fn unsafe_database_exists(
|
||||
database_name: &str,
|
||||
@ -157,11 +159,67 @@ pub async fn drop_databases(
|
||||
results
|
||||
}
|
||||
|
||||
pub async fn list_databases_for_user(
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, FromRow)]
|
||||
pub struct DatabaseRow {
|
||||
pub database: String,
|
||||
}
|
||||
|
||||
pub async fn list_databases(
|
||||
database_names: Vec<String>,
|
||||
unix_user: &UnixUser,
|
||||
connection: &mut MySqlConnection,
|
||||
) -> Result<Vec<String>, ListDatabasesError> {
|
||||
let result = sqlx::query(
|
||||
) -> ListDatabasesOutput {
|
||||
let mut results = BTreeMap::new();
|
||||
|
||||
for database_name in database_names {
|
||||
if let Err(err) = validate_name(&database_name) {
|
||||
results.insert(
|
||||
database_name.clone(),
|
||||
Err(ListDatabasesError::SanitizationError(err)),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Err(err) = validate_ownership_by_unix_user(&database_name, unix_user) {
|
||||
results.insert(
|
||||
database_name.clone(),
|
||||
Err(ListDatabasesError::OwnershipError(err)),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
let result = sqlx::query_as::<_, DatabaseRow>(
|
||||
r#"
|
||||
SELECT `SCHEMA_NAME` AS `database`
|
||||
FROM `information_schema`.`SCHEMATA`
|
||||
WHERE `SCHEMA_NAME` = ?
|
||||
"#,
|
||||
)
|
||||
.bind(&database_name)
|
||||
.fetch_optional(&mut *connection)
|
||||
.await
|
||||
.map_err(|err| ListDatabasesError::MySqlError(err.to_string()))
|
||||
.and_then(|database| {
|
||||
database
|
||||
.map(Ok)
|
||||
.unwrap_or_else(|| Err(ListDatabasesError::DatabaseDoesNotExist))
|
||||
});
|
||||
|
||||
if let Err(err) = &result {
|
||||
log::error!("Failed to list database '{}': {:?}", &database_name, err);
|
||||
}
|
||||
|
||||
results.insert(database_name, result);
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
pub async fn list_all_databases_for_user(
|
||||
unix_user: &UnixUser,
|
||||
connection: &mut MySqlConnection,
|
||||
) -> ListAllDatabasesOutput {
|
||||
let result = sqlx::query_as::<_, DatabaseRow>(
|
||||
r#"
|
||||
SELECT `SCHEMA_NAME` AS `database`
|
||||
FROM `information_schema`.`SCHEMATA`
|
||||
@ -172,12 +230,7 @@ pub async fn list_databases_for_user(
|
||||
.bind(create_user_group_matching_regex(unix_user))
|
||||
.fetch_all(connection)
|
||||
.await
|
||||
.and_then(|rows| {
|
||||
rows.into_iter()
|
||||
.map(|row| row.try_get::<String, _>("database"))
|
||||
.collect::<Result<Vec<String>, sqlx::Error>>()
|
||||
})
|
||||
.map_err(|err| ListDatabasesError::MySqlError(err.to_string()));
|
||||
.map_err(|err| ListAllDatabasesError::MySqlError(err.to_string()));
|
||||
|
||||
if let Err(err) = &result {
|
||||
log::error!(
|
||||
|
Reference in New Issue
Block a user