srt_protocol/access/
mod.rs

1use std::{
2    convert::TryFrom,
3    error::Error,
4    fmt::{self, Display},
5    str::FromStr,
6};
7
8pub use crate::packet::{RejectReason, ServerRejectReason};
9pub use crate::settings::{AcceptParameters, StreamAcceptor};
10
11// See https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-00#appendix-B
12#[derive(Debug, PartialEq, Eq)]
13pub struct AccessControlList(pub Vec<AccessControlEntry>);
14
15#[derive(Debug, PartialEq, Eq)]
16pub struct AccessControlEntry {
17    pub key: String,
18    pub value: String,
19}
20
21#[non_exhaustive]
22#[derive(Debug, Copy, Clone, Eq, PartialEq)]
23pub enum ConnectionType {
24    Stream,
25    File,
26    Auth,
27}
28
29#[non_exhaustive]
30#[derive(Debug, Copy, Clone, Eq, PartialEq)]
31pub enum ConnectionMode {
32    Request,
33    Publish,
34    Bidirectional,
35}
36
37#[derive(Debug, Clone)]
38pub enum StandardAccessControlEntry {
39    UserName(String),
40    ResourceName(String),
41    HostName(String),
42    SessionId(String),
43    Type(ConnectionType),
44    Mode(ConnectionMode),
45}
46
47#[derive(Debug, Eq, PartialEq)]
48#[non_exhaustive]
49pub enum ParseAccessControlEntryError {
50    /// key was found with no value
51    NoValue,
52    /// doesn't start with #!::
53    WrongStart,
54}
55
56impl Display for AccessControlList {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        let mut iter = self.0.iter().fuse();
59        if let Some(item) = iter.next() {
60            write!(f, "#!::{item}")?;
61        }
62
63        for item in iter {
64            write!(f, ",{item}")?;
65        }
66        Ok(())
67    }
68}
69
70impl FromStr for AccessControlList {
71    type Err = ParseAccessControlEntryError;
72    fn from_str(mut s: &str) -> Result<Self, Self::Err> {
73        if !s.starts_with("#!::") {
74            return Err(ParseAccessControlEntryError::WrongStart);
75        }
76        s = &s[4..]; // skip start
77
78        Ok(AccessControlList(
79            s.split(',')
80                .map(str::parse)
81                .collect::<Result<Vec<_>, _>>()?,
82        ))
83    }
84}
85
86impl AccessControlEntry {
87    fn new(key: impl Into<String>, value: impl Into<String>) -> AccessControlEntry {
88        AccessControlEntry {
89            key: key.into(),
90            value: value.into(),
91        }
92    }
93}
94
95impl Display for AccessControlEntry {
96    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
97        write!(f, "{}={}", self.key, self.value)
98    }
99}
100
101impl FromStr for AccessControlEntry {
102    type Err = ParseAccessControlEntryError;
103    fn from_str(s: &str) -> Result<Self, Self::Err> {
104        let eq = s.find('=').ok_or(ParseAccessControlEntryError::NoValue)?;
105        let (k, v) = s.split_at(eq);
106
107        Ok(AccessControlEntry::new(k, &v[1..])) // skip =, which is a one bye char
108    }
109}
110
111impl Display for ConnectionType {
112    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113        match self {
114            ConnectionType::Stream => write!(f, "stream"),
115            ConnectionType::File => write!(f, "file"),
116            ConnectionType::Auth => write!(f, "auth"),
117        }
118    }
119}
120
121impl FromStr for ConnectionType {
122    type Err = ();
123
124    fn from_str(s: &str) -> Result<Self, Self::Err> {
125        match s {
126            "stream" => Ok(ConnectionType::Stream),
127            "file" => Ok(ConnectionType::File),
128            "auth" => Ok(ConnectionType::Auth),
129            _ => Err(()),
130        }
131    }
132}
133
134impl Display for ConnectionMode {
135    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
136        match self {
137            ConnectionMode::Request => write!(f, "request"),
138            ConnectionMode::Publish => write!(f, "publish"),
139            ConnectionMode::Bidirectional => write!(f, "bidirectional"),
140        }
141    }
142}
143
144impl FromStr for ConnectionMode {
145    type Err = ();
146
147    fn from_str(s: &str) -> Result<Self, Self::Err> {
148        match s {
149            "request" => Ok(ConnectionMode::Request),
150            "publish" => Ok(ConnectionMode::Publish),
151            "bidirectional" => Ok(ConnectionMode::Bidirectional),
152            _ => Err(()),
153        }
154    }
155}
156
157impl TryFrom<AccessControlEntry> for StandardAccessControlEntry {
158    type Error = ();
159
160    fn try_from(value: AccessControlEntry) -> Result<Self, Self::Error> {
161        match &value.key[..] {
162            "u" => Ok(StandardAccessControlEntry::UserName(value.value)),
163            "r" => Ok(StandardAccessControlEntry::ResourceName(value.value)),
164            "h" => Ok(StandardAccessControlEntry::HostName(value.value)),
165            "s" => Ok(StandardAccessControlEntry::SessionId(value.value)),
166            "t" => Ok(StandardAccessControlEntry::Type(value.value.parse()?)),
167            "m" => Ok(StandardAccessControlEntry::Mode(value.value.parse()?)),
168            _ => Err(()),
169        }
170    }
171}
172
173impl From<StandardAccessControlEntry> for AccessControlEntry {
174    fn from(sace: StandardAccessControlEntry) -> Self {
175        match sace {
176            StandardAccessControlEntry::UserName(un) => AccessControlEntry::new("u", un),
177            StandardAccessControlEntry::ResourceName(rn) => AccessControlEntry::new("r", rn),
178            StandardAccessControlEntry::HostName(hn) => AccessControlEntry::new("h", hn),
179            StandardAccessControlEntry::SessionId(sid) => AccessControlEntry::new("s", sid),
180            StandardAccessControlEntry::Type(ty) => AccessControlEntry::new("t", format!("{ty}")),
181            StandardAccessControlEntry::Mode(m) => AccessControlEntry::new("m", format!("{m}")),
182        }
183    }
184}
185
186impl Display for StandardAccessControlEntry {
187    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
188        AccessControlEntry::from(self.clone()).fmt(f)
189    }
190}
191
192impl Display for ParseAccessControlEntryError {
193    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
194        match self {
195            ParseAccessControlEntryError::NoValue => write!(f, "No value to corresponding key"),
196            ParseAccessControlEntryError::WrongStart => {
197                write!(f, "Access control entry did not start with #!::")
198            }
199        }
200    }
201}
202
203impl Error for ParseAccessControlEntryError {}
204
205#[cfg(test)]
206mod tests {
207    use super::*;
208
209    #[test]
210    fn parse_ace() {
211        let ace_str = "#!::u=admin,r=bluesbrothers1_hi";
212        let ace = ace_str.parse::<AccessControlList>().unwrap();
213
214        assert_eq!(
215            ace,
216            AccessControlList(vec![
217                AccessControlEntry::new("u", "admin"),
218                AccessControlEntry::new("r", "bluesbrothers1_hi")
219            ])
220        );
221
222        assert_eq!(ace_str, format!("{ace}"))
223    }
224}