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
}