feat(router): small refactoring

This commit is contained in:
Alexander 2025-05-21 15:29:10 +02:00
parent 24a220bc51
commit 088a227dec
29 changed files with 259 additions and 120 deletions

View file

@ -45,7 +45,7 @@ func main() {
log.Fatal(ctx, "failed while creating services: %s", err)
}
router, err := api.NewRouter(&cfg.HTTP, log)
router, err := api.NewRouter(&cfg.HTTP, log, nil, nil, nil, nil)
if err != nil {
log.Fatal(ctx, "failed while creating router: %s", err)
}

View file

@ -34,12 +34,11 @@ func main() {
log.Fatal(ctx, "can't init services: %s", err)
}
router, err := api.NewRouter(&cfg.HTTP, log)
router, err := api.NewRouter(&cfg.HTTP, log, builder.RateLimiter, builder.Auth, nil, builder.AuditTrail)
if err != nil {
log.Fatal(ctx, "failed while creating router: %s", err)
}
router.AddHandlers(api.NoPrefix, builder.IntegrationsAPI)
router.AddMiddlewares(builder.Auth.Middleware, builder.RateLimiter.Middleware, builder.AuditTrail.Middleware)
server.Run(ctx, log, &cfg.HTTP, router)
}

View file

@ -37,12 +37,11 @@ func main() {
log.Fatal(ctx, "can't init services: %s", err)
}
router, err := api.NewRouter(&cfg.HTTP, log)
router, err := api.NewRouter(&cfg.HTTP, log, builder.RateLimiter, builder.Authenticator, builder.Permissions, builder.AuditTrail)
if err != nil {
log.Fatal(ctx, "failed while creating router: %s", err)
}
router.AddHandlers(prefix, builder.SpotsAPI)
router.AddMiddlewares(builder.Auth.Middleware, builder.RateLimiter.Middleware, builder.AuditTrail.Middleware)
server.Run(ctx, log, &cfg.HTTP, router)
}

View file

@ -1,27 +1,28 @@
package analytics
import (
"github.com/go-playground/validator/v10"
"openreplay/backend/pkg/analytics/charts"
"openreplay/backend/pkg/metrics/database"
"time"
"github.com/go-playground/validator/v10"
"openreplay/backend/internal/config/analytics"
"openreplay/backend/pkg/analytics/cards"
"openreplay/backend/pkg/analytics/charts"
"openreplay/backend/pkg/analytics/dashboards"
"openreplay/backend/pkg/db/postgres/pool"
"openreplay/backend/pkg/logger"
"openreplay/backend/pkg/metrics/database"
"openreplay/backend/pkg/metrics/web"
"openreplay/backend/pkg/server/api"
"openreplay/backend/pkg/server/auth"
"openreplay/backend/pkg/server/auth/jwt"
"openreplay/backend/pkg/server/limiter"
"openreplay/backend/pkg/server/tracer"
)
type ServicesBuilder struct {
Auth auth.Auth
RateLimiter *limiter.UserRateLimiter
AuditTrail tracer.Tracer
Auth api.RouterMiddleware
RateLimiter api.RouterMiddleware
AuditTrail api.RouterMiddleware
CardsAPI api.Handlers
DashboardsAPI api.Handlers
ChartsAPI api.Handlers
@ -59,7 +60,7 @@ func NewServiceBuilder(log logger.Logger, cfg *analytics.Config, webMetrics web.
return nil, err
}
return &ServicesBuilder{
Auth: auth.NewAuth(log, cfg.JWTSecret, cfg.JWTSpotSecret, pgconn, nil, api.NoPrefix),
Auth: jwt.NewAuth(log, cfg.JWTSecret, pgconn),
RateLimiter: limiter.NewUserRateLimiter(10, 30, 1*time.Minute, 5*time.Minute),
AuditTrail: audiTrail,
CardsAPI: cardsHandlers,

View file

@ -41,11 +41,11 @@ type handlersImpl struct {
func (e *handlersImpl) GetAll() []*api.Description {
return []*api.Description{
{"/v1/analytics/{projectId}/cards", e.createCard, "POST"},
{"/v1/analytics/{projectId}/cards", e.getCardsPaginated, "GET"},
{"/v1/analytics/{projectId}/cards/{id}", e.getCard, "GET"},
{"/v1/analytics/{projectId}/cards/{id}", e.updateCard, "PUT"},
{"/v1/analytics/{projectId}/cards/{id}", e.deleteCard, "DELETE"},
{"/v1/analytics/{projectId}/cards", "POST", e.createCard, api.NoPermissions, api.DoNotTrack},
{"/v1/analytics/{projectId}/cards", "GET", e.getCardsPaginated, api.NoPermissions, api.DoNotTrack},
{"/v1/analytics/{projectId}/cards/{id}", "GET", e.getCard, api.NoPermissions, api.DoNotTrack},
{"/v1/analytics/{projectId}/cards/{id}", "PUT", e.updateCard, api.NoPermissions, api.DoNotTrack},
{"/v1/analytics/{projectId}/cards/{id}", "DELETE", e.deleteCard, api.NoPermissions, api.DoNotTrack},
}
}

View file

@ -41,8 +41,8 @@ type handlersImpl struct {
func (e *handlersImpl) GetAll() []*api.Description {
return []*api.Description{
{"/v1/analytics/{projectId}/cards/{id}/chart", e.getCardChartData, "POST"},
{"/v1/analytics/{projectId}/cards/{id}/try", e.getCardChartData, "POST"},
{"/v1/analytics/{projectId}/cards/{id}/chart", "POST", e.getCardChartData, api.NoPermissions, api.DoNotTrack},
{"/v1/analytics/{projectId}/cards/{id}/try", "POST", e.getCardChartData, api.NoPermissions, api.DoNotTrack},
}
}

View file

@ -41,13 +41,13 @@ type handlersImpl struct {
func (e *handlersImpl) GetAll() []*api.Description {
return []*api.Description{
{"/v1/analytics/{projectId}/dashboards", e.createDashboard, "POST"},
{"/v1/analytics/{projectId}/dashboards", e.getDashboards, "GET"},
{"/v1/analytics/{projectId}/dashboards/{id}", e.getDashboard, "GET"},
{"/v1/analytics/{projectId}/dashboards/{id}", e.updateDashboard, "PUT"},
{"/v1/analytics/{projectId}/dashboards/{id}", e.deleteDashboard, "DELETE"},
{"/v1/analytics/{projectId}/dashboards/{id}/cards", e.addCardToDashboard, "POST"},
{"/v1/analytics/{projectId}/dashboards/{id}/cards/{cardId}", e.removeCardFromDashboard, "DELETE"},
{"/v1/analytics/{projectId}/dashboards", "POST", e.createDashboard, api.NoPermissions, api.DoNotTrack},
{"/v1/analytics/{projectId}/dashboards", "GET", e.getDashboards, api.NoPermissions, api.DoNotTrack},
{"/v1/analytics/{projectId}/dashboards/{id}", "GET", e.getDashboard, api.NoPermissions, api.DoNotTrack},
{"/v1/analytics/{projectId}/dashboards/{id}", "PUT", e.updateDashboard, api.NoPermissions, api.DoNotTrack},
{"/v1/analytics/{projectId}/dashboards/{id}", "DELETE", e.deleteDashboard, api.NoPermissions, api.DoNotTrack},
{"/v1/analytics/{projectId}/dashboards/{id}/cards", "POST", e.addCardToDashboard, api.NoPermissions, api.DoNotTrack},
{"/v1/analytics/{projectId}/dashboards/{id}/cards/{cardId}", "DELETE", e.removeCardFromDashboard, api.NoPermissions, api.DoNotTrack},
}
}

View file

@ -24,8 +24,8 @@ func NewHandlers(log logger.Logger, responser *api.Responser, tokenizer *token.T
func (e *handlersImpl) GetAll() []*api.Description {
return []*api.Description{
{"/v1/web/conditions/{project}", e.getConditions, "GET"},
{"/v1/mobile/conditions/{project}", e.getConditions, "GET"},
{"GET", "/v1/web/conditions/{project}", e.getConditions, api.NoPermissions, api.DoNotTrack},
{"GET", "/v1/mobile/conditions/{project}", e.getConditions, api.NoPermissions, api.DoNotTrack},
}
}

View file

@ -38,7 +38,7 @@ func NewHandlers(log logger.Logger, responser *api.Responser, jsonSizeLimit int6
func (e *handlersImpl) GetAll() []*api.Description {
return []*api.Description{
{"/v1/web/feature-flags", e.featureFlagsHandlerWeb, "POST"},
{"POST", "/v1/web/feature-flags", e.featureFlagsHandlerWeb, api.NoPermissions, api.DoNotTrack},
}
}

View file

@ -34,11 +34,11 @@ func NewHandlers(log logger.Logger, cfg *integrationsCfg.Config, responser *api.
func (e *handlersImpl) GetAll() []*api.Description {
return []*api.Description{
{"/v1/integrations/{name}/{project}", e.createIntegration, "POST"},
{"/v1/integrations/{name}/{project}", e.getIntegration, "GET"},
{"/v1/integrations/{name}/{project}", e.updateIntegration, "PATCH"},
{"/v1/integrations/{name}/{project}", e.deleteIntegration, "DELETE"},
{"/v1/integrations/{name}/{project}/data/{session}", e.getIntegrationData, "GET"},
{"POST", "/v1/integrations/{name}/{project}", e.createIntegration, api.NoPermissions, api.DoNotTrack},
{"GET", "/v1/integrations/{name}/{project}", e.getIntegration, api.NoPermissions, api.DoNotTrack},
{"PATCH", "/v1/integrations/{name}/{project}", e.updateIntegration, api.NoPermissions, api.DoNotTrack},
{"DELETE", "/v1/integrations/{name}/{project}", e.deleteIntegration, api.NoPermissions, api.DoNotTrack},
{"GET", "/v1/integrations/{name}/{project}/data/{session}", e.getIntegrationData, api.NoPermissions, api.DoNotTrack},
}
}

View file

@ -1,26 +1,26 @@
package integrations
import (
"openreplay/backend/pkg/integrations/service"
"openreplay/backend/pkg/metrics/database"
"openreplay/backend/pkg/metrics/web"
"openreplay/backend/pkg/server/tracer"
"time"
"openreplay/backend/internal/config/integrations"
"openreplay/backend/pkg/db/postgres/pool"
integrationsAPI "openreplay/backend/pkg/integrations/api"
"openreplay/backend/pkg/integrations/service"
"openreplay/backend/pkg/logger"
"openreplay/backend/pkg/metrics/database"
"openreplay/backend/pkg/metrics/web"
"openreplay/backend/pkg/objectstorage/store"
"openreplay/backend/pkg/server/api"
"openreplay/backend/pkg/server/auth"
"openreplay/backend/pkg/server/auth/jwt"
"openreplay/backend/pkg/server/limiter"
"openreplay/backend/pkg/server/tracer"
)
type ServiceBuilder struct {
Auth auth.Auth
RateLimiter *limiter.UserRateLimiter
AuditTrail tracer.Tracer
Auth api.RouterMiddleware
RateLimiter api.RouterMiddleware
AuditTrail api.RouterMiddleware
IntegrationsAPI api.Handlers
}
@ -43,7 +43,7 @@ func NewServiceBuilder(log logger.Logger, cfg *integrations.Config, webMetrics w
return nil, err
}
builder := &ServiceBuilder{
Auth: auth.NewAuth(log, cfg.JWTSecret, "", pgconn, nil, api.NoPrefix),
Auth: jwt.NewAuth(log, cfg.JWTSecret, pgconn),
RateLimiter: limiter.NewUserRateLimiter(10, 30, 1*time.Minute, 5*time.Minute),
AuditTrail: auditrail,
IntegrationsAPI: handlers,

View file

@ -13,8 +13,6 @@ import (
func ReadBody(log logger.Logger, w http.ResponseWriter, r *http.Request, limit int64) ([]byte, error) {
body := http.MaxBytesReader(w, r.Body, limit)
bodyBytes, err := io.ReadAll(body)
// Close body
if closeErr := body.Close(); closeErr != nil {
log.Warn(r.Context(), "error while closing request body: %s", closeErr)
}
@ -47,8 +45,6 @@ func ReadCompressedBody(log logger.Logger, w http.ResponseWriter, r *http.Reques
} else {
bodyBytes, err = io.ReadAll(body)
}
// Close body
if closeErr := body.Close(); closeErr != nil {
log.Warn(r.Context(), "error while closing request body: %s", closeErr)
}

View file

@ -3,11 +3,16 @@ package api
import "net/http"
type Description struct {
Path string
Handler http.HandlerFunc
Method string
Path string
Method string
Handler http.HandlerFunc
Permissions []string
TrackName string
}
type Handlers interface {
GetAll() []*Description
}
var NoPermissions []string
var DoNotTrack string

View file

@ -7,6 +7,22 @@ import (
"openreplay/backend/internal/http/util"
)
type RouterMiddleware interface {
Middleware(next http.Handler) http.Handler
}
type defaultMiddleware struct{}
func NewDefaultMiddleware() RouterMiddleware {
return &defaultMiddleware{}
}
func (d *defaultMiddleware) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
next.ServeHTTP(w, r)
})
}
func (e *routerImpl) health(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}

View file

@ -12,37 +12,51 @@ import (
type Router interface {
AddHandlers(prefix string, handlers ...Handlers)
AddMiddlewares(middlewares ...func(http.Handler) http.Handler)
Get() http.Handler
}
type routerImpl struct {
log logger.Logger
cfg *common.HTTP
router *mux.Router
type endpoint struct {
Permissions []string
TrackName string
}
func NewRouter(cfg *common.HTTP, log logger.Logger) (Router, error) {
type routerImpl struct {
log logger.Logger
cfg *common.HTTP
router *mux.Router
endpoints map[string]*endpoint // map[method+path]endpoint
}
func NewRouter(cfg *common.HTTP, log logger.Logger, rateLimiter, authenticator, permissions, tracer RouterMiddleware) (Router, error) {
switch {
case cfg == nil:
return nil, fmt.Errorf("config is empty")
case log == nil:
return nil, fmt.Errorf("logger is empty")
case rateLimiter == nil:
rateLimiter = NewDefaultMiddleware()
case authenticator == nil:
authenticator = NewDefaultMiddleware()
case permissions == nil:
permissions = NewDefaultMiddleware()
case tracer == nil:
tracer = NewDefaultMiddleware()
}
e := &routerImpl{
log: log,
cfg: cfg,
router: mux.NewRouter(),
log: log,
cfg: cfg,
router: mux.NewRouter(),
endpoints: make(map[string]*endpoint),
}
e.initRouter()
return e, nil
}
func (e *routerImpl) initRouter() {
e.router.HandleFunc("/", e.health)
// Default middlewares
// Add all middlewares
e.router.Use(e.healthMiddleware)
e.router.Use(e.corsMiddleware)
e.router.Use(rateLimiter.Middleware)
e.router.Use(authenticator.Middleware)
e.router.Use(permissions.Middleware)
e.router.Use(tracer.Middleware)
return e, nil
}
const NoPrefix = ""
@ -54,16 +68,14 @@ func (e *routerImpl) AddHandlers(prefix string, handlers ...Handlers) {
if prefix != NoPrefix {
e.router.HandleFunc(prefix+handler.Path, handler.Handler).Methods(handler.Method, "OPTIONS")
}
e.endpoints[handler.Method+handler.Path] = &endpoint{
Permissions: handler.Permissions,
TrackName: handler.TrackName,
}
}
}
}
func (e *routerImpl) AddMiddlewares(middlewares ...func(http.Handler) http.Handler) {
for _, middleware := range middlewares {
e.router.Use(middleware)
}
}
func (e *routerImpl) Get() http.Handler {
return e.router
}

View file

@ -14,7 +14,7 @@ import (
)
type Auth interface {
IsAuthorized(authHeader string, permissions []string, isExtension bool) (*user.User, error)
IsAuthorized(authHeader string, isExtension bool) (*user.User, error)
Middleware(next http.Handler) http.Handler
}

View file

@ -2,7 +2,7 @@ package auth
import "openreplay/backend/pkg/server/user"
func (a *authImpl) IsAuthorized(authHeader string, permissions []string, isExtension bool) (*user.User, error) {
func (a *authImpl) IsAuthorized(authHeader string, isExtension bool) (*user.User, error) {
secret := a.secret
if isExtension {
secret = a.spotSecret

View file

@ -0,0 +1,98 @@
package jwt
import (
"fmt"
"net/http"
"strings"
ctxStore "github.com/docker/distribution/context"
"github.com/golang-jwt/jwt/v5"
"openreplay/backend/pkg/db/postgres/pool"
"openreplay/backend/pkg/logger"
"openreplay/backend/pkg/server/api"
"openreplay/backend/pkg/server/user"
)
type authImpl struct {
log logger.Logger
jwtSecret string
pgconn pool.Pool
}
func NewAuth(log logger.Logger, jwtSecret string, pgConn pool.Pool) api.RouterMiddleware {
return &authImpl{
log: log,
jwtSecret: jwtSecret,
pgconn: pgConn,
}
}
func (a *authImpl) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
w.WriteHeader(http.StatusUnauthorized)
return
}
jwtInfo, err := parseJWT(authHeader, a.jwtSecret)
if err != nil {
a.log.Warn(r.Context(), "Unauthorized request, wrong jwt token: %s", err)
w.WriteHeader(http.StatusUnauthorized)
return
}
userInfo, err := authUser(a.pgconn, jwtInfo.UserId, jwtInfo.TenantID, int(jwtInfo.IssuedAt.Unix()))
if err != nil {
a.log.Warn(r.Context(), "Unauthorized request, user not found: %s", err)
w.WriteHeader(http.StatusUnauthorized)
return
}
r = r.WithContext(ctxStore.WithValues(r.Context(), map[string]interface{}{"userData": userInfo}))
next.ServeHTTP(w, r)
})
}
func parseJWT(authHeader, secret string) (*user.JWTClaims, error) {
if authHeader == "" {
return nil, fmt.Errorf("authorization header missing")
}
tokenParts := strings.Split(authHeader, "Bearer ")
if len(tokenParts) != 2 {
return nil, fmt.Errorf("invalid authorization header")
}
tokenString := tokenParts[1]
claims := &user.JWTClaims{}
token, err := jwt.ParseWithClaims(tokenString, claims,
func(token *jwt.Token) (interface{}, error) {
return []byte(secret), nil
})
if err != nil || !token.Valid {
fmt.Printf("token err: %v\n", err)
return nil, fmt.Errorf("invalid token")
}
return claims, nil
}
func authUser(conn pool.Pool, userID, tenantID, jwtIAT int) (*user.User, error) {
sql := `
SELECT user_id, name, email, EXTRACT(epoch FROM spot_jwt_iat)::BIGINT AS spot_jwt_iat
FROM public.users
WHERE user_id = $1 AND deleted_at IS NULL
LIMIT 1;`
newUser := &user.User{TenantID: 1, AuthMethod: "jwt"}
if err := conn.QueryRow(sql, userID).Scan(&newUser.ID, &newUser.Name, &newUser.Email, &newUser.JwtIat); err != nil {
return nil, fmt.Errorf("user not found")
}
if newUser.JwtIat == 0 || abs(jwtIAT-newUser.JwtIat) > 1 {
return nil, fmt.Errorf("token has been updated")
}
return newUser, nil
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}

View file

@ -10,7 +10,7 @@ import (
func (e *authImpl) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user, err := e.IsAuthorized(r.Header.Get("Authorization"), getPermissions(r.URL.Path), e.isExtensionRequest(r))
user, err := e.IsAuthorized(r.Header.Get("Authorization"), e.isExtensionRequest(r))
if err != nil {
if !e.isSpotWithKeyRequest(r) {
e.log.Warn(r.Context(), "Unauthorized request, wrong jwt token: %s", err)

View file

@ -1,5 +0,0 @@
package auth
func getPermissions(urlPath string) []string {
return nil
}

View file

@ -1,6 +1,7 @@
package limiter
import (
"net/http"
"sync"
"time"
)
@ -46,7 +47,7 @@ func (rl *RateLimiter) Allow() bool {
return false
}
type UserRateLimiter struct {
type userRateLimiter struct {
rateLimiters sync.Map
rate int
burst int
@ -54,8 +55,12 @@ type UserRateLimiter struct {
maxIdleTime time.Duration
}
func NewUserRateLimiter(rate int, burst int, cleanupInterval time.Duration, maxIdleTime time.Duration) *UserRateLimiter {
url := &UserRateLimiter{
type UserRateLimiter interface {
Middleware(next http.Handler) http.Handler
}
func NewUserRateLimiter(rate int, burst int, cleanupInterval time.Duration, maxIdleTime time.Duration) UserRateLimiter {
url := &userRateLimiter{
rate: rate,
burst: burst,
cleanupInterval: cleanupInterval,
@ -65,12 +70,12 @@ func NewUserRateLimiter(rate int, burst int, cleanupInterval time.Duration, maxI
return url
}
func (url *UserRateLimiter) GetRateLimiter(user uint64) *RateLimiter {
func (url *userRateLimiter) getRateLimiter(user uint64) *RateLimiter {
value, _ := url.rateLimiters.LoadOrStore(user, NewRateLimiter(url.rate, url.burst))
return value.(*RateLimiter)
}
func (url *UserRateLimiter) cleanup() {
func (url *userRateLimiter) cleanup() {
for {
time.Sleep(url.cleanupInterval)
now := time.Now()

View file

@ -5,7 +5,7 @@ import (
"openreplay/backend/pkg/server/user"
)
func (rl *UserRateLimiter) Middleware(next http.Handler) http.Handler {
func (url *userRateLimiter) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
userContext := r.Context().Value("userData")
if userContext == nil {
@ -13,7 +13,7 @@ func (rl *UserRateLimiter) Middleware(next http.Handler) http.Handler {
return
}
authUser := userContext.(*user.User)
rl := rl.GetRateLimiter(authUser.ID)
rl := url.getRateLimiter(authUser.ID)
if !rl.Allow() {
http.Error(w, "Too Many Requests", http.StatusTooManyRequests)

View file

@ -0,0 +1,10 @@
package permissions
import (
"openreplay/backend/pkg/logger"
"openreplay/backend/pkg/server/api"
)
func New(log logger.Logger) api.RouterMiddleware {
return api.NewDefaultMiddleware()
}

View file

@ -88,10 +88,10 @@ func NewHandlers(cfg *httpCfg.Config, log logger.Logger, responser *api.Response
func (e *handlersImpl) GetAll() []*api.Description {
return []*api.Description{
{"/v1/mobile/start", e.startMobileSessionHandler, "POST"},
{"/v1/mobile/i", e.pushMobileMessagesHandler, "POST"},
{"/v1/mobile/late", e.pushMobileLateMessagesHandler, "POST"},
{"/v1/mobile/images", e.mobileImagesUploadHandler, "POST"},
{"POST", "/v1/mobile/start", e.startMobileSessionHandler, api.NoPermissions, api.DoNotTrack},
{"POST", "/v1/mobile/i", e.pushMobileMessagesHandler, api.NoPermissions, api.DoNotTrack},
{"POST", "/v1/mobile/late", e.pushMobileLateMessagesHandler, api.NoPermissions, api.DoNotTrack},
{"POST", "/v1/mobile/images", e.mobileImagesUploadHandler, api.NoPermissions, api.DoNotTrack},
}
}

View file

@ -73,9 +73,9 @@ func NewHandlers(cfg *httpCfg.Config, log logger.Logger, responser *api.Response
func (e *handlersImpl) GetAll() []*api.Description {
return []*api.Description{
{"/v1/web/start", e.startSessionHandlerWeb, "POST"},
{"/v1/web/i", e.pushMessagesHandlerWeb, "POST"},
{"/v1/web/images", e.imagesUploaderHandlerWeb, "POST"},
{"POST", "/v1/web/start", e.startSessionHandlerWeb, api.NoPermissions, api.DoNotTrack},
{"POST", "/v1/web/i", e.pushMessagesHandlerWeb, api.NoPermissions, api.DoNotTrack},
{"POST", "/v1/web/images", e.imagesUploaderHandlerWeb, api.NoPermissions, api.DoNotTrack},
}
}

View file

@ -47,18 +47,18 @@ func NewHandlers(log logger.Logger, cfg *spotConfig.Config, responser *api.Respo
func (e *handlersImpl) GetAll() []*api.Description {
return []*api.Description{
{"/v1/spots", e.createSpot, "POST"},
{"/v1/spots/{id}", e.getSpot, "GET"},
{"/v1/spots/{id}", e.updateSpot, "PATCH"},
{"/v1/spots", e.getSpots, "GET"},
{"/v1/spots", e.deleteSpots, "DELETE"},
{"/v1/spots/{id}/comment", e.addComment, "POST"},
{"/v1/spots/{id}/uploaded", e.uploadedSpot, "POST"},
{"/v1/spots/{id}/video", e.getSpotVideo, "GET"},
{"/v1/spots/{id}/public-key", e.getPublicKey, "GET"},
{"/v1/spots/{id}/public-key", e.updatePublicKey, "PATCH"},
{"/v1/spots/{id}/status", e.spotStatus, "GET"},
{"/v1/ping", e.ping, "GET"},
{"POST", "/v1/spots", e.createSpot, api.NoPermissions, "createSpot"},
{"GET", "/v1/spots/{id}", e.getSpot, api.NoPermissions, "getSpot"},
{"PATCH", "/v1/spots/{id}", e.updateSpot, api.NoPermissions, "updateSpot"},
{"GET", "/v1/spots", e.getSpots, api.NoPermissions, api.DoNotTrack},
{"DELETE", "/v1/spots", e.deleteSpots, api.NoPermissions, "deleteSpots"},
{"POST", "/v1/spots/{id}/comment", e.addComment, api.NoPermissions, "addComment"},
{"POST", "/v1/spots/{id}/uploaded", e.uploadedSpot, api.NoPermissions, api.DoNotTrack},
{"GET", "/v1/spots/{id}/video", e.getSpotVideo, api.NoPermissions, "getSpotVideo"},
{"GET", "/v1/spots/{id}/public-key", e.getPublicKey, api.NoPermissions, api.DoNotTrack},
{"PATCH", "/v1/spots/{id}/public-key", e.updatePublicKey, api.NoPermissions, "updatePublicKey"},
{"GET", "/v1/spots/{id}/status", e.spotStatus, api.NoPermissions, api.DoNotTrack},
{"GET", "/v1/ping", e.ping, api.NoPermissions, api.DoNotTrack},
}
}

View file

@ -1,13 +1,13 @@
package spot
import (
"openreplay/backend/pkg/metrics/database"
"time"
"openreplay/backend/internal/config/spot"
"openreplay/backend/pkg/db/postgres/pool"
"openreplay/backend/pkg/flakeid"
"openreplay/backend/pkg/logger"
"openreplay/backend/pkg/metrics/database"
spotMetrics "openreplay/backend/pkg/metrics/spot"
"openreplay/backend/pkg/metrics/web"
"openreplay/backend/pkg/objectstorage/store"
@ -15,6 +15,7 @@ import (
"openreplay/backend/pkg/server/auth"
"openreplay/backend/pkg/server/keys"
"openreplay/backend/pkg/server/limiter"
"openreplay/backend/pkg/server/permissions"
"openreplay/backend/pkg/server/tracer"
spotAPI "openreplay/backend/pkg/spot/api"
"openreplay/backend/pkg/spot/service"
@ -22,10 +23,11 @@ import (
)
type ServicesBuilder struct {
Auth auth.Auth
RateLimiter *limiter.UserRateLimiter
AuditTrail tracer.Tracer
SpotsAPI api.Handlers
RateLimiter api.RouterMiddleware
Authenticator api.RouterMiddleware
Permissions api.RouterMiddleware
AuditTrail api.RouterMiddleware
SpotsAPI api.Handlers
}
func NewServiceBuilder(log logger.Logger, cfg *spot.Config, webMetrics web.Web, spotMetrics spotMetrics.Spot, dbMetrics database.Database, pgconn pool.Pool, prefix string) (*ServicesBuilder, error) {
@ -47,9 +49,10 @@ func NewServiceBuilder(log logger.Logger, cfg *spot.Config, webMetrics web.Web,
return nil, err
}
return &ServicesBuilder{
Auth: auth.NewAuth(log, cfg.JWTSecret, cfg.JWTSpotSecret, pgconn, keys, prefix),
RateLimiter: limiter.NewUserRateLimiter(10, 30, 1*time.Minute, 5*time.Minute),
AuditTrail: auditrail,
SpotsAPI: handlers,
RateLimiter: limiter.NewUserRateLimiter(10, 30, 1*time.Minute, 5*time.Minute),
Authenticator: auth.NewAuth(log, cfg.JWTSecret, cfg.JWTSpotSecret, pgconn, keys, prefix),
Permissions: permissions.New(log),
AuditTrail: auditrail,
SpotsAPI: handlers,
}, nil
}

View file

@ -33,7 +33,7 @@ func NewHandlers(log logger.Logger, responser *api.Responser, tokenizer *token.T
func (e *handlersImpl) GetAll() []*api.Description {
return []*api.Description{
{"/v1/web/tags", e.getTags, "GET"},
{"GET", "/v1/web/tags", e.getTags, api.NoPermissions, api.DoNotTrack},
}
}

View file

@ -43,10 +43,10 @@ func NewHandlers(log logger.Logger, responser *api.Responser, jsonSizeLimit int6
func (e *handlersImpl) GetAll() []*api.Description {
return []*api.Description{
{"/v1/web/uxt/signals/test", e.sendUXTestSignal, "POST"},
{"/v1/web/uxt/signals/task", e.sendUXTaskSignal, "POST"},
{"/v1/web/uxt/test/{id}", e.getUXTestInfo, "GET"},
{"/v1/web/uxt/upload-url", e.getUXUploadUrl, "GET"},
{"POST", "/v1/web/uxt/signals/test", e.sendUXTestSignal, api.NoPermissions, api.DoNotTrack},
{"POST", "/v1/web/uxt/signals/task", e.sendUXTaskSignal, api.NoPermissions, api.DoNotTrack},
{"GET", "/v1/web/uxt/test/{id}", e.getUXTestInfo, api.NoPermissions, api.DoNotTrack},
{"GET", "/v1/web/uxt/upload-url", e.getUXUploadUrl, api.NoPermissions, api.DoNotTrack},
}
}