2021-10-15 10:34:19 +02:00
|
|
|
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
|
|
|
|
|
|
|
func NewFlow(storageDir string) (*keycardFlow, error) {
|
|
|
|
flow := &keycardFlow{
|
|
|
|
wakeUp: make(chan (struct{})),
|
|
|
|
storage: storageDir,
|
|
|
|
}
|
|
|
|
|
|
|
|
return flow, nil
|
|
|
|
}
|
|
|
|
|
2021-10-15 12:38:06 +03:00
|
|
|
func (f *keycardFlow) Start(flowType FlowType, params map[string]interface{}) 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-15 12:38:06 +03:00
|
|
|
func (f *keycardFlow) Resume(params map[string]interface{}) 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
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *keycardFlow) Cancel() error {
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *keycardFlow) runFlow() {
|
2021-10-15 10:35:01 +03:00
|
|
|
repeat := true
|
2021-10-15 12:38:06 +03:00
|
|
|
var result map[string]interface{}
|
2021-10-15 10:35:01 +03:00
|
|
|
|
|
|
|
for repeat {
|
|
|
|
switch f.flowType {
|
2021-10-15 12:38:06 +03:00
|
|
|
case GetAppInfo:
|
2021-10-15 10:35:01 +03:00
|
|
|
repeat, result = f.switchFlow()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if f.state != Cancelling {
|
|
|
|
signal.SendEvent(FlowResult, result)
|
|
|
|
}
|
|
|
|
|
|
|
|
f.state = Idle
|
|
|
|
}
|
|
|
|
|
2021-10-15 12:38:06 +03:00
|
|
|
func (f *keycardFlow) switchFlow() (bool, map[string]interface{}) {
|
2021-10-15 10:35:01 +03:00
|
|
|
kc := f.connect()
|
|
|
|
defer f.closeKeycard(kc)
|
|
|
|
|
|
|
|
if kc == nil {
|
2021-10-15 12:38:06 +03:00
|
|
|
return false, map[string]interface{}{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-15 10:35:01 +03:00
|
|
|
default:
|
2021-10-15 12:38:06 +03:00
|
|
|
return false, map[string]interface{}{ErrorKey: ErrorUnknownFlow}
|
2021-10-15 10:35:01 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-15 12:38:06 +03:00
|
|
|
func (f *keycardFlow) pause(action string, status map[string]interface{}) {
|
2021-10-15 10:35:01 +03:00
|
|
|
signal.SendEvent(action, status)
|
|
|
|
f.state = Paused
|
|
|
|
}
|
|
|
|
|
2021-10-15 12:38:06 +03:00
|
|
|
func (f *keycardFlow) pauseAndWait(action string, status map[string]interface{}) 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
|
|
|
}
|
|
|
|
|
|
|
|
func (f *keycardFlow) closeKeycard(kc *keycardContext) {
|
|
|
|
if kc != nil {
|
|
|
|
kc.stop()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *keycardFlow) connect() *keycardContext {
|
|
|
|
kc, err := startKeycardContext()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-10-15 12:38:06 +03:00
|
|
|
f.pause(InsertCard, map[string]interface{}{})
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
return kc
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-15 12:38:06 +03:00
|
|
|
func (f *keycardFlow) selectKeycard(kc *keycardContext) (bool, error) {
|
|
|
|
appInfo, err := kc.selectApplet()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if requiredInstanceUID, ok := f.params[InstanceUID]; ok {
|
|
|
|
if instanceUID := tox(appInfo.InstanceUID); instanceUID != requiredInstanceUID {
|
|
|
|
if f.pauseAndWait(SwapCard, map[string]interface{}{ErrorKey: InstanceUID, InstanceUID: instanceUID}) {
|
|
|
|
return true, nil
|
|
|
|
} else {
|
|
|
|
return false, errors.New(ErrorCancel)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if requiredKeyUID, ok := f.params[KeyUID]; ok {
|
|
|
|
if keyUID := tox(appInfo.KeyUID); keyUID != requiredKeyUID {
|
|
|
|
if f.pauseAndWait(SwapCard, map[string]interface{}{ErrorKey: KeyUID, KeyUID: keyUID}) {
|
|
|
|
return true, nil
|
|
|
|
} else {
|
|
|
|
return false, errors.New(ErrorCancel)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-10-14 13:14:43 +03:00
|
|
|
|
2021-10-15 10:35:01 +03:00
|
|
|
return false, nil
|
2021-10-14 13:14:43 +03:00
|
|
|
}
|
2021-10-15 12:38:06 +03:00
|
|
|
|
|
|
|
func (f *keycardFlow) getAppInfoFlow(kc *keycardContext) (bool, map[string]interface{}) {
|
|
|
|
restart, err := f.selectKeycard(kc)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return false, map[string]interface{}{ErrorKey: err.Error()}
|
|
|
|
} else if restart {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return false, map[string]interface{}{ErrorKey: ErrorOK, AppInfo: kc.cmdSet.ApplicationInfo}
|
|
|
|
}
|