haproxy_config/config/
userlist.rs

1use std::collections::HashMap;
2
3use super::{error::Error, Name};
4use crate::section::{PasswordRef, borrowed::Section};
5use crate::line::borrowed::Line;
6
7#[derive(Debug, Clone, Hash, PartialEq, Eq)]
8pub struct Group {
9    pub name: String,
10    pub users: Vec<String>,
11}
12
13/// Owned variant of [`PasswordRef`]
14#[derive(Debug, Clone, Hash, PartialEq, Eq)]
15pub enum Password {
16    Secure(String),
17    Insecure(String),
18}
19
20impl From<&PasswordRef<'_>> for Password {
21    fn from(value: &PasswordRef) -> Self {
22        match value {
23            PasswordRef::Secure(p) => Self::Secure((*p).to_string()),
24            PasswordRef::Insecure(p) => Self::Insecure((*p).to_string()),
25        }
26    }
27}
28
29#[derive(Debug, Clone, Hash, PartialEq, Eq)]
30pub struct User {
31    pub name: String,
32    pub password: Password,
33}
34
35#[derive(Debug, Clone, Hash, PartialEq, Eq)]
36pub struct Userlist {
37    pub name: String,
38    pub groups: Vec<Group>,
39    pub users: Vec<User>,
40}
41
42type Pair = (Name, Userlist);
43impl<'a> TryFrom<&'a Section<'a>> for Pair {
44    type Error = Error;
45
46    fn try_from(entry: &'a Section<'a>) -> Result<Pair, Self::Error> {
47        let Section::Userlist{name, lines, ..} = entry else {
48            unreachable!()
49        };
50
51        let mut users = Vec::new();
52        let mut groups = Vec::new();
53        let mut other = Vec::new();
54
55        for line in lines
56            .iter()
57            .filter(|l| !matches!(l, Line::Blank | Line::Comment(_)))
58        {
59            match line {
60                Line::User { name, password, .. } => users.push(User {
61                    name: (*name).to_string(),
62                    password: Password::from(password),
63                }),
64                Line::Group { name, users, .. } => groups.push(Group {
65                    name: (*name).to_string(),
66                    users: users.iter().map(ToString::to_string).collect(),
67                }),
68                wrong => other.push(wrong),
69            }
70        }
71
72        if !other.is_empty() {
73            return Err(Error::wrong_userlist_lines(other));
74        }
75
76        Ok((
77            (*name).to_string(),
78            Userlist {
79                name: (*name).to_string(),
80                users,
81                groups,
82            },
83        ))
84    }
85}
86
87impl<'a> Userlist {
88    pub(crate) fn parse_multiple(entries: &'a [Section<'a>]) -> Result<HashMap<Name, Self>, Error> {
89        entries
90            .iter()
91            .filter(|e| matches!(e, Section::Userlist { .. }))
92            .map(Pair::try_from)
93            .collect()
94    }
95}