imessage_database/util/
bundle_id.rs

1/*!
2 Contains logic for parsing [Apple Bundle IDs](https://developer.apple.com/documentation/appstoreconnectapi/bundle-ids).
3*/
4
5/// Parse an App's Bundle ID out of a Balloon's Bundle ID
6///
7/// For example, a Bundle ID like `com.apple.messages.MSMessageExtensionBalloonPlugin:0000000000:com.apple.SafetyMonitorApp.SafetyMonitorMessages`
8/// should get parsed into `com.apple.SafetyMonitorApp.SafetyMonitorMessages`.
9///
10/// # Example
11///
12/// ```
13/// use imessage_database::util::bundle_id::parse_balloon_bundle_id;
14///
15/// let bundle_id = "com.apple.messages.MSMessageExtensionBalloonPlugin:0000000000:com.apple.SafetyMonitorApp.SafetyMonitorMessages";
16/// let parsed = parse_balloon_bundle_id(Some(bundle_id)); // Some("com.apple.SafetyMonitorApp.SafetyMonitorMessages")
17/// ```
18#[must_use]
19pub fn parse_balloon_bundle_id(bundle_id: Option<&str>) -> Option<&str> {
20    bundle_id.and_then(|id| {
21        let mut parts = id.split(':');
22        let first = parts.next();
23
24        // If there is only one part, use that, otherwise get the third part
25        match parts.next() {
26            None => first,
27            // Will be None if there is no third part
28            Some(_) => parts.next(),
29        }
30    })
31}
32
33#[cfg(test)]
34mod tests {
35    use crate::util::bundle_id::parse_balloon_bundle_id;
36
37    #[test]
38    fn can_get_no_balloon_bundle_id() {
39        assert_eq!(parse_balloon_bundle_id(None), None);
40    }
41
42    #[test]
43    fn can_get_balloon_bundle_id_os() {
44        assert_eq!(
45            parse_balloon_bundle_id(Some("com.apple.Handwriting.HandwritingProvider")),
46            Some("com.apple.Handwriting.HandwritingProvider")
47        );
48    }
49
50    #[test]
51    fn can_get_balloon_bundle_id_url() {
52        assert_eq!(
53            parse_balloon_bundle_id(Some("com.apple.messages.URLBalloonProvider")),
54            Some("com.apple.messages.URLBalloonProvider")
55        );
56    }
57
58    #[test]
59    fn can_get_balloon_bundle_id_apple() {
60        assert_eq!(
61            parse_balloon_bundle_id(Some(
62                "com.apple.messages.MSMessageExtensionBalloonPlugin:0000000000:com.apple.PassbookUIService.PeerPaymentMessagesExtension"
63            )),
64            Some("com.apple.PassbookUIService.PeerPaymentMessagesExtension")
65        );
66    }
67
68    #[test]
69    fn can_get_balloon_bundle_id_third_party() {
70        assert_eq!(
71            parse_balloon_bundle_id(Some(
72                "com.apple.messages.MSMessageExtensionBalloonPlugin:QPU8QS3E62:com.contextoptional.OpenTable.Messages"
73            )),
74            Some("com.contextoptional.OpenTable.Messages")
75        );
76    }
77}