Skip to content
Open

1 #91

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# unix only atm

ifeq ($(GOOS),windows)
EXT = ".exe"
else
SRC=$(shell find . -type d \( -path ./vendor -o -path ./testdata \) -prune -o -name '*.go' -print)
endif


.PHONY: build
build: kooky

.PHONY: all
all: kooky


kooky: ${SRC}
@env GOWORK=off GOEXPERIMENT=rangefunc go build -trimpath -ldflags '-w -s' -o kooky${EXT} ./cmd/kooky


.PHONY: test
test:
@env GOWORK=off GOEXPERIMENT=rangefunc go test -count=1 -timeout=30s ./... | grep -v '^? '

.PHONY: clean
clean:
@rm -f -- kooky kooky.exe kooky.test
10 changes: 10 additions & 0 deletions NOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
### TODO

- [ ] Set up CI
- [x] Make it work on Windows. (Look at
[this](https://play.golang.org/p/fknP9AuLU-) and
[this](https://github.com/cfstras/chromecsv/blob/master/crypt_windows.go)
to learn how to decrypt.)
- [x] Handle rows in Chrome's cookie DB with other than 14 columns (?)
- [ ] Figure out what to do with quoted values, like the "bcookie" cookie from slideshare.net
(related (?): [go issue #46443: net/http: add field Cookie.Quoted bool](https://github.com/golang/go/issues/46443))
55 changes: 20 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# kooky

[![PkgGoDev](https://pkg.go.dev/badge/github.com/browserutils/kooky)](https://pkg.go.dev/github.com/browserutils/kooky)
[![Go Report Card](https://goreportcard.com/badge/zellyn/kooky)](https://goreportcard.com/report/zellyn/kooky)
![Lines of code](https://img.shields.io/tokei/lines/github/zellyn/kooky)
[![PkgGoDev](https://pkg.go.dev/badge/github.com/xiazemin/kooky)](https://pkg.go.dev/github.com/xiazemin/kooky)
[![Go Report Card](https://goreportcard.com/badge/browserutils/kooky)](https://goreportcard.com/report/browserutils/kooky)
![Lines of code](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.codetabs.com%2Fv1%2Floc%2F%3Fgithub%3Dbrowserutils%2Fkooky%26ignored%3Dvendor%2Ctestdata&query=%24%5B%3F(%40.language%3D%3D%22Go%22)%5D.linesOfCode&logo=Go&label=lines%20of%20code&cacheSeconds=3600)
[![No Maintenance Intended](http://unmaintained.tech/badge.svg)](http://unmaintained.tech/)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
[![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://lbesson.mit-license.org/)
Expand Down Expand Up @@ -30,15 +30,6 @@ Some functions might not yet be implemented on some platforms.

PRs more than welcome.

## TODOs

- [ ] Set up CI
- [x] Make it work on Windows. (Look at
[this](https://play.golang.org/p/fknP9AuLU-) and
[this](https://github.com/cfstras/chromecsv/blob/master/crypt_windows.go)
to learn how to decrypt.)
- [x] Handle rows in Chrome's cookie DB with other than 14 columns (?)

## Example usage

### Any Browser - Cookie Filter Usage
Expand All @@ -49,16 +40,16 @@ package main
import (
"fmt"

"github.com/browserutils/kooky"
_ "github.com/browserutils/kooky/browser/all" // register cookie store finders!
"github.com/xiazemin/kooky"
_ "github.com/xiazemin/kooky/browser/all" // register cookie store finders!
)

func main() {
// uses registered finders to find cookie store files in default locations
// applies the passed filters "Valid", "DomainHasSuffix()" and "Name()" in order to the cookies
cookies := kooky.ReadCookies(kooky.Valid, kooky.DomainHasSuffix(`google.com`), kooky.Name(`NID`))
cookiesSeq := kooky.TraverseCookies(context.TODO(), kooky.Valid, kooky.DomainHasSuffix(`google.com`), kooky.Name(`NID`)).OnlyCookies()

for _, cookie := range cookies {
for cookie := range cookiesSeq {
fmt.Println(cookie.Domain, cookie.Name, cookie.Value)
}
}
Expand All @@ -74,17 +65,14 @@ import (
"log"
"os"

"github.com/browserutils/kooky/browser/chrome"
"github.com/xiazemin/kooky/browser/chrome"
)

func main() {
dir, _ := os.UserConfigDir() // "/<USER>/Library/Application Support/"
cookiesFile := dir + "/Google/Chrome/Default/Cookies"
cookies, err := chrome.ReadCookies(cookiesFile)
if err != nil {
log.Fatal(err)
}
for _, cookie := range cookies {
cookiesSeq := chrome.TraverseCookies(cookiesFile).OnlyCookies()
for cookie := range cookiesSeq {
fmt.Println(cookie)
}
}
Expand All @@ -100,30 +88,27 @@ import (
"log"
"os"

"github.com/browserutils/kooky/browser/safari"
"github.com/xiazemin/kooky/browser/safari"
)

func main() {
dir, _ := os.UserHomeDir()
cookiesFile := dir + "/Library/Cookies/Cookies.binarycookies"
cookies, err := safari.ReadCookies(cookiesFile)
if err != nil {
log.Fatal(err)
}
for _, cookie := range cookies {
cookiesFile := dir + "/Library/Containers/com.apple.Safari/Data/Library/Cookies/Cookies.binarycookies"
cookiesSeq := safari.TraverseCookies(cookiesFile).OnlyCookies()
for cookie := range cookiesSeq {
fmt.Println(cookie)
}
}
```

## Thanks/references
- Thanks to [@dacort](http://github.com/dacort) for MacOS cookie decrypting
- Thanks to [@dacort](https://github.com/dacort) for MacOS cookie decrypting
code at https://gist.github.com/dacort/bd6a5116224c594b14db.
- Thanks to [@as0ler](http://github.com/as0ler)
(and originally [@satishb3](http://github.com/satishb3) I believe) for
- Thanks to [@as0ler](https://github.com/as0ler)
(and originally [@satishb3](https://github.com/satishb3) I believe) for
Safari cookie-reading Python code at https://github.com/as0ler/BinaryCookieReader.
- Thanks to all the people who have contributed functionality and fixes:
- [@srlehn](http://github.com/srlehn) - many fixes, Linux support for Chrome, added about a dozen browsers!
- [@zippoxer](http://github.com/zippoxer) - Windows support for Chrome
- [@adamdecaf](http://github.com/adamdecaf) - Firefox support
- [@srlehn](https://github.com/srlehn) - many fixes, Linux support for Chrome, added about a dozen browsers!
- [@zippoxer](https://github.com/zippoxer) - Windows support for Chrome
- [@adamdecaf](https://github.com/adamdecaf) - Firefox support
- [@barnardb](https://github.com/barnardb) - better row abstraction, fixing column length errors
8 changes: 4 additions & 4 deletions auto_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ package kooky_test
import (
"fmt"

"github.com/browserutils/kooky"
_ "github.com/browserutils/kooky/browser/all" // This registers all cookiestore finders!
// _ "github.com/browserutils/kooky/browser/chrome" // load only the chrome cookiestore finder
"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 ExampleReadCookies_all() {
// try to find cookie stores in default locations and
// read the cookies from them.
// decryption is handled automatically.
cookies := kooky.ReadCookies()
cookies := kooky.AllCookies()

for _, cookie := range cookies {
fmt.Println(cookie)
Expand Down
32 changes: 16 additions & 16 deletions browser/all/import.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
package all

import (
_ "github.com/browserutils/kooky/browser/browsh"
_ "github.com/browserutils/kooky/browser/chrome"
_ "github.com/browserutils/kooky/browser/chromium"
_ "github.com/browserutils/kooky/browser/dillo"
_ "github.com/browserutils/kooky/browser/edge"
_ "github.com/browserutils/kooky/browser/elinks"
_ "github.com/browserutils/kooky/browser/epiphany"
_ "github.com/browserutils/kooky/browser/firefox"
_ "github.com/browserutils/kooky/browser/ie"
_ "github.com/browserutils/kooky/browser/konqueror"
_ "github.com/browserutils/kooky/browser/lynx"
_ "github.com/browserutils/kooky/browser/netscape"
_ "github.com/browserutils/kooky/browser/opera"
_ "github.com/browserutils/kooky/browser/safari"
_ "github.com/browserutils/kooky/browser/uzbl"
_ "github.com/browserutils/kooky/browser/w3m"
_ "github.com/xiazemin/kooky/browser/browsh"
_ "github.com/xiazemin/kooky/browser/chrome"
_ "github.com/xiazemin/kooky/browser/chromium"
_ "github.com/xiazemin/kooky/browser/dillo"
_ "github.com/xiazemin/kooky/browser/edge"
_ "github.com/xiazemin/kooky/browser/elinks"
_ "github.com/xiazemin/kooky/browser/epiphany"
_ "github.com/xiazemin/kooky/browser/firefox"
_ "github.com/xiazemin/kooky/browser/ie"
_ "github.com/xiazemin/kooky/browser/konqueror"
_ "github.com/xiazemin/kooky/browser/lynx"
_ "github.com/xiazemin/kooky/browser/netscape"
_ "github.com/xiazemin/kooky/browser/opera"
_ "github.com/xiazemin/kooky/browser/safari"
_ "github.com/xiazemin/kooky/browser/uzbl"
_ "github.com/xiazemin/kooky/browser/w3m"
)
35 changes: 9 additions & 26 deletions browser/browsh/browsh.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,19 @@
package browsh

import (
"net/http"
"context"

"github.com/browserutils/kooky"
"github.com/browserutils/kooky/internal/cookies"
"github.com/browserutils/kooky/internal/firefox"
"github.com/xiazemin/kooky"
"github.com/xiazemin/kooky/internal/cookies"
"github.com/xiazemin/kooky/internal/firefox"
)

func ReadCookies(filename string, filters ...kooky.Filter) ([]*kooky.Cookie, error) {
s, err := cookieStore(filename, filters...)
if err != nil {
return nil, err
}
defer s.Close()

return s.ReadCookies(filters...)
func ReadCookies(ctx context.Context, filename string, filters ...kooky.Filter) ([]*kooky.Cookie, error) {
return cookies.SingleRead(cookieStore, filename, filters...).ReadAllCookies(ctx)
}

// CookieJar returns an initiated http.CookieJar based on the cookies stored by
// the browsh browser. Set cookies are memory stored and do not modify any
// browser files.
func CookieJar(filename string, filters ...kooky.Filter) (http.CookieJar, error) {
j, err := cookieStore(filename, filters...)
if err != nil {
return nil, err
}
defer j.Close()
if err := j.InitJar(); err != nil {
return nil, err
}
return j, nil
func TraverseCookies(filename string, filters ...kooky.Filter) kooky.CookieSeq {
return cookies.SingleRead(cookieStore, filename, filters...)
}

// CookieStore has to be closed with CookieStore.Close() after use.
Expand All @@ -44,5 +27,5 @@ func cookieStore(filename string, filters ...kooky.Filter) (*cookies.CookieJar,
s.FileNameStr = filename
s.BrowserStr = `browsh`

return &cookies.CookieJar{CookieStore: s}, nil
return cookies.NewCookieJar(s, filters...), nil
}
28 changes: 15 additions & 13 deletions browser/browsh/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
"os"
"path/filepath"

"github.com/browserutils/kooky"
"github.com/browserutils/kooky/internal/cookies"
"github.com/browserutils/kooky/internal/firefox"
"github.com/xiazemin/kooky"
"github.com/xiazemin/kooky/internal/cookies"
"github.com/xiazemin/kooky/internal/firefox"
)

type browshFinder struct{}
Expand All @@ -19,23 +19,25 @@ func init() {
kooky.RegisterFinder(`browsh`, &browshFinder{})
}

func (f *browshFinder) FindCookieStores() ([]kooky.CookieStore, error) {
dotConfig, err := os.UserConfigDir()
if err != nil {
return nil, err
}
func (f *browshFinder) FindCookieStores() kooky.CookieStoreSeq {
return func(yield func(kooky.CookieStore, error) bool) {
dotConfig, err := os.UserConfigDir()
if err != nil {
_ = yield(nil, err)
return
}

var ret = []kooky.CookieStore{
&cookies.CookieJar{
st := &cookies.CookieJar{
CookieStore: &firefox.CookieStore{
DefaultCookieStore: cookies.DefaultCookieStore{
BrowserStr: `browsh`,
IsDefaultProfileBool: true,
FileNameStr: filepath.Join(dotConfig, `browsh`, `firefox_profile`, `cookies.sqlite`),
},
},
},
}
if !yield(st, nil) {
return
}
}

return ret, nil
}
35 changes: 9 additions & 26 deletions browser/chrome/chrome.go
Original file line number Diff line number Diff line change
@@ -1,36 +1,19 @@
package chrome

import (
"net/http"
"context"

"github.com/browserutils/kooky"
"github.com/browserutils/kooky/internal/chrome"
"github.com/browserutils/kooky/internal/cookies"
"github.com/xiazemin/kooky"
"github.com/xiazemin/kooky/internal/chrome"
"github.com/xiazemin/kooky/internal/cookies"
)

func ReadCookies(filename string, filters ...kooky.Filter) ([]*kooky.Cookie, error) {
s, err := cookieStore(filename, filters...)
if err != nil {
return nil, err
}
defer s.Close()

return s.ReadCookies(filters...)
func ReadCookies(ctx context.Context, filename string, filters ...kooky.Filter) ([]*kooky.Cookie, error) {
return cookies.SingleRead(cookieStore, filename, filters...).ReadAllCookies(ctx)
}

// CookieJar returns an initiated http.CookieJar based on the cookies stored by
// the Chrome browser. Set cookies are memory stored and do not modify any
// browser files.
func CookieJar(filename string, filters ...kooky.Filter) (http.CookieJar, error) {
j, err := cookieStore(filename, filters...)
if err != nil {
return nil, err
}
defer j.Close()
if err := j.InitJar(); err != nil {
return nil, err
}
return j, nil
func TraverseCookies(filename string, filters ...kooky.Filter) kooky.CookieSeq {
return cookies.SingleRead(cookieStore, filename, filters...)
}

// CookieStore has to be closed with CookieStore.Close() after use.
Expand All @@ -43,5 +26,5 @@ func cookieStore(filename string, filters ...kooky.Filter) (*cookies.CookieJar,
s.FileNameStr = filename
s.BrowserStr = `chrome`

return &cookies.CookieJar{CookieStore: s}, nil
return cookies.NewCookieJar(s, filters...), nil
}
13 changes: 7 additions & 6 deletions browser/chrome/chrome_test.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package chrome

import (
"context"
"testing"
"time"

"github.com/browserutils/kooky"
"github.com/browserutils/kooky/internal/chrome"
"github.com/browserutils/kooky/internal/testutils"
"github.com/xiazemin/kooky"
"github.com/xiazemin/kooky/internal/chrome"
"github.com/xiazemin/kooky/internal/testutils"
)

// d18f6247db68045dfbab126d814baf2cf1512141391
func TestReadCookies(t *testing.T) {
testCookiesPath, err := testutils.GetTestDataFilePath("chrome-macos-cookie-db.sqlite") // this test file was created on macos
if err != nil {
Expand All @@ -24,15 +24,16 @@ func TestReadCookies(t *testing.T) {
oldPassword := s.SetKeyringPassword([]byte("ChromeSafeStoragePasswrd"))
defer s.SetKeyringPassword(oldPassword)

cookies, err := s.ReadCookies()
cookies, err := s.TraverseCookies().ReadAllCookies(context.Background())
if err != nil {
t.Fatal(err)
}

domain := "news.ycombinator.com"
name := "user"

cookies = kooky.FilterCookies(cookies, kooky.Domain(domain), kooky.Name(name))
ctx := context.Background()
cookies = kooky.FilterCookies(ctx, cookies, kooky.Domain(domain), kooky.Name(name)).Collect(ctx)
if len(cookies) == 0 {
t.Fatalf("Found no cookies with domain=%q, name=%q", domain, name)
}
Expand Down
Loading