Skip to content

Commit 2d68380

Browse files
author
Bryan C. Mills
committed
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Jay Conrod <[email protected]>
1 parent 131eb8f commit 2d68380

File tree

2 files changed

+86
-17
lines changed

2 files changed

+86
-17
lines changed

src/cmd/go/internal/web2/web.go

Lines changed: 62 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,29 +37,61 @@ type netrcLine struct {
3737
password string
3838
}
3939

40-
var netrcOnce sync.Once
41-
var netrc []netrcLine
40+
var (
41+
netrcOnce sync.Once
42+
netrc []netrcLine
43+
netrcErr error
44+
)
4245

4346
func parseNetrc(data string) []netrcLine {
47+
// See https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html
48+
// for documentation on the .netrc format.
4449
var nrc []netrcLine
4550
var l netrcLine
51+
inMacro := false
4652
for _, line := range strings.Split(data, "\n") {
53+
if inMacro {
54+
if line == "" {
55+
inMacro = false
56+
}
57+
continue
58+
}
59+
4760
f := strings.Fields(line)
48-
for i := 0; i < len(f)-1; i += 2 {
61+
i := 0
62+
for ; i < len(f)-1; i += 2 {
63+
// Reset at each "machine" token.
64+
// “The auto-login process searches the .netrc file for a machine token
65+
// that matches […]. Once a match is made, the subsequent .netrc tokens
66+
// are processed, stopping when the end of file is reached or another
67+
// machine or a default token is encountered.”
4968
switch f[i] {
5069
case "machine":
51-
l.machine = f[i+1]
70+
l = netrcLine{machine: f[i+1]}
71+
case "default":
72+
break
5273
case "login":
5374
l.login = f[i+1]
5475
case "password":
5576
l.password = f[i+1]
77+
case "macdef":
78+
// “A macro is defined with the specified name; its contents begin with
79+
// the next .netrc line and continue until a null line (consecutive
80+
// new-line characters) is encountered.”
81+
inMacro = true
82+
}
83+
if l.machine != "" && l.login != "" && l.password != "" {
84+
nrc = append(nrc, l)
85+
l = netrcLine{}
5686
}
5787
}
58-
if l.machine != "" && l.login != "" && l.password != "" {
59-
nrc = append(nrc, l)
60-
l = netrcLine{}
88+
89+
if i < len(f) && f[i] == "default" {
90+
// “There can be only one default token, and it must be after all machine tokens.”
91+
break
6192
}
6293
}
94+
6395
return nrc
6496
}
6597

@@ -73,22 +105,36 @@ func havePassword(machine string) bool {
73105
return false
74106
}
75107

76-
func netrcPath() string {
77-
switch runtime.GOOS {
78-
case "windows":
79-
return filepath.Join(os.Getenv("USERPROFILE"), "_netrc")
80-
case "plan9":
81-
return filepath.Join(os.Getenv("home"), ".netrc")
82-
default:
83-
return filepath.Join(os.Getenv("HOME"), ".netrc")
108+
func netrcPath() (string, error) {
109+
if env := os.Getenv("NETRC"); env != "" {
110+
return env, nil
84111
}
112+
dir, err := os.UserHomeDir()
113+
if err != nil {
114+
return "", err
115+
}
116+
base := ".netrc"
117+
if runtime.GOOS == "windows" {
118+
base = "_netrc"
119+
}
120+
return filepath.Join(dir, base), nil
85121
}
86122

87123
func readNetrc() {
88-
data, err := ioutil.ReadFile(netrcPath())
124+
path, err := netrcPath()
125+
if err != nil {
126+
netrcErr = err
127+
return
128+
}
129+
130+
data, err := ioutil.ReadFile(path)
89131
if err != nil {
132+
if !os.IsNotExist(err) {
133+
netrcErr = err
134+
}
90135
return
91136
}
137+
92138
netrc = parseNetrc(string(data))
93139
}
94140

src/cmd/go/internal/web2/web_test.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,46 @@ import (
1010
)
1111

1212
var testNetrc = `
13+
machine incomplete
14+
password none
15+
1316
machine api.github.com
1417
login user
1518
password pwd
1619
1720
machine incomlete.host
1821
login justlogin
19-
22+
2023
machine test.host
2124
login user2
2225
password pwd2
26+
27+
machine oneline login user3 password pwd3
28+
29+
machine ignore.host macdef ignore
30+
login nobody
31+
password nothing
32+
33+
machine hasmacro.too macdef ignore-next-lines login user4 password pwd4
34+
login nobody
35+
password nothing
36+
37+
default
38+
login anonymous
39+
40+
41+
machine after.default
42+
login oops
43+
password too-late-in-file
2344
`
2445

2546
func TestReadNetrc(t *testing.T) {
2647
lines := parseNetrc(testNetrc)
2748
want := []netrcLine{
2849
{"api.github.com", "user", "pwd"},
2950
{"test.host", "user2", "pwd2"},
51+
{"oneline", "user3", "pwd3"},
52+
{"hasmacro.too", "user4", "pwd4"},
3053
}
3154

3255
if !reflect.DeepEqual(lines, want) {

0 commit comments

Comments
 (0)