namespace RelayShared.Services; //TODO: review name of file, potentially rename for Encryption services rather than sockets /// /// The "data plane" wire types for the WebSocket protocol. /// /// Every type here carries a SignalType discriminator so a generic JsonDocument peek /// can identify the variant. The server dispatches on SignalType in ChatSocketBehavior.OnMessage; /// the client dispatches on it in RelaySocketClient.OnMessage. /// /// Encrypted payloads share a uniform 4-tuple shape: (CipherText, Nonce, Tag, EncryptedKey). /// That tuple is hybrid RSA+AES-GCM: EncryptedKey is the per-message AES key wrapped with the /// recipient's RSA public key; CipherText/Nonce/Tag are the AES-GCM ciphertext, nonce, and /// authentication tag for the actual JSON-serialised ChatMessageContent. /// public sealed class SocketRtcSignalMessage { /// Always SignalType.EncryptedSignal in flight. public SignalType Type { get; set; } /// Username of the user generating the SDP/ICE signal. public string SenderUsername { get; set; } = string.Empty; /// The voice channel this signal belongs to. public string ChannelId { get; set; } = string.Empty; /// Base64 AES-GCM ciphertext of the JSON-serialised RtcSignalMessage. public string CipherText { get; set; } = string.Empty; /// Base64 AES-GCM 96-bit nonce. public string Nonce { get; set; } = string.Empty; /// Base64 AES-GCM 128-bit authentication tag. public string Tag { get; set; } = string.Empty; /// Base64 RSA-OAEP-encrypted AES key (encrypted with recipient's public key). public string EncryptedKey { get; set; } = string.Empty; } /// /// The workhorse envelope for chat messages and message lifecycle events. /// Used for both directions and for new sends / edits / delete tombstones. /// public sealed class SocketEncryptedMessage { /// /// EncryptedChat (server→client), ClientEncryptedChat (client→server new message), /// ClientEditMessage / ClientDeleteMessage (client→server lifecycle), MessageEdited (server→client). /// public SignalType Type { get; set; } = SignalType.EncryptedChat; /// Surreal record id (e.g. "channel_messages:abc"). Populated by the server on outbound delivery. public string MessageId { get; set; } = string.Empty; /// Who wrote the message. public string SenderUsername { get; set; } = string.Empty; /// Who this specific delivery is encrypted for. Different per recipient on the same logical message. public string RecipientUsername { get; set; } = string.Empty; /// The channel the message belongs to. public string ChannelId { get; set; } = string.Empty; /// Base64 AES-GCM ciphertext of the JSON-serialised ChatMessageContent. Empty on tombstone deliveries. public string CipherText { get; set; } = string.Empty; /// Base64 AES-GCM 96-bit nonce. public string Nonce { get; set; } = string.Empty; /// Base64 AES-GCM 128-bit authentication tag. public string Tag { get; set; } = string.Empty; /// Base64 RSA-OAEP-encrypted AES key (encrypted with recipient's public key on outbound, server's on inbound). public string EncryptedKey { get; set; } = string.Empty; /// True when this message has been edited at least once. Drives the (edited) footer in the bubble. public bool IsEdited { get; set; } /// True for tombstone deliveries (history only). Client renders a placeholder; no decryption is attempted. public bool IsDeleted { get; set; } } /// /// Server-broadcast tombstone fired the moment a message is deleted. Carries no content — /// recipients use MessageId to find the existing bubble and swap it to a "deleted" placeholder. /// public sealed class SocketMessageDeletedEvent { public SignalType Type { get; set; } = SignalType.MessageDeleted; /// The message being tombstoned. public string MessageId { get; set; } = string.Empty; /// Channel scope — clients that aren't viewing this channel can defer the bubble update. public string ChannelId { get; set; } = string.Empty; } /// /// "{Username} is typing…" hint. Server forwards to every connected member except the sender. /// Client auto-clears the indicator 3 seconds after the last such event. /// public sealed class SocketTypingEvent { public SignalType Type { get; set; } = SignalType.TypingIndicator; /// Who is typing. public string Username { get; set; } = string.Empty; /// Which channel they're typing in. Clients ignore events for channels they're not viewing. public string ChannelId { get; set; } = string.Empty; } /// One historical version of an edited message, re-encrypted for the requester. public sealed class SocketEditHistoryEntry { /// Base64 AES-GCM ciphertext of the JSON-serialised previous ChatMessageContent. public string CipherText { get; set; } = string.Empty; public string Nonce { get; set; } = string.Empty; public string Tag { get; set; } = string.Empty; /// Base64 RSA-OAEP-encrypted AES key (encrypted with requester's public key). public string EncryptedKey { get; set; } = string.Empty; /// When this version was the current text (i.e. when it was replaced). public DateTime EditedAt { get; set; } } /// Server reply to a GetEditHistory request. Entries are ordered oldest→newest. public sealed class SocketEditHistoryResponse { public SignalType Type { get; set; } = SignalType.EditHistory; /// Which message this history is for. public string MessageId { get; set; } = string.Empty; /// Every previous version of the message. Empty if the message has never been edited. public List Entries { get; set; } = []; } /// /// Server-to-client delivery of the server's public RSA key. Sent once per session in /// response to WsAction.GetServerKey. Clients cache this for all outbound encryption. /// public sealed class ServerPublicKeyMessage { public SignalType Type { get; set; } = SignalType.ServerPublicKey; /// Base64 SubjectPublicKeyInfo (DER) of the server's RSA public key. public string PublicKey { get; set; } = string.Empty; } /// The wire discriminator for every data-plane Socket*Message. public enum SignalType { // RTC SDP/ICE wire types (used by the WebView RTC engine, not handled directly here) Offer, Answer, Candidate, OfferUpdated, AnswerUpdated, CandidateAdded, CallLeft, /// Server→client: paginated channel list (SocketChannelList). ChannelList, /// Server→client: ServerPublicKeyMessage delivery. ServerPublicKey, /// Bidirectional: encrypted RTC SDP/ICE signal (SocketRtcSignalMessage). EncryptedSignal, /// Server→client: delivered chat message (SocketEncryptedMessage). EncryptedChat, /// Client→server: new chat message send (SocketEncryptedMessage). ClientEncryptedChat, /// Client→server: request to edit own message (SocketEncryptedMessage with new content). ClientEditMessage, /// Client→server: request to delete own message (SocketEncryptedMessage with only MessageId). ClientDeleteMessage, /// Server→clients: edit broadcast carrying re-encrypted new content (SocketEncryptedMessage). MessageEdited, /// Server→clients: deletion tombstone (SocketMessageDeletedEvent). MessageDeleted, /// Server→peers: typing indicator (SocketTypingEvent). TypingIndicator, /// Server→requester: edit-history response (SocketEditHistoryResponse). EditHistory }