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