|
1 | | -use zeroize::{Zeroize, ZeroizeOnDrop}; |
| 1 | +use zeroize::Zeroize; |
2 | 2 |
|
3 | 3 | use crate::{ |
4 | 4 | CryptoKeystoreResult, Sha256Hash, |
@@ -89,59 +89,39 @@ impl<'a> KeyType for ConversationId<'a> { |
89 | 89 | } |
90 | 90 |
|
91 | 91 | /// [`MlsPendingMessage`]s have no distinct primary key; |
92 | | -/// they must always be accessed via [`MlsPendingMessage::find_all_by_conversation_id`] and |
93 | | -/// cleaned up with [`MlsPendingMessage::delete_by_conversation_id`] |
| 92 | +/// they must always be accessed via the [`SearchableEntity`][crate::traits::SearchableEntity] and |
| 93 | +/// [`DeletableBySearchKey`][crate::traits::DeletableBySearchKey] traits. |
94 | 94 | /// |
95 | | -/// However, we have to fake a primary key type in order to support |
96 | | -/// `KeystoreTransaction::remove_pending_messages_by_conversation_id`. Additionally we need the same one in WASM, where |
97 | | -/// it's necessary for item-level encryption. |
| 95 | +/// However the keystore's support of internal transactions demands a primary key: |
| 96 | +/// ultimately that structure boils down to `Map<CollectionName, Map<PrimaryKey, Entity>>`, so anything other |
| 97 | +/// than a full primary key just breaks things. |
98 | 98 | /// |
99 | | -/// This implementation is fairly inefficient and hopefully temporary. But it at least implements the correct semantics. |
100 | | -#[derive(ZeroizeOnDrop)] |
101 | | -pub struct MlsPendingMessagePrimaryKey { |
102 | | - pub(crate) foreign_id: Vec<u8>, |
103 | | - message: Vec<u8>, |
104 | | -} |
| 99 | +/// We use `blake3` as a fast cryptographically-secure hash implementation, and take 32 bytes of hash to ensure |
| 100 | +/// that the chance of a collision is effectively 0. |
| 101 | +pub struct MlsPendingMessagePrimaryKey([u8; 32]); |
105 | 102 |
|
106 | 103 | impl From<&MlsPendingMessage> for MlsPendingMessagePrimaryKey { |
107 | 104 | fn from(value: &MlsPendingMessage) -> Self { |
108 | | - Self { |
109 | | - foreign_id: value.foreign_id.clone(), |
110 | | - message: value.message.clone(), |
111 | | - } |
| 105 | + Self( |
| 106 | + blake3::Hasher::new() |
| 107 | + .update(&value.foreign_id) |
| 108 | + .update(&value.message) |
| 109 | + .finalize() |
| 110 | + .into(), |
| 111 | + ) |
112 | 112 | } |
113 | 113 | } |
114 | 114 |
|
115 | 115 | impl KeyType for MlsPendingMessagePrimaryKey { |
116 | 116 | fn bytes(&self) -> std::borrow::Cow<'_, [u8]> { |
117 | | - // run-length encoding: 32 bits of size for each field, followed by the field |
118 | | - let fields = [&self.foreign_id, &self.message]; |
119 | | - let mut key = Vec::with_capacity( |
120 | | - ((u32::BITS / u8::BITS) as usize * fields.len()) + self.foreign_id.len() + self.message.len(), |
121 | | - ); |
122 | | - for field in fields { |
123 | | - key.extend((field.len() as u32).to_le_bytes()); |
124 | | - key.extend(field.as_slice()); |
125 | | - } |
126 | | - key.into() |
| 117 | + (&self.0).into() |
127 | 118 | } |
128 | 119 | } |
129 | 120 |
|
130 | 121 | impl OwnedKeyType for MlsPendingMessagePrimaryKey { |
131 | 122 | fn from_bytes(bytes: &[u8]) -> Option<Self> { |
132 | | - // run-length decoding: 32 bits of size for each field, followed by the field |
133 | | - let (len, bytes) = bytes.split_at_checked(4)?; |
134 | | - let len = u32::from_le_bytes(len.try_into().ok()?); |
135 | | - let (foreign_id, bytes) = bytes.split_at_checked(len as _)?; |
136 | | - |
137 | | - let (len, bytes) = bytes.split_at_checked(4)?; |
138 | | - let len = u32::from_le_bytes(len.try_into().ok()?); |
139 | | - let (message, bytes) = bytes.split_at_checked(len as _)?; |
140 | | - |
141 | | - bytes.is_empty().then(|| Self { |
142 | | - foreign_id: foreign_id.to_owned(), |
143 | | - message: message.to_owned(), |
144 | | - }) |
| 123 | + let array = bytes.try_into().ok()?; |
| 124 | + Some(Self(array)) |
145 | 125 | } |
146 | 126 | } |
147 | 127 |
|
|
0 commit comments