]> Cypherpunks.ru repositories - netrc.git/commitdiff
Initial commit master v0.1.0
authorSergey Matveev <stargrave@stargrave.org>
Sat, 12 Aug 2023 09:17:32 +0000 (12:17 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Sat, 12 Aug 2023 10:32:20 +0000 (13:32 +0300)
go.mod [new file with mode: 0644]
netrc.go [new file with mode: 0644]
netrc_test.go [new file with mode: 0644]

diff --git a/go.mod b/go.mod
new file mode 100644 (file)
index 0000000..b191185
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module go.cypherpunks.ru/netrc
+
+go 1.20
diff --git a/netrc.go b/netrc.go
new file mode 100644 (file)
index 0000000..53521d2
--- /dev/null
+++ b/netrc.go
@@ -0,0 +1,92 @@
+// netrc -- parse .netrc file
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// netrc library parses .netrc file. It is copy-paste of
+// golang.org/x/tools/cmd/auth/netrcauth.
+//
+// See https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html
+// for documentation on the .netrc format.
+package netrc
+
+import (
+       "os"
+       "path"
+       "strings"
+)
+
+type Line struct {
+       Machine  string
+       Login    string
+       Password string
+}
+
+func Parse(data string) []Line {
+       var nrc []Line
+       var l Line
+       inMacro := false
+       for _, line := range strings.Split(data, "\n") {
+               if inMacro {
+                       if line == "" {
+                               inMacro = false
+                       }
+                       continue
+               }
+               f := strings.Fields(line)
+               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 = Line{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 = Line{}
+                       }
+               }
+               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
+}
+
+func Path() (netrc string) {
+       p, ok := os.LookupEnv("NETRC")
+       if ok {
+               return p
+       }
+       homeDir, _ := os.UserHomeDir()
+       return path.Join(homeDir, ".netrc")
+}
+
+func Find(host string) (login string, password string) {
+       data, err := os.ReadFile(Path())
+       if err != nil {
+               return "", ""
+       }
+       for _, l := range Parse(string(data)) {
+               if l.Machine == host {
+                       return l.Login, l.Password
+               }
+       }
+       return "", ""
+}
diff --git a/netrc_test.go b/netrc_test.go
new file mode 100644 (file)
index 0000000..7fe98c2
--- /dev/null
@@ -0,0 +1,53 @@
+package netrc
+
+import (
+       "reflect"
+       "testing"
+)
+
+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 TestParse(t *testing.T) {
+       lines := Parse(testNetrc)
+       want := []Line{
+               {"api.github.com", "user", "pwd"},
+               {"test.host", "user2", "pwd2"},
+               {"oneline", "user3", "pwd3"},
+               {"hasmacro.too", "user4", "pwd4"},
+       }
+       if !reflect.DeepEqual(lines, want) {
+               t.Errorf("have %q\nwant %q", lines, want)
+       }
+}