github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/libkb/keylock.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  package libkb
     5  
     6  import "fmt"
     7  
     8  type PassphraseType string
     9  
    10  const (
    11  	PassphraseTypeKeybase PassphraseType = "Keybase"
    12  	PassphraseTypePGP     PassphraseType = "PGP"
    13  )
    14  
    15  type UnlockerFunc func(pw string, storeSecret bool) (ret GenericKey, err error)
    16  
    17  type KeyUnlocker struct {
    18  	tries          int
    19  	reason         string
    20  	keyDesc        string
    21  	which          PassphraseType
    22  	useSecretStore bool
    23  	ui             SecretUI
    24  	unlocker       UnlockerFunc
    25  }
    26  
    27  func NewKeyUnlocker(tries int, reason string, keyDesc string, which PassphraseType, useSecretStore bool, ui SecretUI, unlocker UnlockerFunc) KeyUnlocker {
    28  	return KeyUnlocker{
    29  		tries:          tries,
    30  		reason:         reason,
    31  		keyDesc:        keyDesc,
    32  		which:          which,
    33  		useSecretStore: useSecretStore,
    34  		ui:             ui,
    35  		unlocker:       unlocker,
    36  	}
    37  }
    38  
    39  func (arg KeyUnlocker) Run(m MetaContext) (ret GenericKey, err error) {
    40  	var emsg string
    41  
    42  	if arg.ui == nil {
    43  		err = NoUIError{"secret"}
    44  		return nil, err
    45  	}
    46  
    47  	prompt := "Please enter your " + string(arg.which) + " passphrase to unlock the secret key for:\n" +
    48  		arg.keyDesc + "\n"
    49  	if len(arg.reason) > 0 {
    50  		prompt = prompt + "\nReason: " + arg.reason
    51  	}
    52  
    53  	title := "Your " + string(arg.which) + " passphrase"
    54  
    55  	for i := 0; arg.tries <= 0 || i < arg.tries; i++ {
    56  		res, err := GetSecret(m, arg.ui, title, prompt, emsg, arg.useSecretStore)
    57  		if err != nil {
    58  			// probably canceled
    59  			return nil, err
    60  		}
    61  		ret, err = arg.unlocker(res.Passphrase, res.StoreSecret)
    62  		if err == nil {
    63  			// success
    64  			return ret, nil
    65  		}
    66  		if _, ok := err.(PassphraseError); ok {
    67  			// keep trying
    68  			emsg = "Failed to unlock key; bad passphrase"
    69  		} else {
    70  			// unretryable error
    71  			return nil, err
    72  		}
    73  	}
    74  
    75  	return nil, fmt.Errorf("Too many failures; giving up")
    76  }