1package commands
2
3import (
4	"bufio"
5	"encoding/json"
6	"fmt"
7	"os"
8	"strings"
9
10	"code.cloudfoundry.org/credhub-cli/credhub/credentials"
11	"code.cloudfoundry.org/credhub-cli/credhub/credentials/values"
12	"code.cloudfoundry.org/credhub-cli/errors"
13	"code.cloudfoundry.org/credhub-cli/util"
14	"github.com/howeyc/gopass"
15)
16
17type SetCommand struct {
18	CredentialIdentifier string `short:"n" required:"yes" long:"name" description:"Name of the credential to set"`
19	Type                 string `short:"t" long:"type" description:"Sets the credential type. Valid types include 'value', 'json', 'password', 'user', 'certificate', 'ssh' and 'rsa'."`
20	Value                string `short:"v" long:"value" description:"[Value, JSON] Sets the value for the credential"`
21	CaName               string `short:"m" long:"ca-name" description:"[Certificate] Sets the root CA to a stored CA credential"`
22	Root                 string `short:"r" long:"root" description:"[Certificate] Sets the root CA from file or value"`
23	Certificate          string `short:"c" long:"certificate" description:"[Certificate] Sets the certificate from file or value"`
24	Private              string `short:"p" long:"private" description:"[Certificate, SSH, RSA] Sets the private key from file or value"`
25	Public               string `short:"u" long:"public" description:"[SSH, RSA] Sets the public key from file or value"`
26	Username             string `short:"z" long:"username" description:"[User] Sets the username value of the credential"`
27	Password             string `short:"w" long:"password" description:"[Password, User] Sets the password value of the credential"`
28	OutputJSON           bool   `short:"j" long:"output-json" description:"Return response in JSON format"`
29	ClientCommand
30}
31
32func (c *SetCommand) Execute([]string) error {
33	c.Type = strings.ToLower(c.Type)
34
35	if c.Type == "" {
36		return errors.NewSetEmptyTypeError()
37	}
38
39	c.setFieldsFromInteractiveUserInput()
40
41	err := c.setFieldsFromFileOrString()
42	if err != nil {
43		return err
44	}
45
46	credential, err := c.setCredential()
47	if err != nil {
48		return err
49	}
50
51	credential.Value = "<redacted>"
52	formatOutput(c.OutputJSON, credential)
53
54	return nil
55}
56
57func (c *SetCommand) setFieldsFromInteractiveUserInput() {
58	if c.Value == "" && (c.Type == "value" || c.Type == "json") {
59		promptForInput("value: ", &c.Value)
60	}
61
62	if c.Password == "" && (c.Type == "password" || c.Type == "user") {
63		fmt.Printf("password: ")
64		pass, _ := gopass.GetPasswdMasked()
65		c.Password = string(pass)
66	}
67}
68
69func (c *SetCommand) setFieldsFromFileOrString() error {
70	var err error
71
72	c.Public, err = util.ReadFileOrStringFromField(c.Public)
73	if err != nil {
74		return err
75	}
76
77	c.Private, err = util.ReadFileOrStringFromField(c.Private)
78	if err != nil {
79		return err
80	}
81
82	c.Root, err = util.ReadFileOrStringFromField(c.Root)
83	if err != nil {
84		return err
85	}
86
87	c.Certificate, err = util.ReadFileOrStringFromField(c.Certificate)
88
89	return err
90}
91
92func (c *SetCommand) setCredential() (credentials.Credential, error) {
93	var value interface{}
94
95	switch c.Type {
96	case "password":
97		value = values.Password(c.Password)
98	case "certificate":
99		value = values.Certificate{
100			Ca:          c.Root,
101			Certificate: c.Certificate,
102			PrivateKey:  c.Private,
103			CaName:      c.CaName,
104		}
105	case "ssh":
106		value = values.SSH{
107			PublicKey:  c.Public,
108			PrivateKey: c.Private,
109		}
110	case "rsa":
111		value = values.RSA{
112			PublicKey:  c.Public,
113			PrivateKey: c.Private,
114		}
115	case "user":
116		value = values.User{
117			Password: c.Password,
118			Username: c.Username,
119		}
120	case "json":
121		value = values.JSON{}
122		err := json.Unmarshal([]byte(c.Value), &value)
123		if err != nil {
124			return credentials.Credential{}, err
125		}
126	default:
127		value = values.Value(c.Value)
128	}
129	return c.client.SetCredential(c.CredentialIdentifier, c.Type, value)
130}
131
132func promptForInput(prompt string, value *string) {
133	fmt.Printf(prompt)
134	reader := bufio.NewReader(os.Stdin)
135	val, _ := reader.ReadString('\n')
136	*value = string(strings.TrimSpace(val))
137}
138