diff --git a/cmd/microrouterd/handler/handler.go b/cmd/microrouterd/handler/handler.go index fd3bf34..f9584c6 100644 --- a/cmd/microrouterd/handler/handler.go +++ b/cmd/microrouterd/handler/handler.go @@ -134,7 +134,7 @@ func (h *Handler) Init(service micro.Service, engine *gin.Engine, routerAuth aut WithField("method", route.Method). WithField("path", path). WithField("ratelimitClientIP", route.RatelimitClientIP). - Error("found a route with a limiter but there is no limiter store") + Error("found a route with a clientip limiter but there is no limiter store") continue } @@ -161,7 +161,43 @@ func (h *Handler) Init(service micro.Service, engine *gin.Engine, routerAuth aut } } - g.Handle(route.Method, route.Path, h.proxy(s.Name, route, route.AuthRequired, path, clientIPRatelimiter)) + userRatelimiter := make([]*limiter.Limiter, len(route.RatelimitUser)) + if route.AuthRequired && len(route.RatelimitUser) > 0 { + if h.rlStore == nil { + ilogger.Logrus(). + WithField("service", s.Name). + WithField("endpoint", route.Endpoint). + WithField("method", route.Method). + WithField("path", path). + WithField("ratelimitUser", route.RatelimitUser). + Error("found a route with a user limiter but there is no limiter store") + continue + } + + haveError := false + for idx, rate := range route.RatelimitUser { + rate, err := limiter.NewRateFromFormatted(rate) + if err != nil { + ilogger.Logrus(). + WithField("service", s.Name). + WithField("endpoint", route.Endpoint). + WithField("method", route.Method). + WithField("path", path). + WithField("ratelimitUser", route.RatelimitUser). + Error(err) + haveError = true + break + } + + userRatelimiter[idx] = limiter.New(h.rlStore, rate) + } + + if haveError { + continue + } + } + + g.Handle(route.Method, route.Path, h.proxy(s.Name, route, route.AuthRequired, path, clientIPRatelimiter, userRatelimiter)) h.routes[pathMethod] = route h.routes[pathMethod].Path = path } @@ -179,7 +215,7 @@ func (h *Handler) Stop() error { return nil } -func (h *Handler) proxy(serviceName string, route *routerclientpb.RoutesReply_Route, authRequired bool, path string, clientIPRatelimiter []*limiter.Limiter) func(*gin.Context) { +func (h *Handler) proxy(serviceName string, route *routerclientpb.RoutesReply_Route, authRequired bool, path string, clientIPRatelimiter []*limiter.Limiter, userRatelimiter []*limiter.Limiter) func(*gin.Context) { return func(c *gin.Context) { if len(clientIPRatelimiter) > 0 { @@ -187,23 +223,31 @@ func (h *Handler) proxy(serviceName string, route *routerclientpb.RoutesReply_Ro context, err := l.Get(c, fmt.Sprintf("%s-%s-%s", path, l.Rate.Formatted, c.ClientIP())) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ - "status": http.StatusInternalServerError, - "message": "Internal server error", + "errors": []gin.H{ + gin.H{ + "id": "INTERNAL_SERVER_ERROR", + "message": err, + }, + }, }) c.Abort() return } if idx == 0 { - c.Header("X-RateLimit-Limit", strconv.FormatInt(context.Limit, 10)) - c.Header("X-RateLimit-Remaining", strconv.FormatInt(context.Remaining, 10)) - c.Header("X-RateLimit-Reset", strconv.FormatInt(context.Reset, 10)) + c.Header("X-ClientIPRateLimit-Limit", strconv.FormatInt(context.Limit, 10)) + c.Header("X-ClientIPRateLimit-Remaining", strconv.FormatInt(context.Remaining, 10)) + c.Header("X-ClientIPRateLimit-Reset", strconv.FormatInt(context.Reset, 10)) } if context.Reached { c.JSON(http.StatusTooManyRequests, gin.H{ - "status": http.StatusTooManyRequests, - "message": "To many requests", + "errors": []gin.H{ + gin.H{ + "id": "TO_MANY_REQUESTS", + "message": "To many requests", + }, + }, }) c.Abort() return @@ -263,9 +307,14 @@ func (h *Handler) proxy(serviceName string, route *routerclientpb.RoutesReply_Ro } else { if c.ContentType() == "" { c.JSON(http.StatusUnsupportedMediaType, gin.H{ - "status": http.StatusUnsupportedMediaType, - "message": "provide a content-type header", + "errors": []gin.H{ + gin.H{ + "id": "UNSUPPORTED_MEDIA_TYPE", + "message": "provide a content-type header", + }, + }, }) + c.Abort() return } c.ShouldBind(&request) @@ -280,13 +329,68 @@ func (h *Handler) proxy(serviceName string, route *routerclientpb.RoutesReply_Ro req := h.service.Client().NewRequest(serviceName, route.Endpoint, request, client.WithContentType("application/json")) // Auth - ctx, err := h.routerAuth.ForwardContext(c.Request, c) + u, err := h.routerAuth.Inspect(c.Request) + var ctx context.Context if err != nil && authRequired { c.JSON(http.StatusUnauthorized, gin.H{ - "status": http.StatusUnauthorized, - "message": err, + "errors": []gin.H{ + gin.H{ + "id": "UNAUTHORIZED", + "message": err, + }, + }, }) + c.Abort() return + } else { + ctx, err = h.routerAuth.ForwardContext(u, c.Request, c) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "errors": []gin.H{ + gin.H{ + "id": "INTERNAL_SERVER_ERROR", + "message": err, + }, + }, + }) + } + } + + if len(userRatelimiter) > 0 { + for idx, l := range userRatelimiter { + context, err := l.Get(c, fmt.Sprintf("%s-%s-%s", path, l.Rate.Formatted, u.Id)) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "errors": []gin.H{ + gin.H{ + "id": "INTERNAL_SERVER_ERROR", + "message": err, + }, + }, + }) + c.Abort() + return + } + + if idx == 0 { + c.Header("X-UserRateLimit-Limit", strconv.FormatInt(context.Limit, 10)) + c.Header("X-UserRateLimit-Remaining", strconv.FormatInt(context.Remaining, 10)) + c.Header("X-UserRateLimit-Reset", strconv.FormatInt(context.Reset, 10)) + } + + if context.Reached { + c.JSON(http.StatusTooManyRequests, gin.H{ + "errors": []gin.H{ + gin.H{ + "id": "TO_MANY_REQUESTS", + "message": "To many requests", + }, + }, + }) + c.Abort() + return + } + } } // remote call @@ -297,13 +401,19 @@ func (h *Handler) proxy(serviceName string, route *routerclientpb.RoutesReply_Ro pErr := errors.FromError(err) code := int(http.StatusInternalServerError) + id := pErr.Id if pErr.Code != 0 { code = int(pErr.Code) } c.JSON(code, gin.H{ - "status": code, - "message": pErr.Detail, + "errors": []gin.H{ + gin.H{ + "id": id, + "message": pErr.Detail, + }, + }, }) + c.Abort() return } diff --git a/go.mod b/go.mod index 844958e..0f5e60e 100644 --- a/go.mod +++ b/go.mod @@ -17,11 +17,11 @@ require ( github.com/urfave/cli/v2 v2.16.3 go-micro.dev/v4 v4.8.1 google.golang.org/protobuf v1.28.1 - jochum.dev/jo-micro/auth2 v0.3.2 + jochum.dev/jo-micro/auth2 v0.3.3 ) require ( - github.com/Microsoft/go-winio v0.5.2 // indirect + github.com/Microsoft/go-winio v0.6.0 // indirect github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895 // indirect github.com/acomagu/bufpipe v1.0.3 // indirect github.com/avast/retry-go v3.0.0+incompatible // indirect @@ -74,10 +74,10 @@ require ( github.com/ugorji/go/codec v1.2.7 // indirect github.com/xanzy/ssh-agent v0.3.2 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 // indirect + golang.org/x/crypto v0.0.0-20220924013350-4ba4fb4dd9e7 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/net v0.0.0-20220921203646-d300de134e69 // indirect - golang.org/x/sync v0.0.0-20220907140024-f12130a52804 // indirect + golang.org/x/net v0.0.0-20220923203811-8be639271d50 // indirect + golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 // indirect golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/tools v0.1.12 // indirect diff --git a/go.sum b/go.sum index 19a2c95..a4b1768 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jB github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895 h1:NsReiLpErIPzRrnogAXYwSoU7txA977LjDGrbkewJbg= github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8= @@ -222,6 +224,8 @@ golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 h1:a5Yg6ylndHHYJqIPrdq0AhvR6KTvDTAvgBtaidhEevY= golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220924013350-4ba4fb4dd9e7 h1:WJywXQVIb56P2kAvXeMGTIgQ1ZHQxR60+F9dLsodECc= +golang.org/x/crypto v0.0.0-20220924013350-4ba4fb4dd9e7/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -234,10 +238,14 @@ golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220921203646-d300de134e69 h1:hUJpGDpnfwdJW8iNypFjmSY0sCBEL+spFTZ2eO+Sfps= golang.org/x/net v0.0.0-20220921203646-d300de134e69/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220923203811-8be639271d50 h1:vKyz8L3zkd+xrMeIaBsQ/MNVPVFSffdaU3ZyYlBGFnI= +golang.org/x/net v0.0.0-20220923203811-8be639271d50/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220907140024-f12130a52804 h1:0SH2R3f1b1VmIMG7BXbEZCBUu2dKmHschSmjqGUrW8A= golang.org/x/sync v0.0.0-20220907140024-f12130a52804/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc= +golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -313,3 +321,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= jochum.dev/jo-micro/auth2 v0.3.2 h1:dWY7RPLS3/Sn7YWDz4Kl8Str6lzMXUdfbMBLJLXmehk= jochum.dev/jo-micro/auth2 v0.3.2/go.mod h1:VRGDU1tsDrlEVN9ch3DlvhUslDTQGGp3KLReBRL6V1s= +jochum.dev/jo-micro/auth2 v0.3.3 h1:mL8ipUfgNx2d5/JeuW7i1P/ZUzUpVT8G9WYH02xr/vA= +jochum.dev/jo-micro/auth2 v0.3.3/go.mod h1:14yXAQkyHYC1RyHNoweNZahsRsaHrCEek7YlXDtt7Hg= diff --git a/handler.go b/handler.go index ca4333d..8373de9 100644 --- a/handler.go +++ b/handler.go @@ -32,6 +32,7 @@ func NewHandler(routerURI string, routes ...*Route) *Handler { Params: r.Params, AuthRequired: r.AuthRequired, RatelimitClientIP: r.RatelimitClientIP, + RatelimitUser: r.RatelimitUser, }) } diff --git a/internal/proto/routerclientpb/routerclientpb.pb.go b/internal/proto/routerclientpb/routerclientpb.pb.go index 29813ea..32b1dcb 100644 --- a/internal/proto/routerclientpb/routerclientpb.pb.go +++ b/internal/proto/routerclientpb/routerclientpb.pb.go @@ -89,6 +89,7 @@ type RoutesReply_Route struct { Params []string `protobuf:"bytes,5,rep,name=params,proto3" json:"params,omitempty"` AuthRequired bool `protobuf:"varint,6,opt,name=authRequired,proto3" json:"authRequired,omitempty"` RatelimitClientIP []string `protobuf:"bytes,7,rep,name=ratelimitClientIP,proto3" json:"ratelimitClientIP,omitempty"` + RatelimitUser []string `protobuf:"bytes,8,rep,name=ratelimitUser,proto3" json:"ratelimitUser,omitempty"` } func (x *RoutesReply_Route) Reset() { @@ -172,6 +173,13 @@ func (x *RoutesReply_Route) GetRatelimitClientIP() []string { return nil } +func (x *RoutesReply_Route) GetRatelimitUser() []string { + if x != nil { + return x.RatelimitUser + } + return nil +} + var File_routerclientpb_proto protoreflect.FileDescriptor var file_routerclientpb_proto_rawDesc = []byte{ @@ -179,13 +187,13 @@ var file_routerclientpb_proto_rawDesc = []byte{ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x22, 0xbe, 0x02, 0x0a, 0x0b, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, + 0x6f, 0x74, 0x6f, 0x22, 0xe4, 0x02, 0x0a, 0x0b, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x55, 0x52, 0x49, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x55, 0x52, 0x49, 0x12, 0x39, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x2e, 0x52, - 0x6f, 0x75, 0x74, 0x65, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x1a, 0xd5, 0x01, 0x0a, + 0x6f, 0x75, 0x74, 0x65, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x1a, 0xfb, 0x01, 0x0a, 0x05, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, @@ -199,17 +207,19 @@ var file_routerclientpb_proto_rawDesc = []byte{ 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x2c, 0x0a, 0x11, 0x72, 0x61, 0x74, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x50, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x72, 0x61, 0x74, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x43, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x49, 0x50, 0x32, 0x56, 0x0a, 0x13, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3f, 0x0a, 0x06, 0x52, - 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b, 0x2e, - 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x52, - 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x40, 0x5a, 0x3e, - 0x6a, 0x6f, 0x63, 0x68, 0x75, 0x6d, 0x2e, 0x64, 0x65, 0x76, 0x2f, 0x6a, 0x6f, 0x2d, 0x6d, 0x69, - 0x63, 0x72, 0x6f, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x3b, - 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x74, 0x49, 0x50, 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x61, 0x74, 0x65, 0x6c, 0x69, 0x6d, 0x69, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x61, 0x74, + 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x55, 0x73, 0x65, 0x72, 0x32, 0x56, 0x0a, 0x13, 0x52, 0x6f, + 0x75, 0x74, 0x65, 0x72, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x3f, 0x0a, 0x06, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x1a, 0x1b, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x22, 0x00, 0x42, 0x40, 0x5a, 0x3e, 0x6a, 0x6f, 0x63, 0x68, 0x75, 0x6d, 0x2e, 0x64, 0x65, 0x76, + 0x2f, 0x6a, 0x6f, 0x2d, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x3b, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/internal/proto/routerclientpb/routerclientpb.proto b/internal/proto/routerclientpb/routerclientpb.proto index dc7d524..e75a4cf 100644 --- a/internal/proto/routerclientpb/routerclientpb.proto +++ b/internal/proto/routerclientpb/routerclientpb.proto @@ -20,6 +20,7 @@ message RoutesReply { repeated string params = 5; bool authRequired = 6; repeated string ratelimitClientIP = 7; + repeated string ratelimitUser = 8; } string routerURI = 1; diff --git a/internal/proto/routerserverpb/routerserverpb.pb.go b/internal/proto/routerserverpb/routerserverpb.pb.go index 6a1d46d..3a0198d 100644 --- a/internal/proto/routerserverpb/routerserverpb.pb.go +++ b/internal/proto/routerserverpb/routerserverpb.pb.go @@ -79,6 +79,7 @@ type RoutesReply_Route struct { Endpoint string `protobuf:"bytes,4,opt,name=endpoint,proto3" json:"endpoint,omitempty"` AuthRequired bool `protobuf:"varint,5,opt,name=authRequired,proto3" json:"authRequired,omitempty"` RatelimitClientIP []string `protobuf:"bytes,6,rep,name=ratelimitClientIP,proto3" json:"ratelimitClientIP,omitempty"` + ReatelimitUser []string `protobuf:"bytes,7,rep,name=reatelimitUser,proto3" json:"reatelimitUser,omitempty"` } func (x *RoutesReply_Route) Reset() { @@ -155,6 +156,13 @@ func (x *RoutesReply_Route) GetRatelimitClientIP() []string { return nil } +func (x *RoutesReply_Route) GetReatelimitUser() []string { + if x != nil { + return x.ReatelimitUser + } + return nil +} + var File_routerserverpb_proto protoreflect.FileDescriptor var file_routerserverpb_proto_rawDesc = []byte{ @@ -162,11 +170,11 @@ var file_routerserverpb_proto_rawDesc = []byte{ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x70, 0x62, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x22, 0x84, 0x02, 0x0a, 0x0b, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, + 0x6f, 0x74, 0x6f, 0x22, 0xac, 0x02, 0x0a, 0x0b, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x39, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x1a, 0xb9, + 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x1a, 0xe1, 0x01, 0x0a, 0x05, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, @@ -178,17 +186,20 @@ var file_routerserverpb_proto_rawDesc = []byte{ 0x61, 0x75, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x2c, 0x0a, 0x11, 0x72, 0x61, 0x74, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x50, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x72, 0x61, 0x74, 0x65, 0x6c, 0x69, 0x6d, - 0x69, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x50, 0x32, 0x56, 0x0a, 0x13, 0x52, 0x6f, - 0x75, 0x74, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x12, 0x3f, 0x0a, 0x06, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x1a, 0x1b, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x22, 0x00, 0x42, 0x40, 0x5a, 0x3e, 0x6a, 0x6f, 0x63, 0x68, 0x75, 0x6d, 0x2e, 0x64, 0x65, 0x76, - 0x2f, 0x6a, 0x6f, 0x2d, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x70, 0x62, 0x3b, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x50, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x55, 0x73, 0x65, 0x72, 0x18, 0x07, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x61, 0x74, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x32, 0x56, 0x0a, 0x13, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3f, 0x0a, 0x06, 0x52, 0x6f, 0x75, + 0x74, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b, 0x2e, 0x72, 0x6f, + 0x75, 0x74, 0x65, 0x72, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x6f, 0x75, + 0x74, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x40, 0x5a, 0x3e, 0x6a, 0x6f, + 0x63, 0x68, 0x75, 0x6d, 0x2e, 0x64, 0x65, 0x76, 0x2f, 0x6a, 0x6f, 0x2d, 0x6d, 0x69, 0x63, 0x72, + 0x6f, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x72, + 0x6f, 0x75, 0x74, 0x65, 0x72, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x70, 0x62, 0x3b, 0x72, 0x6f, + 0x75, 0x74, 0x65, 0x72, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/internal/proto/routerserverpb/routerserverpb.proto b/internal/proto/routerserverpb/routerserverpb.proto index f863c6b..604a483 100644 --- a/internal/proto/routerserverpb/routerserverpb.proto +++ b/internal/proto/routerserverpb/routerserverpb.proto @@ -18,6 +18,7 @@ message RoutesReply { string endpoint = 4; bool authRequired = 5; repeated string ratelimitClientIP = 6; + repeated string reatelimitUser = 7; } repeated Route routes = 1; diff --git a/route.go b/route.go index 93e3e19..8600611 100644 --- a/route.go +++ b/route.go @@ -13,6 +13,7 @@ type Route struct { AuthRequired bool // Default false // https://github.com/ulule/limiter - default is no rate Limiter at all, put the strictes limit first RatelimitClientIP []string + RatelimitUser []string } type Option func(*Route) @@ -26,6 +27,7 @@ func NewRoute(opts ...Option) *Route { Params: []string{}, AuthRequired: false, RatelimitClientIP: []string{}, + RatelimitUser: []string{}, } for _, o := range opts { @@ -81,3 +83,9 @@ func RatelimitClientIP(n ...string) Option { o.RatelimitClientIP = n } } + +func RatelimitUser(n ...string) Option { + return func(o *Route) { + o.RatelimitUser = n + } +}