github.com/secman-team/gh-api@v1.8.2/pkg/cmd/auth/gitcredential/helper.go (about)

     1  package login
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"net/url"
     7  	"strings"
     8  
     9  	"github.com/secman-team/gh-api/pkg/cmdutil"
    10  	"github.com/secman-team/gh-api/pkg/iostreams"
    11  	"github.com/spf13/cobra"
    12  )
    13  
    14  const tokenUser = "x-access-token"
    15  
    16  type config interface {
    17  	GetWithSource(string, string) (string, string, error)
    18  }
    19  
    20  type CredentialOptions struct {
    21  	IO     *iostreams.IOStreams
    22  	Config func() (config, error)
    23  
    24  	Operation string
    25  }
    26  
    27  func NewCmdCredential(f *cmdutil.Factory, runF func(*CredentialOptions) error) *cobra.Command {
    28  	opts := &CredentialOptions{
    29  		IO: f.IOStreams,
    30  		Config: func() (config, error) {
    31  			return f.Config()
    32  		},
    33  	}
    34  
    35  	cmd := &cobra.Command{
    36  		Use:    "git-credential",
    37  		Args:   cobra.ExactArgs(1),
    38  		Short:  "Implements git credential helper protocol",
    39  		Hidden: true,
    40  		RunE: func(cmd *cobra.Command, args []string) error {
    41  			opts.Operation = args[0]
    42  
    43  			if runF != nil {
    44  				return runF(opts)
    45  			}
    46  			return helperRun(opts)
    47  		},
    48  	}
    49  
    50  	return cmd
    51  }
    52  
    53  func helperRun(opts *CredentialOptions) error {
    54  	if opts.Operation == "store" {
    55  		// We pretend to implement the "store" operation, but do nothing since we already have a cached token.
    56  		return cmdutil.SilentError
    57  	}
    58  
    59  	if opts.Operation != "get" {
    60  		return fmt.Errorf("gh auth git-credential: %q operation not supported", opts.Operation)
    61  	}
    62  
    63  	wants := map[string]string{}
    64  
    65  	s := bufio.NewScanner(opts.IO.In)
    66  	for s.Scan() {
    67  		line := s.Text()
    68  		if line == "" {
    69  			break
    70  		}
    71  		parts := strings.SplitN(line, "=", 2)
    72  		if len(parts) < 2 {
    73  			continue
    74  		}
    75  		key, value := parts[0], parts[1]
    76  		if key == "url" {
    77  			u, err := url.Parse(value)
    78  			if err != nil {
    79  				return err
    80  			}
    81  			wants["protocol"] = u.Scheme
    82  			wants["host"] = u.Host
    83  			wants["path"] = u.Path
    84  			wants["username"] = u.User.Username()
    85  			wants["password"], _ = u.User.Password()
    86  		} else {
    87  			wants[key] = value
    88  		}
    89  	}
    90  	if err := s.Err(); err != nil {
    91  		return err
    92  	}
    93  
    94  	if wants["protocol"] != "https" {
    95  		return cmdutil.SilentError
    96  	}
    97  
    98  	cfg, err := opts.Config()
    99  	if err != nil {
   100  		return err
   101  	}
   102  
   103  	var gotUser string
   104  	gotToken, source, _ := cfg.GetWithSource(wants["host"], "oauth_token")
   105  	if strings.HasSuffix(source, "_TOKEN") {
   106  		gotUser = tokenUser
   107  	} else {
   108  		gotUser, _, _ = cfg.GetWithSource(wants["host"], "user")
   109  	}
   110  
   111  	if gotUser == "" || gotToken == "" {
   112  		return cmdutil.SilentError
   113  	}
   114  
   115  	if wants["username"] != "" && gotUser != tokenUser && !strings.EqualFold(wants["username"], gotUser) {
   116  		return cmdutil.SilentError
   117  	}
   118  
   119  	fmt.Fprint(opts.IO.Out, "protocol=https\n")
   120  	fmt.Fprintf(opts.IO.Out, "host=%s\n", wants["host"])
   121  	fmt.Fprintf(opts.IO.Out, "username=%s\n", gotUser)
   122  	fmt.Fprintf(opts.IO.Out, "password=%s\n", gotToken)
   123  
   124  	return nil
   125  }