@namespace("chat.1") @compression_type("gzip") protocol remote { import idl "../gregor1" as gregor1; import idl "../keybase1" as keybase1; record MessageBoxed { // This was not present in most V1 messages. MessageBoxedVersion version; // [V1, V2]: Only set when returned from the server; on the way up to the // server, they are null. union { null, MessageServerHeader } serverHeader; // [V1, V2]: MessageClientHeader is needed by clients to get keys via TLF name. // The server needs it as well for sender uid, device id. MessageClientHeader clientHeader; // V1: Encrypted HeaderPlaintext // V2: SignEncrypted HeaderPlaintext (using derived encryption key) SealedData headerCiphertext; // V1: Encrypted BodyPlaintext // V2: Encrypted BodyPlaintext (using derived key) EncryptedData bodyCiphertext; // V1: Missing // V2: KID of the signing key used on headerSealed. // Used to open and verify headerSealed. // Must be asserted to belong to the sender when unboxing. bytes verifyKey; // [V1, V2]: Key generation of the encryption key int keyGeneration; } enum MessageBoxedVersion { // 0 exists from before the version field. It means V1. VNONE_0, // V1: Encrypted header and body. // Hash of body inside header. // Sig of header inside header. V1_1, // V2: SignEncrypted header, encrypted body. // Hash of body inside header. V2_2, // V3: Exactly as V2, except that the message // may be exploding, meaning the body is // encrypted with a separate ephemeral key. V3_3, // V4: Exactly as V3, except if pairwise MACs are included, // then the sender signing key is a dummy. V4_4 } record ThreadViewBoxed { array messages; union { null, Pagination } pagination; } record GetInboxRemoteRes { InboxView inbox; union { null, RateLimit } rateLimit; } record GetInboxByTLFIDRemoteRes { array convs; union { null, RateLimit } rateLimit; } record GetThreadRemoteRes { ThreadViewBoxed thread; ConversationMembersType membersType; keybase1.TLFVisibility visibility; union { null, RateLimit } rateLimit; } record GetConversationMetadataRemoteRes { Conversation conv; union { null, RateLimit } rateLimit; } record PostRemoteRes { MessageServerHeader msgHeader; union { null, RateLimit } rateLimit; } record NewConversationRemoteRes { ConversationID convID; boolean createdComplexTeam; union { null, RateLimit } rateLimit; } record GetMessagesRemoteRes { array msgs; union { null, RateLimit } rateLimit; } record MarkAsReadRes { union { null, RateLimit } rateLimit; } record SetConversationStatusRes { union { null, RateLimit } rateLimit; } record GetPublicConversationsRes { array conversations; union { null, RateLimit } rateLimit; } @timeout_msec(300000) // 5 minutes GetInboxRemoteRes getInboxRemote(InboxVers vers, union { null, GetInboxQuery } query, union { null, Pagination } pagination); GetThreadRemoteRes getThreadRemote(ConversationID conversationID, GetThreadReason reason, union { null, GetThreadQuery } query, union { null, Pagination } pagination); record GetUnreadlineRemoteRes { union { null, MessageID } unreadlineID; union { null, RateLimit } rateLimit; } GetUnreadlineRemoteRes getUnreadlineRemote(ConversationID convID, MessageID readMsgID); GetPublicConversationsRes getPublicConversations(TLFID tlfID, TopicType topicType, boolean summarizeMaxMsgs); enum ChannelMention { NONE_0, ALL_1, HERE_2 } PostRemoteRes postRemote( ConversationID conversationID, MessageBoxed messageBoxed, array atMentions, ChannelMention channelMention, union { null, TopicNameState } topicNameState, // Add any atMentions to the conversation automatically with the given // status union { null, ConversationMemberStatus } joinMentionsAs ); NewConversationRemoteRes newConversationRemote(ConversationIDTriple idTriple); // on duplication of idTriple, and error is returned and the conversation ID of the existing conversation is returned. @lint("ignore") NewConversationRemoteRes newConversationRemote2(ConversationIDTriple idTriple, MessageBoxed TLFMessage, ConversationMembersType membersType, union { null, TopicNameState } topicNameState, union { null, ConversationID } memberSourceConv, union { null, RetentionPolicy } retentionPolicy); GetMessagesRemoteRes getMessagesRemote(ConversationID conversationID, union { null, GetThreadReason } threadReason, array messageIDs); MarkAsReadRes markAsRead(ConversationID conversationID, MessageID msgID); @lint("ignore") SetConversationStatusRes SetConversationStatus(ConversationID conversationID, ConversationStatus status); @lint("ignore") UnreadUpdateFull GetUnreadUpdateFull(InboxVers inboxVers); // The full set of updates of all convs in a single user's inbox record UnreadUpdateFull { // Set if this update should be ignored because the requester was already up to date boolean ignore; // The inbox version that this full update was derived from InboxVers inboxVers; // Inbox sync status SyncInboxResType inboxSyncStatus; array updates; } record S3Params { string bucket; string objectKey; string accessKey; string acl; string regionName; string regionEndpoint; string regionBucketEndpoint; } // getS3Params returns S3 params that the client needs to make S3 // requests. S3Params getS3Params(ConversationID conversationID); // s3Sign signs a payload for S3 requests. bytes s3Sign(int version, bytes payload); // Get the inbox version for a user InboxVers getInboxVersion(gregor1.UID uid); record SyncIncrementalRes { InboxVers vers; array convs; } record ServerCacheVers { int inboxVers; int bodiesVers; } variant SyncInboxRes switch (SyncInboxResType typ) { case CURRENT: void; case INCREMENTAL: SyncIncrementalRes; case CLEAR: void; } // (DEPRECATED) Sync down the inbox given a current version SyncInboxRes syncInbox(InboxVers vers); record SyncChatRes { ServerCacheVers cacheVers; SyncInboxRes inboxRes; } SyncChatRes syncChat(InboxVers vers, boolean summarizeMaxMsgs, InboxParticipantsMode participantsMode); enum SyncAllProtVers { V0_0, V1_1 } enum SyncAllNotificationType { STATE_0, INCREMENTAL_1 } variant SyncAllNotificationRes switch(SyncAllNotificationType typ) { case STATE: gregor1.State; case INCREMENTAL: gregor1.SyncResult; } record SyncAllResult { gregor1.AuthResult auth; SyncChatRes chat; SyncAllNotificationRes notification; UnreadUpdateFull badge; } @compression_type("msgpackzip") SyncAllResult syncAll(gregor1.UID uid, gregor1.DeviceID deviceID, gregor1.SessionToken session, InboxVers inboxVers, gregor1.Time ctime, boolean fresh, SyncAllProtVers protVers, string hostName, boolean summarizeMaxMsgs, InboxParticipantsMode participantsMode); // tlfFinalize is an endpoint for kbfstlfd to notify Gregor that a TLF ID has been finalized. // Gregor keeps an internal record of these TLF IDs, so that it can always return the latest // conversation per TLF ID on GetInboxRemote. void tlfFinalize(TLFID tlfID, string resetUser, string resetDate, gregor1.Time resetTimestamp, string resetFull, union { null, keybase1.UID } resetUID); void tlfResolve(TLFID tlfID, array resolvedWriters, array resolvedReaders); // Typing endpoints void updateTypingRemote(gregor1.UID uid, gregor1.DeviceID deviceID, ConversationID convID, boolean typing); // Channel endpoints record JoinLeaveConversationRemoteRes { union { null, RateLimit } rateLimit; } JoinLeaveConversationRemoteRes joinConversation(ConversationID convID); JoinLeaveConversationRemoteRes leaveConversation(ConversationID convID); JoinLeaveConversationRemoteRes previewConversation(ConversationID convID); record DeleteConversationRemoteRes { union { null, RateLimit } rateLimit; } DeleteConversationRemoteRes deleteConversation(ConversationID convID); record GetMessageBeforeRes { MessageID msgID; union { null, RateLimit } rateLimit; } GetMessageBeforeRes getMessageBefore(ConversationID convID, gregor1.DurationSec age); record GetTLFConversationsRes { array conversations; union { null, RateLimit } rateLimit; } GetTLFConversationsRes getTLFConversations(TLFID tlfID, TopicType topicType, boolean summarizeMaxMsgs); // Chat notification configuration endpoint. Does not need to be complete, just a delta on the // currently configured settings. record SetAppNotificationSettingsRes { union { null, RateLimit } rateLimit; } SetAppNotificationSettingsRes setAppNotificationSettings(ConversationID convID, ConversationNotificationInfo settings); void setGlobalAppNotificationSettings(GlobalAppNotificationSettings settings); GlobalAppNotificationSettings getGlobalAppNotificationSettings(); // Endpoint to indicate a high priority push notification has been processed @compression_type("none") void remoteNotificationSuccessful(gregor1.SessionToken authToken, array companionPushIDs); record SetRetentionRes { union { null, RateLimit } rateLimit; } // sweepChannel should be 0 except for in certain tests. SetRetentionRes setConvRetention(ConversationID convID, RetentionPolicy policy, uint64 sweepChannel); SetRetentionRes setTeamRetention(keybase1.TeamID teamID, RetentionPolicy policy, uint64 sweepChannel); record SetConvMinWriterRoleRes { union { null, RateLimit } rateLimit; } SetConvMinWriterRoleRes setConvMinWriterRole(ConversationID convID, keybase1.TeamRole role); // Used only for testing. record SweepRes { boolean foundTask; boolean deletedMessages; Expunge expunge; } SweepRes retentionSweepConv(ConversationID convID); void upgradeKBFSToImpteam(TLFID tlfID, keybase1.TeamID teamID); // Share extension void registerSharePost(ConversationID convID, gregor1.DeviceID deviceID, OutboxID outboxID); void failSharePost(ConversationID convID, gregor1.DeviceID deviceID, OutboxID outboxID); // Message an entire conv with an arbitrary Gregor message (server-to-server only) void broadcastGregorMessageToConv(ConversationID convID, gregor1.Message msg); // Get the team ID of a conversation (server-to-server only) // Returns null if the conversation no simply-associated team ID (legacy kbfs-backed convs) union { null, keybase1.TeamID } teamIDOfConv(ConversationID convID); record ServerNowRes { union { null, RateLimit } rateLimit; gregor1.Time now; } ServerNowRes serverNow(); // Support for receiving third party API keys from the server enum ExternalAPIKeyTyp { GOOGLEMAPS_0, GIPHY_1 } variant ExternalAPIKey switch(ExternalAPIKeyTyp typ) { case GOOGLEMAPS: string; case GIPHY: string; } array getExternalAPIKeys(array typs); // Bot commands @typedef("uint64") @lint("ignore") record BotInfoHashVers {} @typedef("uint64") @lint("ignore") record CommandConvVers {} record RemoteBotCommandsAdvertisementPublic { ConversationID convID; } record RemoteBotCommandsAdvertisementTLFID { ConversationID convID; TLFID tlfID; } variant RemoteBotCommandsAdvertisement switch(BotCommandsAdvertisementTyp typ) { case PUBLIC: RemoteBotCommandsAdvertisementPublic; case TLFID_MEMBERS: RemoteBotCommandsAdvertisementTLFID; case TLFID_CONVS: RemoteBotCommandsAdvertisementTLFID; } record BotCommandConv { gregor1.UID uid; keybase1.TeamRole untrustedTeamRole; ConversationID convID; CommandConvVers vers; gregor1.Time mtime; } record BotInfo { // server version controls busting client caches. BotInfoHashVers serverHashVers; // client version determines the hash algorithm. BotInfoHashVers clientHashVers; array commandConvs; } record AdvertiseBotCommandsRes { union { null, RateLimit } rateLimit; } record ClearBotCommandsRes { union { null, RateLimit } rateLimit; } AdvertiseBotCommandsRes advertiseBotCommands(array ads); ClearBotCommandsRes clearBotCommands(); enum BotInfoResponseTyp { UPTODATE_0, INFO_1 } variant BotInfoResponse switch (BotInfoResponseTyp typ) { case UPTODATE: void; case INFO: BotInfo; } record GetBotInfoRes { BotInfoResponse response; union { null, RateLimit } rateLimit; } @typedef("bytes") record BotInfoHash {} GetBotInfoRes getBotInfo(ConversationID convID, BotInfoHash infoHash, BotInfoHashVers clientHashVers); record GetDefaultTeamChannelsRes { array convs; union { null, RateLimit } rateLimit; } GetDefaultTeamChannelsRes getDefaultTeamChannels(keybase1.TeamID teamID); record SetDefaultTeamChannelsRes { union { null, RateLimit } rateLimit; } SetDefaultTeamChannelsRes setDefaultTeamChannels(keybase1.TeamID teamID, array convs); record GetRecentJoinsRes { int numJoins; union { null, RateLimit } rateLimit; } GetRecentJoinsRes getRecentJoins(ConversationID convID); record RefreshParticipantsRemoteRes { boolean hashMatch; array uids; string hash; union { null, RateLimit } rateLimit; } RefreshParticipantsRemoteRes refreshParticipantsRemote(ConversationID convID, string hash); record GetLastActiveAtRes { gregor1.Time lastActiveAt; union { null, RateLimit } rateLimit; } GetLastActiveAtRes getLastActiveAt(keybase1.TeamID teamID, gregor1.UID uid); }