+++ /dev/null
-// Copyright 2019 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.
-
-// cookieauth uses a “Netscape cookie file” to implement the GOAUTH protocol
-// described in https://golang.org/issue/26232.
-// It expects the location of the file as the first command-line argument.
-//
-// Example GOAUTH usage:
-// export GOAUTH="cookieauth $(git config --get http.cookieFile)"
-//
-// See http://www.cookiecentral.com/faq/#3.5 for a description of the Netscape
-// cookie file format.
-package main
-
-import (
- "bufio"
- "fmt"
- "io"
- "log"
- "net/http"
- "net/http/cookiejar"
- "net/url"
- "os"
- "strconv"
- "strings"
- "time"
- "unicode"
-)
-
-func main() {
- if len(os.Args) < 2 {
- fmt.Fprintf(os.Stderr, "usage: %s COOKIEFILE [URL]\n", os.Args[0])
- os.Exit(2)
- }
-
- log.SetPrefix("cookieauth: ")
-
- f, err := os.Open(os.Args[1])
- if err != nil {
- log.Fatalf("failed to read cookie file: %v\n", os.Args[1])
- os.Exit(1)
- }
- defer f.Close()
-
- var (
- targetURL *url.URL
- targetURLs = map[string]*url.URL{}
- )
- if len(os.Args) == 3 {
- targetURL, err = url.ParseRequestURI(os.Args[2])
- if err != nil {
- log.Fatalf("invalid request URI (%v): %q\n", err, os.Args[2])
- }
- targetURLs[targetURL.String()] = targetURL
- } else if len(os.Args) > 3 {
- // Extra arguments were passed: maybe the protocol was expanded?
- // We don't know how to interpret the request, so ignore it.
- return
- }
-
- entries, err := parseCookieFile(f.Name(), f)
- if err != nil {
- log.Fatalf("error reading cookie file: %v\n", f.Name())
- }
-
- jar, err := cookiejar.New(nil)
- if err != nil {
- log.Fatalf("failed to initialize cookie jar: %v\n", err)
- }
-
- for _, e := range entries {
- u := &url.URL{
- Scheme: "https",
- Host: e.Host,
- Path: e.Cookie.Path,
- }
-
- if targetURL == nil {
- targetURLs[u.String()] = u
- }
-
- jar.SetCookies(u, []*http.Cookie{&e.Cookie})
- }
-
- for _, u := range targetURLs {
- req := &http.Request{URL: u, Header: make(http.Header)}
- for _, c := range jar.Cookies(req.URL) {
- req.AddCookie(c)
- }
- fmt.Printf("%s\n\n", u)
- req.Header.Write(os.Stdout)
- fmt.Println()
- }
-}
-
-type Entry struct {
- Host string
- Cookie http.Cookie
-}
-
-// parseCookieFile parses a Netscape cookie file as described in
-// http://www.cookiecentral.com/faq/#3.5.
-func parseCookieFile(name string, r io.Reader) ([]*Entry, error) {
- var entries []*Entry
- s := bufio.NewScanner(r)
- line := 0
- for s.Scan() {
- line++
- text := strings.TrimSpace(s.Text())
- if len(text) < 2 || (text[0] == '#' && unicode.IsSpace(rune(text[1]))) {
- continue
- }
-
- e, err := parseCookieLine(text)
- if err != nil {
- log.Printf("%s:%d: %v\n", name, line, err)
- continue
- }
- entries = append(entries, e)
- }
- return entries, s.Err()
-}
-
-func parseCookieLine(line string) (*Entry, error) {
- f := strings.Fields(line)
- if len(f) < 7 {
- return nil, fmt.Errorf("found %d columns; want 7", len(f))
- }
-
- e := new(Entry)
- c := &e.Cookie
-
- if domain := f[0]; strings.HasPrefix(domain, "#HttpOnly_") {
- c.HttpOnly = true
- e.Host = strings.TrimPrefix(domain[10:], ".")
- } else {
- e.Host = strings.TrimPrefix(domain, ".")
- }
-
- isDomain, err := strconv.ParseBool(f[1])
- if err != nil {
- return nil, fmt.Errorf("non-boolean domain flag: %v", err)
- }
- if isDomain {
- c.Domain = e.Host
- }
-
- c.Path = f[2]
-
- c.Secure, err = strconv.ParseBool(f[3])
- if err != nil {
- return nil, fmt.Errorf("non-boolean secure flag: %v", err)
- }
-
- expiration, err := strconv.ParseInt(f[4], 10, 64)
- if err != nil {
- return nil, fmt.Errorf("malformed expiration: %v", err)
- }
- c.Expires = time.Unix(expiration, 0)
-
- c.Name = f[5]
- c.Value = f[6]
-
- return e, nil
-}