package secretsclient import ( "bytes" "encoding/base64" "encoding/json" "errors" "io" "net/http" ) type Client interface { GetString(key string) (string, error) PutString(key string, val string) error GetStringArr(key string) ([]string, error) PutStringArr(key string, val []string) error GetStringMap(key string) (map[string]string, error) PutStringMap(key string, val map[string]string) error Delete(key string) error } func New(base, ca, cert, certKey string) (Client, error) { h, err := newMTLSClient(ca, cert, certKey) if err != nil { return nil, err } return &client{ base: base, h: h, }, nil } // TODO: Propagate errors to the callers. type client struct { base string h *http.Client } func (c *client) GetString(key string) (string, error) { res, err := c.get(key) if err != nil { return "", err } return string(res), nil } func (c *client) PutString(key, val string) error { return c.put(key, []byte(val)) } func (c *client) GetStringArr(key string) ([]string, error) { arrBytes, err := c.get(key) if err != nil { return nil, err } var res []string err = json.Unmarshal(arrBytes, &res) if err != nil { return nil, err } return res, nil } func (c *client) PutStringArr(key string, val []string) error { arrBytes, err := json.Marshal(val) if err != nil { return err } return c.put(key, arrBytes) } func (c *client) GetStringMap(key string) (map[string]string, error) { mapBytes, err := c.get(key) if err != nil { return nil, err } var res map[string]string err = json.Unmarshal(mapBytes, &res) if err != nil { return nil, err } return res, nil } func (c *client) PutStringMap(key string, val map[string]string) error { mapBytes, err := json.Marshal(val) if err != nil { return err } return c.put(key, mapBytes) } func (c *client) get(key string) ([]byte, error) { res, err := c.h.Get(c.urlFromKey(key)) if err != nil { return nil, err } if res.StatusCode != http.StatusOK { return nil, errors.New("request did not succeed") } val, err := io.ReadAll(res.Body) if err != nil { return nil, err } defer res.Body.Close() return val, nil } func (c *client) put(key string, val []byte) error { body := bytes.NewBuffer(val) req, err := http.NewRequest("PUT", c.urlFromKey(key), body) if err != nil { return err } res, err := c.h.Do(req) if err != nil { return err } if res.StatusCode != http.StatusOK { return errors.New("request did not succeed") } return nil } func (c *client) Delete(key string) error { req, err := http.NewRequest("DELETE", c.urlFromKey(key), nil) if err != nil { return err } res, err := c.h.Do(req) if err != nil { return err } if res.StatusCode != http.StatusOK { return errors.New("request did not succeed") } return nil } func (c *client) urlFromKey(key string) string { b64Key := base64.RawURLEncoding.EncodeToString([]byte(key)) return c.base + "?key=" + b64Key }