feat(@desktop/keycard): keycard service updated

Keycard library from this commit brings new changes in terms of
signals being sent by the lib in case of reader is not plugged in,
card is not inserted, card is inserted, that means the following
signals are sent only when it's really needed:
`"{\"type\":\"keycard.flow-result\",\"event\":{\"error\":\"connection-error\"}}"`
`"{\"type\":\"keycard.action.insert-card\",\"event\":{\"error\":\"connection-error\"}}"`
`"{\"type\":\"keycard.action.card-inserted\",\"event\":{}}"`
This commit is contained in:
Sale Djenic 2022-08-31 18:47:57 +02:00 committed by saledjenic
parent 59f23c82f7
commit 912cbe3b1d
4 changed files with 135 additions and 68 deletions

View File

@ -1,26 +1,3 @@
const ResponseKeyType* = "type"
const ResponseKeyEvent* = "event"
const ResponseTypeValueKeycardFlowResult* = "keycard.flow-result"
const ResponseTypeValueInsertCard* = "keycard.action.insert-card"
const ResponseTypeValueCardInserted* = "keycard.action.card-inserted"
const ResponseTypeValueSwapCard* = "keycard.action.swap-card"
const ResponseTypeValueEnterPairing* = "keycard.action.enter-pairing"
const ResponseTypeValueEnterPIN* = "keycard.action.enter-pin"
const ResponseTypeValueEnterPUK* = "keycard.action.enter-puk"
const ResponseTypeValueEnterNewPair* = "keycard.action.enter-new-pairing"
const ResponseTypeValueEnterNewPIN* = "keycard.action.enter-new-pin"
const ResponseTypeValueEnterNewPUK* = "keycard.action.enter-new-puk"
const ResponseTypeValueEnterTXHash* = "keycard.action.enter-tx-hash"
const ResponseTypeValueEnterPath* = "keycard.action.enter-bip44-path"
const ResponseTypeValueEnterMnemonic* = "keycard.action.enter-mnemonic"
const ResponseInitialized* = "initialized"
const ResponseInstanceUID* = "instanceUID"
const ResponseVersion* = "version"
const ResponseAvailableSlots* = "availableSlots"
const ResponseKeyUID* = "keyUID"
const ErrorKey* = "error"
const ErrorOK* = "ok"
const ErrorCancel* = "cancel"
@ -73,6 +50,47 @@ const RequestParamCardMeta* = "card-metadata"
const RequestParamCardName* = "card-name"
const RequestParamWalletPaths* = "wallet-paths"
const RequestParamAddress* = "address"
const RequestParamPublicKey* = "publicKey"
const RequestParamPrivateKey* = "privateKey"
const ResponseKeyType* = "type"
const ResponseKeyEvent* = "event"
const ResponseTypeValueKeycardFlowResult* = "keycard.flow-result"
const ResponseTypeValueInsertCard* = "keycard.action.insert-card"
const ResponseTypeValueCardInserted* = "keycard.action.card-inserted"
const ResponseTypeValueSwapCard* = "keycard.action.swap-card"
const ResponseTypeValueEnterPairing* = "keycard.action.enter-pairing"
const ResponseTypeValueEnterPIN* = "keycard.action.enter-pin"
const ResponseTypeValueEnterPUK* = "keycard.action.enter-puk"
const ResponseTypeValueEnterNewPair* = "keycard.action.enter-new-pairing"
const ResponseTypeValueEnterNewPIN* = "keycard.action.enter-new-pin"
const ResponseTypeValueEnterNewPUK* = "keycard.action.enter-new-puk"
const ResponseTypeValueEnterTXHash* = "keycard.action.enter-tx-hash"
const ResponseTypeValueEnterPath* = "keycard.action.enter-bip44-path"
const ResponseTypeValueEnterMnemonic* = "keycard.action.enter-mnemonic"
const ResponseTypeValueEnterCardName* = "keycard.action.enter-cardname"
const ResponseTypeValueEnterWallets* = "keycard.action.enter-wallets"
const ResponseParamInitialized* = "initialized"
const ResponseParamInstanceUID* = "instanceUID"
const ResponseParamVersion* = "version"
const ResponseParamAvailableSlots* = "availableSlots"
const ResponseParamAppInfoKeyUID* = "keyUID"
const ResponseParamName* = "name"
const ResponseParamWallets* = "wallets"
const ResponseParamPath* = "path"
const ResponseParamAddress* = "address"
const ResponseParamPublicKey* = "publicKey"
const ResponseParamPrivateKey* = "privateKey"
const ResponseParamErrorKey* = ErrorKey
const ResponseParamCardMeta* = RequestParamCardMeta
const ResponseParamFreeSlots* = RequestParamFreeSlots
const ResponseParamPINRetries* = RequestParamPINRetries
const ResponseParamPUKRetries* = RequestParamPUKRetries
const ResponseParamKeyUID* = RequestParamKeyUID
const ResponseParamAppInfo* = RequestParamAppInfo
const ResponseParamEIP1581Key* = RequestParamEIP1581Key
const ResponseParamEncKey* = RequestParamEncKey
const ResponseParamMasterKey* = RequestParamMasterKey
const ResponseParamWalletKey* = RequestParamWalletKey
const ResponseParamWalleRootKey* = RequestParamWalleRootKey
const ResponseParamWhisperKey* = RequestParamWhisperKey
const ResponseParamMnemonicIdxs* = RequestParamMnemonicIdxs

View File

@ -11,6 +11,14 @@ type
availableSlots*: int
keyUID*: string
WalletAccount* = object
path*: string
address*: string
CardMetadata* = object
name*: string
walletAccounts*: seq[WalletAccount]
KeycardEvent* = object
error*: string
applicationInfo*: ApplicationInfo
@ -19,6 +27,7 @@ type
keyUid*: string
pinRetries*: int
pukRetries*: int
cardMetadata*: CardMetadata
eip1581Key*: KeyDetails
encryptionKey*: KeyDetails
masterKey*: KeyDetails
@ -27,49 +36,63 @@ type
whisperKey*: KeyDetails
proc toKeyDetails(jsonObj: JsonNode): KeyDetails =
discard jsonObj.getProp(RequestParamAddress, result.address)
discard jsonObj.getProp(RequestParamPrivateKey, result.privateKey)
if jsonObj.getProp(RequestParamPublicKey, result.publicKey):
discard jsonObj.getProp(ResponseParamAddress, result.address)
discard jsonObj.getProp(ResponseParamPrivateKey, result.privateKey)
if jsonObj.getProp(ResponseParamPublicKey, result.publicKey):
result.publicKey = "0x" & result.publicKey
proc toApplicationInfo(jsonObj: JsonNode): ApplicationInfo =
discard jsonObj.getProp(ResponseInitialized, result.initialized)
discard jsonObj.getProp(ResponseInstanceUID, result.instanceUID)
discard jsonObj.getProp(ResponseVersion, result.version)
discard jsonObj.getProp(ResponseAvailableSlots, result.availableSlots)
discard jsonObj.getProp(ResponseKeyUID, result.keyUID)
discard jsonObj.getProp(ResponseParamInitialized, result.initialized)
discard jsonObj.getProp(ResponseParamInstanceUID, result.instanceUID)
discard jsonObj.getProp(ResponseParamVersion, result.version)
discard jsonObj.getProp(ResponseParamAvailableSlots, result.availableSlots)
discard jsonObj.getProp(ResponseParamAppInfoKeyUID, result.keyUID)
proc toWalletAccount(jsonObj: JsonNode): WalletAccount =
discard jsonObj.getProp(ResponseParamPath, result.path)
discard jsonObj.getProp(ResponseParamAddress, result.address)
proc toCardMetadata(jsonObj: JsonNode): CardMetadata =
discard jsonObj.getProp(ResponseParamName, result.name)
var accountsArr: JsonNode
if jsonObj.getProp(ResponseParamWallets, accountsArr) and accountsArr.kind == JArray:
for acc in accountsArr:
result.walletAccounts.add(acc.toWalletAccount())
proc toKeycardEvent(jsonObj: JsonNode): KeycardEvent =
discard jsonObj.getProp(ErrorKey, result.error)
discard jsonObj.getProp(RequestParamFreeSlots, result.freePairingSlots)
discard jsonObj.getProp(RequestParamPINRetries, result.pinRetries)
discard jsonObj.getProp(RequestParamPUKRetries, result.pukRetries)
if jsonObj.getProp(RequestParamKeyUID, result.keyUid):
discard jsonObj.getProp(ResponseParamErrorKey, result.error)
discard jsonObj.getProp(ResponseParamFreeSlots, result.freePairingSlots)
discard jsonObj.getProp(ResponseParamPINRetries, result.pinRetries)
discard jsonObj.getProp(ResponseParamPUKRetries, result.pukRetries)
if jsonObj.getProp(ResponseParamKeyUID, result.keyUid):
result.keyUid = "0x" & result.keyUid
var obj: JsonNode
if(jsonObj.getProp(RequestParamAppInfo, obj)):
if(jsonObj.getProp(ResponseParamAppInfo, obj)):
result.applicationInfo = toApplicationInfo(obj)
if(jsonObj.getProp(RequestParamEIP1581Key, obj)):
if(jsonObj.getProp(ResponseParamEIP1581Key, obj)):
result.eip1581Key = toKeyDetails(obj)
if(jsonObj.getProp(RequestParamEncKey, obj)):
if(jsonObj.getProp(ResponseParamEncKey, obj)):
result.encryptionKey = toKeyDetails(obj)
if(jsonObj.getProp(RequestParamMasterKey, obj)):
if(jsonObj.getProp(ResponseParamMasterKey, obj)):
result.masterKey = toKeyDetails(obj)
if(jsonObj.getProp(RequestParamWalletKey, obj)):
if(jsonObj.getProp(ResponseParamWalletKey, obj)):
result.walletKey = toKeyDetails(obj)
if(jsonObj.getProp(RequestParamWalleRootKey, obj)):
if(jsonObj.getProp(ResponseParamWalleRootKey, obj)):
result.walletRootKey = toKeyDetails(obj)
if(jsonObj.getProp(RequestParamWhisperKey, obj)):
if(jsonObj.getProp(ResponseParamWhisperKey, obj)):
result.whisperKey = toKeyDetails(obj)
var indexesArr: JsonNode
if jsonObj.getProp(RequestParamMnemonicIdxs, indexesArr) and indexesArr.kind == JArray:
if jsonObj.getProp(ResponseParamMnemonicIdxs, indexesArr) and indexesArr.kind == JArray:
for ind in indexesArr:
result.seedPhraseIndexes.add(ind.getInt)
result.seedPhraseIndexes.add(ind.getInt)
if(jsonObj.getProp(ResponseParamCardMeta, obj)):
result.cardMetadata = toCardMetadata(obj)

View File

@ -6,7 +6,7 @@ import ../../../constants as status_const
import constants
type FlowType {.pure.} = enum
type KCSFlowType* {.pure.} = enum
NoFlow = -1 # this type is added only for the desktop app purpose
GetAppInfo = 0 # enumeration of these flows should follow enumeration in the `status-keycard-go`
RecoverAccount
@ -53,11 +53,13 @@ QtObject:
events: EventEmitter
threadpool: ThreadPool
closingApp: bool
currentFlow: FlowType
currentFlow: KCSFlowType
lastReceivedKeycardData: tuple[flowType: string, flowEvent: KeycardEvent]
setPayloadForCurrentFlow: JsonNode
#################################################
# Forward declaration section
proc runTimer(self: Service)
proc startGetMetadataFlow*(self: Service)
#################################################
@ -74,7 +76,7 @@ QtObject:
result.events = events
result.threadpool = threadpool
result.closingApp = false
result.currentFlow = FlowType.NoFlow
result.currentFlow = KCSFlowType.NoFlow
proc init*(self: Service) =
debug "init keycard using ", pairingsJson=status_const.KEYCARDPAIRINGDATAFILE
@ -98,42 +100,57 @@ QtObject:
let flowType = typeObj.getStr
let flowEvent = toKeycardEvent(eventObj)
self.lastReceivedKeycardData = (flowType: flowType, flowEvent: flowEvent)
self.events.emit(SignalKeycardResponse, KeycardArgs(flowType: flowType, flowEvent: flowEvent))
proc receiveKeycardSignal(self: Service, signal: string) {.slot.} =
self.processSignal(signal)
proc getLastReceivedKeycardData*(self: Service): tuple[flowType: string, flowEvent: KeycardEvent] =
return self.lastReceivedKeycardData
proc buildSeedPhrasesFromIndexes*(self: Service, seedPhraseIndexes: seq[int]): seq[string] =
var seedPhrase: seq[string]
for ind in seedPhraseIndexes:
seedPhrase.add(englishWords[ind])
return seedPhrase
proc updateLocalPayloadForCurrentFlow(self: Service, obj: JsonNode, cleanBefore = false) =
if cleanBefore:
self.setPayloadForCurrentFlow = %* {}
for k, v in obj:
self.setPayloadForCurrentFlow[k] = v
proc getCurrentFlow*(self: Service): KCSFlowType =
return self.currentFlow
proc startFlow(self: Service, payload: JsonNode) =
self.updateLocalPayloadForCurrentFlow(payload, cleanBefore = true)
let response = keycard_go.keycardStartFlow(self.currentFlow.int, $payload)
debug "keycardStartFlow", flowType=self.currentFlow.int, payload=payload, response=response
debug "keycardStartFlow", currentFlow=self.currentFlow.int, payload=payload, response=response
proc resumeFlow(self: Service, payload: JsonNode) =
self.updateLocalPayloadForCurrentFlow(payload)
let response = keycard_go.keycardResumeFlow($payload)
debug "keycardResumeFlow", flowType=self.currentFlow.int, payload=payload, response=response
debug "keycardResumeFlow", currentFlow=self.currentFlow.int, payload=payload, response=response
proc cancelCurrentFlow*(self: Service) =
let response = keycard_go.keycardCancelFlow()
self.currentFlow = FlowType.NoFlow
debug "keycardCancelFlow", flowType=self.currentFlow.int, response=response
self.currentFlow = KCSFlowType.NoFlow
debug "keycardCancelFlow", currentFlow=self.currentFlow.int, response=response
proc generateRandomPUK*(self: Service): string =
for i in 0 ..< PUKLengthForStatusApp:
result = result & $rand(0 .. 9)
proc onTimeout(self: Service, response: string) {.slot.} =
if(self.closingApp or self.currentFlow == FlowType.NoFlow):
if(self.closingApp or self.currentFlow == KCSFlowType.NoFlow):
return
debug "onTimeout, about to start flow: ", flowType=self.currentFlow
self.startFlow(%* { })
debug "onTimeout, about to start flow: ", currentFlow=self.currentFlow
self.startFlow(self.setPayloadForCurrentFlow)
proc runTimer(self: Service) =
if(self.closingApp or self.currentFlow == FlowType.NoFlow):
if(self.closingApp or self.currentFlow == KCSFlowType.NoFlow):
return
let arg = TimerTaskArg(
@ -148,7 +165,7 @@ QtObject:
var payload = %* { }
if factoryReset:
payload[RequestParamFactoryReset] = %* factoryReset
self.currentFlow = FlowType.LoadAccount
self.currentFlow = KCSFlowType.LoadAccount
self.startFlow(payload)
proc startLoadAccountFlowWithSeedPhrase*(self: Service, seedPhraseLength: int, seedPhrase: string, factoryReset: bool) =
@ -163,38 +180,47 @@ QtObject:
}
if factoryReset:
payload[RequestParamFactoryReset] = %* factoryReset
self.currentFlow = FlowType.LoadAccount
self.currentFlow = KCSFlowType.LoadAccount
self.startFlow(payload)
proc startLoginFlow*(self: Service) =
let payload = %* { }
self.currentFlow = FlowType.Login
self.currentFlow = KCSFlowType.Login
self.startFlow(payload)
proc startLoginFlowAutomatically*(self: Service, pin: string) =
let payload = %* {
RequestParamPIN: pin
}
self.currentFlow = FlowType.Login
self.currentFlow = KCSFlowType.Login
self.startFlow(payload)
proc startRecoverAccountFlow*(self: Service) =
let payload = %* { }
self.currentFlow = FlowType.RecoverAccount
self.currentFlow = KCSFlowType.RecoverAccount
self.startFlow(payload)
proc startGetAppInfoFlow*(self: Service, factoryReset: bool) =
var payload = %* { }
if factoryReset:
payload[RequestParamFactoryReset] = %* factoryReset
self.currentFlow = FlowType.GetAppInfo
self.currentFlow = KCSFlowType.GetAppInfo
self.startFlow(payload)
proc startGetMetadataFlow*(self: Service) =
let payload = %* {
RequestParamResolveAddr: true
}
self.currentFlow = FlowType.GetMetadata
self.currentFlow = KCSFlowType.GetMetadata
self.startFlow(payload)
proc startStoreMetadataFlow*(self: Service, cardName: string, pin: string, walletPaths: seq[string]) =
let payload = %* {
RequestParamPIN: pin,
RequestParamCardName: cardName,
RequestParamWalletPaths: walletPaths
}
self.currentFlow = KCSFlowType.StoreMetadata
self.startFlow(payload)
proc storePin*(self: Service, pin: string, puk: string) =

@ -1 +1 @@
Subproject commit 3fd18f5ff11a0efffa8a1a2a672351dd6da63d39
Subproject commit 16f37cb459b4aa2d24fa194bb40fd8a4e6541f93