Initial commit
This commit is contained in:
+194
@@ -0,0 +1,194 @@
|
||||
use uuid::Uuid;
|
||||
use crate::message::{MessageId,Message};
|
||||
use crate::state::{StateType,StateValue,StatePath,StatePermission,StatePermissionKey};
|
||||
use crate::{RoomId,Group,Role,User,GroupPower};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
//StatePath [String]
|
||||
//octal is fine for now
|
||||
//maybe do ACL late???
|
||||
//StatePermissions (u8,u8,u8)
|
||||
//RoomId [i64]
|
||||
|
||||
|
||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||
pub struct TaggedClientMessage {
|
||||
message: ClientMessage,
|
||||
#[serde(with = "serde_bytes")]
|
||||
signature: Box<[u8]>,
|
||||
user: User
|
||||
}
|
||||
|
||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||
pub struct SignedClientMessage {
|
||||
message: ClientMessage,
|
||||
// Should I enforce this being a ecdsa signature?
|
||||
#[serde(with = "serde_bytes")]
|
||||
signature: Box<[u8]>
|
||||
}
|
||||
|
||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||
pub enum ClientMessage {
|
||||
|
||||
Auth{
|
||||
username: String,
|
||||
password: String
|
||||
},
|
||||
// Maybe ask for email too? Or a potential invite code
|
||||
UserCreate {
|
||||
username: String,
|
||||
password: String,
|
||||
},
|
||||
// Used to require accounts to complete some kind of challenge. Simplest
|
||||
// is giving a password/invite code to create an account or join a room
|
||||
ChallengeAnswer {
|
||||
response: String
|
||||
},
|
||||
// TODO I still dont have key management commands
|
||||
|
||||
// Should it be one message type or mutiple?
|
||||
Message {
|
||||
body: String,
|
||||
},
|
||||
// Private message/invite mechanism
|
||||
MessagePost {
|
||||
body: String,
|
||||
user: User
|
||||
},
|
||||
// Replace the body of the message with a new one
|
||||
MessageEdit {
|
||||
body: String,
|
||||
id: MessageId
|
||||
},
|
||||
MessageDelete {
|
||||
id: MessageId
|
||||
},
|
||||
// State Actions
|
||||
StateCreate {
|
||||
path: StatePath,
|
||||
ty: StateType,
|
||||
permissions: Option<Vec<StatePermission>>
|
||||
},
|
||||
StateWrite {
|
||||
path: StatePath,
|
||||
content: StateValue
|
||||
},
|
||||
StateDelete {
|
||||
path: StatePath,
|
||||
},
|
||||
StateAppend {
|
||||
path: StatePath,
|
||||
content: StateValue
|
||||
},
|
||||
StateMove {
|
||||
path: StatePath,
|
||||
target: StatePath,
|
||||
},
|
||||
StateRead {
|
||||
path: StatePath
|
||||
},
|
||||
PermissionAdd {
|
||||
permission: StatePermission
|
||||
},
|
||||
PermissionDelete {
|
||||
permission: StatePermissionKey
|
||||
},
|
||||
// Groups really should have a way to add permissions by user
|
||||
// specifically for who can join or invite others
|
||||
//
|
||||
// Maybe make a group -> role -> member hierarchy?
|
||||
//
|
||||
//
|
||||
// Could always do this through a bot that owns a group??
|
||||
GroupCreate {
|
||||
group: Group,
|
||||
users: Vec<User>
|
||||
},
|
||||
// Only the creator of a group or a server admin can delete groups
|
||||
GroupDelete {
|
||||
group: Group
|
||||
},
|
||||
// Only the creator of a group or a server admin can delete groups
|
||||
// same with adding, though there should be a way to add group officers
|
||||
// at some point
|
||||
GroupUserAdd {
|
||||
group: Group,
|
||||
users: Vec<User>
|
||||
},
|
||||
GroupUserRemove {
|
||||
group: Group,
|
||||
users: Vec<User>
|
||||
},
|
||||
GroupRoleCreate {
|
||||
group: Group,
|
||||
role: Role
|
||||
},
|
||||
GroupRoleDelete {
|
||||
group: Group,
|
||||
role: Role
|
||||
},
|
||||
GroupRoleUserAdd {
|
||||
group: Group,
|
||||
role: Role,
|
||||
users: Vec<User>
|
||||
},
|
||||
GroupRoleUserRemove {
|
||||
group: Group,
|
||||
role: Role,
|
||||
users: Vec<User>
|
||||
},
|
||||
// Should work like discord roles
|
||||
// Can control who can invite to the group
|
||||
// Can be used with permissions to make rooms that are private for individual roles
|
||||
GroupRolePowerAdd {
|
||||
group: Group,
|
||||
role: Role,
|
||||
power: GroupPower
|
||||
},
|
||||
GroupRolePowerRemove {
|
||||
group: Group,
|
||||
role: Role,
|
||||
power: GroupPower
|
||||
},
|
||||
// Returns an ID to use for message sending
|
||||
// The server can potentially use the current username to associate media uploads
|
||||
// with users
|
||||
MediaUpload {
|
||||
#[serde(with = "serde_bytes")]
|
||||
bytes: Vec<u8>
|
||||
},
|
||||
// Join and subscribe
|
||||
Join {
|
||||
room_id: RoomId,
|
||||
},
|
||||
SubscribeMessages {
|
||||
room_id: RoomId,
|
||||
},
|
||||
SubscribeState {
|
||||
room_id: RoomId,
|
||||
state: StatePath
|
||||
},
|
||||
FetchMessages {
|
||||
count: u64,
|
||||
end: MessageId,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize,Deserialize)]
|
||||
enum ServerError {
|
||||
InvalidPermission,
|
||||
// Server can specify the required challenge
|
||||
ChallengeInvitecode,
|
||||
|
||||
}
|
||||
|
||||
#[derive(Serialize,Deserialize)]
|
||||
enum ServerMessage {
|
||||
// Returned on fetch or naturally from subscribe
|
||||
Messages(Vec<Message>),
|
||||
MediaUploaded(Uuid),
|
||||
Error(ServerError),
|
||||
// Returned both on read and from subscribe
|
||||
State(StateValue),
|
||||
Ok,
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::state::{StatePath,StateValue,StatePermissionKey};
|
||||
use crate::message::Message;
|
||||
use crate::{RoomId,User};
|
||||
use crate::client::TaggedClientMessage;
|
||||
// How do remote subscriptions work?
|
||||
// Server pushes subscription to remote
|
||||
// remote keeps track of list, filters on message broadcast
|
||||
// forwards message
|
||||
// local server sends over local channel
|
||||
// local server checks for message ack
|
||||
// if no acks for N times then subscription is cancelled
|
||||
// NOTE: should acks be sent by the client??
|
||||
// NOTE 2: Should they be sent by the server to avoid traffic multiplication attacks?
|
||||
#[derive(Serialize,Deserialize)]
|
||||
pub enum ServerRequest {
|
||||
SubscribeMessages {
|
||||
room_id: RoomId,
|
||||
user: User,
|
||||
|
||||
},
|
||||
UnsubscribeMessages {
|
||||
room_id: RoomId
|
||||
},
|
||||
SubscribeState {
|
||||
room_id: RoomId,
|
||||
user: User,
|
||||
state: StatePath
|
||||
},
|
||||
UnsubscribeState {
|
||||
room_id: RoomId,
|
||||
state: StatePath
|
||||
},
|
||||
FetchRemoteMedia {
|
||||
id: Uuid
|
||||
},
|
||||
// Check to see if a user is in any of the given groups on the remote server
|
||||
CheckGroups {
|
||||
user: User,
|
||||
groups: Vec<StatePermissionKey>
|
||||
},
|
||||
//NOTE: It doesn't make sense to forward every kind of message
|
||||
// But duplicating work here doesn't make sense
|
||||
ForwardedMessage(TaggedClientMessage)
|
||||
}
|
||||
#[derive(Serialize,Deserialize)]
|
||||
pub enum ServerResponse {
|
||||
Messages(Vec<Message>),
|
||||
Error(FederationError),
|
||||
State(StateValue),
|
||||
Media(Uuid,#[serde(with = "serde_bytes")] Vec<u8>),
|
||||
ValidGroups(User,Vec<StatePermissionKey>)
|
||||
}
|
||||
|
||||
#[derive(Serialize,Deserialize)]
|
||||
pub enum FederationError {
|
||||
InvalidPermission,
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
use serde::{Deserialize,Serialize};
|
||||
|
||||
pub mod client;
|
||||
pub mod federation;
|
||||
pub mod state;
|
||||
pub mod message;
|
||||
|
||||
// Room coordinates and originating server
|
||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||
pub struct RoomId{
|
||||
coordinates: Vec<i64>,
|
||||
server: Option<String>
|
||||
}
|
||||
|
||||
#[derive(Serialize,Deserialize,Clone,Hash,Eq,PartialEq,Debug)]
|
||||
pub struct User {
|
||||
name: String,
|
||||
// Should be a fqdn probably, dunno if its worth enforcing that here
|
||||
server: String
|
||||
}
|
||||
|
||||
#[derive(Serialize,Deserialize,Clone,Hash,Eq,PartialEq,Debug)]
|
||||
pub struct Group {
|
||||
name: String,
|
||||
// Should be a fqdn probably, dunno if its worth enforcing that here
|
||||
server: String
|
||||
}
|
||||
|
||||
// Might want to standardize this, idk which powers would be useful though
|
||||
// should be things like who can manage roles, group members, and more specific
|
||||
// stuff like who can post images or join different rooms
|
||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||
pub struct GroupPower(String);
|
||||
|
||||
#[derive(Serialize,Deserialize,Clone,Hash,Eq,PartialEq,Debug)]
|
||||
pub struct Role {
|
||||
name: String
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
use crate::User;
|
||||
use time::OffsetDateTime;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
//Monotonically increasing messageID
|
||||
#[derive(Serialize,Deserialize,Debug,Clone)]
|
||||
pub struct MessageId(u64);
|
||||
|
||||
#[derive(Serialize,Deserialize,Debug,Clone)]
|
||||
pub struct Message {
|
||||
body: String,
|
||||
signature: Box<[u8]>,
|
||||
sender: User,
|
||||
timestamp: OffsetDateTime
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
use serde::{Deserialize,Serialize};
|
||||
use crate::{User,Group,Role};
|
||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||
pub enum StateValue {
|
||||
String(String),
|
||||
Binary(Vec<u8>)
|
||||
}
|
||||
#[derive(Serialize,Deserialize,Debug,Clone)]
|
||||
pub enum StateType {
|
||||
Directory,
|
||||
String,
|
||||
Binary
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize,Deserialize,Clone,Hash,Eq,PartialEq,Debug)]
|
||||
pub enum StatePermissionKey {
|
||||
User(User),
|
||||
Group(Group),
|
||||
Role(Group,Role),
|
||||
//This is a string for now but could get compiled later into an actual regex
|
||||
//should be able to match on name and server
|
||||
UserRegex(String)
|
||||
}
|
||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||
pub enum StatePermissionValue {
|
||||
None,
|
||||
Read,
|
||||
ReadWrite,
|
||||
// Can only set value, does not allow appending
|
||||
Write
|
||||
}
|
||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||
pub struct StatePermission(StatePermissionKey,StatePermissionValue);
|
||||
|
||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||
pub struct StatePath(Vec<String>);
|
||||
Reference in New Issue
Block a user