mysqladm/core/protocol/
request_validation.rs

1use indoc::indoc;
2use itertools::Itertools;
3use serde::{Deserialize, Serialize};
4
5use crate::core::common::UnixUser;
6
7/// This enum is used to differentiate between database and user operations.
8/// Their output are very similar, but there are slight differences in the words used.
9#[derive(Debug, PartialEq, Eq, Clone, Copy)]
10pub enum DbOrUser {
11    Database,
12    User,
13}
14
15impl DbOrUser {
16    pub fn lowercased(&self) -> &'static str {
17        match self {
18            DbOrUser::Database => "database",
19            DbOrUser::User => "user",
20        }
21    }
22
23    pub fn capitalized(&self) -> &'static str {
24        match self {
25            DbOrUser::Database => "Database",
26            DbOrUser::User => "User",
27        }
28    }
29}
30
31#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
32pub enum NameValidationError {
33    EmptyString,
34    InvalidCharacters,
35    TooLong,
36}
37
38impl NameValidationError {
39    pub fn to_error_message(self, name: &str, db_or_user: DbOrUser) -> String {
40        match self {
41            NameValidationError::EmptyString => {
42                format!("{} name cannot be empty.", db_or_user.capitalized()).to_owned()
43            }
44            NameValidationError::TooLong => format!(
45                "{} is too long. Maximum length is 64 characters.",
46                db_or_user.capitalized()
47            )
48            .to_owned(),
49            NameValidationError::InvalidCharacters => format!(
50                indoc! {r#"
51                  Invalid characters in {} name: '{}'
52
53                  Only A-Z, a-z, 0-9, _ (underscore) and - (dash) are permitted.
54                "#},
55                db_or_user.lowercased(),
56                name
57            )
58            .to_owned(),
59        }
60    }
61}
62
63impl OwnerValidationError {
64    pub fn to_error_message(self, name: &str, db_or_user: DbOrUser) -> String {
65        let user = UnixUser::from_enviroment();
66
67        let UnixUser {
68            username,
69            mut groups,
70        } = user.unwrap_or(UnixUser {
71            username: "???".to_string(),
72            groups: vec![],
73        });
74
75        groups.sort();
76
77        match self {
78            OwnerValidationError::NoMatch => format!(
79                indoc! {r#"
80                  Invalid {} name prefix: '{}' does not match your username or any of your groups.
81                  Are you sure you are allowed to create {} names with this prefix?
82                  The format should be: <prefix>_<{} name>
83
84                  Allowed prefixes:
85                    - {}
86                  {}
87                "#},
88                db_or_user.lowercased(),
89                name,
90                db_or_user.lowercased(),
91                db_or_user.lowercased(),
92                username,
93                groups
94                    .into_iter()
95                    .filter(|g| g != &username)
96                    .map(|g| format!("  - {}", g))
97                    .join("\n"),
98            )
99            .to_owned(),
100            OwnerValidationError::StringEmpty => format!(
101                "'{}' is not a valid {} name.",
102                name,
103                db_or_user.lowercased()
104            )
105            .to_string(),
106        }
107    }
108}
109
110#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
111pub enum OwnerValidationError {
112    // The name is valid, but none of the given prefixes matched the name
113    NoMatch,
114
115    // The name is empty, which is invalid
116    StringEmpty,
117}