1use std::sync::Arc;
2
3use xmtp_mls_common::libxmtp_version::LibXMTPVersion;
4
5#[cfg(feature = "bench")]
6pub mod bench;
7pub mod cleanup_duplicate_updates;
8#[cfg(any(test, feature = "test-utils"))]
9pub mod test;
10
11#[cfg(any(test, feature = "test-utils"))]
12pub use self::test::*;
13
14pub mod hash {
15 pub use xmtp_cryptography::hash::sha256_bytes as sha256;
16}
17
18pub mod time {
19 pub fn hmac_epoch() -> i64 {
21 xmtp_push_types::hmac_epoch(xmtp_common::time::now_secs())
22 }
23}
24
25pub mod id {
26 use xmtp_db::group_intent::IntentKind;
27
28 use crate::groups::intents::{IntentError, SendMessageIntentData};
29 use prost::Message;
30 use xmtp_proto::xmtp::mls::message_contents::plaintext_envelope::Content;
31 use xmtp_proto::xmtp::mls::message_contents::{PlaintextEnvelope, plaintext_envelope::V1};
32
33 pub fn calculate_message_id(
36 group_id: impl AsRef<[u8]>,
37 decrypted_message_bytes: &[u8],
38 idempotency_key: &str,
39 ) -> Vec<u8> {
40 let separator = b"\t";
41 let mut id_vec = Vec::new();
42 id_vec.extend_from_slice(group_id.as_ref());
43 id_vec.extend_from_slice(separator);
44 id_vec.extend_from_slice(idempotency_key.as_bytes());
45 id_vec.extend_from_slice(separator);
46 id_vec.extend_from_slice(decrypted_message_bytes);
47 super::hash::sha256(&id_vec)
48 }
49
50 pub fn calculate_message_id_for_intent(
61 intent: &xmtp_db::group_intent::StoredGroupIntent,
62 ) -> Result<Option<Vec<u8>>, IntentError> {
63 if intent.kind != IntentKind::SendMessage {
64 return Ok(None);
65 }
66
67 let data = SendMessageIntentData::from_bytes(&intent.data)?;
68 let envelope: PlaintextEnvelope = PlaintextEnvelope::decode(data.message.as_slice())?;
69
70 let PlaintextEnvelope {
72 content:
73 Some(Content::V1(V1 {
74 content: message,
75 idempotency_key: key,
76 })),
77 } = envelope
78 else {
79 return Ok(None);
80 };
81
82 Ok(Some(calculate_message_id(intent.group_id, &message, &key)))
83 }
84}
85
86#[derive(Clone, Debug, PartialEq)]
87pub struct VersionInfo {
88 pkg_version: Arc<str>,
89 pkg_semver: LibXMTPVersion,
94}
95
96impl Default for VersionInfo {
97 fn default() -> Self {
98 Self::new(env!("CARGO_PKG_VERSION"))
99 }
100}
101
102impl VersionInfo {
103 fn new(version: &str) -> Self {
110 let pkg_semver = LibXMTPVersion::parse(version)
111 .unwrap_or_else(|_| panic!("client pkg_version {version:?} is not valid semver"));
112 Self {
113 pkg_version: version.into(),
114 pkg_semver,
115 }
116 }
117
118 pub fn pkg_version(&self) -> &str {
119 &self.pkg_version
120 }
121
122 pub fn pkg_semver(&self) -> &LibXMTPVersion {
125 &self.pkg_semver
126 }
127
128 #[cfg(test)]
130 pub fn test_update_version(&mut self, version: &str) {
131 *self = Self::new(version);
132 }
133}