1use std::sync::Arc;
2
3use crate::groups::validated_commit::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(
35 group_id: impl AsRef<[u8]>,
36 decrypted_message_bytes: &[u8],
37 idempotency_key: &str,
38 ) -> Vec<u8> {
39 let separator = b"\t";
40 let mut id_vec = Vec::new();
41 id_vec.extend_from_slice(group_id.as_ref());
42 id_vec.extend_from_slice(separator);
43 id_vec.extend_from_slice(idempotency_key.as_bytes());
44 id_vec.extend_from_slice(separator);
45 id_vec.extend_from_slice(decrypted_message_bytes);
46 super::hash::sha256(&id_vec)
47 }
48
49 pub fn calculate_message_id_for_intent(
60 intent: &xmtp_db::group_intent::StoredGroupIntent,
61 ) -> Result<Option<Vec<u8>>, IntentError> {
62 if intent.kind != IntentKind::SendMessage {
63 return Ok(None);
64 }
65
66 let data = SendMessageIntentData::from_bytes(&intent.data)?;
67 let envelope: PlaintextEnvelope = PlaintextEnvelope::decode(data.message.as_slice())?;
68
69 let PlaintextEnvelope {
71 content:
72 Some(Content::V1(V1 {
73 content: message,
74 idempotency_key: key,
75 })),
76 } = envelope
77 else {
78 return Ok(None);
79 };
80
81 Ok(Some(calculate_message_id(intent.group_id, &message, &key)))
82 }
83}
84
85#[derive(Clone, Debug, PartialEq)]
86pub struct VersionInfo {
87 pkg_version: Arc<str>,
88 pkg_semver: LibXMTPVersion,
93}
94
95impl Default for VersionInfo {
96 fn default() -> Self {
97 Self::new(env!("CARGO_PKG_VERSION"))
98 }
99}
100
101impl VersionInfo {
102 fn new(version: &str) -> Self {
109 let pkg_semver = LibXMTPVersion::parse(version)
110 .unwrap_or_else(|_| panic!("client pkg_version {version:?} is not valid semver"));
111 Self {
112 pkg_version: version.into(),
113 pkg_semver,
114 }
115 }
116
117 pub fn pkg_version(&self) -> &str {
118 &self.pkg_version
119 }
120
121 pub fn pkg_semver(&self) -> &LibXMTPVersion {
124 &self.pkg_semver
125 }
126
127 #[cfg(test)]
129 pub fn test_update_version(&mut self, version: &str) {
130 *self = Self::new(version);
131 }
132}