From 6dd80ee7b67095db533c7710c921ad50af6add46 Mon Sep 17 00:00:00 2001 From: Haelnorr Date: Fri, 2 Jan 2026 18:37:01 +1100 Subject: [PATCH] migrated out cookies module --- go.mod | 5 +- go.sum | 4 + internal/handler/account.go | 2 +- internal/handler/login.go | 4 +- internal/handler/logout.go | 5 +- internal/handler/reauthenticatate.go | 5 +- internal/handler/register.go | 4 +- internal/middleware/authentication.go | 6 +- internal/view/layout/global.templ | 108 +++++++++++++------------- pkg/cookies/functions.go | 37 --------- pkg/cookies/pagefrom.go | 36 --------- pkg/cookies/tokens.go | 78 ------------------- 12 files changed, 73 insertions(+), 221 deletions(-) delete mode 100644 pkg/cookies/functions.go delete mode 100644 pkg/cookies/pagefrom.go delete mode 100644 pkg/cookies/tokens.go diff --git a/go.mod b/go.mod index b010702..e7137b3 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,9 @@ module projectreshoot go 1.25.5 require ( + git.haelnorr.com/h/golib/cookies v0.9.0 git.haelnorr.com/h/golib/hlog v0.9.0 - git.haelnorr.com/h/golib/jwt v0.9.0 + git.haelnorr.com/h/golib/jwt v0.9.2 git.haelnorr.com/h/golib/tmdb v0.8.0 github.com/a-h/templ v0.3.977 github.com/joho/godotenv v1.5.1 @@ -15,8 +16,6 @@ require ( modernc.org/sqlite v1.35.0 ) -replace git.haelnorr.com/h/golib/jwt v0.9.0 => /home/haelnorr/projects/golib/jwt - require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect diff --git a/go.sum b/go.sum index 90de7ef..4f3e3f3 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,9 @@ +git.haelnorr.com/h/golib/cookies v0.9.0 h1:Vf+eX1prHkKuGrQon1BHY87yaPc1H+HJFRXDOV/AuWs= +git.haelnorr.com/h/golib/cookies v0.9.0/go.mod h1:y1385YExI9gLwckCVDCYVcsFXr6N7T3brJjnJD2QIuo= git.haelnorr.com/h/golib/hlog v0.9.0 h1:ib8n2MdmiRK2TF067p220kXmhDe9aAnlcsgpuv+QpvE= git.haelnorr.com/h/golib/hlog v0.9.0/go.mod h1:oOlzb8UVHUYP1k7dN5PSJXVskAB2z8EYgRN85jAi0Zk= +git.haelnorr.com/h/golib/jwt v0.9.2 h1:l1Ow7DPGACAU54CnMP/NlZjdc4nRD1wr3xZ8a7taRvU= +git.haelnorr.com/h/golib/jwt v0.9.2/go.mod h1:fbuPrfucT9lL0faV5+Q5Gk9WFJxPlwzRPpbMQKYZok4= git.haelnorr.com/h/golib/tmdb v0.8.0 h1:OQ6M2TB8FHm8fJD7/ebfWm63Duzfp0kmFX9genEig34= git.haelnorr.com/h/golib/tmdb v0.8.0/go.mod h1:mGKYa3o3z0IsQ5EO3MPmnL2Bwl2sSMsUHXVgaIGR7Z0= github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= diff --git a/internal/handler/account.go b/internal/handler/account.go index ee8e622..9ba5c44 100644 --- a/internal/handler/account.go +++ b/internal/handler/account.go @@ -10,8 +10,8 @@ import ( "projectreshoot/internal/view/component/account" "projectreshoot/internal/view/page" "projectreshoot/pkg/contexts" - "projectreshoot/pkg/cookies" + "git.haelnorr.com/h/golib/cookies" "git.haelnorr.com/h/golib/hlog" "github.com/pkg/errors" diff --git a/internal/handler/login.go b/internal/handler/login.go index fda9698..b9a92f6 100644 --- a/internal/handler/login.go +++ b/internal/handler/login.go @@ -10,8 +10,8 @@ import ( "projectreshoot/internal/view/component/form" "projectreshoot/internal/view/page" "projectreshoot/pkg/config" - "projectreshoot/pkg/cookies" + "git.haelnorr.com/h/golib/cookies" "git.haelnorr.com/h/golib/hlog" "git.haelnorr.com/h/golib/jwt" "github.com/pkg/errors" @@ -82,7 +82,7 @@ func LoginRequest( } rememberMe := checkRememberMe(r) - err = cookies.SetTokenCookies(w, r, config, tokenGen, user, true, rememberMe) + err = jwt.SetTokenCookies(w, r, tokenGen, user.ID, true, rememberMe, config.SSL) if err != nil { tx.Rollback() w.WriteHeader(http.StatusInternalServerError) diff --git a/internal/handler/logout.go b/internal/handler/logout.go index 3180dfa..34b09f7 100644 --- a/internal/handler/logout.go +++ b/internal/handler/logout.go @@ -7,8 +7,7 @@ import ( "strings" "time" - "projectreshoot/pkg/cookies" - + "git.haelnorr.com/h/golib/cookies" "git.haelnorr.com/h/golib/hlog" "git.haelnorr.com/h/golib/jwt" @@ -62,7 +61,7 @@ func revokeTokens( r *http.Request, ) error { // get the tokens from the cookies - atStr, rtStr := cookies.GetTokenStrings(r) + atStr, rtStr := jwt.GetTokenCookies(r) // revoke the refresh token first as the access token expires quicker // only matters if there is an error revoking the tokens err := revokeRefresh(tokenGen, tx, rtStr) diff --git a/internal/handler/reauthenticatate.go b/internal/handler/reauthenticatate.go index aa7b0b4..3757499 100644 --- a/internal/handler/reauthenticatate.go +++ b/internal/handler/reauthenticatate.go @@ -9,7 +9,6 @@ import ( "projectreshoot/internal/view/component/form" "projectreshoot/pkg/config" "projectreshoot/pkg/contexts" - "projectreshoot/pkg/cookies" "git.haelnorr.com/h/golib/hlog" "git.haelnorr.com/h/golib/jwt" @@ -24,7 +23,7 @@ func getTokens( r *http.Request, ) (*jwt.AccessToken, *jwt.RefreshToken, error) { // get the existing tokens from the cookies - atStr, rtStr := cookies.GetTokenStrings(r) + atStr, rtStr := jwt.GetTokenCookies(r) aT, err := tokenGen.ValidateAccess(tx, atStr) if err != nil { return nil, nil, errors.Wrap(err, "tokenGen.ValidateAccess") @@ -71,7 +70,7 @@ func refreshTokens( }[aT.TTL] // issue new tokens for the user user := contexts.GetUser(r.Context()) - err = cookies.SetTokenCookies(w, r, config, tokenGen, user.User, true, rememberMe) + err = jwt.SetTokenCookies(w, r, tokenGen, user.ID, true, rememberMe, config.SSL) if err != nil { return errors.Wrap(err, "cookies.SetTokenCookies") } diff --git a/internal/handler/register.go b/internal/handler/register.go index 5202667..25e7587 100644 --- a/internal/handler/register.go +++ b/internal/handler/register.go @@ -10,8 +10,8 @@ import ( "projectreshoot/internal/view/component/form" "projectreshoot/internal/view/page" "projectreshoot/pkg/config" - "projectreshoot/pkg/cookies" + "git.haelnorr.com/h/golib/cookies" "git.haelnorr.com/h/golib/hlog" "git.haelnorr.com/h/golib/jwt" @@ -80,7 +80,7 @@ func RegisterRequest( } rememberMe := checkRememberMe(r) - err = cookies.SetTokenCookies(w, r, config, tokenGen, user, true, rememberMe) + err = jwt.SetTokenCookies(w, r, tokenGen, user.ID, true, rememberMe, config.SSL) if err != nil { tx.Rollback() w.WriteHeader(http.StatusInternalServerError) diff --git a/internal/middleware/authentication.go b/internal/middleware/authentication.go index 302dd35..efa0b25 100644 --- a/internal/middleware/authentication.go +++ b/internal/middleware/authentication.go @@ -11,8 +11,8 @@ import ( "projectreshoot/internal/models" "projectreshoot/pkg/config" "projectreshoot/pkg/contexts" - "projectreshoot/pkg/cookies" + "git.haelnorr.com/h/golib/cookies" "git.haelnorr.com/h/golib/hlog" "git.haelnorr.com/h/golib/jwt" "github.com/pkg/errors" @@ -38,7 +38,7 @@ func refreshAuthTokens( }[ref.TTL] // Set fresh to true because new tokens coming from refresh request - err = cookies.SetTokenCookies(w, req, config, tokenGen, user, false, rememberMe) + err = jwt.SetTokenCookies(w, req, tokenGen, user.ID, false, rememberMe, config.SSL) if err != nil { return nil, errors.Wrap(err, "cookies.SetTokenCookies") } @@ -60,7 +60,7 @@ func getAuthenticatedUser( r *http.Request, ) (*contexts.AuthenticatedUser, error) { // Get token strings from cookies - atStr, rtStr := cookies.GetTokenStrings(r) + atStr, rtStr := jwt.GetTokenCookies(r) if atStr == "" && rtStr == "" { return nil, errors.New("No token strings provided") } diff --git a/internal/view/layout/global.templ b/internal/view/layout/global.templ index b099138..758cce1 100644 --- a/internal/view/layout/global.templ +++ b/internal/view/layout/global.templ @@ -19,18 +19,20 @@ templ Global(title string) { > + (function () { + let theme = localStorage.getItem("theme") || "system"; + if (theme === "system") { + theme = window.matchMedia("(prefers-color-scheme: dark)").matches + ? "dark" + : "light"; + } + if (theme === "dark") { + document.documentElement.classList.add("dark"); + } else { + document.documentElement.classList.remove("dark"); + } + })(); + { title } @@ -40,48 +42,48 @@ templ Global(title string) { + // uncomment this line to enable logging of htmx events + // htmx.logAll(); + + const bodyData = { + showError500: false, + showError503: false, + showConfirmPasswordModal: false, + handleHtmxBeforeOnLoad(event) { + const requestPath = event.detail.pathInfo.requestPath; + if (requestPath === "/reauthenticate") { + // handle password incorrect on refresh attempt + if (event.detail.xhr.status === 445) { + event.detail.shouldSwap = true; + event.detail.isError = false; + } else if (event.detail.xhr.status === 200) { + this.showConfirmPasswordModal = false; + } + } + }, + // handle errors from the server on HTMX requests + handleHtmxError(event) { + const errorCode = event.detail.errorInfo.error; + + // internal server error + if (errorCode.includes("Code 500")) { + this.showError500 = true; + setTimeout(() => (this.showError500 = false), 6000); + } + // service not available error + if (errorCode.includes("Code 503")) { + this.showError503 = true; + setTimeout(() => (this.showError503 = false), 6000); + } + + // user is authorized but needs to refresh their login + if (errorCode.includes("Code 444")) { + this.showConfirmPasswordModal = true; + } + }, + }; + 0 for TTL in seconds) -func SetCookie( - w http.ResponseWriter, - name string, - path string, - value string, - maxAge int, -) { - http.SetCookie(w, &http.Cookie{ - Name: name, - Value: value, - Path: path, - HttpOnly: true, - MaxAge: maxAge, - }) -} diff --git a/pkg/cookies/pagefrom.go b/pkg/cookies/pagefrom.go deleted file mode 100644 index fa4cb0b..0000000 --- a/pkg/cookies/pagefrom.go +++ /dev/null @@ -1,36 +0,0 @@ -package cookies - -import ( - "net/http" - "net/url" -) - -// Check the value of "pagefrom" cookie, delete the cookie, and return the value -func CheckPageFrom(w http.ResponseWriter, r *http.Request) string { - pageFromCookie, err := r.Cookie("pagefrom") - if err != nil { - return "/" - } - pageFrom := pageFromCookie.Value - DeleteCookie(w, pageFromCookie.Name, pageFromCookie.Path) - return pageFrom -} - -// Check the referer of the request, and if it matches the trustedHost, set -// the "pagefrom" cookie as the Path of the referer -func SetPageFrom(w http.ResponseWriter, r *http.Request, trustedHost string) { - referer := r.Referer() - parsedURL, err := url.Parse(referer) - if err != nil { - return - } - var pageFrom string - if parsedURL.Path == "" || parsedURL.Host != trustedHost { - pageFrom = "/" - } else if parsedURL.Path == "/login" || parsedURL.Path == "/register" { - return - } else { - pageFrom = parsedURL.Path - } - SetCookie(w, "pagefrom", "/", pageFrom, 0) -} diff --git a/pkg/cookies/tokens.go b/pkg/cookies/tokens.go deleted file mode 100644 index bd7079c..0000000 --- a/pkg/cookies/tokens.go +++ /dev/null @@ -1,78 +0,0 @@ -package cookies - -import ( - "net/http" - "time" - - "projectreshoot/internal/models" - "projectreshoot/pkg/config" - - "git.haelnorr.com/h/golib/jwt" - "github.com/pkg/errors" -) - -// Get the value of the access and refresh tokens -func GetTokenStrings( - r *http.Request, -) (acc string, ref string) { - accCookie, accErr := r.Cookie("access") - refCookie, refErr := r.Cookie("refresh") - var ( - accStr string = "" - refStr string = "" - ) - if accErr == nil { - accStr = accCookie.Value - } - if refErr == nil { - refStr = refCookie.Value - } - return accStr, refStr -} - -// Set a token with the provided details -func setToken( - w http.ResponseWriter, - config *config.Config, - token string, - scope string, - exp int64, - rememberme bool, -) { - tokenCookie := &http.Cookie{ - Name: scope, - Value: token, - Path: "/", - HttpOnly: true, - SameSite: http.SameSiteLaxMode, - Secure: config.SSL, - } - if rememberme { - tokenCookie.Expires = time.Unix(exp, 0) - } - http.SetCookie(w, tokenCookie) -} - -// Generate new tokens for the user and set them as cookies -func SetTokenCookies( - w http.ResponseWriter, - r *http.Request, - config *config.Config, - tokenGen *jwt.TokenGenerator, - user *models.User, - fresh bool, - rememberMe bool, -) error { - at, atexp, err := tokenGen.NewAccess(user.ID, fresh, rememberMe) - if err != nil { - return errors.Wrap(err, "jwt.GenerateAccessToken") - } - rt, rtexp, err := tokenGen.NewRefresh(user.ID, rememberMe) - if err != nil { - return errors.Wrap(err, "jwt.GenerateRefreshToken") - } - // Don't set the cookies until we know no errors occured - setToken(w, config, at, "access", atexp, rememberMe) - setToken(w, config, rt, "refresh", rtexp, rememberMe) - return nil -}