From 72840af90e2dfbb417bc0716230ae985e19badda Mon Sep 17 00:00:00 2001 From: y a t s <65122-yats@users.noreply.gitgud.io> Date: Thu, 18 Jun 2026 10:02:16 -0400 Subject: [PATCH] Fix overwrite of existing cookiejar. --- auth.go | 23 ++++++++++++++++++----- auth_test.go | 7 +++++++ go.mod | 2 +- http.go | 41 +++++++++++++++++++++++++++-------------- libkiwi.go | 22 +++++++++++----------- 5 files changed, 64 insertions(+), 31 deletions(-) diff --git a/auth.go b/auth.go index 1f4affd..fd122c9 100644 --- a/auth.go +++ b/auth.go @@ -122,18 +122,31 @@ func (kf *KF) TwoFactorAuth(ctx context.Context, resp *http.Response, code uint3 return kf.Do(req) } -func (kf *KF) RefreshSession(ctx context.Context) error { +func (kf *KF) IsLoggedIn() bool { + return getCookie(kf.client.Jar, kf.domain, "xf_user") != nil +} + +func (kf *KF) RefreshSession(ctx context.Context) (string, error) { + const COOKIE_NAME = "xf_session" + + jar := kf.client.Jar + // Clear any existing session token to request a new one. - setCookie(kf.domain, kf.client.Jar, &http.Cookie{ - Name: "xf_session", + setCookie(jar, kf.domain, &http.Cookie{ + Name: COOKIE_NAME, Value: "", }) resp, err := kf.Get(ctx, kf.domain) if err != nil { - return err + return "", err } resp.Body.Close() - return nil + session := getCookie(jar, kf.domain, COOKIE_NAME) + if session == nil { + return "", errors.New("Failed to get new xf_session cookie.") + } + + return session.Value, nil } diff --git a/auth_test.go b/auth_test.go index 77f1142..dd70e41 100644 --- a/auth_test.go +++ b/auth_test.go @@ -63,6 +63,13 @@ func TestLogin(t *testing.T) { } t.Logf("2FA response: %+v\n", lr) } + + session, err := kf.RefreshSession(ctx) + if err != nil { + t.Error(err) + return + } + t.Logf("xf_session: %s\n", session) } func genTest2FACode() (uint32, error) { diff --git a/go.mod b/go.mod index 668b0f6..4b7443b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module gitgud.io/yats/libkiwi -go 1.26.1 +go 1.26.4 require ( gitgud.io/yats/cerberus v0.0.0-20260214165307-66e6f74a4be9 diff --git a/http.go b/http.go index 00275fa..c7e2e3b 100644 --- a/http.go +++ b/http.go @@ -14,25 +14,18 @@ import ( "golang.org/x/net/html/atom" ) -// Get XFToken (data-csrf) from page html. -func XFToken(page io.Reader) (string, error) { - z := html.NewTokenizer(page) - for i := z.Next(); i != html.ErrorToken; i = z.Next() { - tk := z.Token() - if tk.DataAtom == atom.Html { - for _, a := range tk.Attr { - switch a.Key { - case "data-csrf": - return a.Val, nil - } - } +func getCookie(jar http.CookieJar, u *url.URL, name string) *http.Cookie { + cookies := jar.Cookies(u) + for _, c := range cookies { + if c.Name == name { + return c } } - return "", ErrNoXFToken + return nil } -func setCookie(u *url.URL, jar http.CookieJar, newCookie *http.Cookie) { +func setCookie(jar http.CookieJar, u *url.URL, newCookie *http.Cookie) { cookies := jar.Cookies(u) for i, c := range cookies { @@ -48,6 +41,26 @@ func setCookie(u *url.URL, jar http.CookieJar, newCookie *http.Cookie) { jar.SetCookies(u, cookies) } +// Get XFToken (data-csrf) from page html. +func XFToken(page io.Reader) (string, error) { + z := html.NewTokenizer(page) + for i := z.Next(); i != html.ErrorToken; i = z.Next() { + tk := z.Token() + if tk.DataAtom != atom.Html { + continue + } + + for _, a := range tk.Attr { + switch a.Key { + case "data-csrf": + return a.Val, nil + } + } + } + + return "", ErrNoXFToken +} + func (kf *KF) Do(req *http.Request) (*http.Response, error) { var ( ctx = req.Context() diff --git a/libkiwi.go b/libkiwi.go index a0ad681..2b0f777 100644 --- a/libkiwi.go +++ b/libkiwi.go @@ -21,25 +21,25 @@ type KF struct { } // Supply your own http.Client to route through any proxies. -func NewKF(hc http.Client, host *url.URL) (*KF, error) { +func NewKF(hc http.Client, host *url.URL) (KF, error) { u, err := url.Parse(fmt.Sprintf("https://%s", host.Hostname())) if err != nil { - return nil, err + return KF{}, err } - jar, err := cookiejar.New(nil) - if err != nil { - return nil, err + if hc.Jar == nil { + jar, err := cookiejar.New(nil) + if err != nil { + return KF{}, err + } + + hc.Jar = jar } - hc.Jar = jar - - kf := &KF{ + return KF{ client: hc, domain: u, - } - - return kf, nil + }, nil } type User struct {