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  }