mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-08-14 04:59:56 +00:00
core: support contact addresses with DR keys, service requests (#7310)
* core: use double ratchet keys in contact address (#7278) * core: use double ratchet keys in contact address * use PQ from the first message * query plans * update simplexmq * api to rotate keys, option to show full links in CLI * shorter description * ui: add error parameters * disable DR in addresses * core: parameter for create address command to configure ratchet keys * add pqRatchet param to address-related commands * query plan * fix parser * fix kotlin --------- Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com> * core: contact request rejection and service requests (#7292) * update simplexmq * implement service requests and rejections * tests * migration * fix migration * add api event and response * bot api, postgres migration * nix shas * bot types, rename property * update bot type * sign service requests * update bots api * query plan * update plan * update simplexmq * fix test, update bot api * fix bot api * resolve name for service request * refactor --------- Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com> * update simplexmq * update simplexmq * test delays --------- Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
This commit is contained in:
co-authored by
Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
parent
61012d208e
commit
e1a349b90f
@@ -13,10 +13,11 @@ from . import _responses as CR
|
||||
# Network usage: interactive.
|
||||
class APICreateMyAddress(TypedDict):
|
||||
userId: int # int64
|
||||
pqRatchet: NotRequired[bool]
|
||||
|
||||
|
||||
def APICreateMyAddress_cmd_string(self: APICreateMyAddress) -> str:
|
||||
return '/_address ' + str(self['userId'])
|
||||
return '/_address ' + str(self['userId']) + ((' pq_ratchet=' + ('on' if self.get('pqRatchet') else 'off')) if self.get('pqRatchet') is not None else '')
|
||||
|
||||
APICreateMyAddress_Response = CR.UserContactLinkCreated | CR.ChatCmdError
|
||||
|
||||
@@ -62,11 +63,12 @@ APISetProfileAddress_Response = CR.UserProfileUpdated | CR.ChatCmdError
|
||||
# Network usage: interactive.
|
||||
class APISetAddressSettings(TypedDict):
|
||||
userId: int # int64
|
||||
pqRatchet: NotRequired[bool]
|
||||
settings: "T.AddressSettings"
|
||||
|
||||
|
||||
def APISetAddressSettings_cmd_string(self: APISetAddressSettings) -> str:
|
||||
return '/_address_settings ' + str(self['userId']) + ' ' + json.dumps(self['settings'])
|
||||
return '/_address_settings ' + str(self['userId']) + ((' pq_ratchet=' + ('on' if self.get('pqRatchet') else 'off')) if self.get('pqRatchet') is not None else '') + ' ' + json.dumps(self['settings'])
|
||||
|
||||
APISetAddressSettings_Response = CR.UserContactLinkUpdated | CR.ChatCmdError
|
||||
|
||||
@@ -493,6 +495,7 @@ APIAcceptContact_Response = CR.AcceptingContactRequest | CR.ChatCmdError
|
||||
# Network usage: no.
|
||||
class APIRejectContact(TypedDict):
|
||||
contactReqId: int # int64
|
||||
notify: bool
|
||||
|
||||
|
||||
def APIRejectContact_cmd_string(self: APIRejectContact) -> str:
|
||||
@@ -689,6 +692,23 @@ def APISetContactPrefs_cmd_string(self: APISetContactPrefs) -> str:
|
||||
APISetContactPrefs_Response = CR.ContactPrefsUpdated | CR.ChatCmdError
|
||||
|
||||
|
||||
# Service commands
|
||||
# Bots with a double ratchet address can answer service requests.
|
||||
|
||||
# Send a reply to a received service request. Returns the connection ID that correlates the reply delivery event.
|
||||
# Network usage: background.
|
||||
class APISendServiceResponse(TypedDict):
|
||||
userId: int # int64
|
||||
requestId: str
|
||||
responseData: dict[str, object]
|
||||
|
||||
|
||||
def APISendServiceResponse_cmd_string(self: APISendServiceResponse) -> str:
|
||||
return '/_service_response ' + str(self['userId']) + ' ' + self['requestId'] + ' ' + json.dumps(self['responseData'])
|
||||
|
||||
APISendServiceResponse_Response = CR.ServiceReplyAccepted | CR.ChatCmdError
|
||||
|
||||
|
||||
# Chat management
|
||||
# These commands should not be used with CLI-based bots
|
||||
|
||||
@@ -697,10 +717,11 @@ APISetContactPrefs_Response = CR.ContactPrefsUpdated | CR.ChatCmdError
|
||||
class StartChat(TypedDict):
|
||||
mainApp: bool
|
||||
enableSndFiles: bool
|
||||
serviceRequests: bool
|
||||
|
||||
|
||||
def StartChat_cmd_string(self: StartChat) -> str:
|
||||
return '/_start'
|
||||
return '/_start' + ' main=' + ('on' if self['mainApp'] else 'off') + (' snd_files=off' if not self['enableSndFiles'] else '') + (' service_requests=on' if self['serviceRequests'] else '')
|
||||
|
||||
StartChat_Response = CR.ChatStarted | CR.ChatRunning
|
||||
|
||||
|
||||
@@ -303,6 +303,17 @@ class SubscriptionStatus(TypedDict):
|
||||
subscriptionStatus: "T.SubscriptionStatus"
|
||||
connections: list[str]
|
||||
|
||||
class ServiceRequest(TypedDict):
|
||||
type: Literal["serviceRequest"]
|
||||
user: "T.User"
|
||||
requestId: str
|
||||
signerKey: NotRequired[str]
|
||||
requestData: dict[str, object]
|
||||
|
||||
class ServiceReplySent(TypedDict):
|
||||
type: Literal["serviceReplySent"]
|
||||
connectionId: str
|
||||
|
||||
class MessageError(TypedDict):
|
||||
type: Literal["messageError"]
|
||||
user: "T.User"
|
||||
@@ -364,12 +375,14 @@ ChatEvent = (
|
||||
| HostConnected
|
||||
| HostDisconnected
|
||||
| SubscriptionStatus
|
||||
| ServiceRequest
|
||||
| ServiceReplySent
|
||||
| MessageError
|
||||
| ChatError
|
||||
| ChatErrors
|
||||
)
|
||||
|
||||
ChatEvent_Tag = Literal["contactConnected", "contactUpdated", "contactDeletedByContact", "receivedContactRequest", "newMemberContactReceivedInv", "contactSndReady", "newChatItems", "chatItemReaction", "chatItemsDeleted", "chatItemUpdated", "groupChatItemsDeleted", "chatItemsStatusesUpdated", "receivedGroupInvitation", "userJoinedGroup", "groupUpdated", "joinedGroupMember", "memberRole", "deletedMember", "leftMember", "deletedMemberUser", "groupDeleted", "connectedToGroupMember", "memberAcceptedByOther", "memberBlockedForAll", "groupMemberUpdated", "groupLinkDataUpdated", "groupRelayUpdated", "rcvFileDescrReady", "rcvFileComplete", "sndFileCompleteXFTP", "rcvFileStart", "rcvFileSndCancelled", "rcvFileAccepted", "rcvFileError", "rcvFileWarning", "sndFileError", "sndFileWarning", "acceptingContactRequest", "acceptingBusinessRequest", "contactConnecting", "businessLinkConnecting", "joinedGroupMemberConnecting", "groupLinkConnecting", "hostConnected", "hostDisconnected", "subscriptionStatus", "messageError", "chatError", "chatErrors"]
|
||||
ChatEvent_Tag = Literal["contactConnected", "contactUpdated", "contactDeletedByContact", "receivedContactRequest", "newMemberContactReceivedInv", "contactSndReady", "newChatItems", "chatItemReaction", "chatItemsDeleted", "chatItemUpdated", "groupChatItemsDeleted", "chatItemsStatusesUpdated", "receivedGroupInvitation", "userJoinedGroup", "groupUpdated", "joinedGroupMember", "memberRole", "deletedMember", "leftMember", "deletedMemberUser", "groupDeleted", "connectedToGroupMember", "memberAcceptedByOther", "memberBlockedForAll", "groupMemberUpdated", "groupLinkDataUpdated", "groupRelayUpdated", "rcvFileDescrReady", "rcvFileComplete", "sndFileCompleteXFTP", "rcvFileStart", "rcvFileSndCancelled", "rcvFileAccepted", "rcvFileError", "rcvFileWarning", "sndFileError", "sndFileWarning", "acceptingContactRequest", "acceptingBusinessRequest", "contactConnecting", "businessLinkConnecting", "joinedGroupMemberConnecting", "groupLinkConnecting", "hostConnected", "hostDisconnected", "subscriptionStatus", "serviceRequest", "serviceReplySent", "messageError", "chatError", "chatErrors"]
|
||||
|
||||
|
||||
class OnEventDecorator(Protocol):
|
||||
@@ -656,6 +669,18 @@ class OnEventDecorator(Protocol):
|
||||
Callable[["SubscriptionStatus"], Awaitable[None]],
|
||||
]: ...
|
||||
|
||||
@overload
|
||||
def __call__(self, event: Literal["serviceRequest"], /) -> Callable[
|
||||
[Callable[["ServiceRequest"], Awaitable[None]]],
|
||||
Callable[["ServiceRequest"], Awaitable[None]],
|
||||
]: ...
|
||||
|
||||
@overload
|
||||
def __call__(self, event: Literal["serviceReplySent"], /) -> Callable[
|
||||
[Callable[["ServiceReplySent"], Awaitable[None]]],
|
||||
Callable[["ServiceReplySent"], Awaitable[None]],
|
||||
]: ...
|
||||
|
||||
@overload
|
||||
def __call__(self, event: Literal["messageError"], /) -> Callable[
|
||||
[Callable[["MessageError"], Awaitable[None]]],
|
||||
|
||||
@@ -247,6 +247,11 @@ class SentInvitation(TypedDict):
|
||||
connection: "T.PendingContactConnection"
|
||||
customUserProfile: NotRequired["T.Profile"]
|
||||
|
||||
class ServiceReplyAccepted(TypedDict):
|
||||
type: Literal["serviceReplyAccepted"]
|
||||
user: "T.User"
|
||||
connectionId: str
|
||||
|
||||
class SndFileCancelled(TypedDict):
|
||||
type: Literal["sndFileCancelled"]
|
||||
user: "T.User"
|
||||
@@ -352,6 +357,7 @@ ChatResponse = (
|
||||
| SentConfirmation
|
||||
| SentGroupInvitation
|
||||
| SentInvitation
|
||||
| ServiceReplyAccepted
|
||||
| SndFileCancelled
|
||||
| UserAcceptedGroupSent
|
||||
| UserContactLink
|
||||
@@ -365,4 +371,4 @@ ChatResponse = (
|
||||
| ApiChats
|
||||
)
|
||||
|
||||
ChatResponse_Tag = Literal["acceptingContactRequest", "activeUser", "chatItemNotChanged", "chatItemReaction", "chatItemUpdated", "chatItemsDeleted", "chatRunning", "chatStarted", "chatStopped", "cmdOk", "chatCmdError", "connectionPlan", "contactAlreadyExists", "contactConnectionDeleted", "contactDeleted", "contactPrefsUpdated", "contactRequestRejected", "contactsList", "groupDeletedUser", "groupLink", "groupLinkCreated", "groupLinkDeleted", "groupCreated", "publicGroupCreated", "publicGroupCreationFailed", "groupRelays", "groupRelaysAdded", "groupRelaysAddFailed", "relayGroupAllowed", "groupMembers", "groupUpdated", "groupsList", "invitation", "leftMemberUser", "memberAccepted", "membersBlockedForAllUser", "membersRoleUser", "newChatItems", "rcvFileAccepted", "rcvFileAcceptedSndCancelled", "rcvFileCancelled", "sentConfirmation", "sentGroupInvitation", "sentInvitation", "sndFileCancelled", "userAcceptedGroupSent", "userContactLink", "userContactLinkCreated", "userContactLinkDeleted", "userContactLinkUpdated", "userDeletedMembers", "userProfileUpdated", "userProfileNoChange", "usersList", "apiChats"]
|
||||
ChatResponse_Tag = Literal["acceptingContactRequest", "activeUser", "chatItemNotChanged", "chatItemReaction", "chatItemUpdated", "chatItemsDeleted", "chatRunning", "chatStarted", "chatStopped", "cmdOk", "chatCmdError", "connectionPlan", "contactAlreadyExists", "contactConnectionDeleted", "contactDeleted", "contactPrefsUpdated", "contactRequestRejected", "contactsList", "groupDeletedUser", "groupLink", "groupLinkCreated", "groupLinkDeleted", "groupCreated", "publicGroupCreated", "publicGroupCreationFailed", "groupRelays", "groupRelaysAdded", "groupRelaysAddFailed", "relayGroupAllowed", "groupMembers", "groupUpdated", "groupsList", "invitation", "leftMemberUser", "memberAccepted", "membersBlockedForAllUser", "membersRoleUser", "newChatItems", "rcvFileAccepted", "rcvFileAcceptedSndCancelled", "rcvFileCancelled", "sentConfirmation", "sentGroupInvitation", "sentInvitation", "serviceReplyAccepted", "sndFileCancelled", "userAcceptedGroupSent", "userContactLink", "userContactLinkCreated", "userContactLinkDeleted", "userContactLinkUpdated", "userDeletedMembers", "userProfileUpdated", "userProfileNoChange", "usersList", "apiChats"]
|
||||
|
||||
@@ -139,6 +139,32 @@ AgentErrorType = (
|
||||
|
||||
AgentErrorType_Tag = Literal["CMD", "CONN", "NO_USER", "SMP", "NTF", "XFTP", "FILE", "NO_NAME_SERVERS", "PROXY", "RCP", "BROKER", "AGENT", "NOTICE", "INTERNAL", "CRITICAL", "INACTIVE"]
|
||||
|
||||
class AgentServiceError_rejected(TypedDict):
|
||||
type: Literal["rejected"]
|
||||
rejectReason: str
|
||||
|
||||
class AgentServiceError_timeout(TypedDict):
|
||||
type: Literal["timeout"]
|
||||
|
||||
class AgentServiceError_noPendingRequest(TypedDict):
|
||||
type: Literal["noPendingRequest"]
|
||||
|
||||
class AgentServiceError_notDRAddress(TypedDict):
|
||||
type: Literal["notDRAddress"]
|
||||
|
||||
class AgentServiceError_badSignature(TypedDict):
|
||||
type: Literal["badSignature"]
|
||||
|
||||
AgentServiceError = (
|
||||
AgentServiceError_rejected
|
||||
| AgentServiceError_timeout
|
||||
| AgentServiceError_noPendingRequest
|
||||
| AgentServiceError_notDRAddress
|
||||
| AgentServiceError_badSignature
|
||||
)
|
||||
|
||||
AgentServiceError_Tag = Literal["rejected", "timeout", "noPendingRequest", "notDRAddress", "badSignature"]
|
||||
|
||||
class AutoAccept(TypedDict):
|
||||
acceptIncognito: bool
|
||||
|
||||
@@ -1420,6 +1446,7 @@ class Contact(TypedDict):
|
||||
chatTs: NotRequired[str] # ISO-8601 timestamp
|
||||
preparedContact: NotRequired["PreparedContact"]
|
||||
contactRequestId: NotRequired[int] # int64
|
||||
contactRequest: NotRequired["UserContactRequestRef"]
|
||||
contactGroupMemberId: NotRequired[int] # int64
|
||||
contactGrpInvSent: bool
|
||||
groupDirectInv: NotRequired["GroupDirectInvitation"]
|
||||
@@ -1469,7 +1496,7 @@ class ContactShortLinkData(TypedDict):
|
||||
business: bool
|
||||
localBadge: NotRequired["LocalBadge"]
|
||||
|
||||
ContactStatus = Literal["active", "deleted", "deletedByUser"]
|
||||
ContactStatus = Literal["active", "deleted", "deletedByUser", "rejected"]
|
||||
|
||||
class ContactUserPref_contact(TypedDict):
|
||||
type: Literal["contact"]
|
||||
@@ -2761,6 +2788,10 @@ class SMPAgentError_A_QUEUE(TypedDict):
|
||||
type: Literal["A_QUEUE"]
|
||||
queueErr: str
|
||||
|
||||
class SMPAgentError_A_SERVICE(TypedDict):
|
||||
type: Literal["A_SERVICE"]
|
||||
serviceError: "AgentServiceError"
|
||||
|
||||
SMPAgentError = (
|
||||
SMPAgentError_A_MESSAGE
|
||||
| SMPAgentError_A_PROHIBITED
|
||||
@@ -2769,9 +2800,10 @@ SMPAgentError = (
|
||||
| SMPAgentError_A_CRYPTO
|
||||
| SMPAgentError_A_DUPLICATE
|
||||
| SMPAgentError_A_QUEUE
|
||||
| SMPAgentError_A_SERVICE
|
||||
)
|
||||
|
||||
SMPAgentError_Tag = Literal["A_MESSAGE", "A_PROHIBITED", "A_VERSION", "A_LINK", "A_CRYPTO", "A_DUPLICATE", "A_QUEUE"]
|
||||
SMPAgentError_Tag = Literal["A_MESSAGE", "A_PROHIBITED", "A_VERSION", "A_LINK", "A_CRYPTO", "A_DUPLICATE", "A_QUEUE", "A_SERVICE"]
|
||||
|
||||
class SecurityCode(TypedDict):
|
||||
securityCode: str
|
||||
@@ -3537,6 +3569,11 @@ class UserContactRequest(TypedDict):
|
||||
pqSupport: bool
|
||||
welcomeSharedMsgId: NotRequired[str]
|
||||
requestSharedMsgId: NotRequired[str]
|
||||
rejectionSupported: bool
|
||||
|
||||
class UserContactRequestRef(TypedDict):
|
||||
contactRequestId: int # int64
|
||||
rejectionSupported: bool
|
||||
|
||||
class UserInfo(TypedDict):
|
||||
user: "User"
|
||||
|
||||
Reference in New Issue
Block a user