github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/engine/login_with_paperkey.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 // This engine makes sure the user is logged in and unlocked. 5 // It asks for a paper key if need be. It does not ask for a passphrase. 6 7 package engine 8 9 import ( 10 "github.com/keybase/client/go/libkb" 11 ) 12 13 // LoginWithPaperKey is an engine. 14 type LoginWithPaperKey struct { 15 libkb.Contextified 16 username string 17 } 18 19 // NewLoginWithPaperKey creates a LoginWithPaperKey engine. 20 // Uses the paperkey to log in and unlock LKS. 21 func NewLoginWithPaperKey(g *libkb.GlobalContext, username string) *LoginWithPaperKey { 22 return &LoginWithPaperKey{ 23 Contextified: libkb.NewContextified(g), 24 username: username, 25 } 26 } 27 28 // Name is the unique engine name. 29 func (e *LoginWithPaperKey) Name() string { 30 return "LoginWithPaperKey" 31 } 32 33 // GetPrereqs returns the engine prereqs. 34 func (e *LoginWithPaperKey) Prereqs() Prereqs { 35 return Prereqs{} 36 } 37 38 // RequiredUIs returns the required UIs. 39 func (e *LoginWithPaperKey) RequiredUIs() []libkb.UIKind { 40 return []libkb.UIKind{ 41 libkb.LogUIKind, 42 libkb.SecretUIKind, 43 } 44 } 45 46 // SubConsumers returns the other UI consumers for this engine. 47 func (e *LoginWithPaperKey) SubConsumers() []libkb.UIConsumer { 48 return []libkb.UIConsumer{} 49 } 50 51 // Run starts the engine. 52 func (e *LoginWithPaperKey) Run(m libkb.MetaContext) (err error) { 53 var me *libkb.User 54 if e.username == "" { 55 me, err = libkb.LoadMe(libkb.NewLoadUserArgWithMetaContext(m).WithForceReload()) 56 if err != nil { 57 return err 58 } 59 } else { 60 me, err = libkb.LoadUser(libkb.NewLoadUserArgWithMetaContext(m).WithForceReload().WithName(e.username)) 61 if err != nil { 62 return err 63 } 64 } 65 66 if loggedIn, _ := isLoggedIn(m); loggedIn { 67 m.Debug("Already logged in with unlocked device keys") 68 return nil 69 } 70 71 // Prompts for a paper key. 72 m.Debug("No device keys available; getting paper key") 73 kp, err := findPaperKeys(m, me) 74 if err != nil { 75 return err 76 } 77 78 // Switch config file to our new user, and zero out the current active device. 79 if err = m.SwitchUser(me.GetNormalizedName()); err != nil { 80 return err 81 } 82 83 // Convert our paper keys into a provisional active device, to use for 84 // API session authentication. BAM! We're "logged in". 85 m = m.WithProvisioningKeyActiveDevice(kp, me.ToUserVersion()) 86 87 // Get the LKS client half. 88 gen, clientLKS, err := fetchLKS(m, kp.EncryptionKey()) 89 if err != nil { 90 return err 91 } 92 lks := libkb.NewLKSecWithClientHalf(clientLKS, gen, me.GetUID()) 93 m.Debug("Got LKS client half") 94 95 // Get the LKS server half. 96 err = lks.Load(m) 97 if err != nil { 98 return err 99 } 100 m.Debug("Got LKS full") 101 102 secretStore := libkb.NewSecretStore(m, me.GetNormalizedName()) 103 m.Debug("Got secret store") 104 105 // Extract the LKS secret 106 secret, err := lks.GetSecret(m) 107 if err != nil { 108 return err 109 } 110 m.Debug("Got LKS secret") 111 112 err = secretStore.StoreSecret(m, secret) 113 if err != nil { 114 return err 115 } 116 m.Debug("Stored secret with LKS from paperkey") 117 118 // Remove our provisional active device, and fall back to global device 119 m = m.WithGlobalActiveDevice() 120 121 // This could prompt but shouldn't because of the secret store. 122 if _, err = libkb.BootstrapActiveDeviceFromConfig(m, true); err != nil { 123 return err 124 } 125 m.Debug("Unlocked device keys") 126 127 m.Debug("LoginWithPaperkey success, sending login notification") 128 m.G().NotifyRouter.HandleLogin(m.Ctx(), string(m.G().Env.GetUsername())) 129 m.Debug("LoginWithPaperkey success, calling login hooks") 130 m.G().CallLoginHooks(m) 131 132 return nil 133 }