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:
+92
-8
@@ -1,8 +1,9 @@
|
|||||||
use uuid::Uuid;
|
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::state::{StateType,StateValue,StatePath,StatePermission,StatePermissionKey};
|
||||||
use crate::{RoomId,Group,Role,User,GroupPower};
|
use crate::{RoomId,Group,Role,User,GroupPower};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
//StatePath [String]
|
//StatePath [String]
|
||||||
//octal is fine for now
|
//octal is fine for now
|
||||||
@@ -11,17 +12,28 @@ use serde::{Deserialize, Serialize};
|
|||||||
//RoomId [i64]
|
//RoomId [i64]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||||
pub struct TaggedClientMessage {
|
/// This exists solely to allow the DB to finish tagging the message. It is every field of a
|
||||||
message: ClientMessage,
|
/// 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")]
|
#[serde(with = "serde_bytes")]
|
||||||
signature: Box<[u8]>,
|
pub signature: Box<[u8]>,
|
||||||
user: User
|
pub user: User
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||||
pub struct SignedClientMessage {
|
pub struct SignedClientMessage {
|
||||||
pub message: ClientMessage,
|
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?
|
// Should I enforce this being a ecdsa signature?
|
||||||
// What is the signature of????
|
// What is the signature of????
|
||||||
// Can I reserialize the message and check the signature that way??
|
// Can I reserialize the message and check the signature that way??
|
||||||
@@ -30,6 +42,20 @@ pub struct SignedClientMessage {
|
|||||||
#[serde(with = "serde_bytes")]
|
#[serde(with = "serde_bytes")]
|
||||||
pub signature: Box<[u8]>
|
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)]
|
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||||
pub enum ClientMessage {
|
pub enum ClientMessage {
|
||||||
@@ -53,6 +79,7 @@ pub enum ClientMessage {
|
|||||||
// Should it be one message type or mutiple?
|
// Should it be one message type or mutiple?
|
||||||
Message {
|
Message {
|
||||||
body: String,
|
body: String,
|
||||||
|
room_id: RoomId
|
||||||
},
|
},
|
||||||
// Private message/invite mechanism
|
// Private message/invite mechanism
|
||||||
MessagePost {
|
MessagePost {
|
||||||
@@ -61,34 +88,42 @@ pub enum ClientMessage {
|
|||||||
},
|
},
|
||||||
// Replace the body of the message with a new one
|
// Replace the body of the message with a new one
|
||||||
MessageEdit {
|
MessageEdit {
|
||||||
|
room_id: RoomId,
|
||||||
body: String,
|
body: String,
|
||||||
id: MessageId
|
id: MessageId
|
||||||
},
|
},
|
||||||
MessageDelete {
|
MessageDelete {
|
||||||
|
room_id: RoomId,
|
||||||
id: MessageId
|
id: MessageId
|
||||||
},
|
},
|
||||||
// State Actions
|
// State Actions
|
||||||
StateCreate {
|
StateCreate {
|
||||||
|
room_id: RoomId,
|
||||||
path: StatePath,
|
path: StatePath,
|
||||||
ty: StateType,
|
ty: StateType,
|
||||||
permissions: Option<Vec<StatePermission>>
|
permissions: Option<Vec<StatePermission>>
|
||||||
},
|
},
|
||||||
StateWrite {
|
StateWrite {
|
||||||
|
room_id: RoomId,
|
||||||
path: StatePath,
|
path: StatePath,
|
||||||
content: StateValue
|
content: StateValue
|
||||||
},
|
},
|
||||||
StateDelete {
|
StateDelete {
|
||||||
|
room_id: RoomId,
|
||||||
path: StatePath,
|
path: StatePath,
|
||||||
},
|
},
|
||||||
StateAppend {
|
StateAppend {
|
||||||
|
room_id: RoomId,
|
||||||
path: StatePath,
|
path: StatePath,
|
||||||
content: StateValue
|
content: StateValue
|
||||||
},
|
},
|
||||||
StateMove {
|
StateMove {
|
||||||
|
room_id: RoomId,
|
||||||
path: StatePath,
|
path: StatePath,
|
||||||
target: StatePath,
|
target: StatePath,
|
||||||
},
|
},
|
||||||
StateRead {
|
StateRead {
|
||||||
|
room_id: RoomId,
|
||||||
path: StatePath
|
path: StatePath
|
||||||
},
|
},
|
||||||
PermissionAdd {
|
PermissionAdd {
|
||||||
@@ -177,6 +212,49 @@ pub enum ClientMessage {
|
|||||||
end: MessageId,
|
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)]
|
#[derive(Serialize,Deserialize)]
|
||||||
pub enum ServerError {
|
pub enum ServerError {
|
||||||
@@ -184,16 +262,22 @@ pub enum ServerError {
|
|||||||
// Server can specify the required challenge
|
// Server can specify the required challenge
|
||||||
ChallengeInvitecode,
|
ChallengeInvitecode,
|
||||||
NotAuthenticated,
|
NotAuthenticated,
|
||||||
|
AlreadyAuthenticated,
|
||||||
|
NotInChallenge
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize,Deserialize)]
|
||||||
pub enum ServerMessage {
|
pub enum ServerMessage {
|
||||||
// Returned on fetch or naturally from subscribe
|
// Returned on fetch or naturally from subscribe
|
||||||
Messages(Vec<Message>),
|
// This should be
|
||||||
|
Messages(Vec<TaggedMessage>),
|
||||||
MediaUploaded(Uuid),
|
MediaUploaded(Uuid),
|
||||||
Error(ServerError),
|
Error(ServerError),
|
||||||
// Returned both on read and from subscribe
|
// Returned on read
|
||||||
State(StateValue),
|
State(StatePath,StateValue),
|
||||||
|
// Returned on subscribe, forwards state change message to client
|
||||||
|
StateChange(TaggedMessage),
|
||||||
|
OkMessage(MessageId),
|
||||||
Ok,
|
Ok,
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-4
@@ -2,9 +2,8 @@ use serde::{Deserialize, Serialize};
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::state::{StatePath,StateValue,StatePermissionKey};
|
use crate::state::{StatePath,StateValue,StatePermissionKey};
|
||||||
use crate::message::Message;
|
|
||||||
use crate::{RoomId,User};
|
use crate::{RoomId,User};
|
||||||
use crate::client::TaggedClientMessage;
|
use crate::message::TaggedMessage;
|
||||||
// How do remote subscriptions work?
|
// How do remote subscriptions work?
|
||||||
// Server pushes subscription to remote
|
// Server pushes subscription to remote
|
||||||
// remote keeps track of list, filters on message broadcast
|
// remote keeps track of list, filters on message broadcast
|
||||||
@@ -43,11 +42,11 @@ pub enum ServerRequest {
|
|||||||
},
|
},
|
||||||
//NOTE: It doesn't make sense to forward every kind of message
|
//NOTE: It doesn't make sense to forward every kind of message
|
||||||
// But duplicating work here doesn't make sense
|
// But duplicating work here doesn't make sense
|
||||||
ForwardedMessage(TaggedClientMessage)
|
ForwardedMessage(TaggedMessage)
|
||||||
}
|
}
|
||||||
#[derive(Serialize,Deserialize)]
|
#[derive(Serialize,Deserialize)]
|
||||||
pub enum ServerResponse {
|
pub enum ServerResponse {
|
||||||
Messages(Vec<Message>),
|
Messages(Vec<TaggedMessage>),
|
||||||
Error(FederationError),
|
Error(FederationError),
|
||||||
State(StateValue),
|
State(StateValue),
|
||||||
Media(Uuid,#[serde(with = "serde_bytes")] Vec<u8>),
|
Media(Uuid,#[serde(with = "serde_bytes")] Vec<u8>),
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ pub mod state;
|
|||||||
pub mod message;
|
pub mod message;
|
||||||
|
|
||||||
// Room coordinates and originating server
|
// Room coordinates and originating server
|
||||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
#[derive(Serialize,Deserialize,Clone,Debug,Hash,PartialEq,Eq)]
|
||||||
pub struct RoomId{
|
pub struct RoomId{
|
||||||
coordinates: Vec<i64>,
|
coordinates: Vec<i64>,
|
||||||
server: Option<String>
|
server: Option<String>
|
||||||
|
|||||||
+45
-6
@@ -1,15 +1,54 @@
|
|||||||
|
use crate::RoomId;
|
||||||
|
use crate::client::ClientMessage;
|
||||||
|
use crate::state::StatePath;
|
||||||
use crate::User;
|
use crate::User;
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
pub enum VerificationError {
|
||||||
|
NoKey
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//Monotonically increasing messageID
|
//Monotonically increasing messageID
|
||||||
#[derive(Serialize,Deserialize,Debug,Clone)]
|
#[derive(Serialize,Deserialize,Debug,Clone)]
|
||||||
pub struct MessageId(u64);
|
pub struct MessageId(u64);
|
||||||
|
|
||||||
#[derive(Serialize,Deserialize,Debug,Clone)]
|
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||||
pub struct Message {
|
pub struct TaggedMessage {
|
||||||
body: String,
|
pub message: ClientMessage,
|
||||||
signature: Box<[u8]>,
|
#[serde(with="time::serde::timestamp")]
|
||||||
sender: User,
|
pub client_timestamp: OffsetDateTime,
|
||||||
timestamp: OffsetDateTime
|
#[serde(with="time::serde::timestamp")]
|
||||||
|
pub server_timestamp: OffsetDateTime,
|
||||||
|
#[serde(with = "serde_bytes")]
|
||||||
|
pub signature: Box<[u8]>,
|
||||||
|
pub user: User
|
||||||
}
|
}
|
||||||
|
impl TaggedMessage {
|
||||||
|
pub fn verify(&self) -> Result<bool,VerificationError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
// Returns room name or state path
|
||||||
|
pub fn get_relevance(&self) -> Option<Relevance> {
|
||||||
|
self.message.get_relevance()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq,Eq,Hash,Clone,Debug)]
|
||||||
|
pub enum Relevance {
|
||||||
|
Message(RoomId),
|
||||||
|
State(RoomId,StatePath),
|
||||||
|
Post(User)
|
||||||
|
}
|
||||||
|
|
||||||
|
//#[derive(Serialize,Deserialize,Debug,Clone)]
|
||||||
|
//pub struct Message {
|
||||||
|
// body: String,
|
||||||
|
// signature: Box<[u8]>,
|
||||||
|
// sender: User,
|
||||||
|
// // Used for signature check
|
||||||
|
// client_timestamp: OffsetDateTime,
|
||||||
|
// // Used for ordering messages
|
||||||
|
// server_timestamp: OffsetDateTime,
|
||||||
|
//}
|
||||||
|
|||||||
+1
-1
@@ -33,5 +33,5 @@ pub enum StatePermissionValue {
|
|||||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||||
pub struct StatePermission(StatePermissionKey,StatePermissionValue);
|
pub struct StatePermission(StatePermissionKey,StatePermissionValue);
|
||||||
|
|
||||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
#[derive(Serialize,Deserialize,Clone,Debug,Hash,PartialEq,Eq)]
|
||||||
pub struct StatePath(Vec<String>);
|
pub struct StatePath(Vec<String>);
|
||||||
|
|||||||
Reference in New Issue
Block a user