Refactor error handling in prompt mode; add cred flag and reset func

This commit is contained in:
Mitchell Simon 2019-08-31 17:19:25 -04:00
parent 84ea1cacdf
commit 633945b1d1
8 changed files with 72 additions and 33 deletions

View File

@ -19,9 +19,10 @@ var errSourceNotFound = errors.New("source host not found")
type credentialFlagSet struct {
includePasswordFlags bool
includeHostFlag bool
includeCredFlags bool
sourceHost string
primary string
noNumbers bool
noSpecials bool
length uint
@ -32,35 +33,47 @@ func (set credentialFlagSet) withPasswordFlags() credentialFlagSet {
return set
}
func (set credentialFlagSet) withHostFlag() credentialFlagSet {
set.includeHostFlag = true
func (set credentialFlagSet) withCredFlags() credentialFlagSet {
set.includeCredFlags = true
return set
}
func (set *credentialFlagSet) register(cmd *cobra.Command) {
if set.includeHostFlag {
if set.includeCredFlags {
cmd.Flags().StringVarP(&set.sourceHost, "source-host", "s", "", "filter results to this source host")
cmd.Flags().StringVarP(&set.primary, "primary", "p", "", "specify a primary user key (must include tag if applicable)")
}
if set.includePasswordFlags {
cmd.Flags().BoolVarP(&set.noNumbers, "no-numbers", "n", false, "do not use numbers in the generated password")
cmd.Flags().BoolVarP(&set.noSpecials, "no-specials", "p", false, "do not use special characters in the generated password")
cmd.Flags().BoolVarP(&set.noSpecials, "no-specials", "e", false, "do not use special characters in the generated password")
cmd.Flags().UintVarP(&set.length, "length", "l", 32, "length of the generated password")
}
}
func (set *credentialFlagSet) resetValues() {
set.sourceHost = ""
set.primary = ""
set.noNumbers = false
set.noSpecials = false
set.length = 0
}
var checkPromptMode = false
func check(err error) {
if err != nil {
fmt.Println(err)
if checkPromptMode {
panic(err)
}
fmt.Fprintln(os.Stdout, err)
os.Exit(1)
}
}
func selectCredential(client types.CredentialsClient, sourceHost string) types.Credential {
var (
idKey string
prompt survey.Prompt
)
func selectCredential(client types.CredentialsClient, sourceHost string, primary string) types.Credential {
var prompt survey.Prompt
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
@ -128,19 +141,24 @@ receive:
keyIDMap[key] = md.ID
}
prompt = &survey.Select{
Message: "Primary user key (and tag):",
Options: keys,
PageSize: 20,
VimMode: true,
}
if primary == "" {
var idKey string
prompt = &survey.Select{
Message: "Primary user key (and tag):",
Options: keys,
PageSize: 20,
VimMode: true,
}
check(survey.AskOne(prompt, &idKey, nil))
check(survey.AskOne(prompt, &idKey, nil))
primary = idKey
}
ctx, cancel = context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
cred, err := client.Get(ctx, keyIDMap[idKey])
cred, err := client.Get(ctx, keyIDMap[primary])
check(err)
return cred

View File

@ -27,6 +27,8 @@ func makeCreate(repo clitypes.ConfigRepo, initClient credentialsClientInit) *cob
password.`,
Run: func(_ *cobra.Command, args []string) {
defer flags.resetValues()
var (
otp bool
cleancb bool

View File

@ -10,7 +10,7 @@ import (
)
func makeDelete(initClient credentialsClientInit) *cobra.Command {
flags := credentialFlagSet{}.withHostFlag()
flags := credentialFlagSet{}.withCredFlags()
deleteCmd := &cobra.Command{
Use: "delete",
@ -18,12 +18,14 @@ func makeDelete(initClient credentialsClientInit) *cobra.Command {
Long: `Delete a credential using the given ID, permanently. THERE IS NO UNDOING THIS ACTION.`,
Run: func(cmd *cobra.Command, args []string) {
defer flags.resetValues()
ctx, cancel := context.WithTimeout(context.Background(), time.Second*60)
defer cancel()
client := initClient(ctx)
cred := selectCredential(client, flags.sourceHost)
cred := selectCredential(client, flags.sourceHost, flags.primary)
fmt.Println(cred)

View File

@ -16,7 +16,7 @@ import (
)
func makeGet(repo clitypes.ConfigRepo, initClient credentialsClientInit) *cobra.Command {
flags := credentialFlagSet{}.withHostFlag()
flags := credentialFlagSet{}.withCredFlags()
getCmd := &cobra.Command{
Use: "get",
@ -25,6 +25,8 @@ func makeGet(repo clitypes.ConfigRepo, initClient credentialsClientInit) *cobra.
decrypting password.`,
Run: func(cmd *cobra.Command, args []string) {
defer flags.resetValues()
var (
copyPass bool
cleancb bool
@ -38,7 +40,7 @@ decrypting password.`,
masterpass, cfg, err := repo.OpenConfig()
check(err)
cred := selectCredential(client, flags.sourceHost)
cred := selectCredential(client, flags.sourceHost, flags.primary)
fmt.Println(cred)

View File

@ -12,7 +12,7 @@ import (
)
func makeList(initClient credentialsClientInit) *cobra.Command {
flags := credentialFlagSet{}.withHostFlag()
flags := credentialFlagSet{}.withCredFlags()
listCmd := &cobra.Command{
Use: "list",
@ -21,6 +21,8 @@ func makeList(initClient credentialsClientInit) *cobra.Command {
includes almost all the information but the most sensitive.`,
Run: func(cmd *cobra.Command, args []string) {
defer flags.resetValues()
ctx, cancel := context.WithTimeout(context.Background(), time.Second*60)
defer cancel()

View File

@ -19,10 +19,13 @@ import (
func Execute() {
rootCmd := &cobra.Command{
Use: "sp",
Run: run,
Run: runPromptMode,
Short: "This is the CLI client for Selfpass.",
Long: `This is the CLI client for Selfpass, the self-hosted password manager. With this tool you
can interact with the entire Selfpass API.`,
can interact with the entire Selfpass API.
When run without a command specified sp enters prompt mode. All commands and flags are the same,
but your master pass only need be entered once until you exit the prompt.`,
Version: "v0.1.0",
}
@ -47,7 +50,7 @@ can interact with the entire Selfpass API.`,
check(rootCmd.Execute())
}
func run(cmd *cobra.Command, _ []string) {
func runPromptMode(cmd *cobra.Command, _ []string) {
ss := []prompt.Suggest{
{Text: "exit", Description: "Exit selfpass prompt"},
}
@ -67,6 +70,8 @@ func run(cmd *cobra.Command, _ []string) {
return prompt.FilterHasPrefix(ss, d.TextBeforeCursor(), true)
}
checkPromptMode = true
executor := func(argstr string) {
args := strings.Split(argstr, " ")
@ -75,11 +80,15 @@ func run(cmd *cobra.Command, _ []string) {
os.Exit(0)
}
defer func() {
if err := recover(); err != nil {
fmt.Fprint(os.Stderr, err, "\n\n")
}
}()
cmd.SetArgs(args)
err := cmd.Execute()
if err != nil {
fmt.Println(err)
}
cmd.Execute()
fmt.Println()
}
@ -98,6 +107,7 @@ func run(cmd *cobra.Command, _ []string) {
prompt.OptionPreviewSuggestionTextColor(prompt.Red),
)
fmt.Println("\nWelcome to the selfpass prompt.")
p.Run()
}

View File

@ -18,7 +18,7 @@ import (
)
func makeUpdate(repo clitypes.ConfigRepo, initClient credentialsClientInit) *cobra.Command {
flags := credentialFlagSet{}.withHostFlag().withPasswordFlags()
flags := credentialFlagSet{}.withCredFlags().withPasswordFlags()
updateCmd := &cobra.Command{
Use: "update",
@ -27,6 +27,8 @@ func makeUpdate(repo clitypes.ConfigRepo, initClient credentialsClientInit) *cob
password.`,
Run: func(_ *cobra.Command, args []string) {
defer flags.resetValues()
var (
newpass bool
otp bool
@ -43,7 +45,7 @@ password.`,
client := initClient(ctx)
cred := selectCredential(client, flags.sourceHost)
cred := selectCredential(client, flags.sourceHost, flags.primary)
mdqs := []*survey.Question{
{

View File

@ -71,6 +71,7 @@ func (mgr *ConfigManager) OpenConfig() (output string, v *viper.Viper, err error
if err == errConfigDecrypted {
configDecrypted = true
} else if err != nil && err.Error() == crypto.ErrAuthenticationFailed.Error() {
mgr.masterpass = ""
return output, nil, errors.New("incorrect masterpass")
} else if err != nil {
return output, nil, err