Cleaned up messages, spec changes

The protocol changed a bit, I forgot to add room ids for some of the
messages. Other big features are that there are now ways to process
messages built into the library itself. Signature verification is
stubbed out because its a low priority feature, but encoding it in the
lib gives a standardized way to do it
This commit is contained in:
2026-05-17 13:43:23 -07:00
parent 8712e4603d
commit a3f5470549
5 changed files with 142 additions and 20 deletions
+92 -8
View File
@@ -1,8 +1,9 @@
use uuid::Uuid;
use crate::message::{MessageId,Message};
use crate::message::{MessageId,TaggedMessage,VerificationError,Relevance};
use crate::state::{StateType,StateValue,StatePath,StatePermission,StatePermissionKey};
use crate::{RoomId,Group,Role,User,GroupPower};
use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
//StatePath [String]
//octal is fine for now
@@ -11,17 +12,28 @@ use serde::{Deserialize, Serialize};
//RoomId [i64]
#[derive(Serialize,Deserialize,Clone,Debug)]
pub struct TaggedClientMessage {
message: ClientMessage,
/// This exists solely to allow the DB to finish tagging the message. It is every field of a
/// message except for the ID which can be created using a Postgres serial type
pub struct InsertableClientMessage {
pub message: ClientMessage,
#[serde(with="time::serde::timestamp")]
pub client_timestamp: OffsetDateTime,
#[serde(with="time::serde::timestamp")]
pub server_timestamp: OffsetDateTime,
#[serde(with = "serde_bytes")]
signature: Box<[u8]>,
user: User
pub signature: Box<[u8]>,
pub user: User
}
#[derive(Serialize,Deserialize,Clone,Debug)]
pub struct SignedClientMessage {
pub message: ClientMessage,
// timestamp sent by client protects against replay attacks by untrusted server
#[serde(with="time::serde::timestamp")]
pub timestamp: OffsetDateTime,
// Should I enforce this being a ecdsa signature?
// What is the signature of????
// Can I reserialize the message and check the signature that way??
@@ -30,6 +42,20 @@ pub struct SignedClientMessage {
#[serde(with = "serde_bytes")]
pub signature: Box<[u8]>
}
impl SignedClientMessage {
pub fn tag(self, username: User) -> InsertableClientMessage {
InsertableClientMessage {
message: self.message,
client_timestamp: self.timestamp,
server_timestamp: OffsetDateTime::now_utc(),
signature: self.signature,
user: username,
}
}
pub fn verify(&self) -> Result<bool,VerificationError> {
unimplemented!()
}
}
#[derive(Serialize,Deserialize,Clone,Debug)]
pub enum ClientMessage {
@@ -53,6 +79,7 @@ pub enum ClientMessage {
// Should it be one message type or mutiple?
Message {
body: String,
room_id: RoomId
},
// Private message/invite mechanism
MessagePost {
@@ -61,34 +88,42 @@ pub enum ClientMessage {
},
// Replace the body of the message with a new one
MessageEdit {
room_id: RoomId,
body: String,
id: MessageId
},
MessageDelete {
room_id: RoomId,
id: MessageId
},
// State Actions
StateCreate {
room_id: RoomId,
path: StatePath,
ty: StateType,
permissions: Option<Vec<StatePermission>>
},
StateWrite {
room_id: RoomId,
path: StatePath,
content: StateValue
},
StateDelete {
room_id: RoomId,
path: StatePath,
},
StateAppend {
room_id: RoomId,
path: StatePath,
content: StateValue
},
StateMove {
room_id: RoomId,
path: StatePath,
target: StatePath,
},
StateRead {
room_id: RoomId,
path: StatePath
},
PermissionAdd {
@@ -177,6 +212,49 @@ pub enum ClientMessage {
end: MessageId,
}
}
impl ClientMessage<> {
pub fn get_relevance(&self) -> Option<Relevance> {
use ClientMessage::*;
Some(match self {
Message {
body: _,
room_id
// These don't necessarily need cloned, it might make sense to make an owned
// version of Relevance and a reference version of it
} => Relevance::Message(room_id.clone()),
// Private message/invite mechanism
MessagePost {
body: _,
user
} => Relevance::Post(user.clone()),
// Replace the body of the message with a new one
MessageEdit {
room_id,
body: _,
id: _
} => Relevance::Message(room_id.clone()),
MessageDelete {
room_id,
id: _,
} => Relevance::Message(room_id.clone()),
StateWrite {
room_id,
path,
content: _
} => Relevance::State(room_id.clone(),path.clone()),
StateDelete {
room_id,
path,
} => Relevance::State(room_id.clone(),path.clone()),
StateAppend {
room_id,
path,
content: _
} => Relevance::State(room_id.clone(),path.clone()),
_ => return None
})
}
}
#[derive(Serialize,Deserialize)]
pub enum ServerError {
@@ -184,16 +262,22 @@ pub enum ServerError {
// Server can specify the required challenge
ChallengeInvitecode,
NotAuthenticated,
AlreadyAuthenticated,
NotInChallenge
}
#[derive(Serialize,Deserialize)]
pub enum ServerMessage {
// Returned on fetch or naturally from subscribe
Messages(Vec<Message>),
// This should be
Messages(Vec<TaggedMessage>),
MediaUploaded(Uuid),
Error(ServerError),
// Returned both on read and from subscribe
State(StateValue),
// Returned on read
State(StatePath,StateValue),
// Returned on subscribe, forwards state change message to client
StateChange(TaggedMessage),
OkMessage(MessageId),
Ok,
}