mirror of
https://github.com/status-im/status-keycard-go.git
synced 2025-01-31 08:37:16 +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.GetAppInfo, skg.FlowParams{})
|
||||||
testFlow(skg.RecoverAccount, skg.FlowParams{skg.PIN: "234567"})
|
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
|
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) {
|
func (f *KeycardFlow) pause(action string, errMsg string) {
|
||||||
status := FlowParams{}
|
status := FlowParams{}
|
||||||
|
|
||||||
@ -159,6 +127,10 @@ func (f *KeycardFlow) pause(action string, errMsg string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *KeycardFlow) pauseAndWait(action string, errMsg string) error {
|
func (f *KeycardFlow) pauseAndWait(action string, errMsg string) error {
|
||||||
|
if f.state == Cancelling {
|
||||||
|
return errors.New("cancel")
|
||||||
|
}
|
||||||
|
|
||||||
f.pause(action, errMsg)
|
f.pause(action, errMsg)
|
||||||
<-f.wakeUp
|
<-f.wakeUp
|
||||||
|
|
||||||
@ -210,158 +182,38 @@ func (f *KeycardFlow) connect() *keycardContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *KeycardFlow) factoryReset(kc *keycardContext) error {
|
func (f *KeycardFlow) connectedFlow() (FlowStatus, error) {
|
||||||
// on success, remove the FactoryReset switch to avoid re-triggering it
|
kc := f.connect()
|
||||||
// if card is disconnected/reconnected
|
defer f.closeKeycard(kc)
|
||||||
delete(f.params, FactoryReset)
|
|
||||||
return errors.New("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *KeycardFlow) selectKeycard(kc *keycardContext) error {
|
if kc == nil {
|
||||||
appInfo, err := kc.selectApplet()
|
return nil, errors.New(ErrorConnection)
|
||||||
|
|
||||||
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 {
|
if factoryReset, ok := f.params[FactoryReset]; ok && factoryReset.(bool) {
|
||||||
return f.pauseAndRestart(SwapCard, ErrorNotAKeycard)
|
err := f.factoryReset(kc)
|
||||||
}
|
|
||||||
|
|
||||||
if requiredInstanceUID, ok := f.params[InstanceUID]; ok {
|
if err != nil {
|
||||||
if f.cardInfo.instanceUID != requiredInstanceUID {
|
return nil, err
|
||||||
return f.pauseAndRestart(SwapCard, InstanceUID)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if requiredKeyUID, ok := f.params[KeyUID]; ok {
|
err := f.selectKeycard(kc)
|
||||||
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 {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return f.pair(kc)
|
switch f.flowType {
|
||||||
}
|
case GetAppInfo:
|
||||||
|
return f.getAppInfoFlow(kc)
|
||||||
func (f *KeycardFlow) initCard(kc *keycardContext) error {
|
case RecoverAccount:
|
||||||
//NOTE: after init a restart of the flow is always needed
|
return f.recoverAccountFlow(kc)
|
||||||
return errors.New("not implemented")
|
case UnpairThis:
|
||||||
}
|
return f.unpairThisFlow(kc)
|
||||||
|
default:
|
||||||
func (f *KeycardFlow) openSC(kc *keycardContext) error {
|
return nil, errors.New(ErrorUnknownFlow)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *KeycardFlow) getAppInfoFlow(kc *keycardContext) (FlowStatus, error) {
|
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")
|
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