Skip to content
Open
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
57 changes: 50 additions & 7 deletions browser/chromium/chromium.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,66 @@ import (
"github.com/browserutils/kooky/internal/cookies"
)

func ReadCookies(ctx context.Context, filename string, filters ...kooky.Filter) ([]*kooky.Cookie, error) {
return cookies.SingleRead(cookieStore, filename, filters...).ReadAllCookies(ctx)
// KeyringConfig configures how the cookie store retrieves
// the decryption key from the system keyring.
//
// All fields are optional. When empty, defaults are derived
// from the browser name (e.g. "Chromium" → "Chromium Safe Storage").
//
// See the exported Keyring* variables for known browser configurations.
type KeyringConfig struct {
Browser string // browser name for display/filtering, e.g. "vivaldi" (defaults to "chromium")
Account string // keychain account, e.g. "Chrome", "Microsoft Edge"
Storage string // keychain entry, e.g. "Chrome Safe Storage" (derived from Account if empty)
Application string // secret service / kwallet app attr, e.g. "chrome" (derived from Account if empty)
PortalAppID string // xdg-desktop-portal app ID, e.g. "org.chromium.Chromium"
}

func TraverseCookies(filename string, filters ...kooky.Filter) kooky.CookieSeq {
return cookies.SingleRead(cookieStore, filename, filters...)
// Known keyring configurations for Chromium-based browsers
// that do not have their own package.
var (
// linux: $XDG_CONFIG_HOME/vivaldi/Default/Cookies
KeyringConfigVivaldiLinux = &KeyringConfig{Browser: `vivaldi`, Account: `Chrome`, PortalAppID: `com.vivaldi.Vivaldi`}
// macOS: ~/Library/Application Support/Vivaldi/Default/Cookies
KeyringConfigVivaldiDarwin = &KeyringConfig{Browser: `vivaldi`, Account: `Vivaldi`}

// Application may be "arc" or "chrome" depending on version
KeyringConfigArc = &KeyringConfig{Browser: `arc`, Account: `Arc`}
)

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

func TraverseCookies(filename string, keyring *KeyringConfig, filters ...kooky.Filter) kooky.CookieSeq {
return cookies.SingleRead(cookieStoreFunc(keyring), filename, filters...)
}

// CookieStore has to be closed with CookieStore.Close() after use.
func CookieStore(filename string, filters ...kooky.Filter) (kooky.CookieStore, error) {
return cookieStore(filename, filters...)
func CookieStore(filename string, keyring *KeyringConfig, filters ...kooky.Filter) (kooky.CookieStore, error) {
return cookieStore(filename, keyring, filters...)
}

func cookieStoreFunc(keyring *KeyringConfig) func(filename string, filters ...kooky.Filter) (*cookies.CookieJar, error) {
return func(filename string, filters ...kooky.Filter) (*cookies.CookieJar, error) {
return cookieStore(filename, keyring, filters...)
}
}

func cookieStore(filename string, filters ...kooky.Filter) (*cookies.CookieJar, error) {
func cookieStore(filename string, keyring *KeyringConfig, filters ...kooky.Filter) (*cookies.CookieJar, error) {
s := &chrome.CookieStore{}
s.FileNameStr = filename
s.BrowserStr = `chromium`
if keyring != nil && len(keyring.Browser) > 0 {
s.BrowserStr = keyring.Browser
}

if keyring != nil {
s.SetSafeStorage(keyring.Account, keyring.Storage, keyring.Application)
if len(keyring.PortalAppID) > 0 {
s.SetPortalAppID(keyring.PortalAppID)
}
}

return cookies.NewCookieJar(s, filters...), nil
}
2 changes: 1 addition & 1 deletion internal/chrome/cookiestore.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type CookieStore struct {
KeyringPasswordBytes []byte
PasswordBytes []byte
DecryptionMethod func(data, password []byte, dbVersion int64) ([]byte, error)
storage safeStorage
keyringConfig safeStorage
dbVersion int64
dbFile *os.File
}
Expand Down
48 changes: 24 additions & 24 deletions internal/chrome/derivatives.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,69 +9,69 @@ import (

type safeStorage struct {
account string // e.g. "Chromium", "Chrome", "Microsoft Edge"
name string // e.g. "Chromium Safe Storage"
storage string // e.g. "Chromium Safe Storage"
application string // Secret Service application attr, e.g. "chromium", "chrome"
portalAppID string // xdg-desktop-portal app ID, e.g. "com.vivaldi.Vivaldi"
}

func (s *CookieStore) SetSafeStorage(account, name, application string) {
func (s *CookieStore) SetSafeStorage(account, storage, application string) {
if s == nil {
return
}
if len(account) == 0 && len(s.BrowserStr) > 0 {
account = cases.Title(language.English, cases.Compact).String(s.BrowserStr)
}
if len(name) == 0 {
name = account + ` Safe Storage`
if len(storage) == 0 {
storage = account + ` Safe Storage`
}
if len(application) == 0 {
application = strings.ToLower(account)
}
s.storage.account = account
s.storage.name = name
s.storage.application = application
s.keyringConfig.account = account
s.keyringConfig.storage = storage
s.keyringConfig.application = application
}

func (s *CookieStore) safeStorageName() string {
func (s *CookieStore) SetPortalAppID(id string) {
if s == nil {
return ``
return
}
if len(s.storage.name) == 0 {
s.keyringConfig.portalAppID = id
}

func (s *CookieStore) ensureKeyring() {
if s != nil && len(s.keyringConfig.storage) == 0 {
s.SetSafeStorage(``, ``, ``)
}
return s.storage.name
}

func (s *CookieStore) safeStorageAccount() string {
if s == nil {
return ``
}
if len(s.storage.name) == 0 {
s.SetSafeStorage(``, ``, ``)
}
return s.storage.account
s.ensureKeyring()
return s.keyringConfig.account
}

func (s *CookieStore) safeStorageApplication() string {
func (s *CookieStore) safeStorageName() string {
if s == nil {
return ``
}
if len(s.storage.name) == 0 {
s.SetSafeStorage(``, ``, ``)
}
return s.storage.application
s.ensureKeyring()
return s.keyringConfig.storage
}

func (s *CookieStore) SetPortalAppID(id string) {
func (s *CookieStore) safeStorageApplication() string {
if s == nil {
return
return ``
}
s.storage.portalAppID = id
s.ensureKeyring()
return s.keyringConfig.application
}

func (s *CookieStore) portalAppIDValue() string {
if s == nil {
return ``
}
return s.storage.portalAppID
return s.keyringConfig.portalAppID
}