mirror of
https://github.com/golang/go
synced 2024-11-19 03:44:40 -07:00
052fc3cfdb
Updates golang/go#26232 Change-Id: Ic8a7336eeb395fb9e8bbb7589a98a402deed0501 Reviewed-on: https://go-review.googlesource.com/c/tools/+/161669 Run-TryBot: Bryan C. Mills <bcmills@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Jay Conrod <jayconrod@google.com>
167 lines
3.6 KiB
Go
167 lines
3.6 KiB
Go
// 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
|
|
}
|