From 1f2a050695313843c6eeb90c5a39e50cae5ca864 Mon Sep 17 00:00:00 2001 From: Michal Iskierko Date: Wed, 26 Oct 2022 16:08:59 +0200 Subject: [PATCH] feat(@desktop/general): Use compressed community key in deep links Issue #8001 --- src/app/core/custom_urls/urls_manager.nim | 9 +++- src/app/global/utils.nim | 13 ++++++ src/app_service/service/accounts/utils.nim | 44 ++++++++++++++++++- src/backend/accounts.nim | 24 +++++++++- ...ommunityProfilePopupInviteFriendsPanel.qml | 4 +- .../CommunityProfilePopupOverviewPanel.qml | 4 +- ui/app/AppLayouts/Chat/stores/RootStore.qml | 8 ++-- ui/imports/utils/Utils.qml | 26 +++++++++++ 8 files changed, 120 insertions(+), 12 deletions(-) diff --git a/src/app/core/custom_urls/urls_manager.nim b/src/app/core/custom_urls/urls_manager.nim index 3f93fd04f6..5d1ce9d24b 100644 --- a/src/app/core/custom_urls/urls_manager.nim +++ b/src/app/core/custom_urls/urls_manager.nim @@ -2,6 +2,8 @@ import NimQml, strutils, chronicles import ../eventemitter import ../../global/app_signals +import ../../../app_service/common/conversion +import ../../../app_service/service/accounts/utils logScope: topics = "urls-manager" @@ -44,6 +46,11 @@ QtObject: result.protocolUriOnStart = protocolUriOnStart result.loggedIn = false + proc prepareCommunityId(self: UrlsManager, communityId: string): string = + if isCompressedPubKey(communityId): + return changeCommunityKeyCompression(communityId) + return communityId + proc onUrlActivated*(self: UrlsManager, urlRaw: string) {.slot.} = if not self.loggedIn: self.protocolUriOnStart = urlRaw @@ -62,7 +69,7 @@ QtObject: # Open community with `community_key` elif url.startsWith(UriFormatCommunity): data.action = StatusUrlAction.OpenCommunity - data.communityId = url[UriFormatCommunity.len .. url.len-1] + data.communityId = self.prepareCommunityId(url[UriFormatCommunity.len .. url.len-1]) # Open community which has a channel with `channel_key` and makes that channel active elif url.startsWith(UriFormatCommunityChannel): diff --git a/src/app/global/utils.nim b/src/app/global/utils.nim index f28b2c8689..a1655909db 100644 --- a/src/app/global/utils.nim +++ b/src/app/global/utils.nim @@ -151,5 +151,18 @@ QtObject: proc getCompressedPk*(self: Utils, publicKey: string): string {.slot.} = compressPk(publicKey) + proc getDecompressedPk*(self: Utils, compressedKey: string): string {.slot.} = + decompressPk(compressedKey) + + proc decompressCommunityKey*(self: Utils, publicKey: string): string {.slot.} = + decompressCommunityKey(publicKey) + + proc compressCommunityKey*(self: Utils, publicKey: string): string {.slot.} = + compressCommunityKey(publicKey) + proc isCompressedPubKey*(self: Utils, publicKey: string): bool {.slot.} = conversion.isCompressedPubKey(publicKey) + + # Changes publicKey compression between 33-bytes and multiformat zQ.. + proc changeCommunityKeyCompression*(self: Utils, publicKey: string): string {.slot.} = + changeCommunityKeyCompression(publicKey) diff --git a/src/app_service/service/accounts/utils.nim b/src/app_service/service/accounts/utils.nim index 78910db37e..bf429c0c82 100644 --- a/src/app_service/service/accounts/utils.nim +++ b/src/app_service/service/accounts/utils.nim @@ -1,5 +1,6 @@ import json import ../../../backend/accounts as status_account +import ../../common/conversion proc compressPk*(publicKey: string): string = try: @@ -11,8 +12,49 @@ proc compressPk*(publicKey: string): string = except Exception as e: echo "error: `compressPk` " & $e.name & " msg: " & $e.msg +proc decompressPk*(compressedKey: string): string = + try: + let response = status_account.decompressPk(compressedKey) + if(not response.error.isNil): + echo "error decompressPk: " & response.error.message + result = response.result + + except Exception as e: + echo "error: `decompressPk` " & $e.name & " msg: " & $e.msg + +proc decompressCommunityKey*(publicKey: string): string = + try: + let response = status_account.decompressCommunityKey(publicKey) + if(not response.error.isNil): + echo "error decompressCommunityKey: " & response.error.message + result = response.result + + except Exception as e: + echo "error: `decompressCommunityKey` " & $e.name & " msg: " & $e.msg + +proc compressCommunityKey*(publicKey: string): string = + try: + let response = status_account.compressCommunityKey(publicKey) + if(not response.error.isNil): + echo "error compressCommunityKey: " & response.error.message + result = response.result + + except Exception as e: + echo "error: `compressCommunityKey` " & $e.name & " msg: " & $e.msg + proc generateAliasFromPk*(publicKey: string): string = return status_account.generateAlias(publicKey).result.getStr proc isAlias*(value: string): bool = - return status_account.isAlias(value) \ No newline at end of file + return status_account.isAlias(value) + +# Changes publicKey compression between 33-bytes and multiformat zQ.. +proc changeCommunityKeyCompression*(publicKey: string): string = + if isCompressedPubKey(publicKey): + # is zQ + let uncompressedKey = decompressPk(publicKey) + return compressCommunityKey(uncompressedKey) + else: + # is 33-bytes + let uncompressedKey = decompressCommunityKey(publicKey) + return compressPk(uncompressedKey) \ No newline at end of file diff --git a/src/backend/accounts.nim b/src/backend/accounts.nim index 99d75af8ce..ea08e1ab2c 100644 --- a/src/backend/accounts.nim +++ b/src/backend/accounts.nim @@ -89,7 +89,29 @@ proc decompressPk*(publicKey: string): RpcResponse[string] = let secp256k1Code = "fe701" response.removePrefix(secp256k1Code) result.result = "0x" & response - + +proc decompressCommunityKey*(publicKey: string): RpcResponse[string] = + + let response = status_go.decompressPublicKey(publicKey) + + # json response indicates error + try: + let jsonReponse = parseJson(response) + result.error = RpcError(message: jsonReponse["error"].getStr()) + except JsonParsingError as e: + result.result = response + +proc compressCommunityKey*(publicKey: string): RpcResponse[string] = + + let response = status_go.compressPublicKey(publicKey) + + # json response indicates error + try: + let jsonReponse = parseJson(response) + result.error = RpcError(message: jsonReponse["error"].getStr()) + except JsonParsingError as e: + result.result = response + proc compressPk*(publicKey: string): RpcResponse[string] = let secp256k1Code = "0xe701" let base58btc = "z" diff --git a/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupInviteFriendsPanel.qml b/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupInviteFriendsPanel.qml index 6342a8e2cd..7ae2d124ee 100644 --- a/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupInviteFriendsPanel.qml +++ b/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupInviteFriendsPanel.qml @@ -86,11 +86,11 @@ ColumnLayout { StatusDescriptionListItem { title: qsTr("Share community") - subTitle: `${Constants.communityLinkPrefix}${root.community && root.community.id.substring(0, 4)}...${root.community && root.community.id.substring(root.community.id.length -2)}` + subTitle: Utils.getCommunityShareLink(root.community.id, true) tooltip.text: qsTr("Copied!") asset.name: "copy" iconButton.onClicked: { - let link = `${Constants.communityLinkPrefix}${root.community.id}` + let link = Utils.getCommunityShareLink(root.community.id) root.rootStore.copyToClipboard(link) tooltip.visible = !tooltip.visible } diff --git a/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupOverviewPanel.qml b/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupOverviewPanel.qml index 331e664698..c3872ac5b3 100644 --- a/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupOverviewPanel.qml +++ b/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupOverviewPanel.qml @@ -46,11 +46,11 @@ Column { StatusDescriptionListItem { title: qsTr("Share community") - subTitle: `${Constants.communityLinkPrefix}${root.community.id.substring(0, 4)}...${root.community.id.substring(root.community.id.length -2)}` + subTitle: Utils.getCommunityShareLink(root.community.id, true) tooltip.text: qsTr("Copied!") asset.name: "copy" iconButton.onClicked: { - let link = `${Constants.communityLinkPrefix}${root.community.id}` + let link = Utils.getCommunityShareLink(root.community.id) root.copyToClipboard(link); tooltip.visible = !tooltip.visible } diff --git a/ui/app/AppLayouts/Chat/stores/RootStore.qml b/ui/app/AppLayouts/Chat/stores/RootStore.qml index 12694fa6a2..fa10a5c6da 100644 --- a/ui/app/AppLayouts/Chat/stores/RootStore.qml +++ b/ui/app/AppLayouts/Chat/stores/RootStore.qml @@ -388,15 +388,13 @@ QtObject { }*/ // Community - let index = link.lastIndexOf("/c/") - if (index > -1) { - const communityId = link.substring(index + 3) - + const communityId = Utils.getCommunityIdFromShareLink(link) + if (communityId !== "") { const communityName = getSectionNameById(communityId) if (!communityName) { // Unknown community, fetch the info if possible - communitiesModuleInst.requestCommunityInfo(communityId) + root.requestCommunityInfo(communityId) result.communityId = communityId result.fetching = true return result diff --git a/ui/imports/utils/Utils.qml b/ui/imports/utils/Utils.qml index aaf24020a5..d1bc1f02a2 100644 --- a/ui/imports/utils/Utils.qml +++ b/ui/imports/utils/Utils.qml @@ -608,6 +608,19 @@ QtObject { return colorForColorId(pubKeyColorId) } + function getCommunityShareLink(communityId, elided = false) { + if (communityId === "") { + return "" + } + + let compressedPk = communityId + if (!globalUtilsInst.isCompressedPubKey(compressedPk)) { + compressedPk = globalUtilsInst.changeCommunityKeyCompression(compressedPk) + } + return Constants.communityLinkPrefix + + (elided ? StatusQUtils.Utils.elideText(compressedPk, 4, 2) : compressedPk) + } + function getChatKeyFromShareLink(link) { let index = link.lastIndexOf("/u/") if (index === -1) { @@ -616,6 +629,19 @@ QtObject { return link.substring(index + 3) } + function getCommunityIdFromShareLink(link) { + let index = link.lastIndexOf("/c/") + if (index === -1) { + return "" + } + const communityKey = link.substring(index + 3) + if (globalUtilsInst.isCompressedPubKey(communityKey)) { + // is zQ.., need to be converted to standard compression + return globalUtilsInst.changeCommunityKeyCompression(communityKey) + } + return communityKey + } + function getCompressedPk(publicKey) { if (publicKey === "") { return ""