Documentation
¶
Overview ¶
Package kooky contains routines to reach into cookie stores for various browsers and retrieve the cookies.
Example (ChromeSimpleMacOS) ¶
package main
import (
"fmt"
"os"
"github.com/xiazemin/kooky/browser/chrome"
)
// on macOS:
var cookieStorePath = "/Google/Chrome/Default/Cookies"
func main() {
// construct file path for the sqlite database containing the cookies
dir, _ := os.UserConfigDir() // on macOS: "/<USER>/Library/Application Support/"
cookieStoreFile := dir + cookieStorePath
// read the cookies from the file
// decryption is handled automatically
for cookie := range chrome.TraverseCookies(cookieStoreFile).OnlyCookies() {
fmt.Println(cookie)
}
}
Output:
Example (CookieJar) ¶
package main
import (
"context"
"fmt"
"io"
"log"
"net/http"
"net/url"
"strings"
"github.com/xiazemin/kooky"
_ "github.com/xiazemin/kooky/browser/firefox"
)
func main() {
ctx := context.TODO()
stores := kooky.FindAllCookieStores(ctx)
var s kooky.CookieStore
for _, store := range stores {
if store.Browser() != `firefox` || !store.IsDefaultProfile() {
continue
}
s = store
break
}
// jar := s
// only store cookies relevant for the target website in the cookie jar
jar, _ := s.SubJar(ctx, kooky.FilterFunc(func(c *kooky.Cookie) bool {
return kooky.Domain(`github.com`).Filter(c) || kooky.Domain(`.github.com`).Filter(c)
}))
u, _ := url.Parse(`https://github.com/settings/profile`)
cookies := kooky.FilterCookies(ctx, jar.Cookies(u), kooky.Name(`logged_in`)).Collect(ctx)
if len(cookies) == 0 {
log.Fatal(`not logged in`)
}
client := http.Client{Jar: jar}
resp, _ := client.Get(u.String())
body, _ := io.ReadAll(resp.Body)
if !strings.Contains(string(body), `id="user_profile_name"`) {
fmt.Print("not ")
}
fmt.Println("logged in")
}
Output: logged in
Index ¶
- func ExportCookies[S CookieSeq | []*Cookie | []*http.Cookie](ctx context.Context, w io.Writer, cookies S)
- func FilterCookie[T Cookie | http.Cookie](ctx context.Context, cookie *T, filters ...Filter) bool
- func RegisterFinder(browser string, finder CookieStoreFinder)
- type BrowserInfo
- type Cookie
- type CookieSeq
- func (s CookieSeq) Chan(ctx context.Context) <-chan *Cookie
- func (s CookieSeq) Collect(ctx context.Context) Cookies
- func (s CookieSeq) Export(ctx context.Context, w io.Writer)
- func (s CookieSeq) Filter(ctx context.Context, filters ...Filter) CookieSeq
- func (s CookieSeq) FirstMatch(ctx context.Context, filters ...Filter) *Cookie
- func (s CookieSeq) Merge(seqs ...CookieSeq) CookieSeq
- func (s CookieSeq) OnlyCookies() CookieSeq
- func (s CookieSeq) ReadAllCookies(ctx context.Context) (Cookies, error)
- type CookieStore
- type CookieStoreFinder
- type CookieStoreSeq
- type Cookies
- type Filter
- func CreationAfter(u time.Time) Filter
- func CreationBefore(u time.Time) Filter
- func Domain(domain string) Filter
- func DomainContains(substr string) Filter
- func DomainHasPrefix(prefix string) Filter
- func DomainHasSuffix(suffix string) Filter
- func ExpiresAfter(u time.Time) Filter
- func ExpiresBefore(u time.Time) Filter
- func Name(name string) Filter
- func NameContains(substr string) Filter
- func NameHasPrefix(prefix string) Filter
- func NameHasSuffix(suffix string) Filter
- func Path(path string) Filter
- func PathContains(substr string) Filter
- func PathDepth(depth int) Filter
- func PathHasPrefix(prefix string) Filter
- func PathHasSuffix(suffix string) Filter
- func Value(value string) Filter
- func ValueContains(substr string) Filter
- func ValueHasPrefix(prefix string) Filter
- func ValueHasSuffix(suffix string) Filter
- func ValueLen(length int) Filter
- type FilterFunc
- type ValueFilterFunc
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ExportCookies ¶
func ExportCookies[S CookieSeq | []*Cookie | []*http.Cookie](ctx context.Context, w io.Writer, cookies S)
ExportCookies() export "cookies" in the Netscape format.
curl, wget, ... use this format.
Example ¶
package main
import (
"context"
"net/http"
"os"
"github.com/xiazemin/kooky"
)
var cookieFile = `cookies.txt`
func main() {
var cookies = []*kooky.Cookie{{Cookie: http.Cookie{Domain: `.test.com`, Name: `test`, Value: `dGVzdA==`}}}
file, err := os.OpenFile(cookieFile, os.O_RDWR|os.O_CREATE, 0644)
if err != nil {
// TODO: handle error
return
}
defer file.Close()
kooky.ExportCookies(context.TODO(), file, cookies)
}
Output:
func FilterCookie ¶
FilterCookie() tells if a "cookie" passes all "filters".
func RegisterFinder ¶
func RegisterFinder(browser string, finder CookieStoreFinder)
RegisterFinder() registers CookieStoreFinder enabling automatic finding of cookie stores with FindAllCookieStores() and ReadCookies().
RegisterFinder() is called by init() in the browser subdirectories.
Types ¶
type BrowserInfo ¶ added in v0.2.3
type Cookie ¶
Cookie is an http.Cookie augmented with information obtained through the scraping process.
func (*Cookie) MarshalJSON ¶ added in v0.2.3
type CookieSeq ¶ added in v0.2.3
for-rangeable cookie retriever
func FilterCookies ¶
func FilterCookies[S CookieSeq | ~[]*Cookie | ~[]*http.Cookie](ctx context.Context, cookies S, filters ...Filter) CookieSeq
Example ¶
package main
import (
"context"
"github.com/xiazemin/kooky"
_ "github.com/xiazemin/kooky/browser/all" // register cookiestore finders
)
var cookieName = `NID`
func main() {
ctx := context.TODO()
cookies := kooky.AllCookies(). // automatic read
Seq().
Filter(
ctx,
kooky.Valid, // remove expired cookies
kooky.DomainContains(`google`), // cookie domain has to contain "google"
kooky.Name(cookieName), // cookie name is "NID"
kooky.Debug, // print cookies after applying previous filter
).
Collect(ctx) // iterate and collect in a slice
_ = cookies // do something
}
Output:
func MergeCookieSeqs ¶ added in v0.2.3
func TraverseCookies ¶ added in v0.2.3
func (CookieSeq) Collect ¶ added in v0.2.3
Collect() is the same as ReadAllCookies but ignores the error
func (CookieSeq) FirstMatch ¶ added in v0.2.3
func (CookieSeq) OnlyCookies ¶ added in v0.2.3
sequence of non-nil cookies and nil errors
type CookieStore ¶
type CookieStore interface {
http.CookieJar
BrowserInfo
SubJar(context.Context, ...Filter) (http.CookieJar, error)
TraverseCookies(...Filter) CookieSeq
Close() error
}
CookieStore represents a file, directory, etc containing cookies.
Call CookieStore.Close() after using any of its methods.
func FindAllCookieStores ¶
func FindAllCookieStores(ctx context.Context) []CookieStore
FindAllCookieStores() tries to find cookie stores at default locations.
FindAllCookieStores() requires registered CookieStoreFinders.
Register cookie store finders for all browsers like this:
import _ "github.com/xiazemin/kooky/browser/all"
Or only a specific browser:
import _ "github.com/xiazemin/kooky/browser/chrome"
Example ¶
package main
import (
"context"
"fmt"
"github.com/xiazemin/kooky"
_ "github.com/xiazemin/kooky/browser/all"
)
func main() {
ctx := context.TODO()
cookieStores := kooky.FindAllCookieStores(ctx)
for _, store := range cookieStores {
// CookieStore keeps files/databases open for repeated reads
// close those when no longer needed
defer store.Close()
var filters = []kooky.Filter{
kooky.Valid, // remove expired cookies
}
for cookie := range store.TraverseCookies(filters...).OnlyCookies() {
fmt.Printf(
"%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
store.Browser(),
store.Profile(),
store.FilePath(),
cookie.Domain,
cookie.Name,
cookie.Value,
cookie.Expires.Format(`2006.01.02 15:04:05`),
)
}
}
}
Output:
type CookieStoreFinder ¶
type CookieStoreFinder interface {
FindCookieStores() CookieStoreSeq
}
CookieStoreFinder tries to find cookie stores at default locations.
type CookieStoreSeq ¶ added in v0.2.3
type CookieStoreSeq iter.Seq2[CookieStore, error]
func TraverseCookieStores ¶ added in v0.2.3
func TraverseCookieStores(ctx context.Context) CookieStoreSeq
func (CookieStoreSeq) AllCookieStores ¶ added in v0.2.3
func (s CookieStoreSeq) AllCookieStores(ctx context.Context) []CookieStore
func (CookieStoreSeq) OnlyCookieStores ¶ added in v0.2.3
func (s CookieStoreSeq) OnlyCookieStores() CookieStoreSeq
sequence of non-nil cookie stores and nil errors
func (CookieStoreSeq) TraverseCookies ¶ added in v0.2.3
func (s CookieStoreSeq) TraverseCookies(ctx context.Context, filters ...Filter) CookieSeq
type Cookies ¶ added in v0.2.3
type Cookies []*Cookie
func AllCookies ¶ added in v0.2.3
func ReadCookies ¶
Cookie retrieving functions in this package like TraverseCookies(), ReadCookies(), AllCookies() use registered cookiestore finders to read cookies. Erronous reads are skipped.
Register cookie store finders for all browsers like this:
import _ "github.com/xiazemin/kooky/browser/all"
Or only a specific browser:
import _ "github.com/xiazemin/kooky/browser/chrome"
Example (All) ¶
package main
import (
"fmt"
"github.com/xiazemin/kooky"
_ "github.com/xiazemin/kooky/browser/all" // This registers all cookiestore finders!
// _ "github.com/xiazemin/kooky/browser/chrome" // load only the chrome cookiestore finder
)
func main() {
// try to find cookie stores in default locations and
// read the cookies from them.
// decryption is handled automatically.
cookies := kooky.AllCookies()
for _, cookie := range cookies {
fmt.Println(cookie)
}
}
var _ struct{} // ignore this - for correct working of the documentation tool
Output:
type Filter ¶
Filter is used for filtering cookies in ReadCookies() functions. Filter order might be changed for performance reasons (omission of value decryption of filtered out cookies, etc).
A cookie passes the Filter if Filter.Filter returns true.
Example (Regex) ¶
package main
import (
"context"
"fmt"
"net/http"
"regexp"
"github.com/xiazemin/kooky"
)
// example regex matching base64 strings
var reBase64 = regexp.MustCompile(`^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$`)
func main() {
var cookies = []*kooky.Cookie{{Cookie: http.Cookie{Name: `test`, Value: `dGVzdA==`}}}
ctx := context.Background()
cookies = kooky.FilterCookies(
ctx,
cookies,
ValueRegexMatch(reBase64), // filter cookies with the regex filter
// kooky.Debug, // print cookies after applying the regex filter
).Collect(ctx)
for _, cookie := range cookies {
fmt.Println(cookie.Value)
break // only first element
}
}
func ValueRegexMatch(re *regexp.Regexp) kooky.Filter {
return kooky.FilterFunc(func(cookie *kooky.Cookie) bool {
return cookie != nil && re != nil && re.Match([]byte(cookie.Value))
})
}
Output: dGVzdA==
var Debug Filter = FilterFunc(func(cookie *Cookie) bool { fmt.Printf("%+#v\n", cookie) return true })
Debug prints the cookie.
Position Debug after the filter you want to test.
var HTTPOnly Filter = FilterFunc(func(cookie *Cookie) bool { return cookie != nil && cookie.HttpOnly })
var Secure Filter = FilterFunc(func(cookie *Cookie) bool { return cookie != nil && cookie.Secure })
func CreationAfter ¶
func CreationBefore ¶
func DomainContains ¶
func DomainHasPrefix ¶
func DomainHasSuffix ¶
func ExpiresAfter ¶
func ExpiresBefore ¶
func NameContains ¶
func NameHasPrefix ¶
func NameHasSuffix ¶
func PathContains ¶
func PathHasPrefix ¶
func PathHasSuffix ¶
func ValueContains ¶
func ValueHasPrefix ¶
func ValueHasSuffix ¶
type FilterFunc ¶
func (FilterFunc) Filter ¶
func (f FilterFunc) Filter(c *Cookie) bool
type ValueFilterFunc ¶ added in v0.2.3
func (ValueFilterFunc) Filter ¶ added in v0.2.3
func (f ValueFilterFunc) Filter(c *Cookie) bool