569 lines
10 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"
"time"
2021-10-15 10:35:01 +03:00
"github.com/status-im/status-keycard-go/signal"
)
2021-10-14 13:14:43 +03:00
2021-10-20 11:44:57 +03:00
type cardStatus struct {
instanceUID string
keyUID string
freeSlots int
pinRetries int
pukRetries int
}
2021-10-18 14:50:56 +03:00
type KeycardFlow struct {
flowType FlowType
state runState
wakeUp chan (struct{})
2021-10-19 12:19:02 +03:00
pairings *pairingStore
params FlowParams
2021-10-20 11:44:57 +03:00
cardInfo cardStatus
2021-10-18 14:50:56 +03:00
}
func NewFlow(storageDir string) (*KeycardFlow, error) {
2021-10-19 12:19:02 +03:00
p, err := newPairingStore(storageDir)
if err != nil {
return nil, err
}
2021-10-18 14:50:56 +03:00
flow := &KeycardFlow{
2021-10-19 12:19:02 +03:00
wakeUp: make(chan (struct{})),
pairings: p,
2021-10-14 13:14:43 +03:00
}
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
2022-07-12 09:28:10 +02: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 14:50:56 +03:00
func (f *KeycardFlow) runFlow() {
2021-10-18 10:19:09 +03:00
var result FlowStatus
2021-10-18 16:25:20 +03:00
var err error
for {
2021-10-20 11:44:57 +03:00
f.cardInfo = cardStatus{freeSlots: -1, pinRetries: -1, pukRetries: -1}
2021-10-18 16:25:20 +03:00
result, err = f.connectedFlow()
2021-10-15 10:35:01 +03:00
2021-10-18 16:25:20 +03:00
if _, ok := err.(*restartError); !ok {
if result == nil {
result = FlowStatus{ErrorKey: err.Error()}
}
break
}
2021-10-15 10:35:01 +03:00
}
if f.state != Cancelling {
2021-10-25 09:22:00 +03:00
signal.Send(FlowResult, result)
2021-10-15 10:35:01 +03:00
}
2021-10-28 09:52:39 +03:00
f.params = nil
2021-10-15 10:35:01 +03:00
f.state = Idle
}
2022-06-09 11:16:31 +02:00
func (f *KeycardFlow) pause(action string, errMsg string, status FlowParams) {
2021-10-22 09:55:00 +03:00
status[ErrorKey] = errMsg
2021-10-20 11:44:57 +03:00
if f.cardInfo.freeSlots != -1 {
status[InstanceUID] = f.cardInfo.instanceUID
status[KeyUID] = f.cardInfo.keyUID
status[FreeSlots] = f.cardInfo.freeSlots
}
if f.cardInfo.pinRetries != -1 {
status[PINRetries] = f.cardInfo.pinRetries
status[PUKRetries] = f.cardInfo.pukRetries
}
2021-10-25 09:22:00 +03:00
signal.Send(action, status)
2021-10-15 10:35:01 +03:00
f.state = Paused
}
2022-06-09 11:16:31 +02:00
func (f *KeycardFlow) pauseAndWaitWithStatus(action string, errMsg string, status FlowParams) error {
2021-10-20 12:01:38 +03:00
if f.state == Cancelling {
2021-10-22 09:55:00 +03:00
return giveupErr()
2021-10-20 12:01:38 +03:00
}
2022-06-09 11:16:31 +02:00
f.pause(action, errMsg, status)
2021-10-15 10:35:01 +03:00
<-f.wakeUp
2021-10-15 12:38:06 +03:00
if f.state == Resuming {
f.state = Running
2021-10-18 16:29:55 +03:00
return nil
2021-10-15 12:38:06 +03:00
} else {
2021-10-22 09:55:00 +03:00
return giveupErr()
2021-10-15 12:38:06 +03:00
}
2021-10-15 10:35:01 +03:00
}
2022-06-09 11:16:31 +02:00
func (f *KeycardFlow) pauseAndWait(action string, errMsg string) error {
return f.pauseAndWaitWithStatus(action, errMsg, FlowParams{})
}
2021-10-20 11:44:57 +03:00
func (f *KeycardFlow) pauseAndRestart(action string, errMsg string) error {
err := f.pauseAndWait(action, errMsg)
2021-10-18 16:34:15 +03:00
if err != nil {
return err
}
return restartErr()
}
2021-10-21 09:09:20 +03:00
func (f *KeycardFlow) requireKeys() error {
if f.cardInfo.keyUID != "" {
return nil
}
return f.pauseAndRestart(SwapCard, ErrorNoKeys)
}
2021-10-28 09:52:39 +03:00
func (f *KeycardFlow) requireNoKeys() error {
if f.cardInfo.keyUID == "" {
return nil
}
if overwrite, ok := f.params[Overwrite]; ok && overwrite.(bool) {
return nil
}
return f.pauseAndRestart(SwapCard, ErrorHasKeys)
}
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()
}
}
2022-08-12 08:25:46 +02:00
func (f *KeycardFlow) connect() (*keycardContext, error) {
2021-10-15 10:35:01 +03:00
kc, err := startKeycardContext()
if err != nil {
return nil, errors.New(ErrorConnection)
2021-10-15 10:35:01 +03:00
}
t := time.NewTimer(150 * time.Millisecond)
2021-10-15 10:35:01 +03:00
for {
select {
case <-f.wakeUp:
if f.state != Cancelling {
panic("Resuming is not expected during connection")
}
return nil, giveupErr()
case <-kc.connected:
if kc.runErr != nil {
return nil, restartErr()
}
t.Stop()
f.state = Running
signal.Send(CardInserted, FlowStatus{})
return kc, nil
case <-t.C:
f.pause(InsertCard, ErrorConnection, FlowParams{})
}
2021-10-15 10:35:01 +03:00
}
}
2021-10-20 12:01:38 +03:00
func (f *KeycardFlow) connectedFlow() (FlowStatus, error) {
2022-08-12 08:25:46 +02:00
kc, err := f.connect()
2021-10-20 12:01:38 +03:00
defer f.closeKeycard(kc)
2021-10-15 12:38:06 +03:00
2022-08-12 08:25:46 +02:00
if err != nil {
return nil, err
2021-10-18 14:50:56 +03:00
}
2021-10-20 12:01:38 +03:00
if factoryReset, ok := f.params[FactoryReset]; ok && factoryReset.(bool) {
err := f.factoryReset(kc)
2021-10-15 12:38:06 +03:00
2021-10-20 12:01:38 +03:00
if err != nil {
return nil, err
2021-10-15 12:38:06 +03:00
}
}
2021-10-14 13:14:43 +03:00
2022-08-12 08:25:46 +02:00
err = f.selectKeycard(kc)
2021-10-19 12:19:02 +03:00
if err != nil {
2021-10-20 12:01:38 +03:00
return nil, err
2021-10-19 12:19:02 +03:00
}
2021-10-20 12:01:38 +03:00
switch f.flowType {
case GetAppInfo:
return f.getAppInfoFlow(kc)
case RecoverAccount:
2021-10-21 09:31:54 +03:00
return f.exportKeysFlow(kc, true)
case Login:
return f.exportKeysFlow(kc, false)
2021-10-22 11:36:25 +03:00
case ExportPublic:
2021-10-22 11:49:55 +03:00
return f.exportPublicFlow(kc)
2021-10-22 09:32:07 +03:00
case LoadAccount:
return f.loadKeysFlow(kc)
case Sign:
return f.signFlow(kc)
2021-10-22 11:36:25 +03:00
case ChangePIN:
return f.changePINFlow(kc)
case ChangePUK:
return f.changePUKFlow(kc)
case ChangePairing:
return f.changePairingFlow(kc)
2021-10-20 12:01:38 +03:00
case UnpairThis:
return f.unpairThisFlow(kc)
2021-10-22 09:32:07 +03:00
case UnpairOthers:
return f.unpairOthersFlow(kc)
case DeleteAccountAndUnpair:
return f.deleteUnpairFlow(kc)
2022-08-04 11:21:23 +02:00
case StoreMetadata:
return f.storeMetadataFlow(kc)
case GetMetadata:
return f.getMetadataFlow(kc)
2021-10-20 12:01:38 +03:00
default:
return nil, errors.New(ErrorUnknownFlow)
2021-10-19 12:19:02 +03:00
}
2021-10-18 16:25:20 +03:00
}
2021-10-20 12:01:38 +03:00
func (f *KeycardFlow) getAppInfoFlow(kc *keycardContext) (FlowStatus, error) {
2021-10-22 09:32:07 +03:00
res := FlowStatus{ErrorKey: ErrorOK, AppInfo: toAppInfo(kc.cmdSet.ApplicationInfo)}
err := f.openSCAndAuthenticate(kc, true)
if err == nil {
res[Paired] = true
res[PINRetries] = f.cardInfo.pinRetries
res[PUKRetries] = f.cardInfo.pukRetries
} else if _, ok := err.(*giveupError); ok {
res[Paired] = false
} else {
return nil, err
}
return res, nil
2021-10-20 11:44:57 +03:00
}
2021-10-21 09:31:54 +03:00
func (f *KeycardFlow) exportKeysFlow(kc *keycardContext, recover bool) (FlowStatus, error) {
2021-10-21 09:09:20 +03:00
err := f.requireKeys()
if err != nil {
return nil, err
}
2021-10-22 09:32:07 +03:00
err = f.openSCAndAuthenticate(kc, false)
2021-10-21 09:09:20 +03:00
if err != nil {
return nil, err
}
2021-10-21 09:31:54 +03:00
result := FlowStatus{KeyUID: f.cardInfo.keyUID}
2021-10-21 09:09:20 +03:00
key, err := f.exportKey(kc, encryptionPath, false)
if err != nil {
return nil, err
}
result[EncKey] = key
key, err = f.exportKey(kc, whisperPath, false)
if err != nil {
return nil, err
}
result[WhisperKey] = key
2021-10-21 09:31:54 +03:00
if recover {
key, err = f.exportKey(kc, eip1581Path, true)
if err != nil {
return nil, err
}
result[EIP1581Key] = key
2021-10-21 09:09:20 +03:00
2021-10-21 09:31:54 +03:00
key, err = f.exportKey(kc, walletRoothPath, true)
if err != nil {
return nil, err
}
result[WalleRootKey] = key
2021-10-19 12:19:02 +03:00
2021-10-21 09:31:54 +03:00
key, err = f.exportKey(kc, walletPath, true)
if err != nil {
return nil, err
}
result[WalletKey] = key
key, err = f.exportKey(kc, masterPath, true)
if err != nil {
return nil, err
}
result[MasterKey] = key
2021-10-19 12:19:02 +03:00
}
2021-10-21 09:09:20 +03:00
return result, nil
2021-10-18 16:25:20 +03:00
}
2021-10-22 11:49:55 +03:00
func (f *KeycardFlow) exportPublicFlow(kc *keycardContext) (FlowStatus, error) {
err := f.requireKeys()
if err != nil {
return nil, err
}
err = f.openSCAndAuthenticate(kc, false)
if err != nil {
return nil, err
}
2021-10-27 08:46:00 +03:00
key, err := f.exportBIP44Key(kc)
2021-10-22 11:49:55 +03:00
if err != nil {
return nil, err
}
return FlowStatus{KeyUID: f.cardInfo.keyUID, ExportedKey: key}, nil
2021-10-22 11:36:25 +03:00
}
2021-10-22 09:32:07 +03:00
func (f *KeycardFlow) loadKeysFlow(kc *keycardContext) (FlowStatus, error) {
2021-10-28 09:52:39 +03:00
err := f.requireNoKeys()
if err != nil {
return nil, err
}
err = f.openSCAndAuthenticate(kc, false)
if err != nil {
return nil, err
}
err = f.loadKeys(kc)
if err != nil {
return nil, err
}
return FlowStatus{KeyUID: f.cardInfo.keyUID}, nil
2021-10-22 09:32:07 +03:00
}
func (f *KeycardFlow) signFlow(kc *keycardContext) (FlowStatus, error) {
2021-10-27 08:46:00 +03:00
err := f.requireKeys()
if err != nil {
return nil, err
}
err = f.openSCAndAuthenticate(kc, false)
if err != nil {
return nil, err
}
signature, err := f.sign(kc)
if err != nil {
return nil, err
}
return FlowStatus{KeyUID: f.cardInfo.keyUID, TXSignature: signature}, nil
2021-10-22 09:32:07 +03:00
}
2021-10-22 11:36:25 +03:00
func (f *KeycardFlow) changePINFlow(kc *keycardContext) (FlowStatus, error) {
2021-10-25 09:10:43 +03:00
err := f.openSCAndAuthenticate(kc, false)
if err != nil {
return nil, err
}
err = f.changePIN(kc)
if err != nil {
return nil, err
}
return FlowStatus{InstanceUID: f.cardInfo.instanceUID}, nil
2021-10-22 11:36:25 +03:00
}
func (f *KeycardFlow) changePUKFlow(kc *keycardContext) (FlowStatus, error) {
2021-10-25 09:10:43 +03:00
err := f.openSCAndAuthenticate(kc, false)
if err != nil {
return nil, err
}
err = f.changePUK(kc)
if err != nil {
return nil, err
}
return FlowStatus{InstanceUID: f.cardInfo.instanceUID}, nil
2021-10-22 11:36:25 +03:00
}
func (f *KeycardFlow) changePairingFlow(kc *keycardContext) (FlowStatus, error) {
2021-10-25 09:10:43 +03:00
err := f.openSCAndAuthenticate(kc, false)
if err != nil {
return nil, err
}
err = f.changePairing(kc)
if err != nil {
return nil, err
}
return FlowStatus{InstanceUID: f.cardInfo.instanceUID}, nil
2021-10-22 09:32:07 +03:00
}
2021-10-20 12:01:38 +03:00
func (f *KeycardFlow) unpairThisFlow(kc *keycardContext) (FlowStatus, error) {
2021-10-22 09:32:07 +03:00
err := f.openSCAndAuthenticate(kc, true)
2021-10-15 12:38:06 +03:00
if err != nil {
2021-10-18 16:25:20 +03:00
return nil, err
2021-10-15 12:38:06 +03:00
}
2021-10-21 08:48:51 +03:00
err = f.unpairCurrent(kc)
2021-10-21 08:19:25 +03:00
2021-10-21 08:48:51 +03:00
if err != nil {
2021-10-21 08:19:25 +03:00
return nil, err
}
f.cardInfo.freeSlots++
2021-10-22 11:49:55 +03:00
return FlowStatus{InstanceUID: f.cardInfo.instanceUID, FreeSlots: f.cardInfo.freeSlots}, nil
2021-10-18 15:47:27 +03:00
}
2021-10-22 09:32:07 +03:00
func (f *KeycardFlow) unpairOthersFlow(kc *keycardContext) (FlowStatus, error) {
2021-10-25 08:41:53 +03:00
err := f.openSCAndAuthenticate(kc, true)
if err != nil {
return nil, err
}
for i := 0; i < maxFreeSlots; i++ {
if i == kc.cmdSet.PairingInfo.Index {
continue
}
err = f.unpair(kc, i)
if err != nil {
return nil, err
}
}
return FlowStatus{InstanceUID: f.cardInfo.instanceUID, FreeSlots: f.cardInfo.freeSlots}, nil
2021-10-22 09:32:07 +03:00
}
func (f *KeycardFlow) deleteUnpairFlow(kc *keycardContext) (FlowStatus, error) {
2021-10-25 08:41:53 +03:00
err := f.openSCAndAuthenticate(kc, true)
if err != nil {
return nil, err
}
err = f.removeKey(kc)
if err != nil {
return nil, err
}
f.cardInfo.keyUID = ""
err = f.unpairCurrent(kc)
if err != nil {
return nil, err
}
f.cardInfo.freeSlots++
return FlowStatus{InstanceUID: f.cardInfo.instanceUID, KeyUID: f.cardInfo.keyUID, FreeSlots: f.cardInfo.freeSlots}, nil
2021-10-22 09:32:07 +03:00
}
2022-08-04 11:21:23 +02:00
func (f *KeycardFlow) storeMetadataFlow(kc *keycardContext) (FlowStatus, error) {
2022-08-16 14:45:13 +02:00
err := f.openSCAndAuthenticate(kc, false)
2022-08-04 11:21:23 +02:00
if err != nil {
return nil, err
}
err = f.storeMetadata(kc)
if err != nil {
return nil, err
}
return FlowStatus{InstanceUID: f.cardInfo.instanceUID}, nil
}
func (f *KeycardFlow) getMetadataFlow(kc *keycardContext) (FlowStatus, error) {
m, err := f.getMetadata(kc)
if err != nil {
return nil, err
}
if resolveAddr, ok := f.params[ResolveAddr]; ok && resolveAddr.(bool) {
2022-08-22 09:00:31 +02:00
if f.cardInfo.keyUID == "" {
return FlowStatus{ErrorKey: ErrorNoKeys, InstanceUID: f.cardInfo.instanceUID, CardMeta: m}, nil
}
2022-08-04 11:21:23 +02:00
err := f.openSCAndAuthenticate(kc, false)
if err != nil {
return nil, err
}
2022-08-04 11:55:34 +02:00
for i := range m.Wallets {
k, err := f.exportKey(kc, m.Wallets[i].Path, true)
2022-08-04 11:21:23 +02:00
if err != nil {
return nil, err
}
2022-08-04 11:55:34 +02:00
m.Wallets[i].Address = k.Address
2022-08-04 11:21:23 +02:00
}
}
return FlowStatus{InstanceUID: f.cardInfo.instanceUID, CardMeta: m}, nil
}