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  }