1use std::fmt::Display;
6
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)]
10#[serde(rename_all = "kebab-case")]
11pub enum ShareType {
12 #[default]
13 User,
14 Group,
15 Federation,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)]
24#[serde(try_from = "String", into = "String")]
25pub struct OcmAddress {
26 address: String,
27 separator_index: usize
28}
29
30impl OcmAddress {
31 pub fn get_identifier(&self) -> &str {
33 self.address.split_at(self.separator_index).0
34 }
35
36 pub fn get_server_url(&self) -> &str {
39 self.address.split_at(self.separator_index+1).1
40 }
41}
42
43impl TryFrom<&str> for OcmAddress {
44 type Error = &'static str;
45
46 fn try_from(value: &str) -> Result<Self, Self::Error> {
47 value.to_string().try_into()
48 }
49}
50
51impl TryFrom<String> for OcmAddress {
52 type Error = &'static str;
53
54 fn try_from(value: String) -> Result<Self, Self::Error> {
55 if value.is_empty() {
56 Err("OCM Address may not be empty")?
57 }
58
59 let separator_index = value.rfind('@')
60 .ok_or("Missing '@' separator in OCM Address")?;
61
62 if separator_index == 0 {
63 Err("UserId before the '@' character in OCM Address may not be empty")?
64 }
65
66 if separator_index == value.len() - 1 {
67 Err("OCM Server FQDN after the '@' character in OCM Address may not be empty")?
68 }
69
70 let host = value.split_at(separator_index+1).1;
71
72 if host.contains('/') {
73 Err("OCM Address may not contain a path or scheme")?
74 };
75 Ok(Self {
76 address: value,
77 separator_index
78 })
79 }
80}
81
82impl Display for OcmAddress {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 f.write_str(&self.address)?;
85 Ok(())
86 }
87}
88
89impl From<OcmAddress> for String {
90 fn from(val: OcmAddress) -> Self {
91 val.address
92 }
93}
94
95impl AsRef<str> for OcmAddress {
96 fn as_ref(&self) -> &str {
97 &self.address
98 }
99}
100
101#[cfg(test)]
102mod test {
103 use super::OcmAddress;
104
105
106 #[test]
107 fn invalid_ocm_addresses() {
108 OcmAddress::try_from("").expect_err("OCM Address may not be empty");
109 OcmAddress::try_from("user@https://example.org").expect_err("Scheme is not allowed in server address part");
110 OcmAddress::try_from("user@example.org/subfolder").expect_err("Scheme is not allowed in server address part");
111 OcmAddress::try_from("@example.org").expect_err("Empty user Id must be rejected");
112 OcmAddress::try_from("user@").expect_err("Empty Server FQDN must be rejected");
113 OcmAddress::try_from("@").expect_err("Empty User Id and Empty Server FQDN must be rejected");
114 }
115
116 #[test]
117 fn valid_ocm_addresses() {
118 let address = OcmAddress::try_from("asdf@user@example.org").expect("asdf@user@example.org should be accepted");
119 assert_eq!(("asdf@user", "example.org"), (address.get_identifier(), address.get_server_url()));
120
121 let address = OcmAddress::try_from("🤡asdf@user@example.org:8080").expect("🤡asdf@user@example.org:8080 should be accepted");
122 assert_eq!(("🤡asdf@user", "example.org:8080"), (address.get_identifier(), address.get_server_url()));
123
124 let address = OcmAddress::try_from("asdf@user@127.0.0.1").expect("asdf@user@127.0.0.1 should be accepted");
125 assert_eq!(("asdf@user", "127.0.0.1"), (address.get_identifier(), address.get_server_url()));
126
127 let address = OcmAddress::try_from("asdf@user@[fe80::cc7f:2f7d:80f6:3876%en0]").expect("asdf@user@[fe80::cc7f:2f7d:80f6:3876%en0] should be accepted");
128 assert_eq!(("asdf@user", "[fe80::cc7f:2f7d:80f6:3876%en0]"), (address.get_identifier(), address.get_server_url()));
129
130 }
131}