├── .circleci └── config.yml ├── .github └── dependabot.yml ├── LICENSE ├── README.md ├── examples ├── bad_default_order.netrc ├── default_only.netrc ├── emptypassword.netrc ├── good.netrc ├── good.netrc.gpg ├── login.netrc ├── newlineless.netrc ├── octothorpe.netrc ├── password.netrc ├── permissive.netrc ├── sample.netrc ├── sample_multi.netrc ├── sample_multi_with_default.netrc └── sample_with_default.netrc ├── go.mod ├── go.sum ├── netrc.go └── netrc_test.go /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | orbs: 3 | go: circleci/go@1.8.0 4 | jobs: 5 | build: 6 | executor: 7 | name: go/default 8 | tag: '1.21' 9 | steps: 10 | - checkout 11 | - go/load-cache 12 | - go/mod-download 13 | - go/save-cache 14 | - go/test: 15 | covermode: atomic 16 | failfast: true 17 | race: true 18 | workflows: 19 | main: 20 | jobs: 21 | - build -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "gomod" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jeff Dickey 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-netrc [![GoDoc](https://godoc.org/github.com/jdx/go-netrc?status.svg)](http://godoc.org/github.com/jdx/go-netrc) [![CircleCI](https://dl.circleci.com/status-badge/img/gh/jdx/go-netrc/tree/main.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/jdx/go-netrc/tree/main) 2 | 3 | A netrc parser for Go. 4 | 5 | # Usage 6 | 7 | Getting credentials for a host. 8 | 9 | ```go 10 | usr, err := user.Current() 11 | n, err := netrc.Parse(filepath.Join(usr.HomeDir, ".netrc")) 12 | fmt.Println(n.Machine("api.heroku.com").Get("password")) 13 | ``` 14 | 15 | Setting credentials on a host. 16 | 17 | ```go 18 | usr, err := user.Current() 19 | n, err := netrc.Parse(filepath.Join(usr.HomeDir, ".netrc")) 20 | n.Machine("api.heroku.com").Set("password", "newapikey") 21 | n.Save() 22 | ``` 23 | -------------------------------------------------------------------------------- /examples/bad_default_order.netrc: -------------------------------------------------------------------------------- 1 | # I am a comment 2 | machine mail.google.com 3 | login joe@gmail.com 4 | account gmail 5 | password somethingSecret 6 | # I am another comment 7 | 8 | default 9 | login anonymous 10 | password joe@example.com 11 | 12 | machine ray login demo password mypassword 13 | 14 | -------------------------------------------------------------------------------- /examples/default_only.netrc: -------------------------------------------------------------------------------- 1 | # this is my netrc with only a default 2 | default 3 | login ld # this is my default username 4 | password pd 5 | -------------------------------------------------------------------------------- /examples/emptypassword.netrc: -------------------------------------------------------------------------------- 1 | machine api.heroku.com 2 | login mhale@heroku.com 3 | password 4 | machine api.heroku.com 5 | login mhale@heroku.com 6 | password foo 7 | -------------------------------------------------------------------------------- /examples/good.netrc: -------------------------------------------------------------------------------- 1 | # I am a comment 2 | machine mail.google.com 3 | login joe@gmail.com 4 | account justagmail #end of line comment with trailing space 5 | password somethingSecret 6 | # I am another comment 7 | 8 | macdef allput 9 | put src/* 10 | 11 | macdef allput2 12 | put src/* 13 | put src2/* 14 | 15 | machine ray login demo password mypassword 16 | 17 | machine weirdlogin login uname password pass#pass 18 | 19 | default 20 | login anonymous 21 | password joe@example.com 22 | 23 | -------------------------------------------------------------------------------- /examples/good.netrc.gpg: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP MESSAGE----- 2 | Version: GnuPG/MacGPG2 v2.0.22 (Darwin) 3 | Comment: GPGTools - https://gpgtools.org 4 | 5 | hQIMA0WkG+IIsDKOARAAxyV9rO09l5vrXAAOyvEkyw6AW9EtZX16rjGi/iF335Wl 6 | 7TfZyStY/wxWXoeWSxCLQEnblZZUHSTgtApR5fztO2I2laowG3uNpey8J2nlKRxX 7 | eSC9n2ed0TOD4qfA+jQ0YDqkFpyOtspuuc0QpzaZYrOjwF4AdSqGlhIUSWmFmGhz 8 | OTHWkwzsfauVVCSwi4utJ1nlAaV3BgEWYI1anwZEVRi0ndGqEcFycyD5RwJg7waA 9 | 5Dml26ORS7InTDHOAfNzmS4hRxIO/zRWX7t5EwOviILj6CxkAo7tvnU6JrzZ2AjF 10 | IRWksjh+Fz3X795ONT9S+ElyrU3+m7GbM5YYf4/wossOoFKpheNj5SUnSUCq+x3K 11 | MQiNPht6aElJfD7DTM5PIm5azne0iIhvRY3rd2egEBCNJtG38rjwsxRbY/nthZaB 12 | n445M7fXG0/2569yahTDI7KVcURFoAMQq5UAZ57Nyi9B9jKUCdT7doWivb+6weWJ 13 | N+ajOCew8Ecz2CFiFftD5YRl5fqodSMp/MJL1nw1n4VET9TT+pbt3nOOZ46WsVPI 14 | rNH6lmlvggdK//sC0iWdOJS6KbegDq4IqMpQBqec9BfjpxJyk0qXQBXe9iVGhcDu 15 | jfMZVscxCRVZGtq3ohjnxz+cSID1zt2BOc4kqP74xhX4n06Lmfn9UGZPh+tFJ13S 16 | wFgBsv/zkNOC8pcAjUmgkPwsJ3N3GdETLZRkq3NK0sR81wJ4k0N09GmM++VzwoyP 17 | LwxVVzSM07BsA/YEX4jGT8szi+ee7qDAGWGBm8XtSyns1/7vkyD5AmPhyEAI+QXt 18 | foA8dnliaUs7VYGZR5G4cTnUYGhsGNEUdHTegafMSG89CC8unVROZ3umpl6cobuE 19 | 7XzdofB2j0QWM2BTErbU+1wkUS8pRTYieOyWwxpLU6Q/GTWv/RPGlzLYFC1dygco 20 | uokRFFOXo/yeCXz6ZxnG3xx1OU0CHGy+h46fjhbv63MEnBEYikj/wKgDJ1L41xmU 21 | Toyy5W+i0mFUPWBjR7vFojWLFFKh2veAIAKo30by9u+RTmnj4hgI1x7G 22 | =a00i 23 | -----END PGP MESSAGE----- 24 | -------------------------------------------------------------------------------- /examples/login.netrc: -------------------------------------------------------------------------------- 1 | # this is my login netrc 2 | machine api.heroku.com 3 | login jeff@heroku.com # this is my username 4 | password foo 5 | -------------------------------------------------------------------------------- /examples/newlineless.netrc: -------------------------------------------------------------------------------- 1 | # this is my netrc 2 | machine m 3 | login l # this is my username 4 | password p -------------------------------------------------------------------------------- /examples/octothorpe.netrc: -------------------------------------------------------------------------------- 1 | # Octothorpes should be allowed in passwords. 2 | machine hash 3 | login joecool@example.com 4 | password foo#bar$baz%boom 5 | 6 | machine hash2 7 | login joecool@example.com 8 | password foo#bar$baz%boom## 9 | -------------------------------------------------------------------------------- /examples/password.netrc: -------------------------------------------------------------------------------- 1 | # this is my password netrc 2 | machine m 3 | password p # this is my password 4 | -------------------------------------------------------------------------------- /examples/permissive.netrc: -------------------------------------------------------------------------------- 1 | # this is my netrc 2 | machine m 3 | login l # this is my username 4 | password p 5 | -------------------------------------------------------------------------------- /examples/sample.netrc: -------------------------------------------------------------------------------- 1 | # this is my netrc 2 | machine m 3 | login l # this is my username 4 | password p 5 | -------------------------------------------------------------------------------- /examples/sample_multi.netrc: -------------------------------------------------------------------------------- 1 | # this is my netrc with multiple machines 2 | machine m 3 | login lm # this is my m-username 4 | password pm 5 | 6 | machine n 7 | login ln # this is my n-username 8 | password pn 9 | -------------------------------------------------------------------------------- /examples/sample_multi_with_default.netrc: -------------------------------------------------------------------------------- 1 | # this is my netrc with multiple machines and a default 2 | machine m 3 | login lm # this is my m-username 4 | password pm 5 | 6 | machine n 7 | login ln # this is my n-username 8 | password pn 9 | 10 | default 11 | login ld # this is my default username 12 | password pd 13 | -------------------------------------------------------------------------------- /examples/sample_with_default.netrc: -------------------------------------------------------------------------------- 1 | # this is my netrc with default 2 | machine m 3 | login l # this is my username 4 | password p 5 | 6 | default 7 | login default_login # this is my default username 8 | password default_password 9 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/jdx/go-netrc 2 | 3 | go 1.20 4 | 5 | require gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c 6 | 7 | require ( 8 | github.com/kr/pretty v0.2.1 // indirect 9 | github.com/kr/text v0.1.0 // indirect 10 | ) 11 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= 2 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 3 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 4 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 5 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 6 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 7 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 8 | -------------------------------------------------------------------------------- /netrc.go: -------------------------------------------------------------------------------- 1 | package netrc 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "errors" 7 | "io" 8 | "io/ioutil" 9 | "os" 10 | "os/exec" 11 | "path/filepath" 12 | "regexp" 13 | "strings" 14 | "unicode" 15 | ) 16 | 17 | // ErrInvalidNetrc means there was an error parsing the netrc file 18 | var ErrInvalidNetrc = errors.New("Invalid netrc") 19 | 20 | // Netrc file 21 | type Netrc struct { 22 | Path string 23 | machines Machines 24 | tokens []string 25 | } 26 | 27 | // Machine from the netrc file 28 | type Machine struct { 29 | Name string 30 | IsDefault bool 31 | tokens []string 32 | } 33 | type Machines []*Machine 34 | 35 | // New creates and returns a new empty Netrc for writing to. 36 | func New(p string) *Netrc { 37 | return &Netrc{machines: make(Machines, 0, 20), Path: p} 38 | } 39 | 40 | // Parse the netrc file at the given path 41 | // It returns a Netrc instance 42 | func Parse(path string) (*Netrc, error) { 43 | file, err := read(path) 44 | if err != nil { 45 | return nil, err 46 | } 47 | netrc, err := parse(lex(file)) 48 | if err != nil { 49 | return nil, err 50 | } 51 | netrc.Path = path 52 | return netrc, nil 53 | } 54 | 55 | // ParseString behaves just like Parse, but can be used to parse netrc data 56 | // without loading it from a file. 57 | func ParseString(contents string) (*Netrc, error) { 58 | r := strings.NewReader(contents) 59 | netrc, err := parse(lex(r)) 60 | if err != nil { 61 | return nil, err 62 | } 63 | return netrc, nil 64 | } 65 | 66 | // Machine gets a machine by name 67 | func (n *Netrc) Machines() Machines { 68 | return n.machines 69 | } 70 | 71 | 72 | // Machine gets a machine by name 73 | func (n *Netrc) Machine(name string) *Machine { 74 | for _, m := range n.machines { 75 | if m.Name == name { 76 | return m 77 | } 78 | } 79 | return nil 80 | } 81 | 82 | // AddMachine adds a machine 83 | func (n *Netrc) AddMachine(name, login, password string) { 84 | machine := n.Machine(name) 85 | if machine == nil { 86 | machine = &Machine{} 87 | n.machines = append(n.machines, machine) 88 | } 89 | machine.Name = name 90 | machine.tokens = []string{"machine ", name, "\n"} 91 | machine.Set("login", login) 92 | machine.Set("password", password) 93 | } 94 | 95 | // RemoveMachine remove a machine 96 | func (n *Netrc) RemoveMachine(name string) { 97 | for i, machine := range n.machines { 98 | if machine.Name == name { 99 | n.machines = append(n.machines[:i], n.machines[i+1:]...) 100 | // continue removing but start over since the indexes changed 101 | n.RemoveMachine(name) 102 | return 103 | } 104 | } 105 | } 106 | 107 | // Render out the netrc file to a string 108 | func (n *Netrc) Render() string { 109 | var b bytes.Buffer 110 | for _, token := range n.tokens { 111 | b.WriteString(token) 112 | } 113 | for _, machine := range n.machines { 114 | for _, token := range machine.tokens { 115 | b.WriteString(token) 116 | } 117 | } 118 | return b.String() 119 | } 120 | 121 | // Save the file to disk 122 | func (n *Netrc) Save() error { 123 | body := []byte(n.Render()) 124 | if filepath.Ext(n.Path) == ".gpg" { 125 | cmd := exec.Command("gpg", "-a", "--batch", "--default-recipient-self", "-e") 126 | stdin, err := cmd.StdinPipe() 127 | if err != nil { 128 | return err 129 | } 130 | stdin.Write(body) 131 | stdin.Close() 132 | cmd.Stderr = os.Stderr 133 | body, err = cmd.Output() 134 | if err != nil { 135 | return err 136 | } 137 | } 138 | return ioutil.WriteFile(n.Path, body, 0600) 139 | } 140 | 141 | func read(path string) (io.Reader, error) { 142 | if filepath.Ext(path) == ".gpg" { 143 | cmd := exec.Command("gpg", "--batch", "--quiet", "--decrypt", path) 144 | cmd.Stderr = os.Stderr 145 | stdout, err := cmd.StdoutPipe() 146 | if err != nil { 147 | return nil, err 148 | } 149 | err = cmd.Start() 150 | if err != nil { 151 | return nil, err 152 | } 153 | return stdout, nil 154 | } 155 | return os.Open(path) 156 | } 157 | 158 | func lex(file io.Reader) []string { 159 | commentRe := regexp.MustCompile("(^#|\\s+#)") 160 | scanner := bufio.NewScanner(file) 161 | scanner.Split(func(data []byte, eof bool) (int, []byte, error) { 162 | var loc []int 163 | if eof && len(data) == 0 { 164 | return 0, nil, nil 165 | } 166 | inWhitespace := unicode.IsSpace(rune(data[0])) 167 | for i, c := range data { 168 | if c == '#' { 169 | // line might have a comment 170 | // but if our regexp returns nil, keep going 171 | loc = commentRe.FindIndex(data) 172 | if loc != nil && loc[0] == 0 { 173 | // currently in a comment 174 | i = bytes.IndexByte(data, '\n') 175 | if i == -1 { 176 | // no newline at end 177 | if !eof { 178 | return 0, nil, nil 179 | } 180 | i = len(data) 181 | } 182 | for i < len(data) { 183 | if !unicode.IsSpace(rune(data[i])) { 184 | break 185 | } 186 | i++ 187 | } 188 | return i, data[0:i], nil 189 | } 190 | } 191 | if unicode.IsSpace(rune(c)) != inWhitespace { 192 | return i, data[0:i], nil 193 | } 194 | } 195 | if eof { 196 | return len(data), data, nil 197 | } 198 | return 0, nil, nil 199 | }) 200 | tokens := make([]string, 0, 100) 201 | for scanner.Scan() { 202 | tokens = append(tokens, scanner.Text()) 203 | } 204 | return tokens 205 | } 206 | 207 | func parse(tokens []string) (*Netrc, error) { 208 | n := &Netrc{} 209 | n.machines = make(Machines, 0, 20) 210 | var machine *Machine 211 | for i, token := range tokens { 212 | // group tokens into machines 213 | if token == "machine" || token == "default" { 214 | // start new group 215 | machine = &Machine{} 216 | n.machines = append(n.machines, machine) 217 | if token == "default" { 218 | machine.IsDefault = true 219 | machine.Name = "default" 220 | } else { 221 | machine.Name = tokens[i+2] 222 | } 223 | } 224 | if machine == nil { 225 | n.tokens = append(n.tokens, token) 226 | } else { 227 | machine.tokens = append(machine.tokens, token) 228 | } 229 | } 230 | return n, nil 231 | } 232 | 233 | // Get a property from a machine 234 | func (m *Machine) Get(name string) string { 235 | i := 4 236 | if m.IsDefault { 237 | i = 2 238 | } 239 | for { 240 | if i+2 >= len(m.tokens) { 241 | return "" 242 | } 243 | if m.tokens[i] == name { 244 | return m.tokens[i+2] 245 | } 246 | i = i + 4 247 | } 248 | } 249 | 250 | // Set a property on the machine 251 | func (m *Machine) Set(name, value string) { 252 | i := 4 253 | if m.IsDefault { 254 | i = 2 255 | } 256 | for i+2 < len(m.tokens) { 257 | if m.tokens[i] == name { 258 | m.tokens[i+2] = value 259 | return 260 | } 261 | i = i + 4 262 | } 263 | m.tokens = append(m.tokens, " ", name, " ", value, "\n") 264 | } 265 | -------------------------------------------------------------------------------- /netrc_test.go: -------------------------------------------------------------------------------- 1 | package netrc_test 2 | 3 | import ( 4 | "io" 5 | "io/ioutil" 6 | "os" 7 | "path/filepath" 8 | "testing" 9 | 10 | "github.com/jdx/go-netrc" 11 | . "gopkg.in/check.v1" 12 | ) 13 | 14 | // Hook up gocheck into the "go test" runner. 15 | func Test(t *testing.T) { TestingT(t) } 16 | 17 | type NetrcSuite struct{} 18 | 19 | var _ = Suite(&NetrcSuite{}) 20 | 21 | func (s *NetrcSuite) TestLogin(c *C) { 22 | f, err := netrc.Parse("./examples/login.netrc") 23 | c.Assert(err, IsNil) 24 | heroku := f.Machine("api.heroku.com") 25 | c.Check(heroku.Get("login"), Equals, "jeff@heroku.com") 26 | c.Check(heroku.Get("password"), Equals, "foo") 27 | body, _ := ioutil.ReadFile(f.Path) 28 | c.Check(f.Render(), Equals, string(body)) 29 | } 30 | 31 | func (s *NetrcSuite) TestSave(c *C) { 32 | f, err := netrc.Parse("./examples/login.netrc") 33 | c.Assert(err, IsNil) 34 | f.Path = "./examples/login-new.netrc" 35 | err = f.Save() 36 | c.Assert(err, IsNil) 37 | a, _ := ioutil.ReadFile("./examples/login-new.netrc") 38 | b, _ := ioutil.ReadFile("./examples/login.netrc") 39 | c.Check(string(a), Equals, string(b)) 40 | os.Remove("./examples/login-new.netrc") 41 | } 42 | 43 | func (s *NetrcSuite) TestAdd(c *C) { 44 | f, err := netrc.Parse("./examples/login.netrc") 45 | c.Assert(err, IsNil) 46 | f.AddMachine("m", "l", "p") 47 | c.Check(f.Render(), Equals, "# this is my login netrc\nmachine api.heroku.com\n login jeff@heroku.com # this is my username\n password foo\n"+ 48 | "machine m\n login l\n password p\n") 49 | } 50 | 51 | func (s *NetrcSuite) TestMachineSetWithEmptyFile(c *C) { 52 | dir := c.MkDir() 53 | n := netrc.New(filepath.Join(dir, ".netrc")) 54 | n.AddMachine("api.heroku.com", "jeff@heroku.com", "foo") 55 | c.Check(n.Render(), Equals, "machine api.heroku.com\n login jeff@heroku.com\n password foo\n") 56 | } 57 | 58 | func (s *NetrcSuite) TestAddExisting(c *C) { 59 | f, err := netrc.Parse("./examples/login.netrc") 60 | c.Assert(err, IsNil) 61 | f.AddMachine("api.heroku.com", "l", "p") 62 | c.Check(f.Render(), Equals, "# this is my login netrc\nmachine api.heroku.com\n login l\n password p\n") 63 | } 64 | 65 | func (s *NetrcSuite) TestRemove(c *C) { 66 | f, err := netrc.Parse("./examples/sample_multi.netrc") 67 | c.Assert(err, IsNil) 68 | f.RemoveMachine("m") 69 | c.Check(f.Render(), Equals, "# this is my netrc with multiple machines\nmachine n\n login ln # this is my n-username\n password pn\n") 70 | } 71 | 72 | func (s *NetrcSuite) TestSetPassword(c *C) { 73 | f, err := netrc.Parse("./examples/login.netrc") 74 | c.Assert(err, IsNil) 75 | heroku := f.Machine("api.heroku.com") 76 | heroku.Set("password", "foobar") 77 | c.Check(f.Render(), Equals, "# this is my login netrc\nmachine api.heroku.com\n login jeff@heroku.com # this is my username\n password foobar\n") 78 | } 79 | 80 | func (s *NetrcSuite) TestSampleMulti(c *C) { 81 | f, err := netrc.Parse("./examples/sample_multi.netrc") 82 | c.Assert(err, IsNil) 83 | c.Check(f.Machine("m").Get("login"), Equals, "lm") 84 | c.Check(f.Machine("m").Get("password"), Equals, "pm") 85 | c.Check(f.Machine("n").Get("login"), Equals, "ln") 86 | c.Check(f.Machine("n").Get("password"), Equals, "pn") 87 | body, _ := ioutil.ReadFile(f.Path) 88 | c.Check(f.Render(), Equals, string(body)) 89 | } 90 | 91 | func (s *NetrcSuite) TestSampleMultiWithDefault(c *C) { 92 | f, err := netrc.Parse("./examples/sample_multi_with_default.netrc") 93 | c.Assert(err, IsNil) 94 | c.Check(f.Machine("m").Get("login"), Equals, "lm") 95 | c.Check(f.Machine("m").Get("password"), Equals, "pm") 96 | c.Check(f.Machine("n").Get("login"), Equals, "ln") 97 | c.Check(f.Machine("n").Get("password"), Equals, "pn") 98 | body, _ := ioutil.ReadFile(f.Path) 99 | c.Check(f.Render(), Equals, string(body)) 100 | } 101 | 102 | func (s *NetrcSuite) TestNewlineless(c *C) { 103 | f, err := netrc.Parse("./examples/newlineless.netrc") 104 | c.Assert(err, IsNil) 105 | c.Check(f.Machine("m").Get("login"), Equals, "l") 106 | c.Check(f.Machine("m").Get("password"), Equals, "p") 107 | body, _ := ioutil.ReadFile(f.Path) 108 | c.Check(f.Render(), Equals, string(body)) 109 | } 110 | 111 | func (s *NetrcSuite) TestBadDefaultOrder(c *C) { 112 | f, err := netrc.Parse("./examples/bad_default_order.netrc") 113 | c.Assert(err, IsNil) 114 | c.Check(f.Machine("mail.google.com").Get("login"), Equals, "joe@gmail.com") 115 | c.Check(f.Machine("mail.google.com").Get("password"), Equals, "somethingSecret") 116 | c.Check(f.Machine("ray").Get("login"), Equals, "demo") 117 | c.Check(f.Machine("ray").Get("password"), Equals, "mypassword") 118 | body, _ := ioutil.ReadFile(f.Path) 119 | c.Check(f.Render(), Equals, string(body)) 120 | } 121 | 122 | func (s *NetrcSuite) TestDefaultOnly(c *C) { 123 | f, err := netrc.Parse("./examples/default_only.netrc") 124 | c.Assert(err, IsNil) 125 | c.Check(f.Machine("default").Get("login"), Equals, "ld") 126 | c.Check(f.Machine("default").Get("password"), Equals, "pd") 127 | body, _ := ioutil.ReadFile(f.Path) 128 | c.Check(f.Render(), Equals, string(body)) 129 | } 130 | 131 | func (s *NetrcSuite) TestGood(c *C) { 132 | f, err := netrc.Parse("./examples/good.netrc") 133 | c.Assert(err, IsNil) 134 | c.Check(f.Machine("mail.google.com").Get("login"), Equals, "joe@gmail.com") 135 | c.Check(f.Machine("mail.google.com").Get("account"), Equals, "justagmail") 136 | c.Check(f.Machine("mail.google.com").Get("password"), Equals, "somethingSecret") 137 | body, _ := ioutil.ReadFile(f.Path) 138 | c.Check(f.Render(), Equals, string(body)) 139 | } 140 | 141 | func (s *NetrcSuite) TestPassword(c *C) { 142 | f, err := netrc.Parse("./examples/password.netrc") 143 | c.Assert(err, IsNil) 144 | c.Check(f.Machine("m").Get("password"), Equals, "p") 145 | body, _ := ioutil.ReadFile(f.Path) 146 | c.Check(f.Render(), Equals, string(body)) 147 | } 148 | 149 | func (s *NetrcSuite) TestGetOctothorpe(c *C) { 150 | f, err := netrc.Parse("./examples/octothorpe.netrc") 151 | c.Assert(err, IsNil) 152 | c.Check(f.Machine("hash").Get("password"), Equals, "foo#bar$baz%boom") 153 | c.Check(f.Machine("hash2").Get("password"), Equals, "foo#bar$baz%boom##") 154 | body, _ := ioutil.ReadFile(f.Path) 155 | c.Check(f.Render(), Equals, string(body)) 156 | } 157 | 158 | func (s *NetrcSuite) TestPermissive(c *C) { 159 | f, err := netrc.Parse("./examples/permissive.netrc") 160 | c.Assert(err, IsNil) 161 | c.Check(f.Machine("m").Get("login"), Equals, "l") 162 | c.Check(f.Machine("m").Get("password"), Equals, "p") 163 | body, _ := ioutil.ReadFile(f.Path) 164 | c.Check(f.Render(), Equals, string(body)) 165 | } 166 | 167 | func (s *NetrcSuite) TestParseString(c *C) { 168 | file, err := os.Open("./examples/good.netrc") 169 | defer file.Close() 170 | data, err := io.ReadAll(file) 171 | c.Assert(err, IsNil) 172 | f, err := netrc.ParseString(string(data)) 173 | c.Assert(err, IsNil) 174 | c.Check(f.Machine("mail.google.com").Get("login"), Equals, "joe@gmail.com") 175 | c.Check(f.Machine("mail.google.com").Get("account"), Equals, "justagmail") 176 | c.Check(f.Machine("mail.google.com").Get("password"), Equals, "somethingSecret") 177 | } 178 | --------------------------------------------------------------------------------