204 lines
3.9 KiB
Go
Raw Normal View History

package statuskeycardgo
2021-10-14 13:14:43 +03:00
2021-10-15 10:35:01 +03:00
import (
"errors"
"github.com/status-im/status-keycard-go/signal"
)
2021-10-14 13:14:43 +03:00
2021-10-18 14:50:56 +03:00
type KeycardFlow struct {
flowType FlowType
state runState
wakeUp chan (struct{})
storage string
params map[string]interface{}
}
func NewFlow(storageDir string) (*KeycardFlow, error) {
flow := &KeycardFlow{
2021-10-14 13:14:43 +03:00
wakeUp: make(chan (struct{})),
storage: storageDir,
}
return flow, nil
}
2021-10-18 14:50:56 +03:00
func (f *KeycardFlow) Start(flowType FlowType, params FlowParams) error {
2021-10-15 10:35:01 +03:00
if f.state != Idle {
2021-10-14 13:14:43 +03:00
return errors.New("already running")
}
f.flowType = flowType
f.params = params
2021-10-15 10:35:01 +03:00
f.state = Running
2021-10-14 13:14:43 +03:00
go f.runFlow()
return nil
}
2021-10-18 14:50:56 +03:00
func (f *KeycardFlow) Resume(params FlowParams) error {
2021-10-15 10:35:01 +03:00
if f.state != Paused {
2021-10-14 13:14:43 +03:00
return errors.New("only paused flows can be resumed")
}
for k, v := range params {
f.params[k] = v
}
2021-10-15 10:35:01 +03:00
f.state = Resuming
2021-10-14 13:14:43 +03:00
f.wakeUp <- struct{}{}
return nil
}
2021-10-18 14:50:56 +03:00
func (f *KeycardFlow) Cancel() error {
2021-10-14 13:14:43 +03:00
prevState := f.state
2021-10-15 10:35:01 +03:00
if prevState != Idle {
2021-10-14 13:14:43 +03:00
return errors.New("cannot cancel idle flow")
}
2021-10-15 10:35:01 +03:00
f.state = Cancelling
if prevState == Paused {
2021-10-14 13:14:43 +03:00
f.wakeUp <- struct{}{}
}
return nil
}
2021-10-18 15:47:27 +03:00
func errorToStatus(err error) (bool, FlowStatus) {
if _, ok := err.(*restartError); ok {
return true, FlowStatus{}
} else {
return false, FlowStatus{ErrorKey: err.Error()}
}
}
2021-10-18 14:50:56 +03:00
func (f *KeycardFlow) runFlow() {
2021-10-15 10:35:01 +03:00
repeat := true
2021-10-18 10:19:09 +03:00
var result FlowStatus
2021-10-15 10:35:01 +03:00
for repeat {
2021-10-18 15:47:27 +03:00
repeat, result = f.switchFlow()
2021-10-15 10:35:01 +03:00
}
if f.state != Cancelling {
signal.SendEvent(FlowResult, result)
}
f.state = Idle
}
2021-10-18 14:50:56 +03:00
func (f *KeycardFlow) switchFlow() (bool, FlowStatus) {
2021-10-15 10:35:01 +03:00
kc := f.connect()
defer f.closeKeycard(kc)
if kc == nil {
2021-10-18 10:19:09 +03:00
return false, FlowStatus{ErrorKey: ErrorConnection}
2021-10-15 10:35:01 +03:00
}
switch f.flowType {
2021-10-15 12:38:06 +03:00
case GetAppInfo:
return f.getAppInfoFlow(kc)
2021-10-18 15:47:27 +03:00
case RecoverAccount:
return f.recoverAccountFlow(kc)
2021-10-15 10:35:01 +03:00
default:
2021-10-18 10:19:09 +03:00
return false, FlowStatus{ErrorKey: ErrorUnknownFlow}
2021-10-15 10:35:01 +03:00
}
}
2021-10-18 14:50:56 +03:00
func (f *KeycardFlow) pause(action string, status FlowStatus) {
2021-10-15 10:35:01 +03:00
signal.SendEvent(action, status)
f.state = Paused
}
2021-10-18 14:50:56 +03:00
func (f *KeycardFlow) pauseAndWait(action string, status FlowStatus) bool {
2021-10-15 10:35:01 +03:00
f.pause(action, status)
<-f.wakeUp
2021-10-15 12:38:06 +03:00
if f.state == Resuming {
f.state = Running
return true
} else {
return false
}
2021-10-15 10:35:01 +03:00
}
2021-10-18 14:50:56 +03:00
func (f *KeycardFlow) closeKeycard(kc *keycardContext) {
2021-10-15 10:35:01 +03:00
if kc != nil {
kc.stop()
}
}
2021-10-18 14:50:56 +03:00
func (f *KeycardFlow) connect() *keycardContext {
2021-10-15 10:35:01 +03:00
kc, err := startKeycardContext()
if err != nil {
return nil
}
2021-10-18 10:19:09 +03:00
f.pause(InsertCard, FlowStatus{})
2021-10-15 10:35:01 +03:00
select {
case <-f.wakeUp:
if f.state != Cancelling {
panic("Resuming is not expected during connection")
}
return nil
case <-kc.connected:
if kc.runErr != nil {
return nil
}
2021-10-18 14:50:56 +03:00
signal.SendEvent(CardInserted, FlowStatus{})
2021-10-15 10:35:01 +03:00
return kc
}
}
2021-10-18 15:47:27 +03:00
func restartOrCancel(restart bool) error {
if restart {
return restartErr()
} else {
return errors.New("cancel")
}
}
func (f *KeycardFlow) selectKeycard(kc *keycardContext) error {
2021-10-15 12:38:06 +03:00
appInfo, err := kc.selectApplet()
if err != nil {
2021-10-18 15:47:27 +03:00
return err
2021-10-15 12:38:06 +03:00
}
2021-10-18 14:50:56 +03:00
if !appInfo.Installed {
2021-10-18 15:47:27 +03:00
return restartOrCancel(f.pauseAndWait(SwapCard, FlowStatus{ErrorKey: ErrorNotAKeycard}))
2021-10-18 14:50:56 +03:00
}
2021-10-15 12:38:06 +03:00
if requiredInstanceUID, ok := f.params[InstanceUID]; ok {
if instanceUID := tox(appInfo.InstanceUID); instanceUID != requiredInstanceUID {
2021-10-18 15:47:27 +03:00
return restartOrCancel(f.pauseAndWait(SwapCard, FlowStatus{ErrorKey: InstanceUID, InstanceUID: instanceUID}))
2021-10-15 12:38:06 +03:00
}
}
if requiredKeyUID, ok := f.params[KeyUID]; ok {
if keyUID := tox(appInfo.KeyUID); keyUID != requiredKeyUID {
2021-10-18 15:47:27 +03:00
return restartOrCancel(f.pauseAndWait(SwapCard, FlowStatus{ErrorKey: KeyUID, KeyUID: keyUID}))
2021-10-15 12:38:06 +03:00
}
}
2021-10-14 13:14:43 +03:00
2021-10-18 15:47:27 +03:00
return nil
2021-10-14 13:14:43 +03:00
}
2021-10-15 12:38:06 +03:00
2021-10-18 14:50:56 +03:00
func (f *KeycardFlow) getAppInfoFlow(kc *keycardContext) (bool, FlowStatus) {
2021-10-18 15:47:27 +03:00
err := f.selectKeycard(kc)
2021-10-15 12:38:06 +03:00
if err != nil {
2021-10-18 15:47:27 +03:00
return errorToStatus(err)
2021-10-15 12:38:06 +03:00
}
2021-10-18 14:50:56 +03:00
return false, FlowStatus{ErrorKey: ErrorOK, AppInfo: toAppInfo(kc.cmdSet.ApplicationInfo)}
2021-10-15 12:38:06 +03:00
}
2021-10-18 15:47:27 +03:00
func (f *KeycardFlow) recoverAccountFlow(kc *keycardContext) (bool, FlowStatus) {
return false, FlowStatus{}
}