243 lines
6.1 KiB
Go
243 lines
6.1 KiB
Go
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)
|
||
}
|
||
}
|
||
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
|
||
)
|
||
|
||
fmt.Println("MLOW", ctx.Get("Referer"))
|
||
|
||
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))
|
||
// })
|
||
//}
|
||
//*/
|