diff --git a/README.md b/README.md index dd3acfe..7a6b021 100644 --- a/README.md +++ b/README.md @@ -309,7 +309,7 @@ Here's a simple example of loading data from a session and saving new values: ```go func SomeFunction(ctx echo.Context) error { - sess, err := session.Get("some-session-key", ctx) + sess, err := session.Get(ctx, "some-session-key") if err != nil { return err } @@ -1256,7 +1256,6 @@ Thank you to all of the following amazing projects for making this possible. - [bulma](https://github.com/jgthms/bulma) - [docker](https://www.docker.com/) - [echo](https://github.com/labstack/echo) -- [echo-contrib](https://github.com/labstack/echo-contrib) - [ent](https://github.com/ent/ent) - [go](https://go.dev/) - [gocache](https://github.com/eko/gocache) diff --git a/go.mod b/go.mod index 2c8f419..fd052b6 100644 --- a/go.mod +++ b/go.mod @@ -12,10 +12,10 @@ require ( github.com/eko/gocache/store/redis/v4 v4.2.1 github.com/go-playground/validator/v10 v10.19.0 github.com/golang-jwt/jwt v3.2.2+incompatible + github.com/gorilla/context v1.1.2 github.com/gorilla/sessions v1.2.2 github.com/hibiken/asynq v0.24.1 github.com/jackc/pgx/v4 v4.18.3 - github.com/labstack/echo-contrib v0.17.1 github.com/labstack/echo/v4 v4.12.0 github.com/labstack/gommon v0.4.2 github.com/redis/go-redis/v9 v9.5.1 @@ -44,7 +44,6 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/gorilla/context v1.1.2 // indirect github.com/gorilla/securecookie v1.1.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl/v2 v2.20.1 // indirect diff --git a/go.sum b/go.sum index 62235d1..3d70492 100644 --- a/go.sum +++ b/go.sum @@ -166,8 +166,6 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/labstack/echo-contrib v0.17.1 h1:7I/he7ylVKsDUieaGRZ9XxxTYOjfQwVzHzUYrNykfCU= -github.com/labstack/echo-contrib v0.17.1/go.mod h1:SnsCZtwHBAZm5uBSAtQtXQHI3wqEA73hvTn0bYMKnZA= github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0= github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM= github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= diff --git a/pkg/context/context.go b/pkg/context/context.go index 7271f29..95e18ad 100644 --- a/pkg/context/context.go +++ b/pkg/context/context.go @@ -20,6 +20,9 @@ const ( // LoggerKey is the key value used to store a structured logger in context LoggerKey = "logger" + + // SessionKey is the key value used to store the session data in context + SessionKey = "session" ) // IsCanceledError determines if an error is due to a context cancelation diff --git a/pkg/handlers/router.go b/pkg/handlers/router.go index b7b6c2a..d1bc9fc 100644 --- a/pkg/handlers/router.go +++ b/pkg/handlers/router.go @@ -4,7 +4,6 @@ import ( "net/http" "github.com/gorilla/sessions" - "github.com/labstack/echo-contrib/session" echomw "github.com/labstack/echo/v4/middleware" "github.com/mikestefanello/pagoda/config" "github.com/mikestefanello/pagoda/pkg/middleware" @@ -40,7 +39,7 @@ func BuildRouter(c *services.Container) error { echomw.TimeoutWithConfig(echomw.TimeoutConfig{ Timeout: c.Config.App.Timeout, }), - session.Middleware(sessions.NewCookieStore([]byte(c.Config.App.EncryptionKey))), + middleware.Session(sessions.NewCookieStore([]byte(c.Config.App.EncryptionKey))), middleware.LoadAuthenticatedUser(c.Auth), middleware.ServeCachedPage(c.TemplateRenderer), echomw.CSRFWithConfig(echomw.CSRFConfig{ diff --git a/pkg/middleware/session.go b/pkg/middleware/session.go new file mode 100644 index 0000000..2e6a43c --- /dev/null +++ b/pkg/middleware/session.go @@ -0,0 +1,19 @@ +package middleware + +import ( + "github.com/gorilla/context" + "github.com/gorilla/sessions" + "github.com/labstack/echo/v4" + "github.com/mikestefanello/pagoda/pkg/session" +) + +// Session sets the session storage in the request context +func Session(store sessions.Store) echo.MiddlewareFunc { + return func(next echo.HandlerFunc) echo.HandlerFunc { + return func(ctx echo.Context) error { + defer context.Clear(ctx.Request()) + session.Store(ctx, store) + return next(ctx) + } + } +} diff --git a/pkg/middleware/session_test.go b/pkg/middleware/session_test.go new file mode 100644 index 0000000..b48181c --- /dev/null +++ b/pkg/middleware/session_test.go @@ -0,0 +1,24 @@ +package middleware + +import ( + "testing" + + "github.com/gorilla/sessions" + "github.com/mikestefanello/pagoda/pkg/session" + "github.com/mikestefanello/pagoda/pkg/tests" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestSession(t *testing.T) { + ctx, _ := tests.NewContext(c.Web, "/") + _, err := session.Get(ctx, "test") + assert.Equal(t, session.ErrStoreNotFound, err) + + store := sessions.NewCookieStore([]byte("secret")) + err = tests.ExecuteMiddleware(ctx, Session(store)) + require.NoError(t, err) + + _, err = session.Get(ctx, "test") + assert.NotEqual(t, session.ErrStoreNotFound, err) +} diff --git a/pkg/msg/msg.go b/pkg/msg/msg.go index e6309b9..e8274f5 100644 --- a/pkg/msg/msg.go +++ b/pkg/msg/msg.go @@ -2,9 +2,9 @@ package msg import ( "github.com/gorilla/sessions" - "github.com/labstack/echo-contrib/session" "github.com/labstack/echo/v4" "github.com/mikestefanello/pagoda/pkg/log" + "github.com/mikestefanello/pagoda/pkg/session" ) // Type is a message type @@ -78,7 +78,7 @@ func Get(ctx echo.Context, typ Type) []string { // getSession gets the flash message session func getSession(ctx echo.Context) (*sessions.Session, error) { - sess, err := session.Get(sessionName, ctx) + sess, err := session.Get(ctx, sessionName) if err != nil { log.Ctx(ctx).Error("cannot load flash message session", "error", err, diff --git a/pkg/services/auth.go b/pkg/services/auth.go index be1bcd3..b25ebf9 100644 --- a/pkg/services/auth.go +++ b/pkg/services/auth.go @@ -13,8 +13,8 @@ import ( "github.com/mikestefanello/pagoda/ent/passwordtoken" "github.com/mikestefanello/pagoda/ent/user" "github.com/mikestefanello/pagoda/pkg/context" + "github.com/mikestefanello/pagoda/pkg/session" - "github.com/labstack/echo-contrib/session" "github.com/labstack/echo/v4" "golang.org/x/crypto/bcrypt" ) @@ -62,7 +62,7 @@ func NewAuthClient(cfg *config.Config, orm *ent.Client) *AuthClient { // Login logs in a user of a given ID func (c *AuthClient) Login(ctx echo.Context, userID int) error { - sess, err := session.Get(authSessionName, ctx) + sess, err := session.Get(ctx, authSessionName) if err != nil { return err } @@ -73,7 +73,7 @@ func (c *AuthClient) Login(ctx echo.Context, userID int) error { // Logout logs the requesting user out func (c *AuthClient) Logout(ctx echo.Context) error { - sess, err := session.Get(authSessionName, ctx) + sess, err := session.Get(ctx, authSessionName) if err != nil { return err } @@ -83,7 +83,7 @@ func (c *AuthClient) Logout(ctx echo.Context) error { // GetAuthenticatedUserID returns the authenticated user's ID, if the user is logged in func (c *AuthClient) GetAuthenticatedUserID(ctx echo.Context) (int, error) { - sess, err := session.Get(authSessionName, ctx) + sess, err := session.Get(ctx, authSessionName) if err != nil { return 0, err } diff --git a/pkg/session/session.go b/pkg/session/session.go new file mode 100644 index 0000000..56fe573 --- /dev/null +++ b/pkg/session/session.go @@ -0,0 +1,27 @@ +package session + +import ( + "errors" + + "github.com/gorilla/sessions" + "github.com/labstack/echo/v4" + "github.com/mikestefanello/pagoda/pkg/context" +) + +// ErrStoreNotFound indicates that the session store was not present in the context +var ErrStoreNotFound = errors.New("session store not found") + +// Get returns a session +func Get(ctx echo.Context, name string) (*sessions.Session, error) { + s := ctx.Get(context.SessionKey) + if s == nil { + return nil, ErrStoreNotFound + } + store := s.(sessions.Store) + return store.Get(ctx.Request(), name) +} + +// Store sets the session storage in the context +func Store(ctx echo.Context, store sessions.Store) { + ctx.Set(context.SessionKey, store) +} diff --git a/pkg/session/session_test.go b/pkg/session/session_test.go new file mode 100644 index 0000000..62d5d89 --- /dev/null +++ b/pkg/session/session_test.go @@ -0,0 +1,23 @@ +package session + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/gorilla/sessions" + "github.com/labstack/echo/v4" + "github.com/stretchr/testify/assert" +) + +func TestGetStore(t *testing.T) { + e := echo.New() + req := httptest.NewRequest(http.MethodGet, "/", nil) + ctx := e.NewContext(req, httptest.NewRecorder()) + _, err := Get(ctx, "test") + assert.Equal(t, ErrStoreNotFound, err) + + Store(ctx, sessions.NewCookieStore([]byte("secret"))) + _, err = Get(ctx, "test") + assert.NoError(t, err) +} diff --git a/pkg/tests/tests.go b/pkg/tests/tests.go index 1266ce4..17dec0d 100644 --- a/pkg/tests/tests.go +++ b/pkg/tests/tests.go @@ -11,12 +11,12 @@ import ( "time" "github.com/mikestefanello/pagoda/ent" + "github.com/mikestefanello/pagoda/pkg/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/gorilla/sessions" - "github.com/labstack/echo-contrib/session" "github.com/labstack/echo/v4" ) @@ -29,8 +29,7 @@ func NewContext(e *echo.Echo, url string) (echo.Context, *httptest.ResponseRecor // InitSession initializes a session for a given Echo context func InitSession(ctx echo.Context) { - mw := session.Middleware(sessions.NewCookieStore([]byte("secret"))) - _ = ExecuteMiddleware(ctx, mw) + session.Store(ctx, sessions.NewCookieStore([]byte("secret"))) } // ExecuteMiddleware executes a middleware function on a given Echo context diff --git a/templates/layouts/auth.gohtml b/templates/layouts/auth.gohtml index 6279dd7..f315402 100644 --- a/templates/layouts/auth.gohtml +++ b/templates/layouts/auth.gohtml @@ -30,6 +30,6 @@ - {{template "footer"}} + {{template "footer" .}} \ No newline at end of file