+// 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 "", ""
+}