/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/engine/paperprovision.go
248 строк
7 KB
zoom-ua
Avoid owner device lookup during provisioning (#29468)
28 июл 2026, 18:48
Не верифицирован
28 июл 2026, 18:48
a701bba
Код
Авторство
О чём код?
// Copyright 2015 Keybase, Inc. All rights reserved. Use of // this source code is governed by the included BSD license. package engine import ( "errors" "github.com/keybase/client/go/libkb" keybase1 "github.com/keybase/client/go/protocol/keybase1" ) type PaperProvisionEngine struct { libkb.Contextified Username string DeviceName string PaperKey string result error lks *libkb.LKSec User *libkb.User perUserKeyring *libkb.PerUserKeyring deviceWrapEng *DeviceWrap } func NewPaperProvisionEngine(g *libkb.GlobalContext, username, deviceName, paperKey string, ) *PaperProvisionEngine { return &PaperProvisionEngine{ Contextified: libkb.NewContextified(g), Username: username, DeviceName: deviceName, PaperKey: paperKey, } } func (e *PaperProvisionEngine) Name() string { return "PaperProvision" } func (e *PaperProvisionEngine) Prereqs() Prereqs { return Prereqs{} } func (e *PaperProvisionEngine) RequiredUIs() []libkb.UIKind { return []libkb.UIKind{ libkb.ProvisionUIKind, libkb.LogUIKind, libkb.SecretUIKind, libkb.LoginUIKind, } } func (e *PaperProvisionEngine) Run(m libkb.MetaContext) (err error) { defer m.Trace("PaperProvisionEngine#Run", &err)() // clear out any existing session err = m.LogoutKeepSecrets() if err != nil { m.Debug("error on logout: %+v", err) } m = m.WithNewProvisionalLoginContext() // From this point on, if there's an error, we abort the // transaction. defer func() { if err == nil { m = m.CommitProvisionalLogin() } }() // run the LoginLoadUser sub-engine to load a user ueng := newLoginLoadUser(e.G(), e.Username) if err = RunEngine2(m, ueng); err != nil { return err } // make sure the user isn't already provisioned (can // get here if usernameOrEmail is an email address // for an already provisioned on this device user). if ueng.User().HasCurrentDeviceInCurrentInstall() { return libkb.DeviceAlreadyProvisionedError{} } e.User = ueng.User() // Transform the paper key phrase into a key pair bkarg := &PaperKeyGenArg{ Passphrase: libkb.PaperKeyPhrase(e.PaperKey), SkipPush: true, } bkeng := NewPaperKeyGen(e.G(), bkarg) if err := RunEngine2(m, bkeng); err != nil { return err } keys := bkeng.DeviceWithKeys() // Resolve the exact KID against the user loaded for this provisioning // attempt. if err := keys.PopulateFromUser(e.User); err != nil { return err } e.perUserKeyring, err = libkb.NewPerUserKeyring(e.G(), e.User.GetUID()) if err != nil { return err } // Make new device keys and sign them with this paper key if err = e.paper(m, keys); err != nil { return err } // Finish provisoning by calling SwitchConfigAndActiveDevice. we // can't undo that, so do not error out after that. if err := e.deviceWrapEng.SwitchConfigAndActiveDevice(m); err != nil { return err } e.sendNotification(m) return nil } // copied more or less from loginProvision.paper() func (e *PaperProvisionEngine) paper(m libkb.MetaContext, keys *libkb.DeviceWithKeys) error { // After obtaining login session, this will be called before the login state is released. // It signs this new device with the paper key. u := e.User nn := u.GetNormalizedName() uv := u.ToUserVersion() // Set the active device to be a special paper key active device, which keeps // a cached copy around for DeviceKeyGen, which requires it to be in memory. // It also will establish a NIST so that API calls can proceed on behalf of the user. m = m.WithProvisioningKeyActiveDevice(keys, uv) if err := m.LoginContext().SetUsernameUserVersion(nn, uv); err != nil { return err } // need lksec to store device keys locally if err := e.fetchLKS(m, keys.EncryptionKey()); err != nil { return err } if err := e.makeDeviceKeysWithSigner(m, keys.SigningKey()); err != nil { return err } // Cache the paper keys globally now that we're logged in m = m.WithGlobalActiveDevice() m.ActiveDevice().CacheProvisioningKey(m, keys) return nil } func (e *PaperProvisionEngine) sendNotification(m libkb.MetaContext) { e.G().NotifyRouter.HandleLogin(m.Ctx(), string(e.G().Env.GetUsername())) } func (e *PaperProvisionEngine) SubConsumers() []libkb.UIConsumer { return []libkb.UIConsumer{ &loginLoadUser{}, } } func (e *PaperProvisionEngine) Result() error { return e.result } // copied from loginProvision func (e *PaperProvisionEngine) fetchLKS(m libkb.MetaContext, encKey libkb.GenericKey) error { gen, clientLKS, err := fetchLKS(m, encKey) if err != nil { return err } e.lks = libkb.NewLKSecWithClientHalf(clientLKS, gen, e.User.GetUID()) return nil } // copied from loginProvision // makeDeviceKeysWithSigner creates device keys given a signing // key. func (e *PaperProvisionEngine) makeDeviceKeysWithSigner(m libkb.MetaContext, signer libkb.GenericKey) error { args, err := e.makeDeviceWrapArgs(m) if err != nil { return err } args.Signer = signer args.IsEldest = false // just to be explicit args.EldestKID = e.User.GetEldestKID() return e.makeDeviceKeys(m, args) } // copied from loginProvision // makeDeviceWrapArgs creates a base set of args for DeviceWrap. // It ensures that LKSec is created. It also gets a new device // name for this device. func (e *PaperProvisionEngine) makeDeviceWrapArgs(m libkb.MetaContext) (*DeviceWrapArgs, error) { if err := e.ensureLKSec(m); err != nil { return nil, err } return &DeviceWrapArgs{ Me: e.User, DeviceName: e.DeviceName, DeviceType: keybase1.DeviceTypeV2_DESKTOP, Lks: e.lks, PerUserKeyring: e.perUserKeyring, }, nil } // Copied from loginProvision. makeDeviceKeys uses DeviceWrap to // generate device keys and sets active device. func (e *PaperProvisionEngine) makeDeviceKeys(m libkb.MetaContext, args *DeviceWrapArgs) error { e.deviceWrapEng = NewDeviceWrap(m.G(), args) return RunEngine2(m, e.deviceWrapEng) } // copied from loginProvision // ensureLKSec ensures we have LKSec for saving device keys. func (e *PaperProvisionEngine) ensureLKSec(m libkb.MetaContext) error { if e.lks != nil { return nil } pps, err := e.ppStream(m) if err != nil { return err } e.lks = libkb.NewLKSec(pps, e.User.GetUID()) return nil } // copied from loginProvision // ppStream gets the passphrase stream from the cache func (e *PaperProvisionEngine) ppStream(m libkb.MetaContext) (*libkb.PassphraseStream, error) { if m.LoginContext() == nil { return nil, errors.New("loginProvision: ppStream() -> nil ctx.LoginContext") } cached := m.LoginContext().PassphraseStreamCache() if cached == nil { return nil, errors.New("loginProvision: ppStream() -> nil PassphraseStreamCache") } return cached.PassphraseStream(), nil }