diff --git a/src/app/modules/main/profile_section/contacts/controller.nim b/src/app/modules/main/profile_section/contacts/controller.nim index 6693e5b4d0..c93b2392fc 100644 --- a/src/app/modules/main/profile_section/contacts/controller.nim +++ b/src/app/modules/main/profile_section/contacts/controller.nim @@ -73,6 +73,10 @@ proc init*(self: Controller) = var args = ContactArgs(e) self.delegate.onVerificationRequestDeclined(args.contactId) + self.events.on(SIGNAL_CONTACT_VERIFICATION_CANCELLED) do(e: Args): + var args = ContactArgs(e) + self.delegate.onVerificationRequestCanceled(args.contactId) + self.events.on(SIGNAL_CONTACT_VERIFICATION_ADDED) do(e: Args): var args = VerificationRequestArgs(e) self.delegate.onVerificationRequestUpdatedOrAdded(args.verificationRequest) @@ -161,5 +165,3 @@ proc getReceivedVerificationRequests*(self: Controller): seq[VerificationRequest proc getStatusForContactWithId*(self: Controller, publicKey: string): StatusUpdateDto = return self.contactsService.getStatusForContactWithId(publicKey) -proc hasReceivedVerificationRequestFrom*(self: Controller, fromId: string): bool = - self.contactsService.hasReceivedVerificationRequestFrom(fromId) diff --git a/src/app/modules/main/profile_section/contacts/io_interface.nim b/src/app/modules/main/profile_section/contacts/io_interface.nim index 5fd7a4d179..5b328e077b 100644 --- a/src/app/modules/main/profile_section/contacts/io_interface.nim +++ b/src/app/modules/main/profile_section/contacts/io_interface.nim @@ -116,10 +116,10 @@ method contactRequestRejectionRemoved*(self: AccessInterface, publicKey: string) method getReceivedVerificationRequests*(self: AccessInterface): seq[VerificationRequest] {.base.} = raise newException(ValueError, "No implementation available") -method hasReceivedVerificationRequestFrom*(self: AccessInterface, fromId: string): bool {.base.} = +method onVerificationRequestDeclined*(self: AccessInterface, publicKey: string) {.base.} = raise newException(ValueError, "No implementation available") -method onVerificationRequestDeclined*(self: AccessInterface, publicKey: string) {.base.} = +method onVerificationRequestCanceled*(self: AccessInterface, publicKey: string) {.base.} = raise newException(ValueError, "No implementation available") method onVerificationRequestUpdatedOrAdded*(self: AccessInterface, VerificationRequest: VerificationRequest) {.base.} = diff --git a/src/app/modules/main/profile_section/contacts/module.nim b/src/app/modules/main/profile_section/contacts/module.nim index 2787360b89..bc0c4014d1 100644 --- a/src/app/modules/main/profile_section/contacts/module.nim +++ b/src/app/modules/main/profile_section/contacts/module.nim @@ -257,12 +257,12 @@ method acceptVerificationRequest*(self: Module, publicKey: string, response: str method getReceivedVerificationRequests*(self: Module): seq[VerificationRequest] = self.controller.getReceivedVerificationRequests() -method hasReceivedVerificationRequestFrom*(self: Module, fromId: string): bool = - result = self.controller.hasReceivedVerificationRequestFrom(fromId) - method onVerificationRequestDeclined*(self: Module, publicKey: string) = self.view.receivedContactRequestsModel.removeItemById(publicKey) +method onVerificationRequestCanceled*(self: Module, publicKey: string) = + self.view.receivedContactRequestsModel.removeItemById(publicKey) + method onVerificationRequestUpdatedOrAdded*(self: Module, request: VerificationRequest) = let item = self.createItemFromPublicKey(request.fromID) item.incomingVerificationStatus = VerificationRequestStatus(request.status) diff --git a/src/app/modules/main/profile_section/contacts/view.nim b/src/app/modules/main/profile_section/contacts/view.nim index f55e98b22a..1410d0ab0c 100644 --- a/src/app/modules/main/profile_section/contacts/view.nim +++ b/src/app/modules/main/profile_section/contacts/view.nim @@ -186,5 +186,3 @@ QtObject: proc acceptVerificationRequest*(self: View, publicKey: string, response: string) {.slot.} = self.delegate.acceptVerificationRequest(publicKey, response) - proc hasReceivedVerificationRequestFrom*(self: View, fromId: string): bool {.slot.} = - result = self.delegate.hasReceivedVerificationRequestFrom(fromId) diff --git a/src/app_service/service/contacts/dto/contacts.nim b/src/app_service/service/contacts/dto/contacts.nim index 397ac29539..9ba38e6c9e 100644 --- a/src/app_service/service/contacts/dto/contacts.nim +++ b/src/app_service/service/contacts/dto/contacts.nim @@ -140,7 +140,6 @@ proc toContactsDto*(jsonObj: JsonNode): ContactsDto = discard jsonObj.getProp("lastUpdatedLocally", result.lastUpdatedLocally) discard jsonObj.getProp("localNickname", result.localNickname) discard jsonObj.getProp("bio", result.bio) - result.requestState = ContactRequestState.None var requestState: int diff --git a/src/app_service/service/contacts/service.nim b/src/app_service/service/contacts/service.nim index d056a4bec7..ec18d10551 100644 --- a/src/app_service/service/contacts/service.nim +++ b/src/app_service/service/contacts/service.nim @@ -192,10 +192,15 @@ QtObject: if self.contacts.hasKey(request.fromId): self.contacts[request.fromId].trustStatus = TrustStatus.Trusted self.contacts[request.fromId].verificationStatus = VerificationStatus.Trusted - self.events.emit(SIGNAL_CONTACT_TRUSTED, TrustArgs(publicKey: request.fromId, isUntrustworthy: false)) self.events.emit(SIGNAL_CONTACT_VERIFIED, ContactArgs(contactId: request.fromId)) + + if request.status == VerificationStatus.Canceled: + if self.contacts.hasKey(request.fromId): + self.contacts[request.fromId].verificationStatus = VerificationStatus.Canceled + self.events.emit(SIGNAL_CONTACT_VERIFICATION_CANCELLED, ContactArgs(contactId: request.fromId)) + else: self.events.emit(SIGNAL_CONTACT_VERIFICATION_ADDED, data) @@ -664,9 +669,6 @@ QtObject: proc getReceivedVerificationRequests*(self: Service): seq[VerificationRequest] = result = toSeq(self.receivedIdentityRequests.values) - proc hasReceivedVerificationRequestFrom*(self: Service, fromId: string): bool = - result = self.receivedIdentityRequests.contains(fromId) - proc sendVerificationRequest*(self: Service, publicKey: string, challenge: string) = try: let response = status_contacts.sendVerificationRequest(publicKey, challenge) @@ -685,8 +687,15 @@ QtObject: proc cancelVerificationRequest*(self: Service, publicKey: string) = try: - let response = status_contacts.cancelVerificationRequest(publicKey) - if(not response.error.isNil): + var response = status_contacts.getVerificationRequestSentTo(publicKey) + if not response.error.isNil: + let msg = response.error.message + raise newException(RpcException, msg) + + let request = response.result.toVerificationRequest() + + response = status_contacts.cancelVerificationRequest(request.id) + if not response.error.isNil: let msg = response.error.message error "error sending contact verification request", msg return @@ -694,7 +703,7 @@ QtObject: var contact = self.getContactById(publicKey) contact.verificationStatus = VerificationStatus.Unverified self.saveContact(contact) - + self.events.emit(SIGNAL_CONTACT_VERIFICATION_CANCELLED, ContactArgs(contactId: publicKey)) except Exception as e: error "Error canceling verification request", msg = e.msg diff --git a/src/backend/contacts.nim b/src/backend/contacts.nim index 9cffaef8a2..9c69ebbf29 100644 --- a/src/backend/contacts.nim +++ b/src/backend/contacts.nim @@ -103,8 +103,8 @@ proc getReceivedVerificationRequests*(): RpcResponse[JsonNode] {.raises: [Except let payload = %* [] result = callPrivateRPC("getReceivedVerificationRequests".prefix, payload) -proc cancelVerificationRequest*(pubkey: string): RpcResponse[JsonNode] {.raises: [Exception].} = - let payload = %* [pubkey] +proc cancelVerificationRequest*(requestId: string): RpcResponse[JsonNode] {.raises: [Exception].} = + let payload = %* [requestId] result = callPrivateRPC("cancelVerificationRequest".prefix, payload) proc retractContactRequest*(pubkey: string): RpcResponse[JsonNode] {.raises: [Exception].} = diff --git a/storybook/pages/ProfileDialogViewPage.qml b/storybook/pages/ProfileDialogViewPage.qml index 544f985615..9deb788c79 100644 --- a/storybook/pages/ProfileDialogViewPage.qml +++ b/storybook/pages/ProfileDialogViewPage.qml @@ -133,10 +133,6 @@ SplitView { contactsStore: QtObject { readonly property string myPublicKey: "0xdeadbeef" - function hasReceivedVerificationRequestFrom(publicKey) { - return false - } - function joinPrivateChat(publicKey) { logs.logEvent("contactsStore::joinPrivateChat", ["publicKey"], arguments) } diff --git a/ui/app/AppLayouts/Profile/stores/ContactsStore.qml b/ui/app/AppLayouts/Profile/stores/ContactsStore.qml index 78f452eddd..ff7dd3275d 100644 --- a/ui/app/AppLayouts/Profile/stores/ContactsStore.qml +++ b/ui/app/AppLayouts/Profile/stores/ContactsStore.qml @@ -115,10 +115,6 @@ QtObject { return JSON.parse(resp); } - function hasReceivedVerificationRequestFrom(pubKey) { - return root.contactsModule.hasReceivedVerificationRequestFrom(pubKey); - } - function verifiedTrusted(pubKey) { root.contactsModule.verifiedTrusted(pubKey); } diff --git a/ui/app/mainui/Popups.qml b/ui/app/mainui/Popups.qml index b328e2ce31..550c782832 100644 --- a/ui/app/mainui/Popups.qml +++ b/ui/app/mainui/Popups.qml @@ -47,23 +47,14 @@ QtObject { } function openIncomingIDRequestPopup(publicKey, cb) { - try { - const request = root.rootStore.profileSectionStore.contactsStore.getVerificationDetailsFromAsJson(publicKey) - const popupProperties = { - senderPublicKey: request.from, - senderDisplayName: request.displayName, - senderIcon: request.icon, - challengeText: request.challenge, - responseText: request.response, - messageTimestamp: request.requestedAt, - responseTimestamp: request.repliedAt - } + const popupProperties = { + contactsStore: root.rootStore.profileSectionStore.contactsStore, + publicKey: publicKey + } - const popup = Global.openPopup(contactVerificationRequestPopupComponent, popupProperties) - if (cb) - cb(popup) - } catch (e) { - console.error("Error getting or parsing verification data", e) + const popup = Global.openPopup(contactVerificationRequestPopupComponent, popupProperties) + if (cb) { + cb(popup) } } diff --git a/ui/imports/shared/popups/ContactVerificationRequestPopup.qml b/ui/imports/shared/popups/ContactVerificationRequestPopup.qml index a3936228b8..0c533829c7 100644 --- a/ui/imports/shared/popups/ContactVerificationRequestPopup.qml +++ b/ui/imports/shared/popups/ContactVerificationRequestPopup.qml @@ -14,18 +14,52 @@ import shared.views.chat 1.0 StatusModal { id: root - property string senderPublicKey: "" - property string senderDisplayName: "" - property string senderIcon: "" - property string challengeText: "" - property string responseText: "" - property string messageTimestamp: "" - property string responseTimestamp: "" + property var contactsStore + property string publicKey signal verificationRefused(string senderPublicKey) signal responseSent(string senderPublicKey, string response) - header.title: qsTr("%1 is asking you to verify your identity").arg(root.senderDisplayName) + function updateContactDetails() { + try { + const request = root.contactsStore.getVerificationDetailsFromAsJson(root.publicKey) + + if (request.requestStatus === Constants.verificationStatus.canceled) { + root.close() + } + + d.senderPublicKey = request.from, + d.senderDisplayName = request.displayName + d.senderIcon = request.icon + d.challengeText = request.challenge + d.responseText = request.response + d.messageTimestamp = request.requestedAt + d.responseTimestamp = request.repliedAt + } catch (e) { + console.error("Error getting or parsing verification data", e) + } + } + + Connections { + target: root.contactsStore.receivedContactRequestsModel + function onCountChanged() { + root.updateContactDetails() + } + } + + QtObject { + id: d + + property string senderPublicKey: "" + property string senderDisplayName: "" + property string senderIcon: "" + property string challengeText: "" + property string responseText: "" + property string messageTimestamp: "" + property string responseTimestamp: "" + } + + header.title: qsTr("%1 is asking you to verify your identity").arg(d.senderDisplayName) x: Math.round(((parent ? parent.width : 0) - width) / 2) y: Math.round(((parent ? parent.height : 0) - height) / 2) @@ -34,6 +68,7 @@ StatusModal { height: 230 + verificationMessage.height + verificationResponse.height onOpened: { + root.updateContactDetails() verificationResponse.input.edit.forceActiveFocus(Qt.MouseFocusReason) } @@ -51,7 +86,7 @@ StatusModal { anchors.top: parent.top anchors.topMargin: Style.current.padding text: qsTr("%1 would like to verify your identity. Answer the question to prove your identity to %2") - .arg(root.senderDisplayName).arg(root.senderDisplayName) + .arg(d.senderDisplayName).arg(d.senderDisplayName) font.pixelSize: 15 } @@ -62,19 +97,19 @@ StatusModal { width: parent.width isMessage: true shouldRepeatHeader: true - messageTimestamp: root.messageTimestamp - senderId: root.senderPublicKey - senderDisplayName: root.senderDisplayName - senderIsEnsVerified: Utils.isEnsVerified(root.senderPublicKey) - senderIcon: root.senderIcon - messageText: root.challengeText + messageTimestamp: d.messageTimestamp + senderId: d.senderPublicKey + senderDisplayName: d.senderDisplayName + senderIsEnsVerified: d.senderPublicKey !== "" && Utils.isEnsVerified(d.senderPublicKey) + senderIcon: d.senderIcon + messageText: d.challengeText messageContentType: Constants.messageContentType.messageType placeholderMessage: true } StatusInput { id: verificationResponse - visible: !responseText + visible: !d.responseText anchors.top: verificationMessage.bottom anchors.topMargin: 5 input.multiline: true @@ -90,30 +125,30 @@ StatusModal { MessageView { id: responseMessage - visible: !!root.responseText + visible: !!d.responseText anchors.top: verificationMessage.bottom width: parent.width isMessage: true shouldRepeatHeader: true - messageTimestamp: root.responseTimestamp + messageTimestamp: d.responseTimestamp senderId: userProfile.pubKey senderDisplayName: userProfile.displayName senderIsEnsVerified: !!userProfile.preferredName senderIcon: userProfile.icon - messageText: root.responseText + messageText: d.responseText messageContentType: Constants.messageContentType.messageType placeholderMessage: true } StatusBaseText { id: responseSent - visible: !!root.responseText + visible: !!d.responseText width: parent.width color: Theme.palette.baseColor1 wrapMode: Text.WordWrap anchors.top: responseMessage.bottom anchors.topMargin: 58 - text: qsTr("Your answer has been sent to %1.").arg(root.senderDisplayName) + text: qsTr("Your answer has been sent to %1.").arg(d.senderDisplayName) font.pixelSize: 13 horizontalAlignment: Text.AlignHCenter } @@ -121,32 +156,32 @@ StatusModal { rightButtons: [ StatusButton { - visible: !root.responseText + visible: !d.responseText text: qsTr("Refuse Verification") onClicked: { - root.verificationRefused(root.senderPublicKey) + root.verificationRefused(d.senderPublicKey) root.close(); } }, StatusButton { text: qsTr("Send Answer") - visible: !root.responseText + visible: !d.responseText enabled: verificationResponse.text !== "" onClicked: { - root.responseSent(root.senderPublicKey, Utils.escapeHtml(verificationResponse.text)) - root.responseText = verificationResponse.text - root.responseTimestamp = Date.now() + root.responseSent(d.senderPublicKey, Utils.escapeHtml(verificationResponse.text)) + d.responseText = verificationResponse.text + d.responseTimestamp = Date.now() } }, StatusFlatButton { - visible: root.responseText + visible: d.responseText text: qsTr("Change answer") onClicked: { - root.responseText = "" + d.responseText = "" } }, StatusButton { - visible: root.responseText + visible: d.responseText text: qsTr("Close") onClicked: root.close() } diff --git a/ui/imports/shared/views/ProfileDialogView.qml b/ui/imports/shared/views/ProfileDialogView.qml index e83c150e2c..42c1e30afb 100644 --- a/ui/imports/shared/views/ProfileDialogView.qml +++ b/ui/imports/shared/views/ProfileDialogView.qml @@ -68,7 +68,7 @@ Pane { outgoingVerificationStatus !== Constants.verificationStatus.unverified && outgoingVerificationStatus !== Constants.verificationStatus.verified && outgoingVerificationStatus !== Constants.verificationStatus.trusted - readonly property bool isVerificationRequestReceived: d.isCurrentUser ? false : root.contactsStore.hasReceivedVerificationRequestFrom(root.publicKey) + readonly property bool isVerificationRequestReceived: incomingVerificationStatus === Constants.verificationStatus.verifying readonly property bool isTrusted: outgoingVerificationStatus === Constants.verificationStatus.trusted || incomingVerificationStatus === Constants.verificationStatus.trusted diff --git a/ui/imports/shared/views/chat/MessageContextMenuView.qml b/ui/imports/shared/views/chat/MessageContextMenuView.qml index 3b8a461924..38a155d313 100644 --- a/ui/imports/shared/views/chat/MessageContextMenuView.qml +++ b/ui/imports/shared/views/chat/MessageContextMenuView.qml @@ -79,11 +79,11 @@ StatusMenu { return !root.isMe && root.selectedUserPublicKey !== "" && root.store.contactsStore.hasPendingContactRequest(root.selectedUserPublicKey); } - readonly property bool hasReceivedVerificationRequestFrom: { + readonly property bool hasActiveReceivedVerificationRequestFrom: { if (!root.selectedUserPublicKey || root.isMe || !root.isContact) { return false } - return root.store.contactsStore.hasReceivedVerificationRequestFrom(root.selectedUserPublicKey) + return contactDetails.incomingVerificationStatus === Constants.verificationStatus.verifying } readonly property bool isVerificationRequestSent: { if (!root.selectedUserPublicKey || root.isMe || !root.isContact) { @@ -254,7 +254,7 @@ StatusMenu { enabled: root.isProfile && !root.isMe && root.isContact && !root.isBlockedContact && root.outgoingVerificationStatus === Constants.verificationStatus.unverified - && !root.hasReceivedVerificationRequestFrom + && !root.hasActiveReceivedVerificationRequestFrom onTriggered: { Global.openSendIDRequestPopup(root.selectedUserPublicKey, null) root.close() @@ -269,10 +269,10 @@ StatusMenu { icon.name: "checkmark-circle" enabled: root.isProfile && !root.isMe && root.isContact && !root.isBlockedContact && !root.isTrusted - && (root.hasReceivedVerificationRequestFrom + && (root.hasActiveReceivedVerificationRequestFrom || root.isVerificationRequestSent) onTriggered: { - if (hasReceivedVerificationRequestFrom) { + if (hasActiveReceivedVerificationRequestFrom) { Global.openIncomingIDRequestPopup(root.selectedUserPublicKey, null) } else if (root.isVerificationRequestSent) { Global.openOutgoingIDRequestPopup(root.selectedUserPublicKey, null)