package middleware import ( "fmt" "gitea.pena/PenaSide/heruvym/internal/utils/jwt_adapter" "github.com/gofiber/fiber/v2" "strings" "time" "gitea.pena/PenaSide/hlog" "github.com/rs/xid" ) // My MiddleWare with gorilla/mux type Middleware struct { logger hlog.Logger // mongo dal.LayerMongoDb allowedOrigins string allowedRoles map[string]string // key - path, value - roles } const sessionKey = "Sess" const HostKey = "host" func NewMiddleware( logger hlog.Logger, //mongo dal.LayerMongoDb, allowedOrigins string, allowedRoles map[string]string, ) *Middleware { return &Middleware{ logger: logger, allowedOrigins: allowedOrigins, allowedRoles: allowedRoles, } } func (mw *Middleware) MiddlewareLogger(ctx *fiber.Ctx) error { mw.logger.Emit(DebugHttpRequest{ Url: ctx.OriginalURL(), }) return ctx.Next() } func (mw *Middleware) MiddlewareOriginAccess(ctx *fiber.Ctx) error { origin := ctx.Get("Origin") if origin == "" { if mw.allowedOrigins != "*" && !strings.Contains(mw.allowedOrigins, origin) { mw.logger.Emit(ErrorOriginAccess{ Origin: origin, Url: ctx.OriginalURL(), }) return ctx.SendStatus(fiber.StatusForbidden) } } fmt.Println("MWLOGGER", ctx.Get("Origin")) return ctx.Next() } func recFn(rec interface{}) (int, string) { var ( code int message string ) if err, ok := rec.(error); ok { code = fiber.StatusInternalServerError message = err.Error() } else { code = fiber.StatusInternalServerError message = fmt.Sprintf("%v", rec) } return code, message } func (mw *Middleware) MiddlewareRecovery(ctx *fiber.Ctx) error { defer func() { if rec := recover(); rec != nil { code, message := recFn(rec) ctx.Status(code) if _, err := ctx.WriteString(message); err != nil { mw.logger.Emit(ErrorWritingPanicResponse{Err: err}) } mw.logger.Emit(ErrorPanicInHttpHandler{ Code: code, Message: message, Recovered: rec, }) } }() return ctx.Next() } func (mw *Middleware) MiddlewareJwt(ctx *fiber.Ctx) error { var ( token, role string adapter *jwt_adapter.JwtAdapter err error ) switch ctx.Get("Referer") { case "sadmin.pena": role = "admin" case "admin.pena": role = "admin" default: role = "user" } ctx.Locals(jwt_adapter.RoleKey, role) tokenCookie := ctx.Cookies(jwt_adapter.DefaultHeaderKey) if tokenCookie == "" { if ctx.Method() == "GET" { return ctx.Next() } headerToken := ctx.Get(jwt_adapter.DefaultHeaderKey) if headerToken == "" || !strings.HasPrefix(headerToken, "Bearer") { if ctx.Get(sessionKey) == "" { sessCookie := ctx.Cookies(sessionKey) if sessCookie == "" { id := xid.New().String() adapter = &jwt_adapter.JwtAdapter{Id: id} ctx.Cookie(&fiber.Cookie{ Name: sessionKey, Value: id, Expires: time.Now().Add(time.Hour * 24 * 30), SameSite: fiber.CookieSameSiteNoneMode, Secure: true, }) } else { adapter = &jwt_adapter.JwtAdapter{Id: sessCookie} } } else { adapter = &jwt_adapter.JwtAdapter{Id: ctx.Get(sessionKey)} } } else { token = strings.Replace(headerToken, "Bearer ", "", -1) } } else { token = tokenCookie } if adapter == nil { adapter, err = jwt_adapter.Decode(token) if err != nil { mw.logger.Emit(ErrorJwtAccess{Err: err}) return ctx.Status(fiber.StatusUnauthorized).SendString("Unauthorized") } } err = setJwtHeader(adapter, ctx.Response(), mw.logger) if err != nil { mw.logger.Emit(ErrorJwtAccess{Err: err}) return ctx.Status(fiber.StatusUnauthorized).SendString("Unauthorized") } ctx.Locals(jwt_adapter.DefaultHeaderKey, adapter) return ctx.Next() } func (mw *Middleware) ExtractHostMiddleware(ctx *fiber.Ctx) error { host := ctx.Get("Referer") if host != "" { ctx.Locals(HostKey, host) } return ctx.Next() } // todo useless? //func getJwtUserId(r *http.Request) (string, error) { // if jwtAdapter, ok := r.Context().Value(jwt_adapter.DefaultHeaderKey).(*jwt_adapter.JwtAdapter); ok { // return jwtAdapter.Id, nil // } // // return "", errors2.New("no token in context") //} // //func (mw *Middleware) MiddlewareRoleAccess(next http.Handler) http.Handler { // return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // // Если доступ по роли задан // if allowedRoles, ok := mw.allowedRoles[r.URL.Path]; ok { // // // Если роли не указаны // if allowedRoles == "" { // next.ServeHTTP(w, r) // return // } // /* // id, err := getJwtUserId(r) // // if err != nil { // mw.logger.Emit(ErrorRoleAccess{Err: err}) // http.Error(w, "internal server error", http.StatusInternalServerError) // return // }*/ // /* // role, err := mw.mongo.GetProfileRole(r.Context(), id) // // if err != nil { // mw.logger.Emit(ErrorRoleAccess{Err: err}) // http.Error(w, "internal server error", http.StatusInternalServerError) // return // } // */ // // Если у пользователя не задана роль - блокируем доступ // /* if role == "" { // err = errors.UserHaveNoRole("User have no role") // mw.logger.Emit(ErrorRoleAccess{err}) // http.Error(w, err.Error(), http.StatusForbidden) // return // } // // // Если указан астериск - доступ имеет любая роль // if !(allowedRoles == "*" || strings.Contains(allowedRoles, role)) { // err = errors.UserHaveNoRole("User role not allowed") // mw.logger.Emit(ErrorRoleAccess{err}) // http.Error(w, err.Error(), http.StatusForbidden) // return // }*/ // } // // next.ServeHTTP(w, r) // }) //} // //// MiddlewareJwtPlug jwt заглушка для отладки кода, удалить в релизе ///* //func (mw *Middleware) MiddlewareJwtPlug(next http.Handler) http.Handler { // return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // adapter := jwt_adapter.JwtAdapter{ID: "604b79aced1d431b9e911f56"} // adapter.Init() // adapter.SetUserID("604b79aced1d431b9e911f56") // ctx := context.WithValue(r.Context(), "JWT", &adapter) // // next.ServeHTTP(w, r.WithContext(ctx)) // }) //} //*/