//////////////////////////////////////////////////////////////////////////////////// // VeilidChat Protocol Buffer Definitions // // * Timestamps are in microseconds (us) since epoch // * Durations are in microseconds (us) //////////////////////////////////////////////////////////////////////////////////// syntax = "proto3"; package veilidchat; import "veilid.proto"; import "dht.proto"; //////////////////////////////////////////////////////////////////////////////////// // Enumerations //////////////////////////////////////////////////////////////////////////////////// // Contact availability enum Availability { AVAILABILITY_UNSPECIFIED = 0; AVAILABILITY_OFFLINE = 1; AVAILABILITY_FREE = 2; AVAILABILITY_BUSY = 3; AVAILABILITY_AWAY = 4; } // Encryption used on secret keys enum EncryptionKeyType { ENCRYPTION_KEY_TYPE_UNSPECIFIED = 0; ENCRYPTION_KEY_TYPE_NONE = 1; ENCRYPTION_KEY_TYPE_PIN = 2; ENCRYPTION_KEY_TYPE_PASSWORD = 3; } // Scope of a chat enum Scope { // Can read chats but not send messages WATCHERS = 0; // Can send messages subject to moderation // If moderation is disabled, this is equivalent to WATCHERS MODERATED = 1; // Can send messages without moderation TALKERS = 2; // Can moderate messages sent my members if moderation is enabled MODERATORS = 3; // Can perform all actions ADMINS = 4; } //////////////////////////////////////////////////////////////////////////////////// // Attachments //////////////////////////////////////////////////////////////////////////////////// // A single attachment message Attachment { oneof kind { AttachmentMedia media = 1; } // Author signature over all attachment fields and content fields and bytes veilid.Signature signature = 2; } // A file, audio, image, or video attachment message AttachmentMedia { // MIME type of the data string mime = 1; // Title or filename string name = 2; // Pointer to the data content dht.DataReference content = 3; } //////////////////////////////////////////////////////////////////////////////////// // Chat room controls //////////////////////////////////////////////////////////////////////////////////// // Permissions of a chat message Permissions { // Parties in this scope or higher can add members to their own group or lower Scope can_add_members = 1; // Parties in this scope or higher can change the 'info' of a group Scope can_edit_info = 2; // If moderation is enabled or not. bool moderated = 3; } // The membership of a chat message Membership { // Conversation keys for parties in the 'watchers' group repeated veilid.TypedKey watchers = 1; // Conversation keys for parties in the 'moderated' group repeated veilid.TypedKey moderated = 2; // Conversation keys for parties in the 'talkers' group repeated veilid.TypedKey talkers = 3; // Conversation keys for parties in the 'moderators' group repeated veilid.TypedKey moderators = 4; // Conversation keys for parties in the 'admins' group repeated veilid.TypedKey admins = 5; } // The chat settings message ChatSettings { // Title for the chat string title = 1; // Description for the chat string description = 2; // Icon for the chat optional dht.DataReference icon = 3; // Default message expiration duration (in us) uint64 default_expiration = 4; } //////////////////////////////////////////////////////////////////////////////////// // Messages //////////////////////////////////////////////////////////////////////////////////// // A single message as part of a series of messages message Message { // A text message message Text { // Text of the message string text = 1; // Topic of the message / Content warning optional string topic = 2; // Message id replied to (author id + message id) optional bytes reply_id = 3; // Message expiration timestamp uint64 expiration = 4; // Message view limit before deletion uint32 view_limit = 5; // Attachments on the message repeated Attachment attachments = 6; } // A secret message message Secret { // Text message protobuf encrypted by a key bytes ciphertext = 1; // Secret expiration timestamp // This is the time after which an un-revealed secret will get deleted uint64 expiration = 2; } // A 'delete' control message // Deletes a set of messages by their ids message ControlDelete { repeated bytes ids = 1; } // An 'erase' control message // Deletes a set of messages from before some timestamp message ControlErase { // The latest timestamp to delete messages before // If this is zero then all messages are cleared uint64 timestamp = 1; } // A 'change settings' control message message ControlSettings { ChatSettings settings = 1; } // A 'change permissions' control message // Changes the permissions of a chat message ControlPermissions { Permissions permissions = 1; } // A 'change membership' control message // Changes the message ControlMembership { Membership membership = 1; } // A 'moderation' control message // Accepts or rejects a set of messages message ControlModeration { repeated bytes accepted_ids = 1; repeated bytes rejected_ids = 2; } // A 'read receipt' control message message ControlReadReceipt { repeated bytes read_ids = 1; } ////////////////////////////////////////////////////////////////////////// // Unique id for this author stream // Calculated from the hash of the previous message from this author bytes id = 1; // Author of the message (identity public key) veilid.TypedKey author = 2; // Time the message was sent according to sender uint64 timestamp = 3; // Message kind oneof kind { Text text = 4; Secret secret = 5; ControlDelete delete = 6; ControlErase erase = 7; ControlSettings settings = 8; ControlPermissions permissions = 9; ControlMembership membership = 10; ControlModeration moderation = 11; } // Author signature over all of the fields and attachment signatures veilid.Signature signature = 12; } // Locally stored messages for chats message ReconciledMessage { // The message as sent Message content = 1; // The timestamp the message was reconciled uint64 reconciled_time = 2; } //////////////////////////////////////////////////////////////////////////////////// // Chats //////////////////////////////////////////////////////////////////////////////////// // The means of direct communications that is synchronized between // two users. Visible and encrypted for the other party. // Includes communications for: // * Profile changes // * Identity changes // * 1-1 chat messages // * Group chat messages // // DHT Schema: SMPL(0,1,[identityPublicKey]) // DHT Key (UnicastOutbox): localConversation // DHT Secret: None // Encryption: DH(IdentityA, IdentityB) message Conversation { // Profile to publish to friend Profile profile = 1; // Identity master (JSON) to publish to friend or chat room string identity_master_json = 2; // Messages DHTLog veilid.TypedKey messages = 3; } // Either a 1-1 conversation or a group chat // Privately encrypted, this is the local user's copy of the chat message Chat { // Settings ChatSettings settings = 1; // Conversation key for this user veilid.TypedKey local_conversation_record_key = 2; // Conversation key for the other party veilid.TypedKey remote_conversation_record_key = 3; } // A group chat // Privately encrypted, this is the local user's copy of the chat message GroupChat { // Settings ChatSettings settings = 1; // Conversation key for this user veilid.TypedKey local_conversation_record_key = 2; // Conversation keys for the other parties repeated veilid.TypedKey remote_conversation_record_keys = 3; } //////////////////////////////////////////////////////////////////////////////////// // Accounts //////////////////////////////////////////////////////////////////////////////////// // Publicly shared profile information for both contacts and accounts // Contains: // Name - Friendly name // Pronouns - Pronouns of user // Icon - Little picture to represent user in contact list message Profile { // Friendy name string name = 1; // Pronouns of user string pronouns = 2; // Description of the user string about = 3; // Status/away message string status = 4; // Availability Availability availability = 5; // Avatar DHTData optional veilid.TypedKey avatar = 6; } // A record of an individual account // Pointed to by the identity account map in the identity key // // DHT Schema: DFLT(1) // DHT Private: accountSecretKey message Account { // The user's profile that gets shared with contacts Profile profile = 1; // Invisibility makes you always look 'Offline' bool invisible = 2; // Auto-away sets 'away' mode after an inactivity time uint32 auto_away_timeout_sec = 3; // The contacts DHTList for this account // DHT Private dht.OwnedDHTRecordPointer contact_list = 4; // The ContactInvitationRecord DHTShortArray for this account // DHT Private dht.OwnedDHTRecordPointer contact_invitation_records = 5; // The Chats DHTList for this account // DHT Private dht.OwnedDHTRecordPointer chat_list = 6; // The GroupChats DHTList for this account // DHT Private dht.OwnedDHTRecordPointer group_chat_list = 7; } // A record of a contact that has accepted a contact invitation // Contains a copy of the most recent remote profile as well as // a locally edited profile. // Contains a copy of the most recent identity from the contact's // Master identity dht key // // Stored in ContactList DHTList message Contact { // Friend's profile as locally edited Profile edited_profile = 1; // Copy of friend's profile from remote conversation Profile remote_profile = 2; // Copy of friend's IdentityMaster in JSON from remote conversation string identity_master_json = 3; // Copy of friend's most recent identity public key from their identityMaster veilid.TypedKey identity_public_key = 4; // Remote conversation key to sync from friend veilid.TypedKey remote_conversation_record_key = 5; // Our conversation key for friend to sync veilid.TypedKey local_conversation_record_key = 6; // Show availability to this contact bool show_availability = 7; } //////////////////////////////////////////////////////////////////////////////////// // Invitations //////////////////////////////////////////////////////////////////////////////////// // Invitation that is shared for VeilidChat contact connections // serialized to QR code or data blob, not send over DHT, out of band. // Writer secret is unique to this invitation. Writer public key is in the ContactRequestPrivate // in the ContactRequestInbox subkey 0 DHT key message ContactInvitation { // Contact request DHT record key veilid.TypedKey contact_request_inbox_key = 1; // Writer secret key bytes possibly encrypted with nonce appended bytes writer_secret = 2; } // Signature of invitation with identity message SignedContactInvitation { // The serialized bytes for the contact invitation bytes contact_invitation = 1; // The signature of the contact_invitation bytes with the identity veilid.Signature identity_signature = 2; } // Contact request unicastinbox on the DHT // DHTSchema: SMPL 1 owner key, 1 writer key symmetrically encrypted with writer secret message ContactRequest { // The kind of encryption used on the unicastinbox writer key EncryptionKeyType encryption_key_type = 1; // The private part encoded and symmetrically encrypted with the unicastinbox writer secret bytes private = 2; } // The private part of a possibly encrypted contact request // Symmetrically encrypted with writer secret message ContactRequestPrivate { // Writer public key for signing writes to contact request unicastinbox veilid.CryptoKey writer_key = 1; // Snapshot of profile Profile profile = 2; // Identity master DHT record key veilid.TypedKey identity_master_record_key = 3; // Local chat DHT record key veilid.TypedKey chat_record_key = 4; // Expiration timestamp uint64 expiration = 5; } // To accept or reject a contact request, fill this out and send to the ContactRequest unicastinbox message ContactResponse { // Accept or reject bool accept = 1; // Remote identity master DHT record key veilid.TypedKey identity_master_record_key = 2; // Remote chat DHT record key if accepted veilid.TypedKey remote_conversation_record_key = 3; } // Signature of response with identity // Symmetrically encrypted with writer secret message SignedContactResponse { // Serialized bytes for ContactResponse bytes contact_response = 1; // Signature of the contact_accept bytes with the identity veilid.Signature identity_signature = 2; } // Contact request record kept in Account DHTList to keep track of extant contact invitations message ContactInvitationRecord { // Contact request unicastinbox DHT record key (parent is accountkey) dht.OwnedDHTRecordPointer contact_request_inbox = 1; // Writer key sent to contact for the contact_request_inbox smpl inbox subkey veilid.CryptoKey writer_key = 2; // Writer secret sent encrypted in the invitation veilid.CryptoKey writer_secret = 3; // Local chat DHT record key (parent is accountkey, will be moved to Contact if accepted) veilid.TypedKey local_conversation_record_key = 4; // Expiration timestamp uint64 expiration = 5; // A copy of the raw SignedContactInvitation invitation bytes post-encryption and signing bytes invitation = 6; // The message sent along with the invitation string message = 7; }