Commit 2d683807 authored by Bryan C. Mills's avatar Bryan C. Mills

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: default avatarJay Conrod <jayconrod@google.com>
parent 131eb8fb
......@@ -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 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))
}
......
......@@ -10,6 +10,9 @@ import (
)
var testNetrc = `
machine incomplete
password none
machine api.github.com
login user
password pwd
......@@ -20,6 +23,24 @@ machine incomlete.host
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) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment