1026ff073c
This commit adds a new credential helper, NetrcCredentialHelper, to retrieve credentials from a .netrc file. This replaces the old .netrc authorization behaviour, which was done directly from the `doWithAuth()` code. Additionally, this commit moves all of the `.netrc` functionality out of `lfsapi` and into `creds`. This was done both because `creds` is now the logical place for the `.netrc` functionality, and to prevent an import cycle between `creds` and `lfsapi`.
131 lines
3.1 KiB
Go
131 lines
3.1 KiB
Go
package creds
|
|
|
|
import (
|
|
"net"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/git-lfs/git-lfs/config"
|
|
"github.com/git-lfs/go-netrc/netrc"
|
|
"github.com/rubyist/tracerx"
|
|
)
|
|
|
|
type NetrcFinder interface {
|
|
FindMachine(string) *netrc.Machine
|
|
}
|
|
|
|
func ParseNetrc(osEnv config.Environment) (NetrcFinder, string, error) {
|
|
home, _ := osEnv.Get("HOME")
|
|
if len(home) == 0 {
|
|
return &noFinder{}, "", nil
|
|
}
|
|
|
|
nrcfilename := filepath.Join(home, netrcBasename)
|
|
if _, err := os.Stat(nrcfilename); err != nil {
|
|
return &noFinder{}, nrcfilename, nil
|
|
}
|
|
|
|
f, err := netrc.ParseFile(nrcfilename)
|
|
return f, nrcfilename, err
|
|
}
|
|
|
|
type noFinder struct{}
|
|
|
|
func (f *noFinder) FindMachine(host string) *netrc.Machine {
|
|
return nil
|
|
}
|
|
|
|
// NetrcCredentialHelper retrieves credentials from a .netrc file
|
|
type netrcCredentialHelper struct {
|
|
netrcFinder NetrcFinder
|
|
skip map[string]bool
|
|
}
|
|
|
|
var defaultNetrcFinder = &noFinder{}
|
|
|
|
// NewNetrcCredentialHelper creates a new netrc credential helper using a
|
|
// .netrc file gleaned from the OS environment
|
|
func newNetrcCredentialHelper(osEnv config.Environment) *netrcCredentialHelper {
|
|
netrcFinder, netrcfile, err := ParseNetrc(osEnv)
|
|
if err != nil {
|
|
tracerx.Printf("bad netrc file %s: %s", netrcfile, err)
|
|
return nil
|
|
}
|
|
|
|
if netrcFinder == nil {
|
|
netrcFinder = defaultNetrcFinder
|
|
}
|
|
|
|
return &netrcCredentialHelper{netrcFinder: netrcFinder, skip: make(map[string]bool)}
|
|
}
|
|
|
|
func (c *netrcCredentialHelper) Fill(what Creds) (Creds, error) {
|
|
host, err := getNetrcHostname(what["host"])
|
|
if err != nil {
|
|
return nil, credHelperNoOp
|
|
}
|
|
|
|
if c.skip[host] {
|
|
return nil, credHelperNoOp
|
|
}
|
|
|
|
if machine := c.netrcFinder.FindMachine(host); machine != nil {
|
|
creds := make(Creds)
|
|
creds["username"] = machine.Login
|
|
creds["password"] = machine.Password
|
|
creds["protocol"] = what["protocol"]
|
|
creds["host"] = what["host"]
|
|
creds["scheme"] = what["scheme"]
|
|
creds["path"] = what["path"]
|
|
creds["source"] = "netrc"
|
|
tracerx.Printf("netrc: git credential fill (%q, %q, %q)",
|
|
what["protocol"], what["host"], what["path"])
|
|
return creds, nil
|
|
}
|
|
|
|
return nil, credHelperNoOp
|
|
}
|
|
|
|
func getNetrcHostname(hostname string) (string, error) {
|
|
if strings.Contains(hostname, ":") {
|
|
host, _, err := net.SplitHostPort(hostname)
|
|
if err != nil {
|
|
tracerx.Printf("netrc: error parsing %q: %s", hostname, err)
|
|
return "", err
|
|
}
|
|
return host, nil
|
|
}
|
|
|
|
return hostname, nil
|
|
}
|
|
|
|
func (c *netrcCredentialHelper) Approve(what Creds) error {
|
|
if what["source"] == "netrc" {
|
|
host, err := getNetrcHostname(what["host"])
|
|
if err != nil {
|
|
return credHelperNoOp
|
|
}
|
|
tracerx.Printf("netrc: git credential approve (%q, %q, %q)",
|
|
what["protocol"], what["host"], what["path"])
|
|
c.skip[host] = false
|
|
return nil
|
|
}
|
|
return credHelperNoOp
|
|
}
|
|
|
|
func (c *netrcCredentialHelper) Reject(what Creds) error {
|
|
if what["source"] == "netrc" {
|
|
host, err := getNetrcHostname(what["host"])
|
|
if err != nil {
|
|
return credHelperNoOp
|
|
}
|
|
|
|
tracerx.Printf("netrc: git credential reject (%q, %q, %q)",
|
|
what["protocol"], what["host"], what["path"])
|
|
c.skip[host] = true
|
|
return nil
|
|
}
|
|
return credHelperNoOp
|
|
}
|