kooky

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 8, 2021 License: MIT Imports: 6 Imported by: 0

README

kooky

PkgGoDev Go Report Card Lines of code No Maintenance Intended PRs Welcome MIT license

Reaching into browser-specific, vaguely documented, possibly concurrently modified cookie stores to pilfer cookies is a bad idea. Since you've arrived here, you're almost certainly going to do it anyway. Me too. And if we're going to do the Wrong Thing, at least let's try to Do it Right.

Package kooky contains routines to reach into cookie stores for Chrome, Firefox, Safari, ... and retrieve the cookies.

It aspires to be pure Go (I spent quite a while making go-sqlite/sqlite3 work for it).

It also aspires to work for all major browsers, on all three major platforms.

Status

Basic functionality works on Windows, MacOS and Linux. Some functions might not yet be implemented on some platforms. The API is currently not expected to be at all stable.

PRs more than welcome.

TODOs

  • Set up CI
  • Make it work on Windows. (Look at this and this to learn how to decrypt.)
  • Handle rows in Chrome's cookie DB with other than 14 columns (?)

Example usage

package main

import (
	"fmt"

	"github.com/zellyn/kooky"
	_ "github.com/zellyn/kooky/allbrowsers" // 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`))

	for _, cookie := range cookies {
		fmt.Println(cookie.Domain, cookie.Name, cookie.Value)
	}
 }
Chrome on macOS
package main

import (
	"fmt"
	"log"
	"os"

	"github.com/zellyn/kooky/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 {
		fmt.Println(cookie)
	}
}
Safari
package main

import (
	"fmt"
	"log"
	"os"

	"github.com/zellyn/kooky/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 {
		fmt.Println(cookie)
	}
}

Thanks/references

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/zellyn/kooky/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
	cookies, err := chrome.ReadCookies(cookieStoreFile)
	if err != nil {
		// TODO: handle the error
		return
	}

	for _, cookie := range cookies {
		fmt.Println(cookie)
	}
}
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func ExportCookies added in v0.2.0

func ExportCookies(w io.Writer, cookies []*Cookie)

ExportCookies() export "cookies" in the Netscape format.

curl, wget, ... use this format.

Example
package main

import (
	"os"

	"github.com/zellyn/kooky"
)

var cookieFile = `cookies.txt`

func main() {
	var cookies = []*kooky.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(file, cookies)
}
Output:

func FilterCookie added in v0.2.0

func FilterCookie(cookie *Cookie, filters ...Filter) bool

FilterCookie() tells if a "cookie" passes all "filters".

func RegisterFinder added in v0.2.0

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 Cookie struct {
	Domain   string
	Name     string
	Path     string
	Expires  time.Time
	Secure   bool
	HttpOnly bool
	Creation time.Time
	Value    string
}

Cookie is the struct returned by functions in this package. Similar to http.Cookie.

func FilterCookies added in v0.2.0

func FilterCookies(cookies []*Cookie, filters ...Filter) []*Cookie

FilterCookies() applies "filters" in order to the "cookies".

Example
package main

import (
	"github.com/zellyn/kooky"
	_ "github.com/zellyn/kooky/allbrowsers" // register cookiestore finders
)

var cookieName = `NID`

func main() {
	cookies := kooky.ReadCookies() // automatic read

	cookies = kooky.FilterCookies(
		cookies,
		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
	)
}
Output:

func ReadCookies added in v0.2.0

func ReadCookies(filters ...Filter) []*Cookie

ReadCookies() uses registered cookiestore finders to read cookies. Erronous reads are skipped.

Register cookie store finders for all browsers like this:

import _ "github.com/zellyn/kooky/allbrowsers"

Or only a specific browser:

import _ "github.com/zellyn/kooky/chrome"
Example (All)
package main

import (
	"fmt"

	"github.com/zellyn/kooky"
	_ "github.com/zellyn/kooky/allbrowsers" // This registers all cookiestore finders!
	// _ "github.com/zellyn/kooky/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.ReadCookies()

	for _, cookie := range cookies {
		fmt.Println(cookie)
	}
}

var _ struct{} // ignore this - for correct working of the documentation tool
Output:

func (Cookie) HTTPCookie added in v0.2.0

func (c Cookie) HTTPCookie() http.Cookie

HTTPCookie() returns an http.Cookie equivalent to this Cookie.

type CookieStore added in v0.2.0

type CookieStore interface {
	ReadCookies(...Filter) ([]*Cookie, error)
	Browser() string
	Profile() string
	IsDefaultProfile() bool
	FilePath() string
	Close() error
}

CookieStore represents a file, directory, etc containing cookies.

Call CookieStore.Close() after using any of its methods.

func FindAllCookieStores added in v0.2.0

func FindAllCookieStores() []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/zellyn/kooky/allbrowsers"

Or only a specific browser:

import _ "github.com/zellyn/kooky/chrome"
Example
package main

import (
	"fmt"

	"github.com/zellyn/kooky"
	_ "github.com/zellyn/kooky/allbrowsers" // register cookiestore finders
)

var filters = []kooky.Filter{
	kooky.Valid, // remove expired cookies
}

func main() {
	cookieStores := kooky.FindAllCookieStores()

	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
		}

		cookies, _ := store.ReadCookies(filters...)
		for _, cookie := range cookies {
			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 added in v0.2.0

type CookieStoreFinder interface {
	FindCookieStores() ([]CookieStore, error)
}

CookieStoreFinder tries to find cookie stores at default locations.

type Filter added in v0.2.0

type Filter func(*Cookie) bool

Filter is used for filtering cokies in ReadCookies() functions.

A cookie passes the Filter if Filter returns true.

Example (Regex)
package main

import (
	"fmt"
	"regexp"

	"github.com/zellyn/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{{Name: `test`, Value: `dGVzdA==`}}

	cookies = kooky.FilterCookies(
		cookies,
		ValueRegexMatch(reBase64), // filter cookies with the regex filter
		// kooky.Debug,            // print cookies after applying the regex filter
	)

	for _, cookie := range cookies {
		fmt.Println(cookie.Value)
		break // only first element
	}

}

func ValueRegexMatch(re *regexp.Regexp) kooky.Filter {
	return func(cookie *kooky.Cookie) bool {
		return cookie != nil && re != nil && re.Match([]byte(cookie.Value))
	}
}
Output:

dGVzdA==
var Debug Filter = 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 Expired Filter = func(cookie *Cookie) bool {
	return cookie != nil && cookie.Expires.Before(time.Now())

}
var HTTPOnly Filter = func(cookie *Cookie) bool {
	return cookie != nil && cookie.HttpOnly
}
var Secure Filter = func(cookie *Cookie) bool {
	return cookie != nil && cookie.Secure
}
var Valid Filter = func(cookie *Cookie) bool {
	return cookie != nil && cookie.Expires.After(time.Now())

}

func CreationAfter added in v0.2.0

func CreationAfter(u time.Time) Filter

func CreationBefore added in v0.2.0

func CreationBefore(u time.Time) Filter

func Domain added in v0.2.0

func Domain(domain string) Filter

func DomainContains added in v0.2.0

func DomainContains(substr string) Filter

func DomainHasPrefix added in v0.2.0

func DomainHasPrefix(prefix string) Filter

func DomainHasSuffix added in v0.2.0

func DomainHasSuffix(suffix string) Filter

func ExpiresAfter added in v0.2.0

func ExpiresAfter(u time.Time) Filter

func ExpiresBefore added in v0.2.0

func ExpiresBefore(u time.Time) Filter

func Name added in v0.2.0

func Name(name string) Filter

func NameContains added in v0.2.0

func NameContains(substr string) Filter

func NameHasPrefix added in v0.2.0

func NameHasPrefix(prefix string) Filter

func NameHasSuffix added in v0.2.0

func NameHasSuffix(suffix string) Filter

func Path added in v0.2.0

func Path(path string) Filter

func PathContains added in v0.2.0

func PathContains(substr string) Filter

func PathDepth added in v0.2.0

func PathDepth(depth int) Filter

func PathHasPrefix added in v0.2.0

func PathHasPrefix(prefix string) Filter

func PathHasSuffix added in v0.2.0

func PathHasSuffix(suffix string) Filter

func Value added in v0.2.0

func Value(value string) Filter

func ValueContains added in v0.2.0

func ValueContains(substr string) Filter

func ValueHasPrefix added in v0.2.0

func ValueHasPrefix(prefix string) Filter

func ValueHasSuffix added in v0.2.0

func ValueHasSuffix(suffix string) Filter

func ValueLen added in v0.2.0

func ValueLen(length int) Filter

Directories

Path Synopsis
Browsh Browser
Browsh Browser
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL