1package credentials
2
3import (
4	"bufio"
5	"bytes"
6	"encoding/json"
7	"fmt"
8	"io"
9	"os"
10	"strings"
11)
12
13// Credentials holds the information shared between docker and the credentials store.
14type Credentials struct {
15	ServerURL string
16	Username  string
17	Secret    string
18}
19
20// Serve initializes the credentials helper and parses the action argument.
21// This function is designed to be called from a command line interface.
22// It uses os.Args[1] as the key for the action.
23// It uses os.Stdin as input and os.Stdout as output.
24// This function terminates the program with os.Exit(1) if there is an error.
25func Serve(helper Helper) {
26	var err error
27	if len(os.Args) != 2 {
28		err = fmt.Errorf("Usage: %s <store|get|erase|list>", os.Args[0])
29	}
30
31	if err == nil {
32		err = HandleCommand(helper, os.Args[1], os.Stdin, os.Stdout)
33	}
34
35	if err != nil {
36		fmt.Fprintf(os.Stdout, "%v\n", err)
37		os.Exit(1)
38	}
39}
40
41// HandleCommand uses a helper and a key to run a credential action.
42func HandleCommand(helper Helper, key string, in io.Reader, out io.Writer) error {
43	switch key {
44	case "store":
45		return Store(helper, in)
46	case "get":
47		return Get(helper, in, out)
48	case "erase":
49		return Erase(helper, in)
50	case "list":
51		return List(helper, out)
52	}
53	return fmt.Errorf("Unknown credential action `%s`", key)
54}
55
56// Store uses a helper and an input reader to save credentials.
57// The reader must contain the JSON serialization of a Credentials struct.
58func Store(helper Helper, reader io.Reader) error {
59	scanner := bufio.NewScanner(reader)
60
61	buffer := new(bytes.Buffer)
62	for scanner.Scan() {
63		buffer.Write(scanner.Bytes())
64	}
65
66	if err := scanner.Err(); err != nil && err != io.EOF {
67		return err
68	}
69
70	var creds Credentials
71	if err := json.NewDecoder(buffer).Decode(&creds); err != nil {
72		return err
73	}
74
75	return helper.Add(&creds)
76}
77
78// Get retrieves the credentials for a given server url.
79// The reader must contain the server URL to search.
80// The writer is used to write the JSON serialization of the credentials.
81func Get(helper Helper, reader io.Reader, writer io.Writer) error {
82	scanner := bufio.NewScanner(reader)
83
84	buffer := new(bytes.Buffer)
85	for scanner.Scan() {
86		buffer.Write(scanner.Bytes())
87	}
88
89	if err := scanner.Err(); err != nil && err != io.EOF {
90		return err
91	}
92
93	serverURL := strings.TrimSpace(buffer.String())
94
95	username, secret, err := helper.Get(serverURL)
96	if err != nil {
97		return err
98	}
99
100	resp := Credentials{
101		Username: username,
102		Secret:   secret,
103	}
104
105	buffer.Reset()
106	if err := json.NewEncoder(buffer).Encode(resp); err != nil {
107		return err
108	}
109
110	fmt.Fprint(writer, buffer.String())
111	return nil
112}
113
114// Erase removes credentials from the store.
115// The reader must contain the server URL to remove.
116func Erase(helper Helper, reader io.Reader) error {
117	scanner := bufio.NewScanner(reader)
118
119	buffer := new(bytes.Buffer)
120	for scanner.Scan() {
121		buffer.Write(scanner.Bytes())
122	}
123
124	if err := scanner.Err(); err != nil && err != io.EOF {
125		return err
126	}
127
128	serverURL := strings.TrimSpace(buffer.String())
129
130	return helper.Delete(serverURL)
131}
132
133//List returns all the serverURLs of keys in
134//the OS store as a list of strings
135func List(helper Helper, writer io.Writer) error {
136	accts, err := helper.List()
137	if err != nil {
138		return err
139	}
140	return json.NewEncoder(writer).Encode(accts)
141}
142