From 0ffc1ecae27fe6a0f68073d7368b3df61f1aa793 Mon Sep 17 00:00:00 2001 From: Simon Lehn <48837958+srlehn@users.noreply.github.com> Date: Sun, 14 Jun 2026 05:53:14 +0200 Subject: [PATCH] firefox: decode cookie expiry as milliseconds for user_version >= 16 (firefox 142+) Assisted-by: Claude Opus 4.8 --- browser/epiphany/cookiestore.go | 2 +- go.mod | 2 +- go.sum | 6 ++---- internal/chrome/cookiestore.go | 2 +- internal/firefox/README.md | 25 +++++++++++++++++++++++++ internal/firefox/cookiestore.go | 2 +- internal/firefox/firefox.go | 13 ++++++++++++- internal/utils/tablerow.go | 2 +- internal/utils/visittablerows.go | 2 +- 9 files changed, 45 insertions(+), 11 deletions(-) diff --git a/browser/epiphany/cookiestore.go b/browser/epiphany/cookiestore.go index 88b0dba..dfc846b 100644 --- a/browser/epiphany/cookiestore.go +++ b/browser/epiphany/cookiestore.go @@ -6,7 +6,7 @@ import ( "github.com/browserutils/kooky/internal/cookies" "github.com/browserutils/kooky/internal/utils" - "github.com/go-sqlite/sqlite3" + "github.com/browserutils/sqlite3" ) type epiphanyCookieStore struct { diff --git a/go.mod b/go.mod index 4d1feba..ae26ba9 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.24.0 require ( github.com/browserutils/ese v0.0.0-20260314233042-37b6a03a93ce - github.com/go-sqlite/sqlite3 v0.0.0-20180313105335-53dd8e640ee7 + github.com/browserutils/sqlite3 v0.0.2 github.com/godbus/dbus/v5 v5.2.2 github.com/keybase/go-keychain v0.0.1 github.com/pierrec/lz4/v4 v4.1.26 diff --git a/go.sum b/go.sum index 4ae6749..2bce007 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,10 @@ github.com/browserutils/ese v0.0.0-20260314233042-37b6a03a93ce h1:xb/LXUukZgVLMRnTUyEiCfMNH7KUCFOS4aOZnc/N+H8= github.com/browserutils/ese v0.0.0-20260314233042-37b6a03a93ce/go.mod h1:Rj9TJxm7cExxJmdec83sr8cjvyF3raBsszTFviSo/6U= +github.com/browserutils/sqlite3 v0.0.2 h1:RDSivmwoS5DauKYxh06G4Y+m6IX3da7Cq9Jh5x+oIUA= +github.com/browserutils/sqlite3 v0.0.2/go.mod h1:3i7CY1ba3/D+qovGRJyCgfDnu/lGc8sg8ieM6jIUO50= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-sqlite/sqlite3 v0.0.0-20180313105335-53dd8e640ee7 h1:ow5vK9Q/DSKkxbEIJHBST6g+buBDwdaDIyk1dGGwpQo= -github.com/go-sqlite/sqlite3 v0.0.0-20180313105335-53dd8e640ee7/go.mod h1:JxSQ+SvsjFb+p8Y+bn+GhTkiMfKVGBD0fq43ms2xw04= github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= github.com/gonuts/binary v0.2.0 h1:caITwMWAoQWlL0RNvv2lTU/AHqAJlVuu6nZmNgfbKW4= @@ -27,8 +27,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/zalando/go-keyring v0.2.6 h1:r7Yc3+H+Ux0+M72zacZoItR3UDxeWfKTcabvkI8ua9s= -github.com/zalando/go-keyring v0.2.6/go.mod h1:2TCrxYrbUNYfNS/Kgy/LSrkSQzZ5UPVH85RwfczwvcI= github.com/zalando/go-keyring v0.2.7 h1:YbqBw40+g4g69UNk4WsRM/fV9YErfVWwozE2+7Bn+7g= github.com/zalando/go-keyring v0.2.7/go.mod h1:tsMo+VpRq5NGyKfxoBVjCuMrG47yj8cmakZDO5QGii0= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= diff --git a/internal/chrome/cookiestore.go b/internal/chrome/cookiestore.go index 8c06679..a2594f4 100644 --- a/internal/chrome/cookiestore.go +++ b/internal/chrome/cookiestore.go @@ -4,7 +4,7 @@ import ( "errors" "os" - "github.com/go-sqlite/sqlite3" + "github.com/browserutils/sqlite3" "github.com/browserutils/kooky/internal/cookies" "github.com/browserutils/kooky/internal/utils" diff --git a/internal/firefox/README.md b/internal/firefox/README.md index e2de9c8..92208e5 100644 --- a/internal/firefox/README.md +++ b/internal/firefox/README.md @@ -46,3 +46,28 @@ CREATE TABLE moz_cookies( CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes) ) ``` + +## Cookie expiry units: seconds vs milliseconds + +SQLite `user_version` pragma: + +- `user_version <= 15` → `moz_cookies.expiry` is **Unix seconds** → `time.Unix(expiry, 0)` +- `user_version >= 16` → `moz_cookies.expiry` is **Unix milliseconds** → `time.UnixMilli(expiry)` + +Firefox 141 and earlier (schema ≤ 15) store seconds. +Firefox 142 introduced schema 16 and migrated existing values with +`UPDATE moz_cookies SET expiry = expiry * 1000` (Mozilla Bug 1972757). + +- Firefox 141, `user_version` 15, no `expiry` migration: + +- Firefox 142, `user_version` 16, `expiry = expiry * 1000`: + +- Firefox 141, `Cookie::Expiry()` documented as seconds: + +- Firefox 142, `Cookie::Expiry()` documented as milliseconds: + + +## Later schema versions + +Firefox 146 bumped `user_version` to 17, adding an `updateTime` column: + diff --git a/internal/firefox/cookiestore.go b/internal/firefox/cookiestore.go index 14b3313..eb8e272 100644 --- a/internal/firefox/cookiestore.go +++ b/internal/firefox/cookiestore.go @@ -7,7 +7,7 @@ import ( "github.com/browserutils/kooky/internal/cookies" "github.com/browserutils/kooky/internal/utils" - "github.com/go-sqlite/sqlite3" + "github.com/browserutils/sqlite3" ) type CookieStore struct { diff --git a/internal/firefox/firefox.go b/internal/firefox/firefox.go index 1b5c148..efc1990 100644 --- a/internal/firefox/firefox.go +++ b/internal/firefox/firefox.go @@ -24,6 +24,13 @@ func (s *CookieStore) TraverseCookies(filters ...kooky.Filter) kooky.CookieSeq { s.initContainersMap() + // Firefox 141/user_version 15 documented Cookie::Expiry() as seconds: + // https://hg.mozilla.org/releases/mozilla-release/raw-file/FIREFOX_141_0_RELEASE/netwerk/cookie/Cookie.h + // Firefox 142 bumped cookies.sqlite user_version to 16 and migrated + // moz_cookies.expiry from Unix seconds to Unix milliseconds (Mozilla Bug 1972757): + // https://hg.mozilla.org/releases/mozilla-release/raw-file/FIREFOX_142_0_RELEASE/netwerk/cookie/CookiePersistentStorage.cpp + expiryInMillis := s.Database.UserVersion() >= 16 + visitor := func(yield func(*kooky.Cookie, error) bool) func(rowId *int64, row utils.TableRow) error { return func(rowId *int64, row utils.TableRow) error { cookie := kooky.Cookie{} @@ -65,7 +72,11 @@ func (s *CookieStore) TraverseCookies(filters ...kooky.Filter) kooky.CookieSeq { // Expires if expiry, err := row.Int64(`expiry`); err == nil { - cookie.Expires = time.Unix(expiry, 0) + if expiryInMillis { + cookie.Expires = time.UnixMilli(expiry) + } else { + cookie.Expires = time.Unix(expiry, 0) + } } else { return err } diff --git a/internal/utils/tablerow.go b/internal/utils/tablerow.go index a309d5e..e8db007 100644 --- a/internal/utils/tablerow.go +++ b/internal/utils/tablerow.go @@ -4,7 +4,7 @@ import ( "fmt" "reflect" - "github.com/go-sqlite/sqlite3" + "github.com/browserutils/sqlite3" ) type TableRow struct { diff --git a/internal/utils/visittablerows.go b/internal/utils/visittablerows.go index 78a6c13..80480b8 100644 --- a/internal/utils/visittablerows.go +++ b/internal/utils/visittablerows.go @@ -3,7 +3,7 @@ package utils import ( "fmt" - "github.com/go-sqlite/sqlite3" + "github.com/browserutils/sqlite3" ) func VisitTableRows(db *sqlite3.DbFile, tableName string, columnNameMappings map[string]string, f func(rowID *int64, row TableRow) error) error {