mirror of
https://github.com/status-im/status-keycard-go.git
synced 2025-01-18 18:31:56 +00:00
split commands from flows
This commit is contained in:
parent
7829094f92
commit
2b84b6560a
@ -92,4 +92,5 @@ func main() {
|
||||
|
||||
testFlow(skg.GetAppInfo, skg.FlowParams{})
|
||||
testFlow(skg.RecoverAccount, skg.FlowParams{skg.PIN: "234567"})
|
||||
testFlow(skg.UnpairThis, skg.FlowParams{skg.PIN: correctPIN})
|
||||
}
|
||||
|
206
flow.go
206
flow.go
@ -104,38 +104,6 @@ func (f *KeycardFlow) runFlow() {
|
||||
f.state = Idle
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) connectedFlow() (FlowStatus, error) {
|
||||
kc := f.connect()
|
||||
defer f.closeKeycard(kc)
|
||||
|
||||
if kc == nil {
|
||||
return nil, errors.New(ErrorConnection)
|
||||
}
|
||||
|
||||
if factoryReset, ok := f.params[FactoryReset]; ok && factoryReset.(bool) {
|
||||
err := f.factoryReset(kc)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err := f.selectKeycard(kc)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch f.flowType {
|
||||
case GetAppInfo:
|
||||
return f.getAppInfoFlow(kc)
|
||||
case RecoverAccount:
|
||||
return f.recoverAccountFlow(kc)
|
||||
default:
|
||||
return nil, errors.New(ErrorUnknownFlow)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) pause(action string, errMsg string) {
|
||||
status := FlowParams{}
|
||||
|
||||
@ -159,6 +127,10 @@ func (f *KeycardFlow) pause(action string, errMsg string) {
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) pauseAndWait(action string, errMsg string) error {
|
||||
if f.state == Cancelling {
|
||||
return errors.New("cancel")
|
||||
}
|
||||
|
||||
f.pause(action, errMsg)
|
||||
<-f.wakeUp
|
||||
|
||||
@ -210,158 +182,38 @@ func (f *KeycardFlow) connect() *keycardContext {
|
||||
}
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) factoryReset(kc *keycardContext) error {
|
||||
// on success, remove the FactoryReset switch to avoid re-triggering it
|
||||
// if card is disconnected/reconnected
|
||||
delete(f.params, FactoryReset)
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
func (f *KeycardFlow) connectedFlow() (FlowStatus, error) {
|
||||
kc := f.connect()
|
||||
defer f.closeKeycard(kc)
|
||||
|
||||
func (f *KeycardFlow) selectKeycard(kc *keycardContext) error {
|
||||
appInfo, err := kc.selectApplet()
|
||||
|
||||
f.cardInfo.instanceUID = tox(appInfo.InstanceUID)
|
||||
f.cardInfo.keyUID = tox(appInfo.KeyUID)
|
||||
f.cardInfo.freeSlots = bytesToInt(appInfo.AvailableSlots)
|
||||
|
||||
if err != nil {
|
||||
return restartErr()
|
||||
if kc == nil {
|
||||
return nil, errors.New(ErrorConnection)
|
||||
}
|
||||
|
||||
if !appInfo.Installed {
|
||||
return f.pauseAndRestart(SwapCard, ErrorNotAKeycard)
|
||||
}
|
||||
if factoryReset, ok := f.params[FactoryReset]; ok && factoryReset.(bool) {
|
||||
err := f.factoryReset(kc)
|
||||
|
||||
if requiredInstanceUID, ok := f.params[InstanceUID]; ok {
|
||||
if f.cardInfo.instanceUID != requiredInstanceUID {
|
||||
return f.pauseAndRestart(SwapCard, InstanceUID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if requiredKeyUID, ok := f.params[KeyUID]; ok {
|
||||
if f.cardInfo.keyUID != requiredKeyUID {
|
||||
return f.pauseAndRestart(SwapCard, KeyUID)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) pair(kc *keycardContext) error {
|
||||
if f.cardInfo.freeSlots == 0 {
|
||||
return f.pauseAndRestart(SwapCard, FreeSlots)
|
||||
}
|
||||
|
||||
if pairingPass, ok := f.params[PairingPass]; ok {
|
||||
pairing, err := kc.pair(pairingPass.(string))
|
||||
|
||||
if err == nil {
|
||||
return f.pairings.store(f.cardInfo.instanceUID, toPairInfo(pairing))
|
||||
} else if isSCardError(err) {
|
||||
return restartErr()
|
||||
}
|
||||
|
||||
delete(f.params, PairingPass)
|
||||
}
|
||||
|
||||
err := f.pauseAndWait(EnterPairing, "")
|
||||
err := f.selectKeycard(kc)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return f.pair(kc)
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) initCard(kc *keycardContext) error {
|
||||
//NOTE: after init a restart of the flow is always needed
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) openSC(kc *keycardContext) error {
|
||||
if !kc.cmdSet.ApplicationInfo.Initialized {
|
||||
return f.initCard(kc)
|
||||
switch f.flowType {
|
||||
case GetAppInfo:
|
||||
return f.getAppInfoFlow(kc)
|
||||
case RecoverAccount:
|
||||
return f.recoverAccountFlow(kc)
|
||||
case UnpairThis:
|
||||
return f.unpairThisFlow(kc)
|
||||
default:
|
||||
return nil, errors.New(ErrorUnknownFlow)
|
||||
}
|
||||
|
||||
pairing := f.pairings.get(f.cardInfo.instanceUID)
|
||||
|
||||
if pairing != nil {
|
||||
err := kc.openSecureChannel(pairing.Index, pairing.Key)
|
||||
|
||||
if err == nil {
|
||||
appStatus, err := kc.getStatusApplication()
|
||||
|
||||
if err != nil {
|
||||
// getStatus can only fail for connection errors
|
||||
return restartErr()
|
||||
}
|
||||
|
||||
f.cardInfo.pinRetries = appStatus.PinRetryCount
|
||||
f.cardInfo.pukRetries = appStatus.PUKRetryCount
|
||||
|
||||
return nil
|
||||
} else if isSCardError(err) {
|
||||
return restartErr()
|
||||
}
|
||||
|
||||
f.pairings.delete(f.cardInfo.instanceUID)
|
||||
}
|
||||
|
||||
err := f.pair(kc)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f.openSC(kc)
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) unblockPUK(kc *keycardContext) error {
|
||||
return errors.New("not yet implemented")
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) authenticate(kc *keycardContext) error {
|
||||
if f.cardInfo.pukRetries == 0 {
|
||||
return f.pauseAndRestart(SwapCard, PUKRetries)
|
||||
} else if f.cardInfo.pinRetries == 0 {
|
||||
// succesful PUK unblock leaves the card authenticated
|
||||
return f.unblockPUK(kc)
|
||||
}
|
||||
|
||||
pinError := ""
|
||||
|
||||
if pin, ok := f.params[PIN]; ok {
|
||||
err := kc.verifyPin(pin.(string))
|
||||
|
||||
if err == nil {
|
||||
f.cardInfo.pinRetries = maxPINRetries
|
||||
return nil
|
||||
} else if isSCardError(err) {
|
||||
return restartErr()
|
||||
} else if leftRetries, ok := getPinRetries(err); ok {
|
||||
f.cardInfo.pinRetries = leftRetries
|
||||
}
|
||||
|
||||
pinError = PIN
|
||||
}
|
||||
|
||||
err := f.pauseAndWait(EnterPIN, pinError)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f.authenticate(kc)
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) openSCAndAuthenticate(kc *keycardContext) error {
|
||||
err := f.openSC(kc)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f.authenticate(kc)
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) getAppInfoFlow(kc *keycardContext) (FlowStatus, error) {
|
||||
@ -377,3 +229,13 @@ func (f *KeycardFlow) recoverAccountFlow(kc *keycardContext) (FlowStatus, error)
|
||||
|
||||
return nil, errors.New("not yet implemented")
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) unpairThisFlow(kc *keycardContext) (FlowStatus, error) {
|
||||
err := f.openSCAndAuthenticate(kc)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, errors.New("not yet implemented")
|
||||
}
|
||||
|
157
flow_commands.go
Normal file
157
flow_commands.go
Normal file
@ -0,0 +1,157 @@
|
||||
package statuskeycardgo
|
||||
|
||||
import "errors"
|
||||
|
||||
func (f *KeycardFlow) factoryReset(kc *keycardContext) error {
|
||||
// on success, remove the FactoryReset switch to avoid re-triggering it
|
||||
// if card is disconnected/reconnected
|
||||
delete(f.params, FactoryReset)
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) selectKeycard(kc *keycardContext) error {
|
||||
appInfo, err := kc.selectApplet()
|
||||
|
||||
f.cardInfo.instanceUID = tox(appInfo.InstanceUID)
|
||||
f.cardInfo.keyUID = tox(appInfo.KeyUID)
|
||||
f.cardInfo.freeSlots = bytesToInt(appInfo.AvailableSlots)
|
||||
|
||||
if err != nil {
|
||||
return restartErr()
|
||||
}
|
||||
|
||||
if !appInfo.Installed {
|
||||
return f.pauseAndRestart(SwapCard, ErrorNotAKeycard)
|
||||
}
|
||||
|
||||
if requiredInstanceUID, ok := f.params[InstanceUID]; ok {
|
||||
if f.cardInfo.instanceUID != requiredInstanceUID {
|
||||
return f.pauseAndRestart(SwapCard, InstanceUID)
|
||||
}
|
||||
}
|
||||
|
||||
if requiredKeyUID, ok := f.params[KeyUID]; ok {
|
||||
if f.cardInfo.keyUID != requiredKeyUID {
|
||||
return f.pauseAndRestart(SwapCard, KeyUID)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) pair(kc *keycardContext) error {
|
||||
if f.cardInfo.freeSlots == 0 {
|
||||
return f.pauseAndRestart(SwapCard, FreeSlots)
|
||||
}
|
||||
|
||||
if pairingPass, ok := f.params[PairingPass]; ok {
|
||||
pairing, err := kc.pair(pairingPass.(string))
|
||||
|
||||
if err == nil {
|
||||
return f.pairings.store(f.cardInfo.instanceUID, toPairInfo(pairing))
|
||||
} else if isSCardError(err) {
|
||||
return restartErr()
|
||||
}
|
||||
|
||||
delete(f.params, PairingPass)
|
||||
}
|
||||
|
||||
err := f.pauseAndWait(EnterPairing, "")
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f.pair(kc)
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) initCard(kc *keycardContext) error {
|
||||
//NOTE: after init a restart of the flow is always needed
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) openSC(kc *keycardContext) error {
|
||||
if !kc.cmdSet.ApplicationInfo.Initialized {
|
||||
return f.initCard(kc)
|
||||
}
|
||||
|
||||
pairing := f.pairings.get(f.cardInfo.instanceUID)
|
||||
|
||||
if pairing != nil {
|
||||
err := kc.openSecureChannel(pairing.Index, pairing.Key)
|
||||
|
||||
if err == nil {
|
||||
appStatus, err := kc.getStatusApplication()
|
||||
|
||||
if err != nil {
|
||||
// getStatus can only fail for connection errors
|
||||
return restartErr()
|
||||
}
|
||||
|
||||
f.cardInfo.pinRetries = appStatus.PinRetryCount
|
||||
f.cardInfo.pukRetries = appStatus.PUKRetryCount
|
||||
|
||||
return nil
|
||||
} else if isSCardError(err) {
|
||||
return restartErr()
|
||||
}
|
||||
|
||||
f.pairings.delete(f.cardInfo.instanceUID)
|
||||
}
|
||||
|
||||
err := f.pair(kc)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f.openSC(kc)
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) unblockPUK(kc *keycardContext) error {
|
||||
return errors.New("not yet implemented")
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) authenticate(kc *keycardContext) error {
|
||||
if f.cardInfo.pukRetries == 0 {
|
||||
return f.pauseAndRestart(SwapCard, PUKRetries)
|
||||
} else if f.cardInfo.pinRetries == 0 {
|
||||
// succesful PUK unblock leaves the card authenticated
|
||||
return f.unblockPUK(kc)
|
||||
}
|
||||
|
||||
pinError := ""
|
||||
|
||||
if pin, ok := f.params[PIN]; ok {
|
||||
err := kc.verifyPin(pin.(string))
|
||||
|
||||
if err == nil {
|
||||
f.cardInfo.pinRetries = maxPINRetries
|
||||
return nil
|
||||
} else if isSCardError(err) {
|
||||
return restartErr()
|
||||
} else if leftRetries, ok := getPinRetries(err); ok {
|
||||
f.cardInfo.pinRetries = leftRetries
|
||||
}
|
||||
|
||||
pinError = PIN
|
||||
}
|
||||
|
||||
err := f.pauseAndWait(EnterPIN, pinError)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f.authenticate(kc)
|
||||
}
|
||||
|
||||
func (f *KeycardFlow) openSCAndAuthenticate(kc *keycardContext) error {
|
||||
err := f.openSC(kc)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f.authenticate(kc)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user