1
2
3
4
5 package auth
6
7 import (
8 "os"
9 "path/filepath"
10 "runtime"
11 "strings"
12 "sync"
13 )
14
15 type netrcLine struct {
16 machine string
17 login string
18 password string
19 }
20
21 func parseNetrc(data string) []netrcLine {
22
23
24 var nrc []netrcLine
25 var l netrcLine
26 inMacro := false
27 for _, line := range strings.Split(data, "\n") {
28 if inMacro {
29 if line == "" {
30 inMacro = false
31 }
32 continue
33 }
34
35 f := strings.Fields(line)
36 i := 0
37 for ; i < len(f)-1; i += 2 {
38
39
40
41
42
43 switch f[i] {
44 case "machine":
45 l = netrcLine{machine: f[i+1]}
46 case "default":
47 break
48 case "login":
49 l.login = f[i+1]
50 case "password":
51 l.password = f[i+1]
52 case "macdef":
53
54
55
56 inMacro = true
57 }
58 if l.machine != "" && l.login != "" && l.password != "" {
59 nrc = append(nrc, l)
60 l = netrcLine{}
61 }
62 }
63
64 if i < len(f) && f[i] == "default" {
65
66 break
67 }
68 }
69
70 return nrc
71 }
72
73 func netrcPath() (string, error) {
74 if env := os.Getenv("NETRC"); env != "" {
75 return env, nil
76 }
77 dir, err := os.UserHomeDir()
78 if err != nil {
79 return "", err
80 }
81
82
83 if runtime.GOOS == "windows" {
84 legacyPath := filepath.Join(dir, "_netrc")
85 _, err := os.Stat(legacyPath)
86 if err == nil {
87 return legacyPath, nil
88 }
89 if !os.IsNotExist(err) {
90 return "", err
91 }
92
93 }
94
95 return filepath.Join(dir, ".netrc"), nil
96 }
97
98 var readNetrc = sync.OnceValues(func() ([]netrcLine, error) {
99 path, err := netrcPath()
100 if err != nil {
101 return nil, err
102 }
103
104 data, err := os.ReadFile(path)
105 if err != nil {
106 if os.IsNotExist(err) {
107 err = nil
108 }
109 return nil, err
110 }
111
112 return parseNetrc(string(data)), nil
113 })
114
View as plain text