1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
package creds
import (
"net"
"os"
"path/filepath"
"strings"
"sync"
"github.com/git-lfs/git-lfs/v3/config"
"github.com/git-lfs/go-netrc/netrc"
"github.com/rubyist/tracerx"
)
type NetrcFinder interface {
FindMachine(string, 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, loginName string) *netrc.Machine {
return nil
}
// NetrcCredentialHelper retrieves credentials from a .netrc file
type netrcCredentialHelper struct {
netrcFinder NetrcFinder
mu sync.Mutex
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
}
c.mu.Lock()
defer c.mu.Unlock()
if c.skip[host] {
return nil, credHelperNoOp
}
if machine := c.netrcFinder.FindMachine(host, what["username"]); 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, %q)",
what["protocol"], what["host"], machine.Login, 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.mu.Lock()
c.skip[host] = false
c.mu.Unlock()
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.mu.Lock()
c.skip[host] = true
c.mu.Unlock()
return nil
}
return credHelperNoOp
}
|