feat(@desktop/keycard): joining communities using addresses migrated to a keycard

Closes: #12170
This commit is contained in:
Sale Djenic 2023-10-27 19:20:52 +02:00 committed by saledjenic
parent 0e16a4e2fb
commit ad7774799a
24 changed files with 1025 additions and 254 deletions

View File

@ -1,26 +1,22 @@
import stint, std/strutils
import stint, std/strutils, uuids, os
import ./io_interface
import ../../../core/signals/types
import ../../../core/eventemitter
import ../../../../app_service/service/chat/dto/chat
import ../../../../app_service/service/community/service as community_service
import ../../../../app_service/service/contacts/service as contacts_service
import ../../../../app_service/service/chat/service as chat_service
import ../../../../app_service/service/network/service as networks_service
import ../../../../app_service/service/community_tokens/service as community_tokens_service
import ../../../../app_service/service/token/service as token_service
import ../../../../app_service/service/wallet_account/service as wallet_account_service
import app/core/signals/types
import app/core/eventemitter
import app_service/service/chat/dto/chat
import app_service/service/community/service as community_service
import app_service/service/contacts/service as contacts_service
import app_service/service/chat/service as chat_service
import app_service/service/network/service as networks_service
import app_service/service/community_tokens/service as community_tokens_service
import app_service/service/token/service as token_service
import app_service/service/wallet_account/service as wallet_account_service
import app_service/service/keycard/service as keycard_service
import backend/collectibles as backend_collectibles
import ../../shared_modules/keycard_popup/io_interface as keycard_shared_module
import app/modules/shared_modules/keycard_popup/io_interface as keycard_shared_module
const UNIQUE_COMMUNITIES_MODULE_AUTH_IDENTIFIER* = "CommunitiesModule-Action-Authentication"
type
AuthenticationAction* {.pure.} = enum
None = 0,
CommunityJoin = 1,
CommunitySharedAddressesJoin = 2,
const UNIQUE_COMMUNITIES_MODULE_AUTH_IDENTIFIER* = "CommunitiesModule-Authentication"
const UNIQUE_COMMUNITIES_MODULE_SIGNING_IDENTIFIER* = "CommunitiesModule-Signing"
type
Controller* = ref object of RootObj
@ -32,13 +28,13 @@ type
networksService: networks_service.Service
tokenService: token_service.Service
chatService: chat_service.Service
tmpCommunityId: string
tmpCommunityIdForChannelsPermisisons: string
tmpCommunityIdForRevealedAccounts: string
tmpAuthenticationAction: AuthenticationAction
tmpRequestToJoinEnsName: string
tmpAddressesToShare: seq[string]
tmpAirdropAddress: string
walletAccountService: wallet_account_service.Service
keycardService: keycard_service.Service
connectionKeycardResponse: UUID
## the following are used for silent signing in case there are more then a single address for the same keypair
silentSigningPath: string
silentSigningKeyUid: string
silentSigningPin: string
proc newController*(
delegate: io_interface.AccessInterface,
@ -49,6 +45,8 @@ proc newController*(
networksService: networks_service.Service,
tokenService: token_service.Service,
chatService: chat_service.Service,
walletAccountService: wallet_account_service.Service,
keycardService: keycard_service.Service
): Controller =
result = Controller()
result.delegate = delegate
@ -59,12 +57,8 @@ proc newController*(
result.networksService = networksService
result.tokenService = tokenService
result.chatService = chatService
result.tmpCommunityId = ""
result.tmpCommunityIdForChannelsPermisisons = ""
result.tmpCommunityIdForRevealedAccounts = ""
result.tmpRequestToJoinEnsName = ""
result.tmpAirdropAddress = ""
result.tmpAddressesToShare = @[]
result.walletAccountService = walletAccountService
result.keycardService = keycardService
proc delete*(self: Controller) =
discard
@ -171,28 +165,22 @@ proc init*(self: Controller) =
self.events.on(SIGNAL_CHECK_PERMISSIONS_TO_JOIN_RESPONSE) do(e: Args):
let args = CheckPermissionsToJoinResponseArgs(e)
if (args.communityId == self.tmpCommunityId):
self.delegate.onCommunityCheckPermissionsToJoinResponse(args.communityId, args.checkPermissionsToJoinResponse)
self.tmpCommunityId = ""
self.delegate.onCommunityCheckPermissionsToJoinResponse(args.communityId, args.checkPermissionsToJoinResponse)
self.events.on(SIGNAL_CHECK_ALL_CHANNELS_PERMISSIONS_RESPONSE) do(e: Args):
let args = CheckAllChannelsPermissionsResponseArgs(e)
if args.communityId == self.tmpCommunityIdForChannelsPermisisons:
self.delegate.onCommunityCheckAllChannelsPermissionsResponse(
args.communityId,
args.checkAllChannelsPermissionsResponse,
)
self.tmpCommunityIdForChannelsPermisisons = ""
self.delegate.onCommunityCheckAllChannelsPermissionsResponse(
args.communityId,
args.checkAllChannelsPermissionsResponse,
)
self.events.on(SIGNAL_COMMUNITY_MEMBER_REVEALED_ACCOUNTS_LOADED) do(e: Args):
let args = CommunityMemberRevealedAccountsArgs(e)
if self.tmpCommunityIdForRevealedAccounts == args.communityId:
self.delegate.onCommunityMemberRevealedAccountsLoaded(
args.communityId,
args.memberPubkey,
args.memberRevealedAccounts,
)
self.tmpCommunityIdForRevealedAccounts = ""
self.delegate.onCommunityMemberRevealedAccountsLoaded(
args.communityId,
args.memberPubkey,
args.memberRevealedAccounts,
)
self.events.on(SIGNAL_WALLET_ACCOUNT_TOKENS_REBUILT) do(e: Args):
self.delegate.onWalletAccountTokensRebuilt()
@ -211,6 +199,12 @@ proc init*(self: Controller) =
let args = CheckChannelsPermissionsErrorArgs(e)
self.delegate.onCommunityCheckAllChannelPermissionsFailed(args.communityId, args.error)
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_DATA_SIGNED) do(e: Args):
let args = SharedKeycarModuleArgs(e)
if args.uniqueIdentifier != UNIQUE_COMMUNITIES_MODULE_SIGNING_IDENTIFIER:
return
self.delegate.onDataSigned(args.keyUid, args.path, args.r, args.s, args.v, args.pin)
proc getCommunityTags*(self: Controller): string =
result = self.communityService.getCommunityTags()
@ -363,78 +357,92 @@ proc shareCommunityChannelUrlWithChatKey*(self: Controller, communityId: string,
proc shareCommunityChannelUrlWithData*(self: Controller, communityId: string, chatId: string): string =
return self.communityService.shareCommunityChannelUrlWithData(communityId, chatId)
proc userAuthenticationCanceled*(self: Controller) =
self.tmpAuthenticationAction = AuthenticationAction.None
self.tmpCommunityId = ""
self.tmpCommunityIdForChannelsPermisisons = ""
self.tmpRequestToJoinEnsName = ""
self.tmpAirdropAddress = ""
self.tmpAddressesToShare = @[]
proc asyncRequestToJoinCommunity*(self: Controller, communityId: string, ensName: string, addressesToShare: seq[string],
airdropAddress: string, signatures: seq[string]) =
self.communityService.asyncRequestToJoinCommunity(communityId, ensName, addressesToShare, airdropAddress,
signatures)
proc requestToJoinCommunityAuthenticated*(self: Controller, password: string) =
self.communityService.asyncRequestToJoinCommunity(
self.tmpCommunityId,
self.tmpRequestToJoinEnsName,
password,
self.tmpAddressesToShare,
self.tmpAirdropAddress
)
self.tmpAuthenticationAction = AuthenticationAction.None
self.tmpCommunityId = ""
self.tmpRequestToJoinEnsName = ""
self.tmpAirdropAddress = ""
self.tmpAddressesToShare = @[]
proc asyncEditSharedAddresses*(self: Controller, communityId: string, addressesToShare: seq[string],
airdropAddress: string, signatures: seq[string]) =
self.communityService.asyncEditSharedAddresses(communityId, addressesToShare, airdropAddress, signatures)
proc editSharedAddressesAuthenticated*(self: Controller, password: string) =
self.communityService.asyncEditSharedAddresses(
self.tmpCommunityId,
password,
self.tmpAddressesToShare,
self.tmpAirdropAddress,
)
self.tmpAuthenticationAction = AuthenticationAction.None
self.tmpCommunityId = ""
self.tmpAirdropAddress = ""
self.tmpAddressesToShare = @[]
proc userAuthenticated*(self: Controller, password: string) =
if self.tmpAuthenticationAction == AuthenticationAction.CommunityJoin:
self.requestToJoinCommunityAuthenticated(password)
elif self.tmpAuthenticationAction == AuthenticationAction.CommunitySharedAddressesJoin:
self.editSharedAddressesAuthenticated(password)
proc authenticate*(self: Controller, keyUid = "") =
let data = SharedKeycarModuleAuthenticationArgs(uniqueIdentifier: UNIQUE_COMMUNITIES_MODULE_AUTH_IDENTIFIER,
keyUid: keyUid)
proc authenticate*(self: Controller) =
let data = SharedKeycarModuleAuthenticationArgs(uniqueIdentifier: UNIQUE_COMMUNITIES_MODULE_AUTH_IDENTIFIER)
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_AUTHENTICATE_USER, data)
proc authenticateToRequestToJoinCommunity*(self: Controller, communityId: string, ensName: string, addressesToShare: seq[string], airdropAddress: string) =
self.tmpCommunityId = communityId
self.tmpAuthenticationAction = AuthenticationAction.CommunityJoin
self.tmpRequestToJoinEnsName = ensName
self.tmpAirdropAddress = airdropAddress
self.tmpAddressesToShare = addressesToShare
self.authenticate()
proc authenticateToEditSharedAddresses*(self: Controller, communityId: string, addressesToShare: seq[string], airdropAddress: string) =
self.tmpCommunityId = communityId
self.tmpAuthenticationAction = AuthenticationAction.CommunitySharedAddressesJoin
self.tmpAirdropAddress = airdropAddress
self.tmpAddressesToShare = addressesToShare
self.authenticate()
proc getCommunityPublicKeyFromPrivateKey*(self: Controller, communityPrivateKey: string): string =
result = self.communityService.getCommunityPublicKeyFromPrivateKey(communityPrivateKey)
proc asyncCheckPermissionsToJoin*(self: Controller, communityId: string, addressesToShare: seq[string]) =
self.tmpCommunityId = communityId
self.communityService.asyncCheckPermissionsToJoin(communityId, addressesToShare)
proc asyncCheckAllChannelsPermissions*(self: Controller, communityId: string, sharedAddresses: seq[string]) =
self.tmpCommunityIdForChannelsPermisisons = communityId
self.chatService.asyncCheckAllChannelsPermissions(communityId, sharedAddresses)
proc asyncGetRevealedAccountsForMember*(self: Controller, communityId, memberPubkey: string) =
self.tmpCommunityIdForRevealedAccounts = communityId
self.communityService.asyncGetRevealedAccountsForMember(communityId, memberPubkey)
proc generateJoiningCommunityRequestsForSigning*(self: Controller, memberPubKey: string, communityId: string,
addressesToReveal: seq[string]): seq[SignParamsDto] =
return self.communityService.generateJoiningCommunityRequestsForSigning(memberPubKey, communityId, addressesToReveal)
proc generateEditCommunityRequestsForSigning*(self: Controller, memberPubKey: string, communityId: string,
addressesToReveal: seq[string]): seq[SignParamsDto] =
return self.communityService.generateEditCommunityRequestsForSigning(memberPubKey, communityId, addressesToReveal)
proc signCommunityRequests*(self: Controller, communityId: string, signParams: seq[SignParamsDto]): seq[string] =
return self.communityService.signCommunityRequests(communityId, signParams)
proc getKeypairByAccountAddress*(self: Controller, address: string): KeypairDto =
return self.walletAccountService.getKeypairByAccountAddress(address)
proc getKeypairByKeyUid*(self: Controller, keyUid: string): KeypairDto =
return self.walletAccountService.getKeypairByKeyUid(keyUid)
proc getKeypairs*(self: Controller): seq[KeypairDto] =
return self.walletAccountService.getKeypairs()
proc disconnectKeycardReponseSignal(self: Controller) =
self.events.disconnect(self.connectionKeycardResponse)
proc connectKeycardReponseSignal(self: Controller) =
self.connectionKeycardResponse = self.events.onWithUUID(SIGNAL_KEYCARD_RESPONSE) do(e: Args):
let args = KeycardLibArgs(e)
self.disconnectKeycardReponseSignal()
let currentFlow = self.keycardService.getCurrentFlow()
if currentFlow != KCSFlowType.Sign:
return
let keyUid = self.silentSigningKeyUid
let path = self.silentSigningPath
let pin = self.silentSigningPin
self.silentSigningKeyUid = ""
self.silentSigningPath = ""
self.silentSigningPin = ""
self.delegate.onDataSigned(keyUid, path, args.flowEvent.txSignature.r, args.flowEvent.txSignature.s, args.flowEvent.txSignature.v, pin)
proc cancelCurrentFlow*(self: Controller) =
self.keycardService.cancelCurrentFlow()
# in most cases we're running another flow after canceling the current one,
# this way we're giving to the keycard some time to cancel the current flow
sleep(200)
proc runSignFlow(self: Controller, pin, path, dataToSign: string) =
self.cancelCurrentFlow()
self.connectKeycardReponseSignal()
self.keycardService.startSignFlow(path, dataToSign, pin)
proc runSigningOnKeycard*(self: Controller, keyUid: string, path: string, dataToSign: string, pin: string) =
var finalDataToSign = dataToSign
if finalDataToSign.startsWith("0x"):
finalDataToSign = finalDataToSign[2..^1]
if pin.len == 0:
let data = SharedKeycarModuleSigningArgs(uniqueIdentifier: UNIQUE_COMMUNITIES_MODULE_SIGNING_IDENTIFIER,
keyUid: keyUid,
path: path,
dataToSign: finalDataToSign)
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_SIGN_DATA, data)
return
self.silentSigningKeyUid = keyUid
self.silentSigningPath = path
self.silentSigningPin = pin
self.runSignFlow(pin, path, finalDataToSign)

View File

@ -159,10 +159,10 @@ method curatedCommunitiesLoadingFailed*(self: AccessInterface) {.base.} =
method curatedCommunitiesLoaded*(self: AccessInterface, curatedCommunities: seq[CommunityDto]) {.base.} =
raise newException(ValueError, "No implementation available")
method communityInfoAlreadyRequested*(self: AccessInterface) {.base.} =
method communityInfoAlreadyRequested*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method onCommunityTokenMetadataAdded*(self: AccessInterface, communityId: string, tokenMetadata: CommunityTokensMetadataDto) {.base.} =
method onCommunityTokenMetadataAdded*(self: AccessInterface, communityId: string, tokenMetadata: CommunityTokensMetadataDto) {.base.} =
raise newException(ValueError, "No implementation available")
method onWalletAccountTokensRebuilt*(self: AccessInterface) {.base.} =
@ -183,12 +183,20 @@ method shareCommunityChannelUrlWithData*(self: AccessInterface, communityId: str
method onUserAuthenticated*(self: AccessInterface, pin: string, password: string, keyUid: string) {.base.} =
raise newException(ValueError, "No implementation available")
method requestToJoinCommunityWithAuthentication*(self: AccessInterface, communityId, ensName: string, addressesToShare: seq[string],
airdropAddress: string) {.base.} =
method onDataSigned*(self: AccessInterface, keyUid: string, path: string, r: string, s: string, v: string, pin: string) {.base.} =
raise newException(ValueError, "No implementation available")
method editSharedAddressesWithAuthentication*(self: AccessInterface, communityId: string, addressesToShare: seq[string], airdropAddress: string)
{.base.} =
method prepareKeypairsForSigning*(self: AccessInterface, communityId: string, ensName: string, addresses: string,
airdropAddress: string, editMode: bool) {.base.} =
raise newException(ValueError, "No implementation available")
method signSharedAddressesForAllNonKeycardKeypairs*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method signSharedAddressesForKeypair*(self: AccessInterface, keyUid: string, pin: string) {.base.} =
raise newException(ValueError, "No implementation available")
method joinCommunityOrEditSharedAddresses*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method prepareTokenModelForCommunity*(self: AccessInterface, communityId: string) {.base.} =

View File

@ -1,4 +1,4 @@
import NimQml, sequtils, tables, stint, chronicles, json
import NimQml, strutils, sequtils, sugar, tables, stint, chronicles, json
import ./io_interface
import ../io_interface as delegate_interface
@ -12,21 +12,26 @@ import ./models/discord_channels_model
import ./models/discord_file_list_model
import ./models/discord_import_task_item
import ./models/discord_import_tasks_model
import ../../shared_models/[member_item, section_model, section_item, token_permissions_model, token_permission_item,
token_list_item, token_list_model, token_criteria_item, token_criteria_model, token_permission_chat_list_model]
import ../../../global/global_singleton
import ../../../core/eventemitter
import ../../../../app_service/common/types
import ../../../../app_service/service/community/service as community_service
import ../../../../app_service/service/contacts/service as contacts_service
import ../../../../app_service/service/chat/service as chat_service
import ../../../../app_service/service/network/service as networks_service
import ../../../../app_service/service/transaction/service as transaction_service
import ../../../../app_service/service/community_tokens/service as community_tokens_service
import ../../../../app_service/service/token/service as token_service
import ../../../../app_service/service/chat/dto/chat
import app/modules/shared_models/[member_item, section_model, section_item, token_permissions_model, token_permission_item,
token_list_item, token_list_model, token_criteria_item, token_criteria_model, token_permission_chat_list_model, keypair_model]
import app/global/global_singleton
import app/core/eventemitter
import app_service/common/types
import app_service/common/utils as common_utils
import app_service/service/community/service as community_service
import app_service/service/contacts/service as contacts_service
import app_service/service/chat/service as chat_service
import app_service/service/network/service as networks_service
import app_service/service/transaction/service as transaction_service
import app_service/service/community_tokens/service as community_tokens_service
import app_service/service/token/service as token_service
import app_service/service/wallet_account/service as wallet_account_service
import app_service/service/chat/dto/chat
import app_service/service/keycard/service as keycard_service
import ./tokens/module as community_tokens_module
import app/modules/shared/keypairs
export io_interface
type
@ -35,6 +40,41 @@ type
ImportingInProgress
ImportingError
type
Action {.pure.} = enum
None = 0,
JoinCommunity
EditSharedAddresses
type
AddressToShareDetails = object
keyUid: string
address: string
path: string
isAirdropAddress: bool
messageToBeSigned: string
signature: string
type
JoiningCommunityDetails = object
communityId: string
communityIdForChannelsPermisisons: string
communityIdForRevealedAccounts: string
ensName: string
addressesToShare: OrderedTable[string, AddressToShareDetails] ## [address, AddressToShareDetails]
profilePassword: string
profilePin: string
action: Action
proc clear(self: var JoiningCommunityDetails) =
self = JoiningCommunityDetails()
proc allSigned(self: JoiningCommunityDetails): bool =
for _, details in self.addressesToShare.pairs:
if details.signature.len == 0:
return false
return true
type
Module* = ref object of io_interface.AccessInterface
delegate: delegate_interface.AccessInterface
@ -46,6 +86,7 @@ type
communityTokensModule: community_tokens_module.AccessInterface
checkingPermissionToJoinInProgress: bool
checkingAllChannelPermissionsInProgress: bool
joiningCommunityDetails: JoiningCommunityDetails
# Forward declaration
method setCommunityTags*(self: Module, communityTags: string)
@ -62,6 +103,8 @@ proc newModule*(
transactionService: transaction_service.Service,
tokensService: token_service.Service,
chatService: chat_service.Service,
walletAccountService: wallet_account_service.Service,
keycardService: keycard_service.Service,
): Module =
result = Module()
result.delegate = delegate
@ -76,6 +119,8 @@ proc newModule*(
networksService,
tokensService,
chatService,
walletAccountService,
keycardService,
)
result.communityTokensModule = community_tokens_module.newCommunityTokensModule(result, events, communityTokensService, transactionService, networksService, communityService)
result.moduleLoaded = false
@ -89,6 +134,9 @@ method delete*(self: Module) =
self.controller.delete
self.communityTokensModule.delete
proc clean(self: Module) =
self.joiningCommunityDetails.clear()
method load*(self: Module) =
singletonInstance.engine.setRootContextProperty("communitiesModule", self.viewVariant)
self.controller.init()
@ -281,22 +329,27 @@ method createCommunity*(self: Module, name: string,
pinMessageAllMembersEnabled: bool,
bannerJsonStr: string) =
self.controller.createCommunity(name, description, introMessage, outroMessage, access, color, tags,
imagePath, aX, aY, bX, bY, historyArchiveSupportEnabled, pinMessageAllMembersEnabled,
imagePath, aX, aY, bX, bY, historyArchiveSupportEnabled, pinMessageAllMembersEnabled,
bannerJsonStr)
method communityMuted*(self: Module, communityId: string, muted: bool) =
self.view.model().setMuted(communityId, muted)
method communityAccessRequested*(self: Module, communityId: string) =
self.clean()
self.view.communityAccessRequested(communityId)
method communityAccessFailed*(self: Module, communityId, error: string) =
self.view.communityAccessFailed(communityId, error)
method communityAccessFailed*(self: Module, communityId, err: string) =
error "communities: ", err
self.clean()
self.view.communityAccessFailed(communityId, err)
method communityEditSharedAddressesSucceeded*(self: Module, communityId: string) =
self.clean()
self.view.communityEditSharedAddressesSucceeded(communityId)
method communityEditSharedAddressesFailed*(self: Module, communityId, error: string) =
self.clean()
self.view.communityEditSharedAddressesFailed(communityId, error)
method communityHistoryArchivesDownloadStarted*(self: Module, communityId: string) =
@ -344,7 +397,7 @@ method communityImported*(self: Module, community: CommunityDto) =
self.view.addOrUpdateItem(self.getCommunityItem(community))
self.view.emitImportingCommunityStateChangedSignal(community.id, ImportCommunityState.Imported.int, errorMsg = "")
method communityDataImported*(self: Module, community: CommunityDto) =
method communityDataImported*(self: Module, community: CommunityDto) =
self.view.addItem(self.getCommunityItem(community))
self.view.emitCommunityInfoRequestCompleted(community.id, "")
@ -364,7 +417,7 @@ method requestExtractDiscordChannelsAndCategories*(self: Module, filesToImport:
method requestImportDiscordCommunity*(self: Module, name: string, description, introMessage, outroMessage: string, access: int,
color: string, tags: string, imagePath: string, aX: int, aY: int, bX: int, bY: int,
historyArchiveSupportEnabled: bool, pinMessageAllMembersEnabled: bool, filesToImport: seq[string],
historyArchiveSupportEnabled: bool, pinMessageAllMembersEnabled: bool, filesToImport: seq[string],
fromTimestamp: int) =
self.view.setDiscordImportHasCommunityImage(imagePath != "")
self.controller.requestImportDiscordCommunity(name, description, introMessage, outroMessage, access, color, tags, imagePath, aX, aY, bX, bY, historyArchiveSupportEnabled, pinMessageAllMembersEnabled, filesToImport, fromTimestamp)
@ -534,32 +587,166 @@ method shareCommunityChannelUrlWithChatKey*(self: Module, communityId: string, c
method shareCommunityChannelUrlWithData*(self: Module, communityId: string, chatId: string): string =
return self.controller.shareCommunityChannelUrlWithData(communityId, chatId)
method signRevealedAddressesThatBelongToRegularKeypairs(self: Module): bool =
var signingParams: seq[SignParamsDto]
for address, details in self.joiningCommunityDetails.addressesToShare.pairs:
if details.signature.len > 0:
continue
let keypair = self.controller.getKeypairByAccountAddress(address)
if keypair.isNil:
self.communityAccessFailed(self.joiningCommunityDetails.communityId, "cannot resolve keypair for address" & address)
return false
if keypair.migratedToKeycard():
continue
signingParams.add(
SignParamsDto(
address: address,
data: details.messageToBeSigned,
password: common_utils.hashPassword(self.joiningCommunityDetails.profilePassword),
)
)
if signingParams.len == 0:
return true
# signatures are returned in the same order as signingParams
let signatures = self.controller.signCommunityRequests(self.joiningCommunityDetails.communityId, signingParams)
for i in 0 ..< len(signingParams):
self.joiningCommunityDetails.addressesToShare[signingParams[i].address].signature = signatures[i]
return true
method onUserAuthenticated*(self: Module, pin: string, password: string, keyUid: string) =
if password == "" and pin == "":
self.view.userAuthenticationCanceled()
self.controller.userAuthenticationCanceled()
info "unsuccesful authentication"
self.clean()
return
self.controller.userAuthenticated(password)
self.joiningCommunityDetails.profilePassword = password
self.joiningCommunityDetails.profilePin = pin
if self.signRevealedAddressesThatBelongToRegularKeypairs():
self.view.sendSharedAddressesForAllNonKeycardKeypairsSignedSignal()
method requestToJoinCommunityWithAuthentication*(self: Module, communityId, ensName: string, addressesToShare: seq[string],
airdropAddress: string) =
self.controller.authenticateToRequestToJoinCommunity(communityId, ensName, addressesToShare, airdropAddress)
method onDataSigned*(self: Module, keyUid: string, path: string, r: string, s: string, v: string, pin: string) =
if keyUid.len == 0 or path.len == 0 or r.len == 0 or s.len == 0 or v.len == 0 or pin.len == 0:
# being here is not an error
return
method editSharedAddressesWithAuthentication*(self: Module, communityId: string, addressesToShare: seq[string], airdropAddress: string) =
self.controller.authenticateToEditSharedAddresses(communityId, addressesToShare, airdropAddress)
for address, details in self.joiningCommunityDetails.addressesToShare.pairs:
if details.keyUid != keyUid or details.path != path:
continue
self.joiningCommunityDetails.addressesToShare[address].signature = "0x" & r & s & v
break
self.signSharedAddressesForKeypair(keyUid, pin)
method prepareKeypairsForSigning*(self: Module, communityId, ensName: string, addresses: string,
airdropAddress: string, editMode: bool) =
var addressesToShare: seq[string]
try:
addressesToShare = map(parseJson(addresses).getElems(), proc(x:JsonNode):string = x.getStr())
except Exception as e:
self.communityAccessFailed(communityId, "error parsing addresses: " & e.msg)
return
let allKeypairs = keypairs.buildKeyPairsList(self.controller.getKeypairs(), excludeAlreadyMigratedPairs = false,
excludePrivateKeyKeypairs = false)
for it in allKeypairs:
let addressesToRemove = it.getAccountsModel().getItems()
.map(x => x.getAddress())
.filter(x => addressesToShare.filter(y => cmpIgnoreCase(y, x) == 0).len == 0)
for address in addressesToRemove:
it.removeAccountByAddress(address)
let keypairsForSigning = allKeypairs.filter(x => x.getAccountsModel().getCount() > 0)
self.view.setKeypairsSigningModelItems(keypairsForSigning)
self.joiningCommunityDetails.communityId = communityId
var signingParams: seq[SignParamsDto]
if editMode:
self.joiningCommunityDetails.action = Action.EditSharedAddresses
signingParams = self.controller.generateEditCommunityRequestsForSigning(
singletonInstance.userProfile.getPubKey(), communityId, addressesToShare)
else:
self.joiningCommunityDetails.action = Action.JoinCommunity
self.joiningCommunityDetails.ensName = ensName
signingParams = self.controller.generateJoiningCommunityRequestsForSigning(
singletonInstance.userProfile.getPubKey(), communityId, addressesToShare)
let findKeyUidAndPathForAddress = proc (items: seq[KeyPairItem], address: string): tuple[keyUid: string, path: string] =
for it in items:
for acc in it.getAccountsModel().getItems():
if cmpIgnoreCase(acc.getAddress(), address) == 0:
return (it.getKeyUid(), acc.getPath())
return ("", "")
for param in signingParams:
let (keyUid, path) = findKeyUidAndPathForAddress(keypairsForSigning, param.address)
let details = AddressToShareDetails(
keyUid: keyUid,
address: param.address,
path: path,
isAirdropAddress: if cmpIgnoreCase(param.address, airdropAddress) == 0: true else: false,
messageToBeSigned: param.data
)
self.joiningCommunityDetails.addressesToShare[param.address] = details
method signSharedAddressesForAllNonKeycardKeypairs*(self: Module) =
self.controller.authenticate()
# if pin is provided we're signing on a keycard silently
method signSharedAddressesForKeypair*(self: Module, keyUid: string, pin: string) =
let keypair = self.controller.getKeypairByKeyUid(keyUid)
if keypair.isNil:
self.communityAccessFailed(self.joiningCommunityDetails.communityId, "cannot resolve keypair for keyUid " & keyUid)
return
for acc in keypair.accounts:
for address, details in self.joiningCommunityDetails.addressesToShare.pairs:
if cmpIgnoreCase(address, acc.address) != 0:
continue
if details.signature.len > 0:
continue
self.controller.runSigningOnKeycard(keyUid, details.path, details.messageToBeSigned, pin)
return
self.view.keypairsSigningModel().setOwnershipVerified(keyUid, true)
method joinCommunityOrEditSharedAddresses*(self: Module) =
if not self.joiningCommunityDetails.allSigned():
self.communityAccessFailed(self.joiningCommunityDetails.communityId, "unexpected call to join community function before all addresses are signed")
return
var
addressesToShare: seq[string]
airdropAddress: string
signatures: seq[string]
for _, details in self.joiningCommunityDetails.addressesToShare.pairs:
addressesToShare.add(details.address)
if details.isAirdropAddress:
airdropAddress = details.address
signatures.add(details.signature)
if self.joiningCommunityDetails.action == Action.JoinCommunity:
self.controller.asyncRequestToJoinCommunity(self.joiningCommunityDetails.communityId,
self.joiningCommunityDetails.ensName,
addressesToShare,
airdropAddress,
signatures)
return
if self.joiningCommunityDetails.action == Action.EditSharedAddresses:
self.controller.asyncEditSharedAddresses(self.joiningCommunityDetails.communityId,
addressesToShare,
airdropAddress,
signatures)
return
self.communityAccessFailed(self.joiningCommunityDetails.communityId, "unexpected action")
method getCommunityPublicKeyFromPrivateKey*(self: Module, communityPrivateKey: string): string =
result = self.controller.getCommunityPublicKeyFromPrivateKey(communityPrivateKey)
method checkPermissions*(self: Module, communityId: string, sharedAddresses: seq[string]) =
self.joiningCommunityDetails.communityIdForChannelsPermisisons = communityId
self.controller.asyncCheckPermissionsToJoin(communityId, sharedAddresses)
self.controller.asyncCheckAllChannelsPermissions(communityId, sharedAddresses)
self.view.setCheckingPermissionsInProgress(inProgress = true)
method prepareTokenModelForCommunity*(self: Module, communityId: string) =
self.joiningCommunityDetails.communityIdForRevealedAccounts = communityId
self.controller.asyncGetRevealedAccountsForMember(communityId, singletonInstance.userProfile.getPubKey())
let community = self.controller.getCommunityById(communityId)
@ -633,12 +820,16 @@ method onCommunityCheckAllChannelPermissionsFailed*(self: Module, communityId: s
method onCommunityCheckPermissionsToJoinResponse*(self: Module, communityId: string,
checkPermissionsToJoinResponse: CheckPermissionsToJoinResponseDto) =
if self.joiningCommunityDetails.communityId != communityId:
return
self.applyPermissionResponse(communityId, checkPermissionsToJoinResponse.permissions)
self.checkingPermissionToJoinInProgress = false
self.updateCheckingPermissionsInProgressIfNeeded(inProgress = false)
method onCommunityCheckAllChannelsPermissionsResponse*(self: Module, communityId: string,
checkChannelPermissionsResponse: CheckAllChannelsPermissionsResponseDto) =
if self.joiningCommunityDetails.communityIdForChannelsPermisisons != communityId:
return
self.checkingAllChannelPermissionsInProgress = false
self.updateCheckingPermissionsInProgressIfNeeded(inProgress = false)
for _, channelPermissionResponse in checkChannelPermissionsResponse.channels:
@ -653,6 +844,8 @@ method onCommunityCheckAllChannelsPermissionsResponse*(self: Module, communityId
method onCommunityMemberRevealedAccountsLoaded*(self: Module, communityId, memberPubkey: string,
revealedAccounts: seq[RevealedAccount]) =
if self.joiningCommunityDetails.communityIdForRevealedAccounts != communityId:
return
if memberPubkey == singletonInstance.userProfile.getPubKey():
var addresses: seq[string] = @[]
var airdropAddress = ""

View File

@ -2,7 +2,7 @@ import NimQml, json, strutils, sequtils
import ./io_interface
import ../../shared_models/[section_model, section_item, token_list_model, token_list_item,
token_permissions_model]
token_permissions_model, keypair_model]
import ./models/curated_community_model
import ./models/discord_file_list_model
import ./models/discord_file_item
@ -55,6 +55,8 @@ QtObject:
checkingPermissionsInProgress: bool
myRevealedAddressesStringForCurrentCommunity: string
myRevealedAirdropAddressForCurrentCommunity: string
keypairsSigningModel: KeyPairModel
keypairsSigningModelVariant: QVariant
proc delete*(self: View) =
self.model.delete
@ -75,6 +77,10 @@ QtObject:
self.tokenListModelVariant.delete
self.collectiblesListModel.delete
self.collectiblesListModelVariant.delete
if not self.keypairsSigningModel.isNil:
self.keypairsSigningModel.delete
if not self.keypairsSigningModelVariant.isNil:
self.keypairsSigningModelVariant.delete
self.QObject.delete
@ -318,6 +324,15 @@ QtObject:
proc prepareTokenModelForCommunity(self: View, communityId: string) {.slot.} =
self.delegate.prepareTokenModelForCommunity(communityId)
proc signSharedAddressesForAllNonKeycardKeypairs*(self: View) {.slot.} =
self.delegate.signSharedAddressesForAllNonKeycardKeypairs()
proc signSharedAddressesForKeypair*(self: View, keyUid: string) {.slot.} =
self.delegate.signSharedAddressesForKeypair(keyUid, pin = "")
proc joinCommunityOrEditSharedAddresses*(self: View) {.slot.} =
self.delegate.joinCommunityOrEditSharedAddresses()
proc checkPermissions*(self: View, communityId: string, addressesToShare: string) {.slot.} =
try:
let sharedAddresses = map(parseJson(addressesToShare).getElems(), proc(x:JsonNode):string = x.getStr())
@ -460,7 +475,7 @@ QtObject:
historyArchiveSupportEnabled: bool,
pinMessageAllMembersEnabled: bool, bannerJsonStr: string) {.slot.} =
self.delegate.createCommunity(name, description, introMessage, outroMessage, access, color, tags,
imagePath, aX, aY, bX, bY, historyArchiveSupportEnabled, pinMessageAllMembersEnabled,
imagePath, aX, aY, bX, bY, historyArchiveSupportEnabled, pinMessageAllMembersEnabled,
bannerJsonStr)
proc clearFileList*(self: View) {.slot.} =
@ -673,25 +688,9 @@ QtObject:
proc shareCommunityChannelUrlWithData*(self: View, communityId: string, chatId: string): string {.slot.} =
return self.delegate.shareCommunityChannelUrlWithData(communityId, chatId)
proc userAuthenticationCanceled*(self: View) {.signal.}
proc requestToJoinCommunityWithAuthentication*(self: View, communityId: string, ensName: string) {.slot.} =
self.delegate.requestToJoinCommunityWithAuthentication(communityId, ensName, @[], "")
proc requestToJoinCommunityWithAuthenticationWithSharedAddresses*(self: View, communityId: string, ensName: string,
addressesToShare: string, airdropAddress: string) {.slot.} =
try:
let addressesArray = map(parseJson(addressesToShare).getElems(), proc(x:JsonNode):string = x.getStr())
self.delegate.requestToJoinCommunityWithAuthentication(communityId, ensName, addressesArray, airdropAddress)
except Exception as e:
echo "Error requesting to join community with authentication and shared addresses: ", e.msg
proc editSharedAddressesWithAuthentication*(self: View, communityId: string, addressesToShare: string, airdropAddress: string) {.slot.} =
try:
let addressesArray = map(parseJson(addressesToShare).getElems(), proc(x:JsonNode):string = x.getStr())
self.delegate.editSharedAddressesWithAuthentication(communityId, addressesArray, airdropAddress)
except Exception as e:
echo "Error editing shared addresses with authentication: ", e.msg
proc prepareKeypairsForSigning*(self: View, communityId: string, ensName: string, addresses: string,
airdropAddress: string, editMode: bool) {.slot.} =
self.delegate.prepareKeypairsForSigning(communityId, ensName, addresses, airdropAddress, editMode)
proc getCommunityPublicKeyFromPrivateKey*(self: View, communityPrivateKey: string): string {.slot.} =
result = self.delegate.getCommunityPublicKeyFromPrivateKey(communityPrivateKey)
@ -731,3 +730,25 @@ QtObject:
QtProperty[bool] requirementsCheckPending:
read = getCheckingPermissionsInProgress
notify = checkingPermissionsInProgressChanged
proc keypairsSigningModel*(self: View): KeyPairModel =
return self.keypairsSigningModel
proc keypairsSigningModelChanged*(self: View) {.signal.}
proc getKeypairsSigningModel(self: View): QVariant {.slot.} =
return newQVariant(self.keypairsSigningModel)
QtProperty[QVariant] keypairsSigningModel:
read = getKeypairsSigningModel
notify = keypairsSigningModelChanged
proc setKeypairsSigningModelItems*(self: View, items: seq[KeyPairItem]) =
if self.keypairsSigningModel.isNil:
self.keypairsSigningModel = newKeyPairModel()
if self.keypairsSigningModelVariant.isNil:
self.keypairsSigningModelVariant = newQVariant(self.keypairsSigningModel)
self.keypairsSigningModel.setItems(items)
self.keypairsSigningModelChanged()
proc sharedAddressesForAllNonKeycardKeypairsSigned(self: View) {.signal.}
proc sendSharedAddressesForAllNonKeycardKeypairsSignedSignal*(self: View) =
self.sharedAddressesForAllNonKeycardKeypairsSigned()

View File

@ -28,6 +28,7 @@ QtObject:
syncedFrom: string
accounts: KeyPairAccountModel
observedAccount: KeyPairAccountItem
ownershipVerified: bool
proc setup*(self: KeyPairItem,
keyUid: string,
@ -40,7 +41,8 @@ QtObject:
derivedFrom: string,
lastUsedDerivationIndex: int,
migratedToKeycard: bool,
syncedFrom: string
syncedFrom: string,
ownershipVerified: bool
) =
self.QObject.setup
self.keyUid = keyUid
@ -54,6 +56,7 @@ QtObject:
self.lastUsedDerivationIndex = lastUsedDerivationIndex
self.migratedToKeycard = migratedToKeycard
self.syncedFrom = syncedFrom
self.ownershipVerified = ownershipVerified
self.accounts = newKeyPairAccountModel()
proc delete*(self: KeyPairItem) =
@ -69,10 +72,11 @@ QtObject:
derivedFrom = "",
lastUsedDerivationIndex = 0,
migratedToKeycard = false,
syncedFrom = ""): KeyPairItem =
syncedFrom = "",
ownershipVerified = false): KeyPairItem =
new(result, delete)
result.setup(keyUid, pubKey, locked, name, image, icon, pairType, derivedFrom, lastUsedDerivationIndex,
migratedToKeycard, syncedFrom)
migratedToKeycard, syncedFrom, ownershipVerified)
proc `$`*(self: KeyPairItem): string =
result = fmt"""KeyPairItem[
@ -88,7 +92,8 @@ QtObject:
migratedToKeycard: {self.migratedToKeycard},
operability: {self.operability},
syncedFrom: {self.syncedFrom},
accounts: {$self.accounts}
ownershipVerified: {$self.ownershipVerified}
accounts: {$self.accounts},
]"""
proc keyUidChanged*(self: KeyPairItem) {.signal.}
@ -224,6 +229,17 @@ QtObject:
write = setSyncedFrom
notify = syncedFromChanged
proc ownershipVerifiedChanged*(self: KeyPairItem) {.signal.}
proc getOwnershipVerified*(self: KeyPairItem): bool {.slot.} =
return self.ownershipVerified
proc setOwnershipVerified*(self: KeyPairItem, value: bool) {.slot.} =
self.ownershipVerified = value
self.ownershipVerifiedChanged()
QtProperty[bool] ownershipVerified:
read = getOwnershipVerified
write = setOwnershipVerified
notify = ownershipVerifiedChanged
proc observedAccountChanged*(self: KeyPairItem) {.signal.}
proc getObservedAccountAsVariant*(self: KeyPairItem): QVariant {.slot.} =
return newQVariant(self.observedAccount)
@ -288,4 +304,5 @@ QtObject:
self.setMigratedToKeycard(item.getMigratedToKeycard())
self.setLastUsedDerivationIndex(item.getLastUsedDerivationIndex())
self.setAccounts(item.getAccountsModel().getItems())
self.setOwnershipVerified(item.getOwnershipVerified())
self.setLastAccountAsObservedAccount()

View File

@ -109,6 +109,12 @@ QtObject:
return
item.setName(name)
proc setOwnershipVerified*(self: KeyPairModel, keyUid: string, ownershipVerified: bool) =
let item = self.findItemByKeyUid(keyUid)
if item.isNil:
return
item.setOwnershipVerified(ownershipVerified)
proc setBalanceForAddress*(self: KeyPairModel, address: string, balance: CurrencyAmount) =
for item in self.items:
item.setBalanceForAddress(address, balance)

View File

@ -25,7 +25,7 @@ QtObject:
): KeycardItem =
new(result, delete)
result.KeyPairItem.setup(keyUid, pubKey, locked, name, image, icon, pairType, derivedFrom,lastUsedDerivationIndex,
migratedToKeycard, syncedFrom = "")
migratedToKeycard, syncedFrom = "", ownershipVerified = false)
result.keycardUid = keycardUid
proc `$`*(self: KeycardItem): string =

View File

@ -157,15 +157,15 @@ type
AsyncRequestToJoinCommunityTaskArg = ref object of QObjectTaskArg
communityId: string
ensName: string
password: string
addressesToShare: seq[string]
signatures: seq[string]
airdropAddress: string
const asyncRequestToJoinCommunityTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[AsyncRequestToJoinCommunityTaskArg](argEncoded)
try:
let response = status_go.requestToJoinCommunity(arg.communityId, arg.ensName, arg.password, arg.addressesToShare,
arg.airdropAddress)
let response = status_go.requestToJoinCommunity(arg.communityId, arg.ensName, arg.addressesToShare,
arg.signatures, arg.airdropAddress)
arg.finish(%* {
"response": response,
"communityId": arg.communityId,
@ -180,14 +180,14 @@ const asyncRequestToJoinCommunityTask: Task = proc(argEncoded: string) {.gcsafe,
type
AsyncEditSharedAddressesTaskArg = ref object of QObjectTaskArg
communityId: string
password: string
addressesToShare: seq[string]
signatures: seq[string]
airdropAddress: string
const asyncEditSharedAddressesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[AsyncEditSharedAddressesTaskArg](argEncoded)
try:
let response = status_go.editSharedAddresses(arg.communityId, arg.password, arg.addressesToShare,
let response = status_go.editSharedAddresses(arg.communityId, arg.addressesToShare, arg.signatures,
arg.airdropAddress)
arg.finish(%* {
"response": response,

View File

@ -0,0 +1,21 @@
import json
include app_service/common/json_utils
type SignParamsDto* = object
data*: string
address*: string
password*: string
proc toSignParamsDto*(jsonObj: JsonNode): SignParamsDto =
result = SignParamsDto()
discard jsonObj.getProp("data", result.data)
discard jsonObj.getProp("account", result.address)
discard jsonObj.getProp("password", result.password)
proc toJson*(self: SignParamsDto): JsonNode =
return %* {
"data": $self.data,
"account": $self.address,
"password": $self.password
}

View File

@ -2,6 +2,7 @@ import NimQml, Tables, json, sequtils, std/sets, std/algorithm, strformat, strut
import json_serialization/std/tables as ser_tables
import ./dto/community as community_dto
import ./dto/sign_params as sign_params_dto
import ../community_tokens/dto/community_token as community_token_dto
import ../activity_center/service as activity_center_service
@ -20,7 +21,7 @@ import ../../../app_service/common/utils
include ./async_tasks
export community_dto
export community_dto, sign_params_dto
logScope:
topics = "community-service"
@ -1503,8 +1504,52 @@ QtObject:
error: errMsg,
))
proc asyncRequestToJoinCommunity*(self: Service, communityId: string, ensName: string, password: string,
addressesToShare: seq[string], airdropAddress: string) =
proc generateJoiningCommunityRequestsForSigning*(self: Service, memberPubKey: string, communityId: string,
addressesToReveal: seq[string]): seq[SignParamsDto] =
try:
let response = status_go.generateJoiningCommunityRequestsForSigning(memberPubKey, communityId, addressesToReveal)
if not response.error.isNil:
raise newException(RpcException, response.error.message)
result = map(response.result.getElems(), x => x.toSignParamsDto())
except Exception as e:
error "Error while generating join community request", msg = e.msg
self.events.emit(SIGNAL_COMMUNITY_MY_REQUEST_FAILED, CommunityRequestFailedArgs(
communityId: communityId,
error: e.msg
))
proc generateEditCommunityRequestsForSigning*(self: Service, memberPubKey: string, communityId: string,
addressesToReveal: seq[string]): seq[SignParamsDto] =
try:
let response = status_go.generateEditCommunityRequestsForSigning(memberPubKey, communityId, addressesToReveal)
if not response.error.isNil:
raise newException(RpcException, response.error.message)
result = map(response.result.getElems(), x => x.toSignParamsDto())
except Exception as e:
error "Error while generating edit community request", msg = e.msg
self.events.emit(SIGNAL_COMMUNITY_EDIT_SHARED_ADDRESSES_FAILED, CommunityRequestFailedArgs(
communityId: communityId,
error: e.msg
))
proc signCommunityRequests*(self: Service, communityId: string, signParams: seq[SignParamsDto]): seq[string] =
try:
var data = %* []
for param in signParams:
data.add(param.toJson())
let response = status_go.signData(data)
if not response.error.isNil:
raise newException(RpcException, response.error.message)
result = map(response.result.getElems(), x => x.getStr())
except Exception as e:
error "Error while signing joining community request", msg = e.msg
self.events.emit(SIGNAL_COMMUNITY_MY_REQUEST_FAILED, CommunityRequestFailedArgs(
communityId: communityId,
error: e.msg
))
proc asyncRequestToJoinCommunity*(self: Service, communityId: string, ensName: string, addressesToShare: seq[string],
airdropAddress: string, signatures: seq[string]) =
try:
let arg = AsyncRequestToJoinCommunityTaskArg(
tptr: cast[ByteAddress](asyncRequestToJoinCommunityTask),
@ -1512,8 +1557,8 @@ QtObject:
slot: "onAsyncRequestToJoinCommunityDone",
communityId: communityId,
ensName: ensName,
password: if password != "": utils.hashPassword(password) else: "",
addressesToShare: addressesToShare,
signatures: signatures,
airdropAddress: airdropAddress,
)
self.threadpool.start(arg)
@ -1539,15 +1584,15 @@ QtObject:
error: e.msg
))
proc asyncEditSharedAddresses*(self: Service, communityId: string, password: string, addressesToShare: seq[string],
airdropAddress: string) =
proc asyncEditSharedAddresses*(self: Service, communityId: string, addressesToShare: seq[string], airdropAddress: string,
signatures: seq[string]) =
let arg = AsyncEditSharedAddressesTaskArg(
tptr: cast[ByteAddress](asyncEditSharedAddressesTask),
vptr: cast[ByteAddress](self.vptr),
slot: "onAsyncEditSharedAddressesDone",
communityId: communityId,
password: if password != "": utils.hashPassword(password) else: "",
addressesToShare: addressesToShare,
signatures: signatures,
airdropAddress: airdropAddress,
)
self.threadpool.start(arg)

View File

@ -346,7 +346,7 @@ QtObject:
self.currentFlow = KCSFlowType.StoreMetadata
self.startFlow(payload)
proc startSignFlow*(self: Service, bip44Path: string, txHash: string, pin: string) =
proc startSignFlow*(self: Service, bip44Path: string, txHash: string, pin: string = "") =
var payload = %* {
RequestParamTXHash: EmptyTxHash,
RequestParamBIP44Path: DefaultBIP44Path

View File

@ -31,31 +31,54 @@ proc getAllCommunities*(): RpcResponse[JsonNode] {.raises: [Exception].} =
proc spectateCommunity*(communityId: string): RpcResponse[JsonNode] {.raises: [Exception].} =
result = callPrivateRPC("spectateCommunity".prefix, %*[communityId])
proc generateJoiningCommunityRequestsForSigning*(
memberPubKey: string,
communityId: string,
addressesToReveal: seq[string]
): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %*[memberPubKey, communityId, addressesToReveal]
result = callPrivateRPC("generateJoiningCommunityRequestsForSigning".prefix, payload)
proc generateEditCommunityRequestsForSigning*(
memberPubKey: string,
communityId: string,
addressesToReveal: seq[string]
): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %*[memberPubKey, communityId, addressesToReveal]
result = callPrivateRPC("generateEditCommunityRequestsForSigning".prefix, payload)
## `signParams` represents a json array of SignParamsDto.
proc signData*(signParams: JsonNode): RpcResponse[JsonNode] {.raises: [Exception].} =
if signParams.kind != JArray:
raise newException(Exception, "signParams must be an array")
let payload = %*[signParams]
result = callPrivateRPC("signData".prefix, payload)
proc requestToJoinCommunity*(
communityId: string,
ensName: string,
password: string,
addressesToShare: seq[string],
signatures: seq[string],
airdropAddress: string,
): RpcResponse[JsonNode] {.raises: [Exception].} =
result = callPrivateRPC("requestToJoinCommunity".prefix, %*[{
"communityId": communityId,
"ensName": ensName,
"password": password,
"addressesToReveal": addressesToShare,
"signatures": signatures,
"airdropAddress": airdropAddress,
}])
proc editSharedAddresses*(
communityId: string,
password: string,
addressesToShare: seq[string],
signatures: seq[string],
airdropAddress: string,
): RpcResponse[JsonNode] {.raises: [Exception].} =
result = callPrivateRPC("editSharedAddressesForCommunity".prefix, %*[{
"communityId": communityId,
"password": password,
"addressesToReveal": addressesToShare,
"signatures": signatures,
"airdropAddress": airdropAddress,
}])

View File

@ -13,6 +13,7 @@ StatusModal {
property alias stackItems: stackLayout.children
property alias currentIndex: stackLayout.currentIndex
property alias replaceLoader: replaceLoader
property alias replaceItem: replaceLoader.sourceComponent
property alias subHeaderItem: subHeaderLoader.sourceComponent

View File

@ -229,8 +229,22 @@ StackLayout {
assetsModel: root.rootStore.assetsModel
collectiblesModel: root.rootStore.collectiblesModel
onJoined: {
root.rootStore.requestToJoinCommunityWithAuthentication(communityIntroDialog.communityId, root.rootStore.userProfileInst.name, sharedAddresses, airdropAddress)
onPrepareForSigning: {
root.rootStore.prepareKeypairsForSigning(sharedAddresses)
communityIntroDialog.keypairSigningModel = root.rootStore.communitiesModuleInst.keypairsSigningModel
}
onSignSharedAddressesForAllNonKeycardKeypairs: {
root.rootStore.signSharedAddressesForAllNonKeycardKeypairs()
}
onSignSharedAddressesForKeypair: {
root.rootStore.signSharedAddressesForKeypair(keyUid)
}
onJoinCommunity: {
root.rootStore.joinCommunityOrEditSharedAddresses()
}
onCancelMembershipRequest: {
@ -245,6 +259,16 @@ StackLayout {
onClosed: {
destroy()
}
Connections {
target: root.rootStore.communitiesModuleInst
function onSharedAddressesForAllNonKeycardKeypairsSigned() {
if (!!communityIntroDialog.replaceItem) {
communityIntroDialog.replaceLoader.item.sharedAddressesForAllNonKeycardKeypairsSigned()
}
}
}
}
}

View File

@ -394,8 +394,20 @@ QtObject {
return communitiesModuleInst.spectateCommunity(id, ensName)
}
function requestToJoinCommunityWithAuthentication(communityId, ensName, addressesToShare = [], airdropAddress = "") {
communitiesModuleInst.requestToJoinCommunityWithAuthenticationWithSharedAddresses(communityId, ensName, JSON.stringify(addressesToShare), airdropAddress)
function prepareKeypairsForSigning(communityId, ensName, addressesToShare = [], airdropAddress = "", editMode = false) {
communitiesModuleInst.prepareKeypairsForSigning(communityId, ensName, JSON.stringify(addressesToShare), airdropAddress, editMode)
}
function signSharedAddressesForAllNonKeycardKeypairs() {
communitiesModuleInst.signSharedAddressesForAllNonKeycardKeypairs()
}
function signSharedAddressesForKeypair(keyUid) {
communitiesModuleInst.signSharedAddressesForKeypair(keyUid)
}
function joinCommunityOrEditSharedAddresses() {
communitiesModuleInst.joinCommunityOrEditSharedAddresses()
}
function getChainIdForChat() {
@ -612,9 +624,9 @@ QtObject {
readonly property bool amIMember: chatCommunitySectionModule ? chatCommunitySectionModule.amIMember : false
property var oneToOneChatContact: undefined
readonly property string oneToOneChatContactName: !!_d.oneToOneChatContact ? ProfileUtils.displayName(_d.oneToOneChatContact.localNickname,
_d.oneToOneChatContact.name,
_d.oneToOneChatContact.displayName,
readonly property string oneToOneChatContactName: !!_d.oneToOneChatContact ? ProfileUtils.displayName(_d.oneToOneChatContact.localNickname,
_d.oneToOneChatContact.name,
_d.oneToOneChatContact.displayName,
_d.oneToOneChatContact.alias) : ""
//Update oneToOneChatContact when the contact is updated
@ -674,7 +686,7 @@ QtObject {
//Update oneToOneChatContact when activeChat id changes
Binding on oneToOneChatContact {
when: _d.activeChatId && _d.activeChatType === Constants.chatType.oneToOne
when: _d.activeChatId && _d.activeChatType === Constants.chatType.oneToOne
value: Utils.getContactDetailsAsJson(_d.activeChatId, false)
restoreMode: Binding.RestoreBindingOrValue
}

View File

@ -51,13 +51,14 @@ Control {
enabled: d.dirty
type: d.lostCommunityPermission || d.lostChannelPermissions ? StatusBaseButton.Type.Danger : StatusBaseButton.Type.Normal
visible: root.isEditMode
icon.name: type === StatusBaseButton.Type.Normal && d.selectedAddressesDirty ? Constants.authenticationIconByType[root.loginType] : ""
icon.name: type === StatusBaseButton.Type.Normal && d.selectedAddressesDirty?
!root.isEditMode? Constants.authenticationIconByType[root.loginType] : ""
: ""
text: d.lostCommunityPermission ? qsTr("Save changes & leave %1").arg(root.communityName) :
d.lostChannelPermissions ? qsTr("Save changes & update my permissions")
: qsTr("Save changes")
: qsTr("Prove ownership")
onClicked: {
root.saveSelectedAddressesClicked(root.selectedAirdropAddress, root.selectedSharedAddresses)
root.close()
root.prepareForSigning(root.selectedAirdropAddress, root.selectedSharedAddresses)
}
}
StatusButton {
@ -78,7 +79,7 @@ Control {
signal sharedAddressesChanged(string airdropAddress, var sharedAddresses)
signal shareSelectedAddressesClicked(string airdropAddress, var sharedAddresses)
signal saveSelectedAddressesClicked(string airdropAddress, var sharedAddresses)
signal prepareForSigning(string airdropAddress, var sharedAddresses)
signal close()
@ -118,11 +119,14 @@ Control {
function setOldSharedAddresses(oldSharedAddresses) {
d.initialSelectedSharedAddresses = oldSharedAddresses
accountSelector.selectedSharedAddresses = Qt.binding(() => d.initialSelectedSharedAddresses)
accountSelector.applyChange()
}
function setOldAirdropAddress(oldAirdropAddress) {
d.initialSelectedAirdropAddress = oldAirdropAddress
accountSelector.selectedAirdropAddress = oldAirdropAddress
accountSelector.selectedAirdropAddress = Qt.binding(() => d.initialSelectedAirdropAddress)
accountSelector.applyChange()
}
SortFilterProxyModel {
@ -178,7 +182,8 @@ Control {
model: root.walletAccountsModel
selectedSharedAddresses: d.initialSelectedSharedAddresses
selectedAirdropAddress: d.initialSelectedAirdropAddress
onAddressesChanged: {
onAddressesChanged: accountSelector.applyChange()
function applyChange() {
root.selectedSharedAddresses = selectedSharedAddresses
root.selectedAirdropAddress = selectedAirdropAddress
root.sharedAddressesChanged(selectedAirdropAddress, selectedSharedAddresses)

View File

@ -0,0 +1,181 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
import utils 1.0
import shared.popups.keycard.helpers 1.0
import SortFilterProxyModel 0.2
ColumnLayout {
id: root
property var keypairSigningModel
readonly property string title: qsTr("Prove ownership of keypairs")
readonly property var rightButtons: [d.rightBtn]
readonly property bool allSigned: regularKeypairs.visible == d.sharedAddressesForAllNonKeycardKeypairsSigned &&
keycardKeypairs.visible == d.allKeycardKeypairsSigned
signal joinCommunity()
signal signSharedAddressesForAllNonKeycardKeypairs()
signal signSharedAddressesForKeypair(string keyUid)
function sharedAddressesForAllNonKeycardKeypairsSigned() {
d.sharedAddressesForAllNonKeycardKeypairsSigned = true
}
QtObject {
id: d
property bool sharedAddressesForAllNonKeycardKeypairsSigned: false
property bool allKeycardKeypairsSigned: false
readonly property var rightBtn: StatusButton {
enabled: root.allSigned
text: qsTr("Share your addresses to join")
onClicked: {
root.joinCommunity()
}
}
function reEvaluateSignedKeypairs() {
let allKeypairsSigned = true
for(var i = 0; i< keycardKeypairs.model.count; i++) {
if(!keycardKeypairs.model.get(i).keyPair.ownershipVerified) {
allKeypairsSigned = false
break
}
}
d.allKeycardKeypairsSigned = allKeypairsSigned
}
}
ColumnLayout {
Layout.fillWidth: true
Layout.margins: Style.current.xlPadding
spacing: Style.current.padding
RowLayout {
Layout.fillWidth: true
visible: regularKeypairs.visible
StatusBaseText {
Layout.fillWidth: true
text: qsTr("Keypairs we need an authentication for")
font.pixelSize: Constants.keycard.general.fontSize2
color: Theme.palette.baseColor1
wrapMode: Text.WordWrap
}
StatusButton {
text: d.sharedAddressesForAllNonKeycardKeypairsSigned? qsTr("Authenticated") : qsTr("Authenticate")
enabled: !d.sharedAddressesForAllNonKeycardKeypairsSigned
icon.name: userProfile.usingBiometricLogin? "touch-id" : "password"
onClicked: {
root.signSharedAddressesForAllNonKeycardKeypairs()
}
}
}
StatusListView {
id: regularKeypairs
Layout.fillWidth: true
Layout.preferredHeight: regularKeypairs.contentHeight
visible: regularKeypairs.model.count > 0
spacing: Style.current.padding
model: SortFilterProxyModel {
sourceModel: root.keypairSigningModel
filters: ExpressionFilter {
expression: !model.keyPair.migratedToKeycard
}
}
delegate: KeyPairItem {
width: ListView.view.width
sensor.hoverEnabled: false
additionalInfoForProfileKeypair: ""
keyPairType: model.keyPair.pairType
keyPairKeyUid: model.keyPair.keyUid
keyPairName: model.keyPair.name
keyPairIcon: model.keyPair.icon
keyPairImage: model.keyPair.image
keyPairDerivedFrom: model.keyPair.derivedFrom
keyPairAccounts: model.keyPair.accounts
}
}
Item {
visible: regularKeypairs.visible && keycardKeypairs.visible
Layout.fillWidth: true
Layout.preferredHeight: Style.current.xlPadding
}
StatusBaseText {
Layout.fillWidth: true
visible: keycardKeypairs.visible
text: qsTr("Keypairs that need to be singed using appropriate Keycard")
font.pixelSize: Constants.keycard.general.fontSize2
color: Theme.palette.baseColor1
wrapMode: Text.WordWrap
}
StatusListView {
id: keycardKeypairs
Layout.fillWidth: true
Layout.preferredHeight: keycardKeypairs.contentHeight
visible: keycardKeypairs.model.count > 0
spacing: Style.current.padding
model: SortFilterProxyModel {
sourceModel: root.keypairSigningModel
filters: ExpressionFilter {
expression: model.keyPair.migratedToKeycard
}
}
delegate: KeyPairItem {
width: ListView.view.width
sensor.hoverEnabled: !model.keyPair.ownershipVerified
additionalInfoForProfileKeypair: ""
keyPairType: model.keyPair.pairType
keyPairKeyUid: model.keyPair.keyUid
keyPairName: model.keyPair.name
keyPairIcon: model.keyPair.icon
keyPairImage: model.keyPair.image
keyPairDerivedFrom: model.keyPair.derivedFrom
keyPairAccounts: model.keyPair.accounts
components: [
StatusBaseText {
font.weight: Font.Medium
font.underline: mouseArea.containsMouse
font.pixelSize: Theme.primaryTextFontSize
color: model.keyPair.ownershipVerified? Theme.palette.baseColor1 : Theme.palette.primaryColor1
text: model.keyPair.ownershipVerified? qsTr("Signed") : qsTr("Sign")
MouseArea {
id: mouseArea
anchors.fill: parent
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
hoverEnabled: !model.keyPair.ownershipVerified
enabled: !model.keyPair.ownershipVerified
onEnabledChanged: {
d.reEvaluateSignedKeypairs()
}
onClicked: {
root.signSharedAddressesForKeypair(model.keyPair.keyUid)
}
}
}
]
}
}
}
}

View File

@ -30,6 +30,7 @@ ProfilePopupInviteMessagePanel 1.0 ProfilePopupInviteMessagePanel.qml
ProfilePopupOverviewPanel 1.0 ProfilePopupOverviewPanel.qml
RequirementsCheckPendingLoader 1.0 RequirementsCheckPendingLoader.qml
SharedAddressesPanel 1.0 SharedAddressesPanel.qml
SharedAddressesSigningPanel 1.0 SharedAddressesSigningPanel.qml
SortableTokenHoldersList 1.0 SortableTokenHoldersList.qml
SortableTokenHoldersPanel 1.0 SortableTokenHoldersPanel.qml
TagsPanel 1.0 TagsPanel.qml

View File

@ -1,6 +1,10 @@
import QtQuick 2.15
import QtQml.Models 2.15
import QtQuick.Layouts 1.15
import StatusQ.Controls 0.1
import StatusQ.Popups.Dialog 0.1
import StatusQ.Core.Theme 0.1
import AppLayouts.Communities.panels 1.0
@ -12,6 +16,7 @@ StatusDialog {
property bool isEditMode
property bool requirementsCheckPending
property var keypairSigningModel
required property string communityName
required property string communityIcon
@ -22,46 +27,138 @@ StatusDialog {
required property var assetsModel
required property var collectiblesModel
property alias selectedSharedAddresses: panel.selectedSharedAddresses
property alias selectedAirdropAddress: panel.selectedAirdropAddress
signal shareSelectedAddressesClicked(string airdropAddress, var sharedAddresses)
signal saveSelectedAddressesClicked(string airdropAddress, var sharedAddresses)
signal sharedAddressesChanged(string airdropAddress, var sharedAddresses)
signal prepareForSigning(string airdropAddress, var sharedAddresses)
signal editRevealedAddresses()
signal signSharedAddressesForAllNonKeycardKeypairs()
signal signSharedAddressesForKeypair(string keyUid)
function setOldSharedAddresses(oldSharedAddresses) {
panel.setOldSharedAddresses(oldSharedAddresses)
if (!d.displaySigningPanel && !!loader.item) {
d.oldSharedAddresses = oldSharedAddresses
loader.item.setOldSharedAddresses(oldSharedAddresses)
}
}
function setOldAirdropAddress(oldAirdropAddress) {
panel.setOldAirdropAddress(oldAirdropAddress)
if (!d.displaySigningPanel && !!loader.item) {
d.oldAirdropAddress = oldAirdropAddress
loader.item.setOldAirdropAddress(oldAirdropAddress)
}
}
title: panel.title
function sharedAddressesForAllNonKeycardKeypairsSigned() {
if (d.displaySigningPanel && !!loader.item) {
loader.item.sharedAddressesForAllNonKeycardKeypairsSigned()
}
}
title: !!loader.item? loader.item.title : ""
implicitWidth: 640 // by design
padding: 0
contentItem: SharedAddressesPanel {
id: panel
isEditMode: root.isEditMode
requirementsCheckPending: root.requirementsCheckPending
communityName: root.communityName
communityIcon: root.communityIcon
loginType: root.loginType
walletAccountsModel: root.walletAccountsModel
permissionsModel: root.permissionsModel
assetsModel: root.assetsModel
collectiblesModel: root.collectiblesModel
onShareSelectedAddressesClicked: root.shareSelectedAddressesClicked(airdropAddress, sharedAddresses)
onSaveSelectedAddressesClicked: root.saveSelectedAddressesClicked(airdropAddress, sharedAddresses)
onSharedAddressesChanged: {
root.sharedAddressesChanged(airdropAddress, sharedAddresses)
QtObject {
id: d
property bool displaySigningPanel: false
property bool allSigned: false
property var oldSharedAddresses
property string oldAirdropAddress
property var selectAddressesPanelButtons: ObjectModel {}
readonly property var signingPanelButtons: ObjectModel {
StatusFlatButton {
visible: root.isEditMode
borderColor: Theme.palette.baseColor2
text: qsTr("Cancel")
onClicked: root.close()
}
StatusButton {
text: qsTr("Save changes")
enabled: d.allSigned
onClicked: {
root.editRevealedAddresses()
root.close()
}
}
}
readonly property var signingPanelBackButtons: ObjectModel {
StatusBackButton {
onClicked: {
d.displaySigningPanel = false
}
}
}
}
contentItem: Loader {
id: loader
sourceComponent: d.displaySigningPanel? sharedAddressesSigningPanelComponent : selectSharedAddressesPanelComponent
onLoaded: {
if (!d.displaySigningPanel) {
if (!!d.oldSharedAddresses) {
root.setOldSharedAddresses(d.oldSharedAddresses)
}
if (!!d.oldAirdropAddress) {
root.setOldAirdropAddress(d.oldAirdropAddress)
}
d.selectAddressesPanelButtons = loader.item.buttons
}
}
}
Component {
id: selectSharedAddressesPanelComponent
SharedAddressesPanel {
isEditMode: root.isEditMode
requirementsCheckPending: root.requirementsCheckPending
communityName: root.communityName
communityIcon: root.communityIcon
loginType: root.loginType
walletAccountsModel: root.walletAccountsModel
permissionsModel: root.permissionsModel
assetsModel: root.assetsModel
collectiblesModel: root.collectiblesModel
onShareSelectedAddressesClicked: root.shareSelectedAddressesClicked(airdropAddress, sharedAddresses)
onPrepareForSigning: {
root.prepareForSigning(airdropAddress, sharedAddresses)
d.displaySigningPanel = true
}
onSharedAddressesChanged: {
root.sharedAddressesChanged(airdropAddress, sharedAddresses)
}
onClose: root.close()
}
}
Component {
id: sharedAddressesSigningPanelComponent
SharedAddressesSigningPanel {
keypairSigningModel: root.keypairSigningModel
onSignSharedAddressesForAllNonKeycardKeypairs: {
root.signSharedAddressesForAllNonKeycardKeypairs()
}
onSignSharedAddressesForKeypair: {
root.signSharedAddressesForKeypair(keyUid)
}
onAllSignedChanged: {
d.allSigned = allSigned
}
}
onClose: root.close()
}
footer: StatusDialogFooter {
spacing: Style.current.padding
rightButtons: panel.buttons
rightButtons: d.displaySigningPanel? d.signingPanelButtons : d.selectAddressesPanelButtons
leftButtons: d.displaySigningPanel? d.signingPanelBackButtons : null
}
}

View File

@ -61,7 +61,8 @@ Item {
|| root.communitiesStore.discordImportInProgress
property bool invitationPending: root.store.isCommunityRequestPending(communityData.id)
property bool isJoinBtnLoading: false
property bool joiningCommunityInProgress: false
}
ColumnHeaderPanel {
@ -468,7 +469,7 @@ Item {
anchors.bottomMargin: Style.current.halfPadding
anchors.horizontalCenter: parent.horizontalCenter
enabled: !root.communityData.amIBanned
loading: d.isJoinBtnLoading
loading: d.joiningCommunityInProgress
text: {
if (root.communityData.amIBanned) return qsTr("You were banned from community")
@ -479,22 +480,23 @@ Item {
}
onClicked: {
Global.openPopup(communityIntroDialog);
Global.openPopup(communityIntroDialogComponent);
}
Connections {
enabled: d.isJoinBtnLoading
enabled: d.joiningCommunityInProgress
target: root.store.communitiesModuleInst
function onCommunityAccessRequested(communityId: string) {
if (communityId === communityData.id) {
d.invitationPending = root.store.isCommunityRequestPending(communityData.id)
d.isJoinBtnLoading = false
d.joiningCommunityInProgress = false
}
}
function onCommunityAccessFailed(communityId: string) {
function onCommunityAccessFailed(communityId: string, error: string) {
if (communityId === communityData.id) {
d.invitationPending = false
d.isJoinBtnLoading = false
d.joiningCommunityInProgress = false
Global.displayToastMessage(qsTr("Request to join failed"),
qsTr("Please try again later"),
"",
@ -503,15 +505,12 @@ Item {
"")
}
}
function onUserAuthenticationCanceled() {
d.invitationPending = false
d.isJoinBtnLoading = false
}
}
Component {
id: communityIntroDialog
id: communityIntroDialogComponent
CommunityIntroDialog {
id: communityIntroDialog
isInvitationPending: d.invitationPending
requirementsCheckPending: root.store.requirementsCheckPending
@ -528,19 +527,47 @@ Item {
assetsModel: root.store.assetsModel
collectiblesModel: root.store.collectiblesModel
onJoined: {
d.isJoinBtnLoading = true
root.store.requestToJoinCommunityWithAuthentication(communityData.id, root.store.userProfileInst.name, sharedAddresses, airdropAddress)
onPrepareForSigning: {
root.store.prepareKeypairsForSigning(communityData.id, root.store.userProfileInst.name, sharedAddresses, airdropAddress, false)
communityIntroDialog.keypairSigningModel = root.store.communitiesModuleInst.keypairsSigningModel
}
onSignSharedAddressesForAllNonKeycardKeypairs: {
root.store.signSharedAddressesForAllNonKeycardKeypairs()
}
onSignSharedAddressesForKeypair: {
root.store.signSharedAddressesForKeypair(keyUid)
}
onJoinCommunity: {
d.joiningCommunityInProgress = true
root.store.joinCommunityOrEditSharedAddresses()
}
onCancelMembershipRequest: {
root.store.cancelPendingRequest(communityData.id)
d.invitationPending = root.store.isCommunityRequestPending(communityData.id)
}
onSharedAddressesUpdated: {
root.store.updatePermissionsModel(communityData.id, sharedAddresses)
}
onClosed: destroy()
onClosed: {
destroy()
}
Connections {
target: root.store.communitiesModuleInst
function onSharedAddressesForAllNonKeycardKeypairsSigned() {
if (!!communityIntroDialog.replaceItem) {
communityIntroDialog.replaceLoader.item.sharedAddressesForAllNonKeycardKeypairsSigned()
}
}
}
}
}
}

View File

@ -242,7 +242,24 @@ SettingsContentBase {
assetsModel: chatStore.assetsModel
collectiblesModel: chatStore.collectiblesModel
onJoined: chatStore.requestToJoinCommunityWithAuthentication(communityIntroDialog.communityId, root.rootStore.userProfileInst.name, sharedAddresses, airdropAddress)
onPrepareForSigning: {
chatStore.prepareKeypairsForSigning(communityIntroDialog.communityId, root.rootStore.userProfileInst.name, sharedAddresses, airdropAddress, false)
communityIntroDialog.keypairSigningModel = chatStore.communitiesModuleInst.keypairsSigningModel
}
onSignSharedAddressesForAllNonKeycardKeypairs: {
chatStore.signSharedAddressesForAllNonKeycardKeypairs()
}
onSignSharedAddressesForKeypair: {
chatStore.signSharedAddressesForKeypair(keyUid)
}
onJoinCommunity: {
chatStore.joinCommunityOrEditSharedAddresses()
}
onCancelMembershipRequest: root.rootStore.cancelPendingRequest(communityIntroDialog.communityId)
onSharedAddressesUpdated: {
@ -250,6 +267,16 @@ SettingsContentBase {
}
onClosed: destroy()
Connections {
target: chatStore.communitiesModuleInst
function onSharedAddressesForAllNonKeycardKeypairsSigned() {
if (!!communityIntroDialog.replaceItem) {
communityIntroDialog.replaceLoader.item.sharedAddressesForAllNonKeycardKeypairsSigned()
}
}
}
}
}
}

View File

@ -241,14 +241,20 @@ QtObject {
mainModuleInst.windowDeactivated()
}
function requestToJoinCommunityWithAuthentication(communityId, ensName, addressesToShare = [], airdropAddress = "") {
communitiesModuleInst.requestToJoinCommunityWithAuthenticationWithSharedAddresses(
communityId, ensName, JSON.stringify(addressesToShare), airdropAddress)
function prepareKeypairsForSigning(communityId, ensName, addressesToShare = [], airdropAddress = "", editMode = false) {
communitiesModuleInst.prepareKeypairsForSigning(communityId, ensName, JSON.stringify(addressesToShare), airdropAddress, editMode)
}
function editSharedAddressesWithAuthentication(communityId, addressesToShare = [], airdropAddress = "") {
communitiesModuleInst.editSharedAddressesWithAuthentication(
communityId, JSON.stringify(addressesToShare), airdropAddress)
function signSharedAddressesForAllNonKeycardKeypairs() {
communitiesModuleInst.signSharedAddressesForAllNonKeycardKeypairs()
}
function signSharedAddressesForKeypair(keyUid) {
communitiesModuleInst.signSharedAddressesForKeypair(keyUid)
}
function joinCommunityOrEditSharedAddresses() {
communitiesModuleInst.joinCommunityOrEditSharedAddresses()
}
function updatePermissionsModel(communityId, sharedAddresses) {

View File

@ -531,7 +531,24 @@ QtObject {
}
assetsModel: root.rootStore.assetsModel
collectiblesModel: root.rootStore.collectiblesModel
onJoined: root.rootStore.requestToJoinCommunityWithAuthentication(communityIntroDialog.communityId, communityIntroDialog.name, sharedAddresses, airdropAddress)
onPrepareForSigning: {
root.rootStore.prepareKeypairsForSigning(communityIntroDialog.communityId, communityIntroDialog.name, sharedAddresses, airdropAddress, false)
communityIntroDialog.keypairSigningModel = root.rootStore.communitiesModuleInst.keypairsSigningModel
}
onSignSharedAddressesForAllNonKeycardKeypairs: {
root.rootStore.signSharedAddressesForAllNonKeycardKeypairs()
}
onSignSharedAddressesForKeypair: {
root.rootStore.signSharedAddressesForKeypair(keyUid)
}
onJoinCommunity: {
root.rootStore.joinCommunityOrEditSharedAddresses()
}
onCancelMembershipRequest: root.rootStore.cancelPendingRequest(communityIntroDialog.communityId)
Connections {
target: root.communitiesStore.communitiesModuleInst
@ -541,20 +558,27 @@ QtObject {
root.communitiesStore.spectateCommunity(communityId);
communityIntroDialog.close();
}
function onCommunityAccessFailed(communityId: string) {
function onCommunityAccessFailed(communityId: string, error: string) {
if (communityId !== communityIntroDialog.communityId)
return
communityIntroDialog.close();
}
function onUserAuthenticationCanceled() {
communityIntroDialog.close();
}
}
onSharedAddressesUpdated: {
root.rootStore.updatePermissionsModel(communityIntroDialog.communityId, sharedAddresses)
}
onAboutToShow: { root.rootStore.communityKeyToImport = communityIntroDialog.communityId; }
onClosed: { root.rootStore.communityKeyToImport = ""; destroy(); }
Connections {
target: root.rootStore.communitiesModuleInst
function onSharedAddressesForAllNonKeycardKeypairsSigned() {
if (!!communityIntroDialog.replaceItem) {
communityIntroDialog.replaceLoader.item.sharedAddressesForAllNonKeycardKeypairsSigned()
}
}
}
}
},
@ -738,9 +762,33 @@ QtObject {
onSharedAddressesChanged: root.rootStore.updatePermissionsModel(
editSharedAddressesPopup.communityId, sharedAddresses)
onSaveSelectedAddressesClicked: root.rootStore.editSharedAddressesWithAuthentication(
editSharedAddressesPopup.communityId, sharedAddresses, airdropAddress)
onPrepareForSigning: {
root.rootStore.prepareKeypairsForSigning(editSharedAddressesPopup.communityId, "", sharedAddresses, airdropAddress, true)
editSharedAddressesPopup.keypairSigningModel = root.rootStore.communitiesModuleInst.keypairsSigningModel
}
onSignSharedAddressesForAllNonKeycardKeypairs: {
root.rootStore.signSharedAddressesForAllNonKeycardKeypairs()
}
onSignSharedAddressesForKeypair: {
root.rootStore.signSharedAddressesForKeypair(keyUid)
}
onEditRevealedAddresses: {
root.rootStore.joinCommunityOrEditSharedAddresses()
}
onClosed: destroy()
Connections {
target: root.rootStore.communitiesModuleInst
function onSharedAddressesForAllNonKeycardKeypairsSigned() {
editSharedAddressesPopup.sharedAddressesForAllNonKeycardKeypairsSigned()
}
}
}
},

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 9f69c3259397821483bad722ab92eb52470185de
Subproject commit 11a36122901967bc3fac2daf8d2f8bce9b5ed427