1
0
mirror of https://github.com/golang/go synced 2024-11-24 07:40:17 -07:00

cmd/go/internal/web2: make netrc parsing more robust

- Respect the NETRC environment variable if set.

- Ignore lines that contain macro definitions.

- Associate the 'machine' token with only the tokens that follow (not
  precede) it.

Updates #29888
Updates #26232

Change-Id: I3128b7d6da2d6492df7c864e165eea1a27384f0f
Reviewed-on: https://go-review.googlesource.com/c/go/+/161698
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
This commit is contained in:
Bryan C. Mills 2019-02-08 11:24:29 -05:00
parent 131eb8fbf8
commit 2d68380713
2 changed files with 86 additions and 17 deletions

View File

@ -37,29 +37,61 @@ type netrcLine struct {
password string
}
var netrcOnce sync.Once
var netrc []netrcLine
var (
netrcOnce sync.Once
netrc []netrcLine
netrcErr error
)
func parseNetrc(data string) []netrcLine {
// See https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html
// for documentation on the .netrc format.
var nrc []netrcLine
var l netrcLine
inMacro := false
for _, line := range strings.Split(data, "\n") {
if inMacro {
if line == "" {
inMacro = false
}
continue
}
f := strings.Fields(line)
for i := 0; i < len(f)-1; i += 2 {
i := 0
for ; i < len(f)-1; i += 2 {
// Reset at each "machine" token.
// “The auto-login process searches the .netrc file for a machine token
// that matches […]. Once a match is made, the subsequent .netrc tokens
// are processed, stopping when the end of file is reached or another
// machine or a default token is encountered.”
switch f[i] {
case "machine":
l.machine = f[i+1]
l = netrcLine{machine: f[i+1]}
case "default":
break
case "login":
l.login = f[i+1]
case "password":
l.password = f[i+1]
case "macdef":
// “A macro is defined with the specified name; its contents begin with
// the next .netrc line and continue until a null line (consecutive
// new-line characters) is encountered.”
inMacro = true
}
if l.machine != "" && l.login != "" && l.password != "" {
nrc = append(nrc, l)
l = netrcLine{}
}
}
if l.machine != "" && l.login != "" && l.password != "" {
nrc = append(nrc, l)
l = netrcLine{}
if i < len(f) && f[i] == "default" {
// “There can be only one default token, and it must be after all machine tokens.”
break
}
}
return nrc
}
@ -73,22 +105,36 @@ func havePassword(machine string) bool {
return false
}
func netrcPath() string {
switch runtime.GOOS {
case "windows":
return filepath.Join(os.Getenv("USERPROFILE"), "_netrc")
case "plan9":
return filepath.Join(os.Getenv("home"), ".netrc")
default:
return filepath.Join(os.Getenv("HOME"), ".netrc")
func netrcPath() (string, error) {
if env := os.Getenv("NETRC"); env != "" {
return env, nil
}
dir, err := os.UserHomeDir()
if err != nil {
return "", err
}
base := ".netrc"
if runtime.GOOS == "windows" {
base = "_netrc"
}
return filepath.Join(dir, base), nil
}
func readNetrc() {
data, err := ioutil.ReadFile(netrcPath())
path, err := netrcPath()
if err != nil {
netrcErr = err
return
}
data, err := ioutil.ReadFile(path)
if err != nil {
if !os.IsNotExist(err) {
netrcErr = err
}
return
}
netrc = parseNetrc(string(data))
}

View File

@ -10,16 +10,37 @@ import (
)
var testNetrc = `
machine incomplete
password none
machine api.github.com
login user
password pwd
machine incomlete.host
login justlogin
machine test.host
login user2
password pwd2
machine oneline login user3 password pwd3
machine ignore.host macdef ignore
login nobody
password nothing
machine hasmacro.too macdef ignore-next-lines login user4 password pwd4
login nobody
password nothing
default
login anonymous
password gopher@golang.org
machine after.default
login oops
password too-late-in-file
`
func TestReadNetrc(t *testing.T) {
@ -27,6 +48,8 @@ func TestReadNetrc(t *testing.T) {
want := []netrcLine{
{"api.github.com", "user", "pwd"},
{"test.host", "user2", "pwd2"},
{"oneline", "user3", "pwd3"},
{"hasmacro.too", "user4", "pwd4"},
}
if !reflect.DeepEqual(lines, want) {