...

Source file src/github.com/docker/docker-credential-helpers/credentials/credentials.go

Documentation: github.com/docker/docker-credential-helpers/credentials

     1  package credentials
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io"
     9  	"os"
    10  	"strings"
    11  )
    12  
    13  // Action defines the name of an action (sub-command) supported by a
    14  // credential-helper binary. It is an alias for "string", and mostly
    15  // for convenience.
    16  type Action = string
    17  
    18  // List of actions (sub-commands) supported by credential-helper binaries.
    19  const (
    20  	ActionStore   Action = "store"
    21  	ActionGet     Action = "get"
    22  	ActionErase   Action = "erase"
    23  	ActionList    Action = "list"
    24  	ActionVersion Action = "version"
    25  )
    26  
    27  // Credentials holds the information shared between docker and the credentials store.
    28  type Credentials struct {
    29  	ServerURL string
    30  	Username  string
    31  	Secret    string
    32  }
    33  
    34  // isValid checks the integrity of Credentials object such that no credentials lack
    35  // a server URL or a username.
    36  // It returns whether the credentials are valid and the error if it isn't.
    37  // error values can be errCredentialsMissingServerURL or errCredentialsMissingUsername
    38  func (c *Credentials) isValid() (bool, error) {
    39  	if len(c.ServerURL) == 0 {
    40  		return false, NewErrCredentialsMissingServerURL()
    41  	}
    42  
    43  	if len(c.Username) == 0 {
    44  		return false, NewErrCredentialsMissingUsername()
    45  	}
    46  
    47  	return true, nil
    48  }
    49  
    50  // CredsLabel holds the way Docker credentials should be labeled as such in credentials stores that allow labelling.
    51  // That label allows to filter out non-Docker credentials too at lookup/search in macOS keychain,
    52  // Windows credentials manager and Linux libsecret. Default value is "Docker Credentials"
    53  var CredsLabel = "Docker Credentials"
    54  
    55  // SetCredsLabel is a simple setter for CredsLabel
    56  func SetCredsLabel(label string) {
    57  	CredsLabel = label
    58  }
    59  
    60  // Serve initializes the credentials-helper and parses the action argument.
    61  // This function is designed to be called from a command line interface.
    62  // It uses os.Args[1] as the key for the action.
    63  // It uses os.Stdin as input and os.Stdout as output.
    64  // This function terminates the program with os.Exit(1) if there is an error.
    65  func Serve(helper Helper) {
    66  	if len(os.Args) != 2 {
    67  		_, _ = fmt.Fprintln(os.Stdout, usage())
    68  		os.Exit(1)
    69  	}
    70  
    71  	switch os.Args[1] {
    72  	case "--version", "-v":
    73  		_ = PrintVersion(os.Stdout)
    74  		os.Exit(0)
    75  	case "--help", "-h":
    76  		_, _ = fmt.Fprintln(os.Stdout, usage())
    77  		os.Exit(0)
    78  	}
    79  
    80  	if err := HandleCommand(helper, os.Args[1], os.Stdin, os.Stdout); err != nil {
    81  		_, _ = fmt.Fprintln(os.Stdout, err)
    82  		os.Exit(1)
    83  	}
    84  }
    85  
    86  func usage() string {
    87  	return fmt.Sprintf("Usage: %s <store|get|erase|list|version>", Name)
    88  }
    89  
    90  // HandleCommand runs a helper to execute a credential action.
    91  func HandleCommand(helper Helper, action Action, in io.Reader, out io.Writer) error {
    92  	switch action {
    93  	case ActionStore:
    94  		return Store(helper, in)
    95  	case ActionGet:
    96  		return Get(helper, in, out)
    97  	case ActionErase:
    98  		return Erase(helper, in)
    99  	case ActionList:
   100  		return List(helper, out)
   101  	case ActionVersion:
   102  		return PrintVersion(out)
   103  	default:
   104  		return fmt.Errorf("%s: unknown action: %s", Name, action)
   105  	}
   106  }
   107  
   108  // Store uses a helper and an input reader to save credentials.
   109  // The reader must contain the JSON serialization of a Credentials struct.
   110  func Store(helper Helper, reader io.Reader) error {
   111  	scanner := bufio.NewScanner(reader)
   112  
   113  	buffer := new(bytes.Buffer)
   114  	for scanner.Scan() {
   115  		buffer.Write(scanner.Bytes())
   116  	}
   117  
   118  	if err := scanner.Err(); err != nil && err != io.EOF {
   119  		return err
   120  	}
   121  
   122  	var creds Credentials
   123  	if err := json.NewDecoder(buffer).Decode(&creds); err != nil {
   124  		return err
   125  	}
   126  
   127  	if ok, err := creds.isValid(); !ok {
   128  		return err
   129  	}
   130  
   131  	return helper.Add(&creds)
   132  }
   133  
   134  // Get retrieves the credentials for a given server url.
   135  // The reader must contain the server URL to search.
   136  // The writer is used to write the JSON serialization of the credentials.
   137  func Get(helper Helper, reader io.Reader, writer io.Writer) error {
   138  	scanner := bufio.NewScanner(reader)
   139  
   140  	buffer := new(bytes.Buffer)
   141  	for scanner.Scan() {
   142  		buffer.Write(scanner.Bytes())
   143  	}
   144  
   145  	if err := scanner.Err(); err != nil && err != io.EOF {
   146  		return err
   147  	}
   148  
   149  	serverURL := strings.TrimSpace(buffer.String())
   150  	if len(serverURL) == 0 {
   151  		return NewErrCredentialsMissingServerURL()
   152  	}
   153  
   154  	username, secret, err := helper.Get(serverURL)
   155  	if err != nil {
   156  		return err
   157  	}
   158  
   159  	buffer.Reset()
   160  	err = json.NewEncoder(buffer).Encode(Credentials{
   161  		ServerURL: serverURL,
   162  		Username:  username,
   163  		Secret:    secret,
   164  	})
   165  	if err != nil {
   166  		return err
   167  	}
   168  
   169  	_, _ = fmt.Fprint(writer, buffer.String())
   170  	return nil
   171  }
   172  
   173  // Erase removes credentials from the store.
   174  // The reader must contain the server URL to remove.
   175  func Erase(helper Helper, reader io.Reader) error {
   176  	scanner := bufio.NewScanner(reader)
   177  
   178  	buffer := new(bytes.Buffer)
   179  	for scanner.Scan() {
   180  		buffer.Write(scanner.Bytes())
   181  	}
   182  
   183  	if err := scanner.Err(); err != nil && err != io.EOF {
   184  		return err
   185  	}
   186  
   187  	serverURL := strings.TrimSpace(buffer.String())
   188  	if len(serverURL) == 0 {
   189  		return NewErrCredentialsMissingServerURL()
   190  	}
   191  
   192  	return helper.Delete(serverURL)
   193  }
   194  
   195  // List returns all the serverURLs of keys in
   196  // the OS store as a list of strings
   197  func List(helper Helper, writer io.Writer) error {
   198  	accts, err := helper.List()
   199  	if err != nil {
   200  		return err
   201  	}
   202  	return json.NewEncoder(writer).Encode(accts)
   203  }
   204  
   205  // PrintVersion outputs the current version.
   206  func PrintVersion(writer io.Writer) error {
   207  	_, _ = fmt.Fprintf(writer, "%s (%s) %s\n", Name, Package, Version)
   208  	return nil
   209  }
   210  

View as plain text