tauri_plugin_widgets/
group.rs1use crate::error::{Error, Result};
7
8pub fn validate_group(group: &str) -> Result<&str> {
15 if group.is_empty() {
16 return Err(Error::new("group must not be empty"));
17 }
18 if !group
19 .chars()
20 .all(|c| c.is_ascii_alphanumeric() || matches!(c, '.' | '_' | '-'))
21 {
22 return Err(Error::new("group contains invalid characters"));
23 }
24 if group == "." || group == ".." {
25 return Err(Error::new("group is not a valid identifier"));
26 }
27 #[cfg(any(target_os = "macos", target_os = "ios"))]
28 {
29 const PREFIX: &str = "group.";
30 if !group.starts_with(PREFIX) {
31 return Err(Error::new(
32 "group must be an App Group id starting with 'group.'",
33 ));
34 }
35 let rest = &group[PREFIX.len()..];
36 if rest.is_empty() || rest == "." || rest == ".." {
37 return Err(Error::new("group App Group suffix is invalid"));
38 }
39 }
40 Ok(group)
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46
47 #[test]
48 fn accepts_reverse_dns() {
49 assert!(validate_group("group.com.example.app").is_ok());
50 #[cfg(not(any(target_os = "macos", target_os = "ios")))]
51 assert!(validate_group("com.example.app").is_ok());
52 }
53
54 #[test]
55 fn rejects_path_chars() {
56 assert!(validate_group("group.com/../../tmp").is_err());
57 assert!(validate_group("group.com\\evil").is_err());
58 assert!(validate_group("").is_err());
59 assert!(validate_group("..").is_err());
60 }
61
62 #[test]
63 #[cfg(any(target_os = "macos", target_os = "ios"))]
64 fn apple_requires_group_prefix() {
65 assert!(validate_group("com.example.app").is_err());
66 assert!(validate_group("group.").is_err());
67 assert!(validate_group("group..").is_err());
68 assert!(validate_group("group...").is_err());
69 }
70}