pub enum RoomMessageBody {
Public {
content_type: u32,
content_version: u32,
data: Vec<u8>,
},
Private {
content_type: u32,
content_version: u32,
ciphertext: Vec<u8>,
nonce: [u8; 12],
secret_version: SecretVersion,
},
}Expand description
Message body that can be either public or private (encrypted).
Content is opaque to the contract - interpretation happens client-side. This design enables adding new content types without contract redeployment.
§Content Types
content_type = 1: Text message (TextContentV1)content_type = 2: Action on another message (ActionContentV1)content_type = 3: Reply to another message (ReplyContentV1)content_type = 4: Room event like join/leave (EventContentV1)- Allowed as Public even in private rooms (contains no sensitive content)
- Old clients display as “[Unsupported message type 4.1 - please upgrade]”
- Future types can be added without contract changes
§Extensibility
- New content types: Just use a new content_type number
- New action types: Just use a new action_type number within ActionContentV1
- New fields: Add to content structs (old clients ignore unknown fields)
- Breaking changes: Bump content_version
§Do NOT apply serde_bytes to data / ciphertext
Both are bare Vec<u8>, so like ActionContentV1::payload before
freenet/river#443 they serialize as a CBOR array of integers (~2 bytes per
byte). That looks like the same easy win, and it is NOT: these fields live
inside MessageV1, which verify_struct RE-SERIALIZES to check the
signature (AuthorizedMessageV1::verify). Changing their encoding would
invalidate the signature of every existing message in every room —
unlike ActionContentV1, which is pre-encoded into these opaque bytes and
is therefore outside the signed representation.
The #443 fix was safe precisely because it stopped at that boundary. If the on-wire size of message bodies ever needs to shrink, it requires a versioned migration, not a serde attribute.
Variants§
Public
Public (unencrypted) message
Fields
Private
Private (encrypted) message
Fields
ciphertext: Vec<u8>Encrypted CBOR-encoded content.
Do NOT add serde(with = "serde_bytes") — see the type-level note.
secret_version: SecretVersionVersion of the room secret used for encryption
Implementations§
Source§impl RoomMessageBody
impl RoomMessageBody
Sourcepub fn join_event() -> Self
pub fn join_event() -> Self
Create a join event message
Sourcepub fn public_raw(
content_type: u32,
content_version: u32,
data: Vec<u8>,
) -> Self
pub fn public_raw( content_type: u32, content_version: u32, data: Vec<u8>, ) -> Self
Create a new public message with raw content
Sourcepub fn private(
content_type: u32,
content_version: u32,
ciphertext: Vec<u8>,
nonce: [u8; 12],
secret_version: SecretVersion,
) -> Self
pub fn private( content_type: u32, content_version: u32, ciphertext: Vec<u8>, nonce: [u8; 12], secret_version: SecretVersion, ) -> Self
Create a new private message
Sourcepub fn private_text(
ciphertext: Vec<u8>,
nonce: [u8; 12],
secret_version: SecretVersion,
) -> Self
pub fn private_text( ciphertext: Vec<u8>, nonce: [u8; 12], secret_version: SecretVersion, ) -> Self
Create a private text message (convenience method)
Sourcepub fn remove_reaction(target: MessageId, emoji: String) -> Self
pub fn remove_reaction(target: MessageId, emoji: String) -> Self
Create a remove reaction action (public)
Sourcepub fn reply(
text: String,
target_message_id: MessageId,
target_author_name: String,
target_content_preview: String,
) -> Self
pub fn reply( text: String, target_message_id: MessageId, target_author_name: String, target_content_preview: String, ) -> Self
Create a public reply message
Sourcepub fn private_action(
ciphertext: Vec<u8>,
nonce: [u8; 12],
secret_version: SecretVersion,
) -> Self
pub fn private_action( ciphertext: Vec<u8>, nonce: [u8; 12], secret_version: SecretVersion, ) -> Self
Create a private action message (encrypted)
Use this for any action (edit, delete, reaction, remove_reaction) in a private room. The caller should:
- Create the ActionContentV1 (e.g.,
ActionContentV1::edit(target, new_text)) - Encode it:
action.encode() - Encrypt the bytes with the room secret
- Pass the ciphertext here
Sourcepub fn is_private(&self) -> bool
pub fn is_private(&self) -> bool
Check if this is a private message
Sourcepub fn content_type(&self) -> u32
pub fn content_type(&self) -> u32
Get the content type
Sourcepub fn content_version(&self) -> u32
pub fn content_version(&self) -> u32
Get the content version
Sourcepub fn decode_content(&self) -> Option<DecodedContent>
pub fn decode_content(&self) -> Option<DecodedContent>
Decode the content (for public messages only) Returns None for private messages - decrypt first
Sourcepub fn content_len(&self) -> usize
pub fn content_len(&self) -> usize
Get the content length for validation (contract uses this for size limits)
Sourcepub fn measure_text(text: &str, encrypted: bool) -> usize
pub fn measure_text(text: &str, encrypted: bool) -> usize
Exact Self::content_len of the body Self::public builds for
text — or, with encrypted, of the private body the senders build
by AES-256-GCM-sealing the encoded TextContentV1.
Send gates and byte counters MUST use the measure_* functions, not
text.len(): the contract validates encoded content bytes (CBOR
framing, plus the AEAD tag in private rooms), so a raw-text gate
passes messages the contract then silently prunes (freenet/river#430,
the “message was lost” reports).
Sourcepub fn measure_reply(
text: &str,
target_message_id: MessageId,
target_author_name: &str,
target_content_preview: &str,
encrypted: bool,
) -> usize
pub fn measure_reply( text: &str, target_message_id: MessageId, target_author_name: &str, target_content_preview: &str, encrypted: bool, ) -> usize
Exact Self::content_len of the body Self::reply builds — or,
with encrypted, of the private reply body (encrypted encoded
ReplyContentV1). Reply bodies embed the quoted author name and
content preview, so their overhead is much larger than plain text.
Sourcepub fn measure_edit(target: MessageId, new_text: &str, encrypted: bool) -> usize
pub fn measure_edit(target: MessageId, new_text: &str, encrypted: bool) -> usize
Exact Self::content_len of the body Self::edit builds — or,
with encrypted, of the private edit body (encrypted encoded
ActionContentV1).
Sourcepub fn secret_version(&self) -> Option<SecretVersion>
pub fn secret_version(&self) -> Option<SecretVersion>
Get the secret version (if private)
Sourcepub fn to_string_lossy(&self) -> String
pub fn to_string_lossy(&self) -> String
Get a string representation for display purposes
Sourcepub fn as_public_string(&self) -> Option<String>
pub fn as_public_string(&self) -> Option<String>
Try to get the public plaintext, returns None if private or not a text message
Trait Implementations§
Source§impl Clone for RoomMessageBody
impl Clone for RoomMessageBody
Source§fn clone(&self) -> RoomMessageBody
fn clone(&self) -> RoomMessageBody
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more