1// Copyright 2015 Keybase, Inc. All rights reserved. Use of 2// this source code is governed by the included BSD license. 3 4package libkb 5 6import "fmt" 7 8type PassphraseType string 9 10const ( 11 PassphraseTypeKeybase PassphraseType = "Keybase" 12 PassphraseTypePGP PassphraseType = "PGP" 13) 14 15type UnlockerFunc func(pw string, storeSecret bool) (ret GenericKey, err error) 16 17type 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 27func 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 39func (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} 77