github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/cmd/auth/netrcauth/netrcauth.go (about) 1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // netrcauth uses a .netrc file (or _netrc file on Windows) to implement the 6 // GOAUTH protocol described in https://golang.org/issue/26232. 7 // It expects the location of the file as the first command-line argument. 8 // 9 // Example GOAUTH usage: 10 // 11 // export GOAUTH="netrcauth $HOME/.netrc" 12 // 13 // See https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html 14 // or run 'man 5 netrc' for a description of the .netrc file format. 15 package main 16 17 import ( 18 "fmt" 19 "io/ioutil" 20 "log" 21 "net/http" 22 "net/url" 23 "os" 24 "strings" 25 ) 26 27 func main() { 28 if len(os.Args) < 2 { 29 fmt.Fprintf(os.Stderr, "usage: %s NETRCFILE [URL]", os.Args[0]) 30 os.Exit(2) 31 } 32 33 log.SetPrefix("netrcauth: ") 34 35 if len(os.Args) != 2 { 36 // An explicit URL was passed on the command line, but netrcauth does not 37 // have any URL-specific output: it dumps the entire .netrc file at the 38 // first call. 39 return 40 } 41 42 path := os.Args[1] 43 44 data, err := ioutil.ReadFile(path) 45 if err != nil { 46 if os.IsNotExist(err) { 47 return 48 } 49 log.Fatalf("failed to read %s: %v\n", path, err) 50 } 51 52 u := &url.URL{Scheme: "https"} 53 lines := parseNetrc(string(data)) 54 for _, l := range lines { 55 u.Host = l.machine 56 fmt.Printf("%s\n\n", u) 57 58 req := &http.Request{Header: make(http.Header)} 59 req.SetBasicAuth(l.login, l.password) 60 req.Header.Write(os.Stdout) 61 fmt.Println() 62 } 63 } 64 65 // The following functions were extracted from src/cmd/go/internal/web2/web.go 66 // as of https://golang.org/cl/161698. 67 68 type netrcLine struct { 69 machine string 70 login string 71 password string 72 } 73 74 func parseNetrc(data string) []netrcLine { 75 // See https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html 76 // for documentation on the .netrc format. 77 var nrc []netrcLine 78 var l netrcLine 79 inMacro := false 80 for _, line := range strings.Split(data, "\n") { 81 if inMacro { 82 if line == "" { 83 inMacro = false 84 } 85 continue 86 } 87 88 f := strings.Fields(line) 89 i := 0 90 for ; i < len(f)-1; i += 2 { 91 // Reset at each "machine" token. 92 // “The auto-login process searches the .netrc file for a machine token 93 // that matches […]. Once a match is made, the subsequent .netrc tokens 94 // are processed, stopping when the end of file is reached or another 95 // machine or a default token is encountered.” 96 switch f[i] { 97 case "machine": 98 l = netrcLine{machine: f[i+1]} 99 case "default": 100 break 101 case "login": 102 l.login = f[i+1] 103 case "password": 104 l.password = f[i+1] 105 case "macdef": 106 // “A macro is defined with the specified name; its contents begin with 107 // the next .netrc line and continue until a null line (consecutive 108 // new-line characters) is encountered.” 109 inMacro = true 110 } 111 if l.machine != "" && l.login != "" && l.password != "" { 112 nrc = append(nrc, l) 113 l = netrcLine{} 114 } 115 } 116 117 if i < len(f) && f[i] == "default" { 118 // “There can be only one default token, and it must be after all machine tokens.” 119 break 120 } 121 } 122 123 return nrc 124 }