feat: adds nonce check for oidc token exchange

- feat: adds filters support on conversations list
- refactor middlewares.go
- Adds new paginate.go for generating filtered paginated SQL queries this removes sql generation code from the conversations package.
- rename some components
- removes hardcoded `/uploads/`
This commit is contained in:
Abhinav Raut
2024-10-17 04:21:22 +05:30
parent 98df9efd63
commit 2b25ce32b6
54 changed files with 780 additions and 384 deletions

View File

@@ -4,33 +4,59 @@ import (
"net/http"
"github.com/abhinavxd/artemis/internal/envelope"
umodels "github.com/abhinavxd/artemis/internal/user/models"
"github.com/valyala/fasthttp"
"github.com/zerodha/fastglue"
)
// authMiddleware does session validation, CSRF checking, and permission enforcement.
func authMiddleware(handler fastglue.FastRequestHandler, object, action string) fastglue.FastRequestHandler {
// reqAuth makes sure the user is logged in.
func reqAuth(handler fastglue.FastRequestHandler) fastglue.FastRequestHandler {
return func(r *fastglue.Request) error {
app := r.Context.(*App)
var (
app = r.Context.(*App)
)
// Validate session and fetch user.
userSession, err := app.auth.ValidateSession(r)
if err != nil || userSession.ID <= 0 {
app.lo.Error("error validating session", "error", err)
return r.SendErrorEnvelope(http.StatusUnauthorized, "Invalid or expired session", nil, envelope.PermissionError)
}
// Set user in the request context.
user, err := app.user.Get(userSession.ID)
if err != nil {
return sendErrorEnvelope(r, err)
}
r.RequestCtx.SetUserValue("user", user)
return handler(r)
}
}
// reqAuthAndPerm does session validation, CSRF, and permission enforcement.
func reqAuthAndPerm(handler fastglue.FastRequestHandler, object, action string) fastglue.FastRequestHandler {
return func(r *fastglue.Request) error {
var (
app = r.Context.(*App)
cookieToken = string(r.RequestCtx.Request.Header.Cookie("csrf_token"))
hdrToken = string(r.RequestCtx.Request.Header.Peek("X-CSRFTOKEN"))
)
if cookieToken == "" || hdrToken == "" || cookieToken != hdrToken {
app.lo.Error("csrf token mismatch", "cookie_token", cookieToken, "header_token", hdrToken)
return r.SendErrorEnvelope(http.StatusForbidden, "Invalid CSRF token", nil, envelope.PermissionError)
}
// Validate session and fetch user.
userSession, err := app.auth.ValidateSession(r)
if err != nil || userSession.ID <= 0 {
app.lo.Error("error validating session", "error", err)
return r.SendErrorEnvelope(http.StatusUnauthorized, "Invalid or expired session", nil, envelope.PermissionError)
}
user, err := app.user.Get(userSession.ID)
if err != nil {
return r.SendErrorEnvelope(http.StatusInternalServerError, "Something went wrong", nil, envelope.GeneralError)
}
// CSRF check.
cookieToken := string(r.RequestCtx.Request.Header.Cookie("csrf_token"))
hdrToken := string(r.RequestCtx.Request.Header.Peek("X-CSRFTOKEN"))
if cookieToken == "" || hdrToken == "" || cookieToken != hdrToken {
return r.SendErrorEnvelope(http.StatusForbidden, "Invalid CSRF token", nil, envelope.PermissionError)
return sendErrorEnvelope(r, err)
}
// Permission enforcement.
@@ -47,24 +73,25 @@ func authMiddleware(handler fastglue.FastRequestHandler, object, action string)
// Set user in the request context.
r.RequestCtx.SetUserValue("user", user)
// Proceed to the next handler.
return handler(r)
}
}
// getUserFromContext retrieves the authenticated user from the request context.
func getUserFromContext(r *fastglue.Request) (umodels.User, bool) {
user, ok := r.RequestCtx.UserValue("user").(umodels.User)
return user, ok
}
// authenticatedPage ensures the user is logged in; otherwise, redirects to the login page.
func authenticatedPage(handler fastglue.FastRequestHandler) fastglue.FastRequestHandler {
return func(r *fastglue.Request) error {
user, ok := getUserFromContext(r)
if ok && user.ID > 0 {
app := r.Context.(*App)
// Validate session.
user, err := app.auth.ValidateSession(r)
if err != nil {
app.lo.Error("error validating session", "error", err)
return r.SendErrorEnvelope(http.StatusUnauthorized, "Invalid or expired session", nil, envelope.PermissionError)
}
if user.ID > 0 {
return handler(r)
}
nextURI := r.RequestCtx.QueryArgs().Peek("next")
if len(nextURI) == 0 {
nextURI = r.RequestCtx.RequestURI()
@@ -78,7 +105,15 @@ func authenticatedPage(handler fastglue.FastRequestHandler) fastglue.FastRequest
// notAuthenticatedPage allows access only if the user is not authenticated; otherwise, redirects to the dashboard.
func notAuthenticatedPage(handler fastglue.FastRequestHandler) fastglue.FastRequestHandler {
return func(r *fastglue.Request) error {
user, _ := getUserFromContext(r)
app := r.Context.(*App)
// Validate session.
user, err := app.auth.ValidateSession(r)
if err != nil {
app.lo.Error("error validating session", "error", err)
return r.SendErrorEnvelope(http.StatusUnauthorized, "Invalid or expired session", nil, envelope.PermissionError)
}
if user.ID != 0 {
nextURI := string(r.RequestCtx.QueryArgs().Peek("next"))
if nextURI == "" {