bifrost_sdp/
encryption_key.rs

1use std::fmt;
2
3use http::Uri;
4use nom::{
5    branch::alt,
6    bytes::complete::{is_not, tag},
7    character::complete::line_ending,
8    combinator::map_res,
9    IResult,
10};
11
12use crate::Parse;
13
14/// A parsed encryption key line, defined in
15/// [RFC 4566](https://tools.ietf.org/html/rfc4566#section-5.12).
16#[derive(Clone, Debug, PartialEq)]
17pub enum EncryptionKey {
18    Clear(String),
19    Base64(String),
20    Uri(Uri),
21    Prompt,
22}
23
24impl fmt::Display for EncryptionKey {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        match self {
27            Self::Clear(key) => writeln!(f, "k=clear:{}\r", key),
28            Self::Base64(key) => writeln!(f, "k=base64:{}\r", key),
29            Self::Uri(uri) => writeln!(f, "k=uri:{}\r", uri),
30            Self::Prompt => writeln!(f, "k=prompt\r"),
31        }
32    }
33}
34
35impl Parse for EncryptionKey {
36    fn parse(input: &str) -> IResult<&str, Self> {
37        // k=<method>
38        // k=<method>:<encryption key>
39        let (rest, _) = tag("k=")(input)?;
40        let (rest, key) = alt((parse_clear, parse_base64, parse_uri, parse_prompt))(rest)?;
41        let (rest, _) = line_ending(rest)?;
42        Ok((rest, key))
43    }
44}
45
46fn parse_clear(input: &str) -> IResult<&str, EncryptionKey> {
47    let (rest, _) = tag("clear:")(input)?;
48    let (rest, key) = is_not("\r\n")(rest)?;
49    Ok((rest, EncryptionKey::Clear(key.to_owned())))
50}
51
52fn parse_base64(input: &str) -> IResult<&str, EncryptionKey> {
53    let (rest, _) = tag("base64:")(input)?;
54    let (rest, key) = is_not("\r\n")(rest)?;
55    Ok((rest, EncryptionKey::Base64(key.to_owned())))
56}
57
58fn parse_uri(input: &str) -> IResult<&str, EncryptionKey> {
59    let (rest, _) = tag("uri:")(input)?;
60    let (rest, key) = map_res(is_not("\r\n"), str::parse)(rest)?;
61    Ok((rest, EncryptionKey::Uri(key)))
62}
63
64fn parse_prompt(input: &str) -> IResult<&str, EncryptionKey> {
65    let (rest, _) = tag("prompt")(input)?;
66    Ok((rest, EncryptionKey::Prompt))
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72    use crate::test_util::{assert_err, assert_parse_display};
73
74    #[test]
75    fn test_clear() {
76        assert_parse_display(
77            "k=clear:foo\r\nmore",
78            "more",
79            &EncryptionKey::Clear("foo".to_owned()),
80            "k=clear:foo\r\n",
81        );
82        assert_err::<EncryptionKey>("k=clear\r\nmore");
83        assert_err::<EncryptionKey>("k=clear:\r\nmore");
84    }
85
86    #[test]
87    fn test_base64() {
88        assert_parse_display(
89            "k=base64:foo\r\n\rmore",
90            "\rmore",
91            &EncryptionKey::Base64("foo".to_owned()),
92            "k=base64:foo\r\n",
93        );
94        assert_err::<EncryptionKey>("k=base64\r\nmore");
95        assert_err::<EncryptionKey>("k=base64:\r\nmore");
96    }
97
98    #[test]
99    fn test_uri() {
100        let uri_str = "https://example.org/key";
101        let uri = uri_str.parse().unwrap();
102
103        assert_parse_display(
104            &format!("k=uri:{}\r\n\nmore\r", uri_str),
105            "\nmore\r",
106            &EncryptionKey::Uri(uri),
107            &format!("k=uri:{}\r\n", uri_str),
108        );
109        assert_err::<EncryptionKey>("k=uri\r\nmore");
110        assert_err::<EncryptionKey>("k=uri:\r\nmore");
111        assert_err::<EncryptionKey>("k=uri:!@#$\r\nmore");
112    }
113
114    #[test]
115    fn test_prompt() {
116        assert_parse_display(
117            "k=prompt\r\nmore",
118            "more",
119            &EncryptionKey::Prompt,
120            "k=prompt\r\n",
121        );
122        assert_err::<EncryptionKey>("k=prompt:foo\r\nmore");
123        assert_err::<EncryptionKey>("k=prompt:\r\nmore");
124    }
125
126    #[test]
127    fn test_invalid() {
128        assert_err::<EncryptionKey>("k=foo\r\nmore");
129        assert_err::<EncryptionKey>("k=foo:\r\nmore");
130        assert_err::<EncryptionKey>("k=foo:bar\r\nmore");
131    }
132}