credentials.go 3.6 KB

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