summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/controllers/sessions/controller.go7
-rw-r--r--app/controllers/sessions/controller_test.go10
-rw-r--r--go.mod8
-rw-r--r--go.sum10
-rw-r--r--pkg/web/cookie/expire.go14
-rw-r--r--pkg/web/cookie/new.go18
-rw-r--r--pkg/web/cookie/option.go57
-rw-r--r--pkg/web/cookie/option_test.go53
-rw-r--r--pkg/web/cookie/reset.go16
9 files changed, 56 insertions, 137 deletions
diff --git a/app/controllers/sessions/controller.go b/app/controllers/sessions/controller.go
index b9240c6..50aac63 100644
--- a/app/controllers/sessions/controller.go
+++ b/app/controllers/sessions/controller.go
@@ -4,6 +4,7 @@ import (
"net/http"
"time"
+ xcookie "github.com/xlgmokha/x/pkg/cookie"
"github.com/xlgmokha/x/pkg/log"
"gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/middleware"
"gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/oidc"
@@ -37,8 +38,8 @@ func (c *Controller) New(w http.ResponseWriter, r *http.Request) {
http.SetCookie(w, cookie.New(
"oauth_state",
nonce,
- cookie.WithSameSite(http.SameSiteLaxMode),
- cookie.WithExpiration(time.Now().Add(10*time.Minute)),
+ xcookie.WithSameSite(http.SameSiteLaxMode),
+ xcookie.WithExpiration(time.Now().Add(10*time.Minute)),
))
http.Redirect(w, r, url, http.StatusFound)
}
@@ -138,7 +139,7 @@ func (c *Controller) Create(w http.ResponseWriter, r *http.Request) {
return
}
- http.SetCookie(w, cookie.New("session", encoded, cookie.WithExpiration(tokens.Expiry)))
+ http.SetCookie(w, cookie.New("session", encoded, xcookie.WithExpiration(tokens.Expiry)))
http.Redirect(w, r, "/dashboard", http.StatusFound)
}
diff --git a/app/controllers/sessions/controller_test.go b/app/controllers/sessions/controller_test.go
index c40dbe7..8efc813 100644
--- a/app/controllers/sessions/controller_test.go
+++ b/app/controllers/sessions/controller_test.go
@@ -6,10 +6,12 @@ import (
"net/http"
"net/url"
"testing"
+ "time"
"github.com/oauth2-proxy/mockoidc"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ "github.com/xlgmokha/x/pkg/x"
xcfg "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/cfg"
"gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/domain"
"gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/oidc"
@@ -150,6 +152,14 @@ func TestSessions(t *testing.T) {
sub, err := token.Claims.GetSubject()
require.NoError(t, err)
assert.Equal(t, user.Subject, sub)
+
+ assert.Equal(t, "/", cookie.Path)
+ assert.Equal(t, "localhost", cookie.Domain)
+ assert.Equal(t, "session", cookie.Name)
+ assert.Zero(t, cookie.SameSite)
+ assert.Equal(t, x.Must(time.Parse(time.RFC3339, tokens["expiry"].(string))).Unix(), cookie.Expires.Unix())
+ assert.True(t, cookie.HttpOnly)
+ assert.True(t, cookie.Secure)
})
t.Run("stores the refresh token in a session cookie", func(t *testing.T) {
diff --git a/go.mod b/go.mod
index 64f6872..125aea5 100644
--- a/go.mod
+++ b/go.mod
@@ -9,8 +9,8 @@ require (
github.com/rs/zerolog v1.34.0
github.com/stretchr/testify v1.10.0
github.com/testcontainers/testcontainers-go v0.36.0
- github.com/xlgmokha/x v0.0.0-20250430185455-b691eda27477
- golang.org/x/oauth2 v0.29.0
+ github.com/xlgmokha/x v0.0.0-20250507143633-104ccfbf81d1
+ golang.org/x/oauth2 v0.30.0
)
require (
@@ -69,8 +69,8 @@ require (
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
- golang.org/x/crypto v0.37.0 // indirect
- golang.org/x/sys v0.32.0 // indirect
+ golang.org/x/crypto v0.38.0 // indirect
+ golang.org/x/sys v0.33.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
diff --git a/go.sum b/go.sum
index 144f9b8..8b0718a 100644
--- a/go.sum
+++ b/go.sum
@@ -138,6 +138,8 @@ github.com/xlgmokha/x v0.0.0-20250428220023-07723124c0a2 h1:bMuGvVZ8MEV3De4yn/+5
github.com/xlgmokha/x v0.0.0-20250428220023-07723124c0a2/go.mod h1:axGPKzoJCNTmPJxYqN5l+Z9gGbPe0yolkT61a5p3QiI=
github.com/xlgmokha/x v0.0.0-20250430185455-b691eda27477 h1:oeKrn9BSDSic5MTXKhQesxhIhB7byxl86IHtCD+yw4k=
github.com/xlgmokha/x v0.0.0-20250430185455-b691eda27477/go.mod h1:axGPKzoJCNTmPJxYqN5l+Z9gGbPe0yolkT61a5p3QiI=
+github.com/xlgmokha/x v0.0.0-20250507143633-104ccfbf81d1 h1:iW9a6GiZ8kYduHkUXl6v81CpKyBzSqBMh/fBMqBStKk=
+github.com/xlgmokha/x v0.0.0-20250507143633-104ccfbf81d1/go.mod h1:FhvU8e/Zcpo0Lw8n5WkPtqQwzGrLD7FhFEi0MbEBLGk=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
@@ -168,6 +170,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
+golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
+golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@@ -184,6 +188,8 @@ golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
+golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
+golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -209,6 +215,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
+golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -216,6 +224,7 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
+golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
@@ -224,6 +233,7 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
+golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/pkg/web/cookie/expire.go b/pkg/web/cookie/expire.go
index b44fc38..7d90274 100644
--- a/pkg/web/cookie/expire.go
+++ b/pkg/web/cookie/expire.go
@@ -1,7 +1,17 @@
package cookie
-import "net/http"
+import (
+ "net/http"
+
+ "github.com/xlgmokha/x/pkg/cookie"
+ "github.com/xlgmokha/x/pkg/env"
+)
func Expire(w http.ResponseWriter, name string) {
- http.SetCookie(w, Reset(name))
+ cookie.Expire(w, name,
+ cookie.WithPath("/"),
+ cookie.WithDomain(env.Fetch("HOST", "localhost")),
+ cookie.WithHttpOnly(true),
+ cookie.WithSecure(true),
+ )
}
diff --git a/pkg/web/cookie/new.go b/pkg/web/cookie/new.go
index 8c04dd6..be0241d 100644
--- a/pkg/web/cookie/new.go
+++ b/pkg/web/cookie/new.go
@@ -3,6 +3,7 @@ package cookie
import (
"net/http"
+ "github.com/xlgmokha/x/pkg/cookie"
"github.com/xlgmokha/x/pkg/env"
"github.com/xlgmokha/x/pkg/x"
)
@@ -10,15 +11,14 @@ import (
func New(name, value string, options ...x.Option[*http.Cookie]) *http.Cookie {
options = x.Prepend[x.Option[*http.Cookie]](
options,
- With(func(c *http.Cookie) {
- c.Name = name
- c.Value = value // TODO:: digitally sign the value
- }),
- WithPath("/"),
- WithHttpOnly(true),
- WithSecure(true),
- WithSameSite(http.SameSiteDefaultMode),
- WithDomain(env.Fetch("HOST", "localhost")),
+ cookie.WithName(name),
+ cookie.WithValue(value), // TODO:: digitally sign the value
+ cookie.WithPath("/"),
+ cookie.WithHttpOnly(true),
+ cookie.WithSecure(true),
+ cookie.WithSameSite(http.SameSiteDefaultMode),
+ cookie.WithDomain(env.Fetch("HOST", "localhost")),
)
+
return x.New[*http.Cookie](options...)
}
diff --git a/pkg/web/cookie/option.go b/pkg/web/cookie/option.go
deleted file mode 100644
index 58a2e93..0000000
--- a/pkg/web/cookie/option.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package cookie
-
-import (
- "net/http"
- "time"
-
- "github.com/xlgmokha/x/pkg/x"
-)
-
-func With(with func(*http.Cookie)) x.Option[*http.Cookie] {
- return func(c *http.Cookie) *http.Cookie {
- with(c)
- return c
- }
-}
-
-func WithPath(value string) x.Option[*http.Cookie] {
- return With(func(c *http.Cookie) {
- c.Path = value
- })
-}
-
-func WithHttpOnly(value bool) x.Option[*http.Cookie] {
- return With(func(c *http.Cookie) {
- c.HttpOnly = value
- })
-}
-
-func WithSecure(value bool) x.Option[*http.Cookie] {
- return With(func(c *http.Cookie) {
- c.Secure = value
- })
-}
-
-func WithDomain(value string) x.Option[*http.Cookie] {
- return With(func(c *http.Cookie) {
- c.Domain = value
- })
-}
-
-func WithSameSite(value http.SameSite) x.Option[*http.Cookie] {
- return With(func(c *http.Cookie) {
- c.SameSite = value
- })
-}
-
-func WithExpiration(expires time.Time) x.Option[*http.Cookie] {
- return With(func(c *http.Cookie) {
- c.Expires = expires
- if expires.Before(time.Now()) {
- c.MaxAge = -1
- } else {
- duration := time.Until(expires).Round(time.Second)
- c.MaxAge = int(duration.Seconds())
- }
- })
-}
diff --git a/pkg/web/cookie/option_test.go b/pkg/web/cookie/option_test.go
deleted file mode 100644
index 97913ba..0000000
--- a/pkg/web/cookie/option_test.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package cookie
-
-import (
- "net/http"
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestOption(t *testing.T) {
- t.Run("WithPath", func(t *testing.T) {
- assert.Equal(t, "/blah", New("name", "value", WithPath("/blah")).Path)
- })
-
- t.Run("WithHttpOnly", func(t *testing.T) {
- assert.False(t, New("x", "v", WithHttpOnly(false)).HttpOnly)
- assert.True(t, New("x", "v", WithHttpOnly(true)).HttpOnly)
- })
-
- t.Run("WithSecure", func(t *testing.T) {
- assert.False(t, New("x", "v", WithSecure(false)).Secure)
- assert.True(t, New("x", "v", WithSecure(true)).Secure)
- })
-
- t.Run("WithDomain", func(t *testing.T) {
- assert.Equal(t, "example.com", New("x", "v", WithDomain("example.com")).Domain)
- })
-
- t.Run("WithSameSite", func(t *testing.T) {
- assert.Equal(t, http.SameSiteLaxMode, New("x", "v", WithSameSite(http.SameSiteLaxMode)).SameSite)
- assert.Equal(t, http.SameSiteStrictMode, New("x", "v", WithSameSite(http.SameSiteStrictMode)).SameSite)
- assert.Equal(t, http.SameSiteNoneMode, New("x", "v", WithSameSite(http.SameSiteNoneMode)).SameSite)
- })
-
- t.Run("WithExpiration", func(t *testing.T) {
- now := time.Now()
-
- t.Run("with future time", func(t *testing.T) {
- expires := now.Add(1 * time.Second)
- cookie := New("x", "v", WithExpiration(expires))
- assert.Equal(t, expires, cookie.Expires)
- assert.Equal(t, 1, cookie.MaxAge)
- })
-
- t.Run("with past time", func(t *testing.T) {
- expires := now.Add(-1 * time.Second)
- cookie := New("x", "v", WithExpiration(expires))
- assert.Equal(t, expires, cookie.Expires)
- assert.Equal(t, -1, cookie.MaxAge)
- })
- })
-}
diff --git a/pkg/web/cookie/reset.go b/pkg/web/cookie/reset.go
index 167cdb6..39625e6 100644
--- a/pkg/web/cookie/reset.go
+++ b/pkg/web/cookie/reset.go
@@ -2,20 +2,18 @@ package cookie
import (
"net/http"
- "time"
+ "github.com/xlgmokha/x/pkg/cookie"
"github.com/xlgmokha/x/pkg/env"
)
func Reset(name string) *http.Cookie {
- return New(
+ return cookie.Reset(
name,
- "",
- WithExpiration(time.Unix(0, 0)),
- WithPath("/"),
- WithHttpOnly(true),
- WithSecure(true),
- WithSameSite(http.SameSiteDefaultMode),
- WithDomain(env.Fetch("HOST", "localhost")),
+ cookie.WithPath("/"),
+ cookie.WithHttpOnly(true),
+ cookie.WithSecure(true),
+ cookie.WithSameSite(http.SameSiteDefaultMode),
+ cookie.WithDomain(env.Fetch("HOST", "localhost")),
)
}