github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/passphrase_state.go (about)

     1  // Copyright 2019 Keybase, Inc. All rights reserved. Use of
     2  // this source code is governed by the included BSD license.
     3  
     4  package libkb
     5  
     6  import (
     7  	"fmt"
     8  	"time"
     9  
    10  	"github.com/keybase/client/go/protocol/keybase1"
    11  )
    12  
    13  func randomPassphraseToState(hasRandomPassphrase bool) keybase1.PassphraseState {
    14  	if hasRandomPassphrase {
    15  		return keybase1.PassphraseState_RANDOM
    16  	}
    17  	return keybase1.PassphraseState_KNOWN
    18  }
    19  
    20  func LoadPassphraseState(mctx MetaContext) (passphraseState keybase1.PassphraseState, err error) {
    21  	return LoadPassphraseStateWithForceRepoll(mctx)
    22  }
    23  
    24  // forceRepoll only forces repoll when the state is RANDOM, but not when it is KNOWN.
    25  func LoadPassphraseStateWithForceRepoll(mctx MetaContext) (passphraseState keybase1.PassphraseState, err error) {
    26  	mctx = mctx.WithLogTag("PPSTATE")
    27  	defer mctx.Trace("LoadPassphraseState()", &err)()
    28  
    29  	// If we're in standalone mode, we don't get the gregor msg about
    30  	// passphrase_state changes. So, force a repoll to the server if the state
    31  	// isn't currently KNOWN.
    32  	forceRepoll := mctx.G().GregorListener == nil
    33  
    34  	if len(mctx.G().Env.GetUsername().String()) == 0 {
    35  		mctx.Debug("LoadPassphraseState: user is not logged in")
    36  		return passphraseState, NewLoginRequiredError("LoadPassphraseState")
    37  	}
    38  
    39  	configState := mctx.G().Env.GetConfig().GetPassphraseState()
    40  	if configState != nil {
    41  		mctx.Debug("LoadPassphraseState: state found in config.json: %#v", configState)
    42  		if !forceRepoll || *configState == keybase1.PassphraseState_KNOWN {
    43  			return *configState, nil
    44  		}
    45  	}
    46  
    47  	mctx.Debug("LoadPassphraseState: state not found in config.json; checking legacy leveldb")
    48  
    49  	legacyState, err := loadPassphraseStateFromLegacy(mctx)
    50  	if err == nil {
    51  		mctx.Debug("LoadPassphraseState: state found in legacy leveldb: %#v", legacyState)
    52  		MaybeSavePassphraseState(mctx, legacyState)
    53  		if !forceRepoll || legacyState == keybase1.PassphraseState_KNOWN {
    54  			return legacyState, nil
    55  		}
    56  	}
    57  	mctx.Debug("LoadPassphraseState: could not find state in legacy leveldb (%s); checking remote", err)
    58  
    59  	remoteState, err := LoadPassphraseStateFromRemote(mctx)
    60  	if err == nil {
    61  		MaybeSavePassphraseState(mctx, remoteState)
    62  		return remoteState, nil
    63  	}
    64  	return passphraseState, fmt.Errorf("failed to load passphrase state from any path, including remote: %s", err)
    65  }
    66  
    67  func MaybeSavePassphraseState(mctx MetaContext, passphraseState keybase1.PassphraseState) {
    68  	err := mctx.G().Env.GetConfigWriter().SetPassphraseState(passphraseState)
    69  	if err == nil {
    70  		mctx.Debug("Added PassphraseState=%#v to config file", passphraseState)
    71  	} else {
    72  		mctx.Warning("Failed to save passphraseState=%#v to config file: %s", passphraseState, err)
    73  	}
    74  }
    75  
    76  func loadPassphraseStateFromLegacy(mctx MetaContext) (passphraseState keybase1.PassphraseState, err error) {
    77  	currentUID := mctx.CurrentUID()
    78  	cacheKey := DbKey{
    79  		Typ: DBLegacyHasRandomPW,
    80  		Key: currentUID.String(),
    81  	}
    82  	var hasRandomPassphrase bool
    83  	found, err := mctx.G().GetKVStore().GetInto(&hasRandomPassphrase, cacheKey)
    84  	if err != nil {
    85  		return passphraseState, err
    86  	}
    87  	if !found {
    88  		return passphraseState, fmt.Errorf("passphrase state not found in leveldb")
    89  	}
    90  	return randomPassphraseToState(hasRandomPassphrase), nil
    91  }
    92  
    93  func LoadPassphraseStateFromRemote(mctx MetaContext) (passphraseState keybase1.PassphraseState, err error) {
    94  	var ret struct {
    95  		AppStatusEmbed
    96  		RandomPassphrase bool `json:"random_pw"`
    97  	}
    98  	err = mctx.G().API.GetDecode(mctx, APIArg{
    99  		Endpoint:       "user/has_random_pw",
   100  		SessionType:    APISessionTypeREQUIRED,
   101  		InitialTimeout: 10 * time.Second,
   102  	}, &ret)
   103  	if err != nil {
   104  		return passphraseState, err
   105  	}
   106  	return randomPassphraseToState(ret.RandomPassphrase), nil
   107  }