Files
go-extractor/cookiejar.go
Steve Dudenhoeffer 963696cd62
All checks were successful
CI / vet (pull_request) Successful in 40s
CI / build (pull_request) Successful in 1m22s
CI / test (pull_request) Successful in 1m28s
enhance: thread-safe CookieJar, SameSite cookie attr, dynamic Google countries
- Wrap staticCookieJar in struct with sync.RWMutex for thread safety
- Add SameSite field to Cookie struct with Strict/Lax/None constants
- Update Playwright cookie conversion functions for SameSite
- Replace hardcoded 4-country switch with dynamic country code generation

Closes #20, #22, #23
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 16:34:54 +00:00

93 lines
2.0 KiB
Go

package extractor
import (
"net/url"
"strings"
"time"
)
// SameSite represents the SameSite attribute of a cookie.
type SameSite string
const (
SameSiteStrict SameSite = "Strict"
SameSiteLax SameSite = "Lax"
SameSiteNone SameSite = "None"
)
type Cookie struct {
Host string
Path string
Expires time.Time
Secure bool
HttpOnly bool
Name string
Value string
SameSite SameSite
}
func (c Cookie) IsTargetMatch(target string) (bool, error) {
u, err := url.Parse(target)
if err != nil {
return false, err
}
// the host of the cookie is the same as the host of the target
// if the cookie host starts with a dot, that means it matches any subdomain
if c.Host == u.Host || strings.HasPrefix(c.Host, ".") && strings.HasSuffix(u.Host, c.Host) {
if c.Path == "" {
return true, nil
}
if !strings.HasPrefix(u.Path, c.Path) {
return false, nil
}
// if the cookie path is a prefix of the target path, then it's a match
// so now these would both match:
// cookie path: /foo
// target path: /foo/bar
// cookie path: /foo
// target path: /foosball
// because foseball is not an actual match, we need to check to see that either the path is an exact match
// or that the next character in the target path is a slash
if len(u.Path) > len(c.Path) && !strings.HasSuffix(c.Path, "/") && u.Path[len(c.Path)] != '/' {
return false, nil
}
return true, nil
}
return false, nil
}
type CookieJar interface {
GetAll() ([]Cookie, error)
Get(url string) ([]Cookie, error)
Set(cookie Cookie) error
Delete(cookie Cookie) error
}
// ReadOnlyCookieJar is a wrapper for CookieJar that allows only read operations on cookies, but all
// write operations are no-ops.
type ReadOnlyCookieJar struct {
Jar CookieJar
}
func (r ReadOnlyCookieJar) GetAll() ([]Cookie, error) {
return r.Jar.GetAll()
}
func (r ReadOnlyCookieJar) Get(url string) ([]Cookie, error) {
return r.Jar.Get(url)
}
func (r ReadOnlyCookieJar) Set(_ Cookie) error {
return nil
}
func (r ReadOnlyCookieJar) Delete(_ Cookie) error {
return nil
}