/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/engine/device_add.go
164 строки
5 KB
zoom-ua
modernize error handling with errors.As/Is (#29350)
25 июн 2026, 17:41
Не верифицирован
25 июн 2026, 17:41
e09e254
Код
Авторство
О чём код?
// Copyright 2015 Keybase, Inc. All rights reserved. Use of // this source code is governed by the included BSD license. package engine import ( "context" "errors" "github.com/keybase/client/go/kex2" "github.com/keybase/client/go/libkb" keybase1 "github.com/keybase/client/go/protocol/keybase1" ) // DeviceAdd is an engine. type DeviceAdd struct { libkb.Contextified } // NewDeviceAdd creates a DeviceAdd engine. func NewDeviceAdd(g *libkb.GlobalContext) *DeviceAdd { return &DeviceAdd{ Contextified: libkb.NewContextified(g), } } // Name is the unique engine name. func (e *DeviceAdd) Name() string { return "DeviceAdd" } // GetPrereqs returns the engine prereqs. func (e *DeviceAdd) Prereqs() Prereqs { return Prereqs{Device: true} } // RequiredUIs returns the required UIs. func (e *DeviceAdd) RequiredUIs() []libkb.UIKind { return []libkb.UIKind{libkb.ProvisionUIKind} } // SubConsumers returns the other UI consumers for this engine. func (e *DeviceAdd) SubConsumers() []libkb.UIConsumer { return []libkb.UIConsumer{ &Kex2Provisioner{}, } } func (e *DeviceAdd) promptLoop(m libkb.MetaContext, provisioner *Kex2Provisioner, secret *libkb.Kex2Secret, provisioneeType keybase1.DeviceType) (err error) { sb := secret.Secret() arg := keybase1.DisplayAndPromptSecretArg{ Secret: sb[:], Phrase: secret.Phrase(), OtherDeviceType: provisioneeType, } for i := range 10 { receivedSecret, err := m.UIs().ProvisionUI.DisplayAndPromptSecret(m.Ctx(), arg) if err != nil { m.Warning("DisplayAndPromptSecret error: %s", err) return err } if len(receivedSecret.Secret) > 0 { m.Debug("received secret, adding to provisioner") var ks kex2.Secret copy(ks[:], receivedSecret.Secret) provisioner.AddSecret(ks) return nil } if len(receivedSecret.Phrase) > 0 { m.Debug("received secret phrase, checking validity") checker := libkb.MakeCheckKex2SecretPhrase(m.G()) if !checker.F(receivedSecret.Phrase) { m.Debug("secret phrase failed validity check (attempt %d)", i+1) arg.PreviousErr = checker.Hint continue } uid := m.CurrentUID() m.Debug("received secret phrase, adding to provisioner with uid=%s", uid) ks, err := libkb.NewKex2SecretFromUIDAndPhrase(uid, receivedSecret.Phrase) if err != nil { m.Warning("NewKex2SecretFromPhrase error: %s", err) return err } provisioner.AddSecret(ks.Secret()) return nil } if provisioneeType == keybase1.DeviceType_MOBILE { // for mobile provisionee, only displaying the secret so it's // ok/expected that nothing came back m.Debug("device add DisplayAndPromptSecret returned empty secret, stopping retry loop") return nil } } return libkb.RetryExhaustedError{} } // Run starts the engine. func (e *DeviceAdd) Run(m libkb.MetaContext) (err error) { defer m.Trace("DeviceAdd#Run", &err)() m.G().LocalSigchainGuard().Set(m.Ctx(), "DeviceAdd") defer m.G().LocalSigchainGuard().Clear(m.Ctx(), "DeviceAdd") arg := keybase1.ChooseDeviceTypeArg{Kind: keybase1.ChooseType_NEW_DEVICE} provisioneeType, err := m.UIs().ProvisionUI.ChooseDeviceType(context.TODO(), arg) if err != nil { return err } uid := m.CurrentUID() // make a new secret; continue to generate legacy Kex2 secrets for now. kex2SecretTyp := libkb.Kex2SecretTypeV1Desktop if provisioneeType == keybase1.DeviceType_MOBILE || m.G().IsMobileAppType() { kex2SecretTyp = libkb.Kex2SecretTypeV1Mobile } m.Debug("provisionee device type: %v; uid: %s; secret type: %d", provisioneeType, uid, kex2SecretTyp) secret, err := libkb.NewKex2SecretFromTypeAndUID(kex2SecretTyp, uid) if err != nil { return err } m.Debug("secret phrase received") // provisioner needs ppstream, and UI is confusing when it asks for // it at the same time as asking for the secret, so get it first // before prompting for the kex2 secret: pps, err := libkb.GetPassphraseStreamStored(m) if err != nil { return err } // create provisioner engine provisioner := NewKex2Provisioner(m.G(), secret.Secret(), pps) var canceler func() m, canceler = m.WithContextCancel() // display secret and prompt for secret from X in a goroutine: go func() { err := e.promptLoop(m, provisioner, secret, provisioneeType) if err != nil { m.Debug("DeviceAdd prompt loop error: %s", err) canceler() } }() defer func() { canceler() }() if err := RunEngine2(m, provisioner); err != nil { if errors.Is(err, kex2.ErrHelloTimeout) { err = libkb.CanceledError{M: "Failed to provision device: are you sure you typed the secret properly?"} } return err } m.G().KeyfamilyChanged(m.Ctx(), m.G().Env.GetUID()) return nil }