1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package main
16
17 import (
18 "bufio"
19 "fmt"
20 "io"
21 "log"
22 "net/http"
23 "net/http/cookiejar"
24 "net/url"
25 "os"
26 "strconv"
27 "strings"
28 "time"
29 "unicode"
30 )
31
32 func main() {
33 if len(os.Args) < 2 {
34 fmt.Fprintf(os.Stderr, "usage: %s COOKIEFILE [URL]\n", os.Args[0])
35 os.Exit(2)
36 }
37
38 log.SetPrefix("cookieauth: ")
39
40 f, err := os.Open(os.Args[1])
41 if err != nil {
42 log.Fatalf("failed to read cookie file: %v\n", os.Args[1])
43 }
44 defer f.Close()
45
46 var (
47 targetURL *url.URL
48 targetURLs = map[string]*url.URL{}
49 )
50 if len(os.Args) == 3 {
51 targetURL, err = url.ParseRequestURI(os.Args[2])
52 if err != nil {
53 log.Fatalf("invalid request URI (%v): %q\n", err, os.Args[2])
54 }
55 targetURLs[targetURL.String()] = targetURL
56 } else if len(os.Args) > 3 {
57
58
59 return
60 }
61
62 entries, err := parseCookieFile(f.Name(), f)
63 if err != nil {
64 log.Fatalf("error reading cookie file: %v\n", f.Name())
65 }
66
67 jar, err := cookiejar.New(nil)
68 if err != nil {
69 log.Fatalf("failed to initialize cookie jar: %v\n", err)
70 }
71
72 for _, e := range entries {
73 u := &url.URL{
74 Scheme: "https",
75 Host: e.Host,
76 Path: e.Cookie.Path,
77 }
78
79 if targetURL == nil {
80 targetURLs[u.String()] = u
81 }
82
83 jar.SetCookies(u, []*http.Cookie{&e.Cookie})
84 }
85
86 for _, u := range targetURLs {
87 req := &http.Request{URL: u, Header: make(http.Header)}
88 for _, c := range jar.Cookies(req.URL) {
89 req.AddCookie(c)
90 }
91 fmt.Printf("%s\n\n", u)
92 req.Header.Write(os.Stdout)
93 fmt.Println()
94 }
95 }
96
97 type Entry struct {
98 Host string
99 Cookie http.Cookie
100 }
101
102
103
104 func parseCookieFile(name string, r io.Reader) ([]*Entry, error) {
105 var entries []*Entry
106 s := bufio.NewScanner(r)
107 line := 0
108 for s.Scan() {
109 line++
110 text := strings.TrimSpace(s.Text())
111 if len(text) < 2 || (text[0] == '#' && unicode.IsSpace(rune(text[1]))) {
112 continue
113 }
114
115 e, err := parseCookieLine(text)
116 if err != nil {
117 log.Printf("%s:%d: %v\n", name, line, err)
118 continue
119 }
120 entries = append(entries, e)
121 }
122 return entries, s.Err()
123 }
124
125 func parseCookieLine(line string) (*Entry, error) {
126 f := strings.Fields(line)
127 if len(f) < 7 {
128 return nil, fmt.Errorf("found %d columns; want 7", len(f))
129 }
130
131 e := new(Entry)
132 c := &e.Cookie
133
134 if domain := f[0]; strings.HasPrefix(domain, "#HttpOnly_") {
135 c.HttpOnly = true
136 e.Host = strings.TrimPrefix(domain[10:], ".")
137 } else {
138 e.Host = strings.TrimPrefix(domain, ".")
139 }
140
141 isDomain, err := strconv.ParseBool(f[1])
142 if err != nil {
143 return nil, fmt.Errorf("non-boolean domain flag: %v", err)
144 }
145 if isDomain {
146 c.Domain = e.Host
147 }
148
149 c.Path = f[2]
150
151 c.Secure, err = strconv.ParseBool(f[3])
152 if err != nil {
153 return nil, fmt.Errorf("non-boolean secure flag: %v", err)
154 }
155
156 expiration, err := strconv.ParseInt(f[4], 10, 64)
157 if err != nil {
158 return nil, fmt.Errorf("malformed expiration: %v", err)
159 }
160 c.Expires = time.Unix(expiration, 0)
161
162 c.Name = f[5]
163 c.Value = f[6]
164
165 return e, nil
166 }
167
View as plain text