feat(@desktop/general): signing flow added globally

Signing flow can be run globally (similar as authentication flow is run) emitting
`SIGNAL_SHARED_KEYCARD_MODULE_SIGN_DATA` from any part of the app
and listening for a signal `SIGNAL_SHARED_KEYCARD_MODULE_DATA_SIGNED`
to get corresponding result.
This commit is contained in:
Sale Djenic 2023-10-27 19:19:25 +02:00 committed by saledjenic
parent 9c9bcef6d2
commit 0e16a4e2fb
6 changed files with 106 additions and 64 deletions

View File

@ -32,6 +32,7 @@ logScope:
topics = "main-module-controller"
const UNIQUE_MAIN_MODULE_AUTHENTICATE_KEYPAIR_IDENTIFIER* = "MainModule-AuthenticateKeypair"
const UNIQUE_MAIN_MODULE_SIGNING_DATA_IDENTIFIER* = "MainModule-SigningData"
const UNIQUE_MAIN_MODULE_KEYCARD_SYNC_IDENTIFIER* = "MainModule-KeycardSyncPurpose"
const UNIQUE_MAIN_MODULE_SHARED_KEYCARD_MODULE_IDENTIFIER* = "MainModule-SharedKeycardModule"
@ -53,6 +54,7 @@ type
communityTokensService: community_tokens_service.Service
activeSectionId: string
authenticateUserFlowRequestedBy: string
keycardSigningFlowRequestedBy: string
walletAccountService: wallet_account_service.Service
tokenService: token_service.Service
networksService: networks_service.Service
@ -399,35 +401,57 @@ proc init*(self: Controller) =
self.delegate.onSharedKeycarModuleFlowTerminated(args.lastStepInTheCurrentFlow, args.continueWithNextFlow,
args.forceFlow, args.continueWithKeyUid, args.returnToFlow)
return
if args.uniqueIdentifier != UNIQUE_MAIN_MODULE_AUTHENTICATE_KEYPAIR_IDENTIFIER or
self.authenticateUserFlowRequestedBy.len == 0:
if args.uniqueIdentifier == UNIQUE_MAIN_MODULE_SIGNING_DATA_IDENTIFIER and
self.keycardSigningFlowRequestedBy.len > 0:
self.delegate.onSharedKeycarModuleForAuthenticationOrSigningTerminated(args.lastStepInTheCurrentFlow)
let data = SharedKeycarModuleArgs(uniqueIdentifier: self.keycardSigningFlowRequestedBy,
pin: args.pin,
keyUid: args.keyUid,
keycardUid: args.keycardUid,
path: args.path,
r: args.r,
s: args.s,
v: args.v)
self.keycardSigningFlowRequestedBy = ""
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_DATA_SIGNED, data)
return
self.delegate.onSharedKeycarModuleForAuthenticationTerminated(args.lastStepInTheCurrentFlow)
let data = SharedKeycarModuleArgs(uniqueIdentifier: self.authenticateUserFlowRequestedBy,
password: args.password,
pin: args.pin,
keyUid: args.keyUid,
keycardUid: args.keycardUid,
additinalPathsDetails: args.additinalPathsDetails)
self.authenticateUserFlowRequestedBy = ""
## Whenever user provides a password/pin we need to make all partially operable accounts (if any exists) a fully operable.
self.events.emit(SIGNAL_IMPORT_PARTIALLY_OPERABLE_ACCOUNTS, ImportAccountsArgs(keyUid: data.keyUid, password: data.password))
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED, data)
if args.uniqueIdentifier == UNIQUE_MAIN_MODULE_AUTHENTICATE_KEYPAIR_IDENTIFIER and
self.authenticateUserFlowRequestedBy.len > 0:
self.delegate.onSharedKeycarModuleForAuthenticationOrSigningTerminated(args.lastStepInTheCurrentFlow)
let data = SharedKeycarModuleArgs(uniqueIdentifier: self.authenticateUserFlowRequestedBy,
password: args.password,
pin: args.pin,
keyUid: args.keyUid,
keycardUid: args.keycardUid,
additinalPathsDetails: args.additinalPathsDetails)
self.authenticateUserFlowRequestedBy = ""
## Whenever user provides a password/pin we need to make all partially operable accounts (if any exists) a fully operable.
self.events.emit(SIGNAL_IMPORT_PARTIALLY_OPERABLE_ACCOUNTS, ImportAccountsArgs(keyUid: data.keyUid, password: data.password))
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED, data)
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_DISPLAY_POPUP) do(e: Args):
let args = SharedKeycarModuleBaseArgs(e)
if args.uniqueIdentifier == UNIQUE_MAIN_MODULE_SHARED_KEYCARD_MODULE_IDENTIFIER:
self.delegate.onDisplayKeycardSharedModuleFlow()
return
if args.uniqueIdentifier != UNIQUE_MAIN_MODULE_AUTHENTICATE_KEYPAIR_IDENTIFIER or
self.authenticateUserFlowRequestedBy.len == 0:
if args.uniqueIdentifier == UNIQUE_MAIN_MODULE_SIGNING_DATA_IDENTIFIER and
self.keycardSigningFlowRequestedBy.len > 0:
self.delegate.onDisplayKeycardSharedModuleForAuthenticationOrSigning()
return
self.delegate.onDisplayKeycardSharedModuleForAuthentication()
if args.uniqueIdentifier == UNIQUE_MAIN_MODULE_AUTHENTICATE_KEYPAIR_IDENTIFIER and
self.authenticateUserFlowRequestedBy.len > 0:
self.delegate.onDisplayKeycardSharedModuleForAuthenticationOrSigning()
return
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_SIGN_DATA) do(e: Args):
let args = SharedKeycarModuleSigningArgs(e)
self.keycardSigningFlowRequestedBy = args.uniqueIdentifier
self.delegate.runAuthenticationOrSigningPopup(keycard_shared_module.FlowType.Sign, args.keyUid, @[args.path], args.dataToSign)
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_AUTHENTICATE_USER) do(e: Args):
let args = SharedKeycarModuleAuthenticationArgs(e)
self.authenticateUserFlowRequestedBy = args.uniqueIdentifier
self.delegate.runAuthenticationPopup(args.keyUid, args.additionalBip44Paths)
self.delegate.runAuthenticationOrSigningPopup(keycard_shared_module.FlowType.Authentication, args.keyUid, args.additionalBip44Paths)
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_TRY_KEYCARD_SYNC) do(e: Args):
let args = SharedKeycarModuleArgs(e)

View File

@ -256,13 +256,13 @@ method onStatusUrlRequested*(self: AccessInterface, action: StatusUrlAction, com
method getVerificationRequestFrom*(self: AccessInterface, publicKey: string): VerificationRequest {.base.} =
raise newException(ValueError, "No implementation available")
method getKeycardSharedModuleForAuthentication*(self: AccessInterface): QVariant {.base.} =
method getKeycardSharedModuleForAuthenticationOrSigning*(self: AccessInterface): QVariant {.base.} =
raise newException(ValueError, "No implementation available")
method onDisplayKeycardSharedModuleForAuthentication*(self: AccessInterface) {.base.} =
method onDisplayKeycardSharedModuleForAuthenticationOrSigning*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method onSharedKeycarModuleForAuthenticationTerminated*(self: AccessInterface, lastStepInTheCurrentFlow: bool) {.base.} =
method onSharedKeycarModuleForAuthenticationOrSigningTerminated*(self: AccessInterface, lastStepInTheCurrentFlow: bool) {.base.} =
raise newException(ValueError, "No implementation available")
method getKeycardSharedModule*(self: AccessInterface): QVariant {.base.} =
@ -275,7 +275,8 @@ method onSharedKeycarModuleFlowTerminated*(self: AccessInterface, lastStepInTheC
nextFlow: keycard_shared_module.FlowType, forceFlow: bool, nextKeyUid: string, returnToFlow: keycard_shared_module.FlowType) {.base.} =
raise newException(ValueError, "No implementation available")
method runAuthenticationPopup*(self: AccessInterface, keyUid: string, bip44Paths: seq[string] = @[]) {.base.} =
method runAuthenticationOrSigningPopup*(self: AccessInterface, flow: keycard_shared_module.FlowType, keyUid: string,
bip44Paths: seq[string] = @[], dataToSign: string = "") {.base.} =
raise newException(ValueError, "No implementation available")
method onSharedKeycarModuleRunningKeycardFlowsPurposeTerminated*(self: AccessInterface, lastStepInTheCurrentFlow: bool) {.base.} =

View File

@ -103,7 +103,7 @@ type
communitiesModule: communities_module.AccessInterface
appSearchModule: app_search_module.AccessInterface
nodeSectionModule: node_section_module.AccessInterface
keycardSharedModuleForAuthentication: keycard_shared_module.AccessInterface
keycardSharedModuleForAuthenticationOrSigning: keycard_shared_module.AccessInterface
keycardSharedModuleKeycardSyncPurpose: keycard_shared_module.AccessInterface
keycardSharedModule: keycard_shared_module.AccessInterface
networkConnectionModule: network_connection_module.AccessInterface
@ -214,7 +214,8 @@ proc newModule*[T](
result.stickersModule = stickers_module.newModule(result, events, stickersService, settingsService, walletAccountService, networkService, tokenService)
result.activityCenterModule = activity_center_module.newModule(result, events, activityCenterService, contactsService,
messageService, chatService, communityService)
result.communitiesModule = communities_module.newModule(result, events, communityService, contactsService, communityTokensService, networkService, transactionService, tokenService, chatService)
result.communitiesModule = communities_module.newModule(result, events, communityService, contactsService, communityTokensService,
networkService, transactionService, tokenService, chatService, walletAccountService, keycardService)
result.appSearchModule = app_search_module.newModule(result, events, contactsService, chatService, communityService,
messageService)
result.nodeSectionModule = node_section_module.newModule(result, events, settingsService, nodeService, nodeConfigurationService)
@ -234,8 +235,8 @@ method delete*[T](self: Module[T]) =
self.browserSectionModule.delete
self.appSearchModule.delete
self.nodeSectionModule.delete
if not self.keycardSharedModuleForAuthentication.isNil:
self.keycardSharedModuleForAuthentication.delete
if not self.keycardSharedModuleForAuthenticationOrSigning.isNil:
self.keycardSharedModuleForAuthenticationOrSigning.delete
if not self.keycardSharedModuleKeycardSyncPurpose.isNil:
self.keycardSharedModuleKeycardSyncPurpose.delete
if not self.keycardSharedModule.isNil:
@ -267,7 +268,7 @@ proc createTokenItemImproved[T](self: Module[T], tokenDto: CommunityTokenDto, co
if details["address"].getStr == tokenDto.address:
tokenDetails = details
break
if tokenDetails.kind == JNull:
error "Token details not found for token", name = tokenDto.name, address = tokenDto.address
return
@ -1231,7 +1232,7 @@ method displayEphemeralNotification*[T](self: Module[T], title: string, subTitle
finalEphNotifType = EphemeralNotificationType.Success
elif(ephNotifType == EphemeralNotificationType.Danger.int):
finalEphNotifType = EphemeralNotificationType.Danger
let item = ephemeral_notification_item.initItem(id, title, TOAST_MESSAGE_VISIBILITY_DURATION_IN_MS, subTitle, icon,
loading, finalEphNotifType, url, details)
self.view.ephemeralNotificationModel().addItem(item)
@ -1327,34 +1328,38 @@ method onStatusUrlRequested*[T](self: Module[T], action: StatusUrlAction, commun
# self.browserSectionModule.openUrl(url)
################################################################################
## keycard shared module - authentication purpose
## keycard shared module - authentication/sign purpose
################################################################################
proc isSharedKeycardModuleForAuthenticationRunning[T](self: Module[T]): bool =
return not self.keycardSharedModuleForAuthentication.isNil
proc isSharedKeycardModuleForAuthenticationOrSigningRunning[T](self: Module[T]): bool =
return not self.keycardSharedModuleForAuthenticationOrSigning.isNil
method getKeycardSharedModuleForAuthentication*[T](self: Module[T]): QVariant =
if self.isSharedKeycardModuleForAuthenticationRunning():
return self.keycardSharedModuleForAuthentication.getModuleAsVariant()
method getKeycardSharedModuleForAuthenticationOrSigning*[T](self: Module[T]): QVariant =
if self.isSharedKeycardModuleForAuthenticationOrSigningRunning():
return self.keycardSharedModuleForAuthenticationOrSigning.getModuleAsVariant()
proc createSharedKeycardModuleForAuthentication[T](self: Module[T]) =
self.keycardSharedModuleForAuthentication = keycard_shared_module.newModule[Module[T]](self, UNIQUE_MAIN_MODULE_AUTHENTICATE_KEYPAIR_IDENTIFIER,
proc createSharedKeycardModuleForAuthenticationOrSigning[T](self: Module[T], identifier: string) =
self.keycardSharedModuleForAuthenticationOrSigning = keycard_shared_module.newModule[Module[T]](self, identifier,
self.events, self.keycardService, self.settingsService, self.networkService, self.privacyService, self.accountsService,
self.walletAccountService, self.keychainService)
method onSharedKeycarModuleForAuthenticationTerminated*[T](self: Module[T], lastStepInTheCurrentFlow: bool) =
if self.isSharedKeycardModuleForAuthenticationRunning():
self.view.emitDestroyKeycardSharedModuleForAuthentication()
self.keycardSharedModuleForAuthentication.delete
self.keycardSharedModuleForAuthentication = nil
method onSharedKeycarModuleForAuthenticationOrSigningTerminated*[T](self: Module[T], lastStepInTheCurrentFlow: bool) =
if self.isSharedKeycardModuleForAuthenticationOrSigningRunning():
self.view.emitDestroyKeycardSharedModuleForAuthenticationOrSigning()
self.keycardSharedModuleForAuthenticationOrSigning.delete
self.keycardSharedModuleForAuthenticationOrSigning = nil
method runAuthenticationPopup*[T](self: Module[T], keyUid: string, bip44Paths: seq[string] = @[]) =
self.createSharedKeycardModuleForAuthentication()
if self.keycardSharedModuleForAuthentication.isNil:
method runAuthenticationOrSigningPopup*[T](self: Module[T], flow: keycard_shared_module.FlowType, keyUid: string,
bip44Paths: seq[string] = @[], dataToSign = "") =
var identifier = UNIQUE_MAIN_MODULE_AUTHENTICATE_KEYPAIR_IDENTIFIER
if flow == keycard_shared_module.FlowType.Sign:
identifier = UNIQUE_MAIN_MODULE_SIGNING_DATA_IDENTIFIER
self.createSharedKeycardModuleForAuthenticationOrSigning(identifier)
if self.keycardSharedModuleForAuthenticationOrSigning.isNil:
return
self.keycardSharedModuleForAuthentication.runFlow(keycard_shared_module.FlowType.Authentication, keyUid, bip44Paths)
self.keycardSharedModuleForAuthenticationOrSigning.runFlow(flow, keyUid, bip44Paths, dataToSign)
method onDisplayKeycardSharedModuleForAuthentication*[T](self: Module[T]) =
self.view.emitDisplayKeycardSharedModuleForAuthentication()
method onDisplayKeycardSharedModuleForAuthenticationOrSigning*[T](self: Module[T]) =
self.view.emitDisplayKeycardSharedModuleForAuthenticationOrSigning()
################################################################################
################################################################################

View File

@ -245,13 +245,13 @@ QtObject:
proc emitDisplayUserProfileSignal*(self: View, publicKey: string) =
self.displayUserProfile(publicKey)
proc getKeycardSharedModuleForAuthentication(self: View): QVariant {.slot.} =
let module = self.delegate.getKeycardSharedModuleForAuthentication()
proc getKeycardSharedModuleForAuthenticationOrSigning(self: View): QVariant {.slot.} =
let module = self.delegate.getKeycardSharedModuleForAuthenticationOrSigning()
if not module.isNil:
return module
return newQVariant()
QtProperty[QVariant] keycardSharedModuleForAuthentication:
read = getKeycardSharedModuleForAuthentication
QtProperty[QVariant] keycardSharedModuleForAuthenticationOrSigning:
read = getKeycardSharedModuleForAuthenticationOrSigning
proc activateStatusDeepLink*(self: View, statusDeepLink: string) {.slot.} =
self.delegate.activateStatusDeepLink(statusDeepLink)
@ -264,13 +264,13 @@ QtObject:
QtProperty[QVariant] keycardSharedModule:
read = getKeycardSharedModule
proc displayKeycardSharedModuleForAuthentication*(self: View) {.signal.}
proc emitDisplayKeycardSharedModuleForAuthentication*(self: View) =
self.displayKeycardSharedModuleForAuthentication()
proc displayKeycardSharedModuleForAuthenticationOrSigning*(self: View) {.signal.}
proc emitDisplayKeycardSharedModuleForAuthenticationOrSigning*(self: View) =
self.displayKeycardSharedModuleForAuthenticationOrSigning()
proc destroyKeycardSharedModuleForAuthentication*(self: View) {.signal.}
proc emitDestroyKeycardSharedModuleForAuthentication*(self: View) =
self.destroyKeycardSharedModuleForAuthentication()
proc destroyKeycardSharedModuleForAuthenticationOrSigning*(self: View) {.signal.}
proc emitDestroyKeycardSharedModuleForAuthenticationOrSigning*(self: View) =
self.destroyKeycardSharedModuleForAuthenticationOrSigning()
proc displayKeycardSharedModuleFlow*(self: View) {.signal.}
proc emitDisplayKeycardSharedModuleFlow*(self: View) =

View File

@ -45,6 +45,8 @@ const SIGNAL_SHARED_KEYCARD_MODULE_AUTHENTICATE_USER* = "sharedKeycarModuleAuthe
const SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED* = "sharedKeycarModuleUserAuthenticated"
const SIGNAL_SHARED_KEYCARD_MODULE_TRY_KEYCARD_SYNC* = "sharedKeycarModuleTryKeycardSync"
const SIGNAL_SHARED_KEYCARD_MODULE_KEYCARD_SYNC_TERMINATED* = "sharedKeycarModuleKeycardSyncTerminated"
const SIGNAL_SHARED_KEYCARD_MODULE_SIGN_DATA* = "sharedKeycarModuleSignData"
const SIGNAL_SHARED_KEYCARD_MODULE_DATA_SIGNED* = "sharedKeycarModuleDataSigned"
## Authentication in the app is a global thing and may be used from any part of the app. How to achieve that... it's enough just to send
## `SIGNAL_SHARED_KEYCARD_MODULE_AUTHENTICATE_USER` signal with properly set `SharedKeycarModuleAuthenticationArgs` and props there:
@ -74,6 +76,10 @@ type
keyUid*: string
keycardUid*: string
additinalPathsDetails*: Table[string, KeyDetails] # [path, KeyDetails]
path*: string
r*: string
s*: string
v*: string
type
SharedKeycarModuleFlowTerminatedArgs* = ref object of SharedKeycarModuleArgs
@ -88,6 +94,12 @@ type
keyUid*: string
additionalBip44Paths*: seq[string] # can be used in authentication flow to export additinal paths if needed except encryption path
type
SharedKeycarModuleSigningArgs* = ref object of SharedKeycarModuleBaseArgs
keyUid*: string
path*: string
dataToSign*: string
type
AccessInterface* {.pure inheritable.} = ref object of RootObj

View File

@ -77,12 +77,12 @@ Item {
popups.openProfilePopup(publicKey)
}
function onDisplayKeycardSharedModuleForAuthentication() {
keycardPopupForAuthentication.active = true
function onDisplayKeycardSharedModuleForAuthenticationOrSigning() {
keycardPopupForAuthenticationOrSigning.active = true
}
function onDestroyKeycardSharedModuleForAuthentication() {
keycardPopupForAuthentication.active = false
function onDestroyKeycardSharedModuleForAuthenticationOrSigning() {
keycardPopupForAuthenticationOrSigning.active = false
}
function onDisplayKeycardSharedModuleFlow() {
@ -333,7 +333,7 @@ Item {
let loading = false
let notificationType = Constants.ephemeralNotificationType.normal
let icon = ""
switch (state)
{
case Constants.communityImported:
@ -1612,14 +1612,14 @@ Item {
}
Loader {
id: keycardPopupForAuthentication
id: keycardPopupForAuthenticationOrSigning
active: false
sourceComponent: KeycardPopup {
sharedKeycardModule: appMain.rootStore.mainModuleInst.keycardSharedModuleForAuthentication
sharedKeycardModule: appMain.rootStore.mainModuleInst.keycardSharedModuleForAuthenticationOrSigning
}
onLoaded: {
keycardPopupForAuthentication.item.open()
keycardPopupForAuthenticationOrSigning.item.open()
}
}