From cc27f3b25f550ed07440718ec64e1345558334a4 Mon Sep 17 00:00:00 2001 From: Roman Nikitin Date: Fri, 17 Nov 2023 13:51:06 +0300 Subject: [PATCH 01/18] Add grpc-web support, generating TS proto --- cmd/server/main.go | 39 ++-- compose.yml | 1 + go.mod | 8 +- go.sum | 336 +++++++++++++++++++++++++++++ internal/server/config/config.go | 2 +- internal/server/exploits/server.go | 16 +- pkg/mu/options.go | 26 +++ pkg/mu/server.go | 55 +++++ proto/buf.gen.yaml | 15 ++ 9 files changed, 475 insertions(+), 23 deletions(-) create mode 100644 pkg/mu/options.go create mode 100644 pkg/mu/server.go diff --git a/cmd/server/main.go b/cmd/server/main.go index 03c749b..d4cb814 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -2,8 +2,8 @@ package main import ( "context" + "errors" "fmt" - "net" "net/http" "os/signal" "strings" @@ -25,6 +25,7 @@ import ( "github.com/c4t-but-s4d/neo/v2/internal/server/fs" logs "github.com/c4t-but-s4d/neo/v2/internal/server/logs" "github.com/c4t-but-s4d/neo/v2/pkg/grpcauth" + "github.com/c4t-but-s4d/neo/v2/pkg/mu" "github.com/c4t-but-s4d/neo/v2/pkg/neosync" epb "github.com/c4t-but-s4d/neo/v2/proto/go/exploits" fspb "github.com/c4t-but-s4d/neo/v2/proto/go/fileserver" @@ -73,11 +74,6 @@ func main() { } logsServer := logs.New(logStore) - lis, err := net.Listen("tcp", cfg.Addr) - if err != nil { - logrus.Fatalf("Failed to listen: %v", err) - } - var opts []grpc.ServerOption if cfg.GrpcAuthKey != "" { authInterceptor := grpcauth.NewServerInterceptor(cfg.GrpcAuthKey) @@ -91,13 +87,13 @@ func main() { logspb.RegisterServiceServer(s, logsServer) reflection.Register(s) - http.Handle("/metrics", promhttp.Handler()) - go func() { - logrus.Infof("Starting metrics server on %s", viper.GetString("metrics.address")) - if err := http.ListenAndServe(viper.GetString("metrics.address"), http.DefaultServeMux); err != nil { - logrus.Fatalf("Failed to serve metrics: %v", err) - } - }() + httpMux := http.NewServeMux() + httpMux.Handle("/metrics", promhttp.Handler()) + muHandler := mu.NewHandler(s, mu.WithHTTPHandler(httpMux)) + httpServer := &http.Server{ + Handler: muHandler, + Addr: cfg.Address, + } runCtx, cancel := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT) defer cancel() @@ -117,11 +113,19 @@ func main() { defer wg.Done() <-runCtx.Done() logrus.Info("Received shutdown signal, stopping server") - s.GracefulStop() + + shutdownCtx, shutdownCancel := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT) + defer shutdownCancel() + shutdownCtx, shutdownCancel = context.WithTimeout(shutdownCtx, 10*time.Second) + defer shutdownCancel() + + if err := httpServer.Shutdown(shutdownCtx); err != nil { + logrus.Errorf("Failed to shutdown http server: %v", err) + } }() - logrus.Infof("Starting server on %s", cfg.Addr) - if err := s.Serve(lis); err != nil { + logrus.Infof("Starting multiproto server on %s", cfg.Address) + if err := httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { logrus.Fatalf("Failed to serve: %v", err) } @@ -153,8 +157,7 @@ func setupConfig() error { viper.SetDefault("config", "server_config.yml") viper.SetDefault("ping_every", time.Second*5) viper.SetDefault("submit_every", time.Second*2) - viper.SetDefault("metrics.address", ":3000") - viper.SetDefault("addr", ":5005") + viper.SetDefault("address", ":5005") return nil } diff --git a/compose.yml b/compose.yml index 1919ee1..58eeeb8 100644 --- a/compose.yml +++ b/compose.yml @@ -33,6 +33,7 @@ services: victoria: image: victoriametrics/victoria-metrics:v1.92.1 + user: 0 volumes: - ./monitoring/cfg/prometheus:/etc/prometheus - ./volumes/victoria-metrics:/victoria-metrics-data diff --git a/go.mod b/go.mod index 4d538b6..9809c07 100644 --- a/go.mod +++ b/go.mod @@ -23,26 +23,32 @@ require ( ) require ( + github.com/improbable-eng/grpc-web v0.15.0 github.com/prometheus/client_golang v1.17.0 github.com/prometheus/common v0.44.0 github.com/samber/lo v1.38.1 + golang.org/x/net v0.17.0 golang.org/x/sys v0.13.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v4 v4.1.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/klauspost/compress v1.17.0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect + github.com/rs/cors v1.7.0 // indirect github.com/sagikazarmark/locafero v0.3.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect @@ -51,8 +57,8 @@ require ( github.com/subosito/gotenv v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/net v0.17.0 // indirect golang.org/x/text v0.13.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c // indirect gopkg.in/ini.v1 v1.67.0 // indirect + nhooyr.io/websocket v1.8.6 // indirect ) diff --git a/go.sum b/go.sum index 5d00ded..bd308fc 100644 --- a/go.sum +++ b/go.sum @@ -38,43 +38,122 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ= github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI= +github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= +github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -102,6 +181,7 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -116,6 +196,7 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -130,24 +211,81 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= +github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -155,46 +293,148 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod h1:x5OoJHDHqxHS801UIuhqGl6QdSAEJvtausosHSdazIo= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ= github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= @@ -203,15 +443,23 @@ github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY= github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI= github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -221,25 +469,48 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= @@ -254,6 +525,7 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= @@ -281,16 +553,24 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -298,6 +578,7 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -310,6 +591,7 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= @@ -332,19 +614,32 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -352,10 +647,13 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -367,6 +665,7 @@ golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= @@ -382,15 +681,19 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -400,6 +703,8 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -407,6 +712,7 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -436,6 +742,7 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -456,6 +763,7 @@ google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= @@ -467,6 +775,7 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= @@ -483,6 +792,7 @@ google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= @@ -497,13 +807,19 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c h1:jHkCUWkseRf+W+edG5hMzr/Uh1xkDREY4caybAq4dpY= google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -513,6 +829,7 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= @@ -532,21 +849,36 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -554,6 +886,10 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= +nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/internal/server/config/config.go b/internal/server/config/config.go index 43faffd..1957128 100644 --- a/internal/server/config/config.go +++ b/internal/server/config/config.go @@ -9,7 +9,7 @@ import ( type Config struct { Debug bool `mapstructure:"debug"` - Addr string `mapstructure:"addr"` + Address string `mapstructure:"address"` DBPath string `mapstructure:"db_path"` RedisURL string `mapstructure:"redis_url"` BaseDir string `mapstructure:"base_dir"` diff --git a/internal/server/exploits/server.go b/internal/server/exploits/server.go index c084691..15b9562 100644 --- a/internal/server/exploits/server.go +++ b/internal/server/exploits/server.go @@ -61,7 +61,7 @@ func (s *Server) Ping(ctx context.Context, r *epb.PingRequest) (*epb.PingRespons case *epb.PingRequest_LeaveRequest: s.visits.MarkInvalid(r.ClientId) default: - return nil, s.WrapErrorf(ctx, codes.InvalidArgument, "Unknown payload type: %T", p) + return nil, s.WrapErrorf(ctx, codes.InvalidArgument, "unknown payload type: %T", p) } return &epb.PingResponse{ @@ -78,7 +78,7 @@ func (s *Server) Exploit(ctx context.Context, r *epb.ExploitRequest) (*epb.Explo state, ok := s.storage.GetState(r.ExploitId) if !ok { - return nil, s.WrapErrorf(ctx, codes.NotFound, "Failed to find an exploit state = %v", state.ExploitId) + return nil, s.WrapErrorf(ctx, codes.NotFound, "finding an exploit state = %v", state.ExploitId) } return &epb.ExploitResponse{ State: state, @@ -88,9 +88,19 @@ func (s *Server) Exploit(ctx context.Context, r *epb.ExploitRequest) (*epb.Explo func (s *Server) UpdateExploit(ctx context.Context, r *epb.UpdateExploitRequest) (*epb.UpdateExploitResponse, error) { s.LogRequest(ctx, r) + if r.State.Config == nil { + return nil, s.WrapErrorf(ctx, codes.InvalidArgument, "config required") + } + if r.State.Config.Timeout.AsDuration() == 0 { + return nil, s.WrapErrorf(ctx, codes.InvalidArgument, "timeout required") + } + if r.State.Config.RunEvery.AsDuration() == 0 { + return nil, s.WrapErrorf(ctx, codes.InvalidArgument, "run_every required") + } + newState, err := s.storage.UpdateExploitVersion(r.State) if err != nil { - return nil, s.WrapErrorf(ctx, codes.Internal, "Failed to update exploit version: %v", err) + return nil, s.WrapErrorf(ctx, codes.Internal, "updating exploit version: %v", err) } return &epb.UpdateExploitResponse{State: newState}, nil } diff --git a/pkg/mu/options.go b/pkg/mu/options.go new file mode 100644 index 0000000..725121b --- /dev/null +++ b/pkg/mu/options.go @@ -0,0 +1,26 @@ +package mu + +import ( + "net/http" + + "golang.org/x/net/http2" +) + +type Config struct { + http2Server *http2.Server + httpHandler http.Handler +} + +type Option func(cfg *Config) + +func WithHTTP2Server(server *http2.Server) Option { + return func(cfg *Config) { + cfg.http2Server = server + } +} + +func WithHTTPHandler(handler http.Handler) Option { + return func(cfg *Config) { + cfg.httpHandler = handler + } +} diff --git a/pkg/mu/server.go b/pkg/mu/server.go new file mode 100644 index 0000000..706a38d --- /dev/null +++ b/pkg/mu/server.go @@ -0,0 +1,55 @@ +package mu + +import ( + "net/http" + + "github.com/improbable-eng/grpc-web/go/grpcweb" + "golang.org/x/net/http2" + "golang.org/x/net/http2/h2c" + "google.golang.org/grpc" +) + +func NewHandler(grpcServer *grpc.Server, opts ...Option) http.Handler { + cfg := &Config{ + http2Server: &http2.Server{}, + httpHandler: http.DefaultServeMux, + } + for _, opt := range opts { + opt(cfg) + } + + return h2c.NewHandler( + &Server{ + grpcServer: grpcServer, + webServer: grpcweb.WrapServer( + grpcServer, + grpcweb.WithWebsockets(true), + grpcweb.WithOriginFunc(func(string) bool { + return true + }), + grpcweb.WithWebsocketOriginFunc(func(*http.Request) bool { + return true + }), + ), + httpHandler: cfg.httpHandler, + }, + cfg.http2Server, + ) +} + +type Server struct { + grpcServer *grpc.Server + webServer *grpcweb.WrappedGrpcServer + httpHandler http.Handler +} + +func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { + switch { + case r.ProtoMajor == 2 && r.Header.Get("Content-Type") == "application/grpc": + s.grpcServer.ServeHTTP(w, r) + case s.webServer.IsAcceptableGrpcCorsRequest(r) || s.webServer.IsGrpcWebRequest(r) || s.webServer.IsGrpcWebSocketRequest(r): + s.webServer.ServeHTTP(w, r) + default: + s.httpHandler.ServeHTTP(w, r) + } +} diff --git a/proto/buf.gen.yaml b/proto/buf.gen.yaml index 9d3ad12..2d9dae1 100644 --- a/proto/buf.gen.yaml +++ b/proto/buf.gen.yaml @@ -13,3 +13,18 @@ plugins: out: go opt: - paths=source_relative + + # Typescript + - plugin: buf.build/community/stephenh-ts-proto + out: ../front/src/proto + opt: + - enumsAsLiterals=true + - env=browser + - esModuleInterop=true + - forceLong=long + - oneof=unions + - outputServices=nice-grpc,outputServices=generic-definitions + - unrecognizedEnum=false + - removeEnumPrefix=true + - useDate=false + - useMapType=true From 067cd4b370f60f5a779a4b648f91c64ae5970e02 Mon Sep 17 00:00:00 2001 From: Roman Nikitin Date: Fri, 17 Nov 2023 14:22:11 +0300 Subject: [PATCH 02/18] Fix service users --- compose.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compose.yml b/compose.yml index 58eeeb8..40a7677 100644 --- a/compose.yml +++ b/compose.yml @@ -18,6 +18,7 @@ services: grafana: image: grafana/grafana-oss:10.0.3 + user: '0' volumes: - ./volumes/grafana:/var/lib/grafana - ./monitoring/cfg/grafana/provisioning:/etc/grafana/provisioning @@ -33,7 +34,7 @@ services: victoria: image: victoriametrics/victoria-metrics:v1.92.1 - user: 0 + user: '0' volumes: - ./monitoring/cfg/prometheus:/etc/prometheus - ./volumes/victoria-metrics:/victoria-metrics-data From dc5dcd2d65feb9bed72662d3709f0b47bc87f9a8 Mon Sep 17 00:00:00 2001 From: Roman Nikitin Date: Fri, 17 Nov 2023 15:34:03 +0300 Subject: [PATCH 03/18] First working version of front --- front/.eslintrc.cjs | 26 + front/.gitignore | 15 + front/add_ts_ignore.sh | 5 + front/index.html | 13 + front/package.json | 43 + front/pnpm-lock.yaml | 3216 +++++++++++++++++++ front/public/logo.png | Bin 0 -> 7955 bytes front/public/logo_toolbar.png | Bin 0 -> 239111 bytes front/src/components/ExploitUpdateForm.tsx | 152 + front/src/components/ExploitsView.tsx | 59 + front/src/components/LogsRootView.tsx | 132 + front/src/components/LogsView.tsx | 63 + front/src/config.ts | 10 + front/src/index.css | 8 + front/src/main.tsx | 51 + front/src/proto/exploits/api.ts | 1963 +++++++++++ front/src/proto/fileserver/api.ts | 218 ++ front/src/proto/google/protobuf/duration.ts | 182 ++ front/src/proto/google/protobuf/empty.ts | 79 + front/src/proto/logs/api.ts | 404 +++ front/src/routes/auth.tsx | 86 + front/src/routes/authContext.ts | 14 + front/src/routes/exploits.tsx | 50 + front/src/routes/logs.tsx | 40 + front/src/routes/root.tsx | 36 + front/src/routes/rootContext.ts | 13 + front/src/services/exploits.ts | 38 + front/src/services/logs.ts | 32 + front/src/theme.ts | 28 + front/src/utils/duration.ts | 60 + front/src/utils/storage.ts | 19 + front/src/utils/window.ts | 34 + front/src/vite-env.d.ts | 1 + front/tsconfig.json | 40 + front/tsconfig.node.json | 13 + front/vite.config.ts | 10 + 36 files changed, 7153 insertions(+) create mode 100644 front/.eslintrc.cjs create mode 100644 front/.gitignore create mode 100755 front/add_ts_ignore.sh create mode 100644 front/index.html create mode 100644 front/package.json create mode 100644 front/pnpm-lock.yaml create mode 100644 front/public/logo.png create mode 100644 front/public/logo_toolbar.png create mode 100644 front/src/components/ExploitUpdateForm.tsx create mode 100644 front/src/components/ExploitsView.tsx create mode 100644 front/src/components/LogsRootView.tsx create mode 100644 front/src/components/LogsView.tsx create mode 100644 front/src/config.ts create mode 100644 front/src/index.css create mode 100644 front/src/main.tsx create mode 100644 front/src/proto/exploits/api.ts create mode 100644 front/src/proto/fileserver/api.ts create mode 100644 front/src/proto/google/protobuf/duration.ts create mode 100644 front/src/proto/google/protobuf/empty.ts create mode 100644 front/src/proto/logs/api.ts create mode 100644 front/src/routes/auth.tsx create mode 100644 front/src/routes/authContext.ts create mode 100644 front/src/routes/exploits.tsx create mode 100644 front/src/routes/logs.tsx create mode 100644 front/src/routes/root.tsx create mode 100644 front/src/routes/rootContext.ts create mode 100644 front/src/services/exploits.ts create mode 100644 front/src/services/logs.ts create mode 100644 front/src/theme.ts create mode 100644 front/src/utils/duration.ts create mode 100644 front/src/utils/storage.ts create mode 100644 front/src/utils/window.ts create mode 100644 front/src/vite-env.d.ts create mode 100644 front/tsconfig.json create mode 100644 front/tsconfig.node.json create mode 100644 front/vite.config.ts diff --git a/front/.eslintrc.cjs b/front/.eslintrc.cjs new file mode 100644 index 0000000..6850255 --- /dev/null +++ b/front/.eslintrc.cjs @@ -0,0 +1,26 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/strict-type-checked", + "plugin:react-hooks/recommended", + "plugin:react/recommended", + "plugin:react/jsx-runtime", + ], + ignorePatterns: ["dist", ".eslintrc.cjs", "src/proto/**/*"], + parser: "@typescript-eslint/parser", + plugins: ["react-refresh"], + rules: { + "react-refresh/only-export-components": [ + "warn", + { allowConstantExport: true }, + ], + }, + parserOptions: { + ecmaVersion: "latest", + sourceType: "module", + project: ["./tsconfig.json", "./tsconfig.node.json"], + tsconfigRootDir: __dirname, + }, +}; diff --git a/front/.gitignore b/front/.gitignore new file mode 100644 index 0000000..29a21ea --- /dev/null +++ b/front/.gitignore @@ -0,0 +1,15 @@ +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/front/add_ts_ignore.sh b/front/add_ts_ignore.sh new file mode 100755 index 0000000..6e4f687 --- /dev/null +++ b/front/add_ts_ignore.sh @@ -0,0 +1,5 @@ +#!/bin/bash -e + +for file in $(find src/proto -name '*.ts' -type f); do + (echo "// @ts-nocheck" && cat "${file}") > .kek && mv .kek "${file}" +done \ No newline at end of file diff --git a/front/index.html b/front/index.html new file mode 100644 index 0000000..92b6e10 --- /dev/null +++ b/front/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
+ + + diff --git a/front/package.json b/front/package.json new file mode 100644 index 0000000..54396d0 --- /dev/null +++ b/front/package.json @@ -0,0 +1,43 @@ +{ + "name": "front", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" + }, + "dependencies": { + "@emotion/react": "^11.11.1", + "@emotion/styled": "^11.11.0", + "@fontsource/roboto": "^5.0.8", + "@mui/icons-material": "^5.14.16", + "@mui/material": "^5.14.17", + "@types/react-window": "^1.8.8", + "long": "^5.2.3", + "nice-grpc-common": "^2.0.2", + "nice-grpc-web": "^3.3.2", + "protobufjs": "^7.2.5", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-helmet-async": "^1.3.0", + "react-hook-form": "^7.48.2", + "react-router-dom": "^6.18.0", + "react-window": "^1.8.9" + }, + "devDependencies": { + "@types/react": "^18.2.15", + "@types/react-dom": "^18.2.7", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "@vitejs/plugin-react": "^4.0.3", + "eslint": "^8.45.0", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.3", + "typescript": "^5.0.2", + "vite": "^4.4.5" + } +} diff --git a/front/pnpm-lock.yaml b/front/pnpm-lock.yaml new file mode 100644 index 0000000..2a7467f --- /dev/null +++ b/front/pnpm-lock.yaml @@ -0,0 +1,3216 @@ +lockfileVersion: '6.1' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@emotion/react': + specifier: ^11.11.1 + version: 11.11.1(@types/react@18.2.15)(react@18.2.0) + '@emotion/styled': + specifier: ^11.11.0 + version: 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.15)(react@18.2.0) + '@fontsource/roboto': + specifier: ^5.0.8 + version: 5.0.8 + '@mui/icons-material': + specifier: ^5.14.16 + version: 5.14.16(@mui/material@5.14.17)(@types/react@18.2.15)(react@18.2.0) + '@mui/material': + specifier: ^5.14.17 + version: 5.14.17(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.15)(react-dom@18.2.0)(react@18.2.0) + '@types/react-window': + specifier: ^1.8.8 + version: 1.8.8 + long: + specifier: ^5.2.3 + version: 5.2.3 + nice-grpc-common: + specifier: ^2.0.2 + version: 2.0.2 + nice-grpc-web: + specifier: ^3.3.2 + version: 3.3.2(ws@8.14.2) + protobufjs: + specifier: ^7.2.5 + version: 7.2.5 + react: + specifier: ^18.2.0 + version: 18.2.0 + react-dom: + specifier: ^18.2.0 + version: 18.2.0(react@18.2.0) + react-helmet-async: + specifier: ^1.3.0 + version: 1.3.0(react-dom@18.2.0)(react@18.2.0) + react-hook-form: + specifier: ^7.48.2 + version: 7.48.2(react@18.2.0) + react-router-dom: + specifier: ^6.18.0 + version: 6.18.0(react-dom@18.2.0)(react@18.2.0) + react-window: + specifier: ^1.8.9 + version: 1.8.9(react-dom@18.2.0)(react@18.2.0) + +devDependencies: + '@types/react': + specifier: ^18.2.15 + version: 18.2.15 + '@types/react-dom': + specifier: ^18.2.7 + version: 18.2.7 + '@typescript-eslint/eslint-plugin': + specifier: ^6.0.0 + version: 6.0.0(@typescript-eslint/parser@6.0.0)(eslint@8.45.0)(typescript@5.0.2) + '@typescript-eslint/parser': + specifier: ^6.0.0 + version: 6.0.0(eslint@8.45.0)(typescript@5.0.2) + '@vitejs/plugin-react': + specifier: ^4.0.3 + version: 4.0.3(vite@4.4.5) + eslint: + specifier: ^8.45.0 + version: 8.45.0 + eslint-plugin-react: + specifier: ^7.33.2 + version: 7.33.2(eslint@8.45.0) + eslint-plugin-react-hooks: + specifier: ^4.6.0 + version: 4.6.0(eslint@8.45.0) + eslint-plugin-react-refresh: + specifier: ^0.4.3 + version: 0.4.3(eslint@8.45.0) + typescript: + specifier: ^5.0.2 + version: 5.0.2 + vite: + specifier: ^4.4.5 + version: 4.4.5 + +packages: + + /@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + dev: true + + /@ampproject/remapping@2.2.1: + resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 + dev: true + + /@babel/code-frame@7.22.13: + resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.22.20 + chalk: 2.4.2 + + /@babel/compat-data@7.23.3: + resolution: {integrity: sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/core@7.23.3: + resolution: {integrity: sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.22.13 + '@babel/generator': 7.23.3 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.3) + '@babel/helpers': 7.23.2 + '@babel/parser': 7.23.3 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.3 + '@babel/types': 7.23.3 + convert-source-map: 2.0.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/generator@7.23.3: + resolution: {integrity: sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.3 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 + jsesc: 2.5.2 + dev: true + + /@babel/helper-compilation-targets@7.22.15: + resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.23.3 + '@babel/helper-validator-option': 7.22.15 + browserslist: 4.22.1 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: true + + /@babel/helper-environment-visitor@7.22.20: + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-function-name@7.23.0: + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/types': 7.23.3 + dev: true + + /@babel/helper-hoist-variables@7.22.5: + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.3 + dev: true + + /@babel/helper-module-imports@7.22.15: + resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.3 + + /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.3): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + dev: true + + /@babel/helper-plugin-utils@7.22.5: + resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-simple-access@7.22.5: + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.3 + dev: true + + /@babel/helper-split-export-declaration@7.22.6: + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.3 + dev: true + + /@babel/helper-string-parser@7.22.5: + resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-option@7.22.15: + resolution: {integrity: sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helpers@7.23.2: + resolution: {integrity: sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.3 + '@babel/types': 7.23.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/highlight@7.22.20: + resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + + /@babel/parser@7.23.3: + resolution: {integrity: sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.23.3 + dev: true + + /@babel/plugin-transform-react-jsx-self@7.23.3(@babel/core@7.23.3): + resolution: {integrity: sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-react-jsx-source@7.23.3(@babel/core@7.23.3): + resolution: {integrity: sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/runtime@7.23.2: + resolution: {integrity: sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.0 + dev: false + + /@babel/template@7.22.15: + resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.22.13 + '@babel/parser': 7.23.3 + '@babel/types': 7.23.3 + dev: true + + /@babel/traverse@7.23.3: + resolution: {integrity: sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.22.13 + '@babel/generator': 7.23.3 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.23.3 + '@babel/types': 7.23.3 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/types@7.23.3: + resolution: {integrity: sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + + /@emotion/babel-plugin@11.11.0: + resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==} + dependencies: + '@babel/helper-module-imports': 7.22.15 + '@babel/runtime': 7.23.2 + '@emotion/hash': 0.9.1 + '@emotion/memoize': 0.8.1 + '@emotion/serialize': 1.1.2 + babel-plugin-macros: 3.1.0 + convert-source-map: 1.9.0 + escape-string-regexp: 4.0.0 + find-root: 1.1.0 + source-map: 0.5.7 + stylis: 4.2.0 + dev: false + + /@emotion/cache@11.11.0: + resolution: {integrity: sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==} + dependencies: + '@emotion/memoize': 0.8.1 + '@emotion/sheet': 1.2.2 + '@emotion/utils': 1.2.1 + '@emotion/weak-memoize': 0.3.1 + stylis: 4.2.0 + dev: false + + /@emotion/hash@0.9.1: + resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} + dev: false + + /@emotion/is-prop-valid@1.2.1: + resolution: {integrity: sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==} + dependencies: + '@emotion/memoize': 0.8.1 + dev: false + + /@emotion/memoize@0.8.1: + resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==} + dev: false + + /@emotion/react@11.11.1(@types/react@18.2.15)(react@18.2.0): + resolution: {integrity: sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA==} + peerDependencies: + '@types/react': '*' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.2 + '@emotion/babel-plugin': 11.11.0 + '@emotion/cache': 11.11.0 + '@emotion/serialize': 1.1.2 + '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.2.0) + '@emotion/utils': 1.2.1 + '@emotion/weak-memoize': 0.3.1 + '@types/react': 18.2.15 + hoist-non-react-statics: 3.3.2 + react: 18.2.0 + dev: false + + /@emotion/serialize@1.1.2: + resolution: {integrity: sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==} + dependencies: + '@emotion/hash': 0.9.1 + '@emotion/memoize': 0.8.1 + '@emotion/unitless': 0.8.1 + '@emotion/utils': 1.2.1 + csstype: 3.1.2 + dev: false + + /@emotion/sheet@1.2.2: + resolution: {integrity: sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==} + dev: false + + /@emotion/styled@11.11.0(@emotion/react@11.11.1)(@types/react@18.2.15)(react@18.2.0): + resolution: {integrity: sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==} + peerDependencies: + '@emotion/react': ^11.0.0-rc.0 + '@types/react': '*' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.2 + '@emotion/babel-plugin': 11.11.0 + '@emotion/is-prop-valid': 1.2.1 + '@emotion/react': 11.11.1(@types/react@18.2.15)(react@18.2.0) + '@emotion/serialize': 1.1.2 + '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.2.0) + '@emotion/utils': 1.2.1 + '@types/react': 18.2.15 + react: 18.2.0 + dev: false + + /@emotion/unitless@0.8.1: + resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} + dev: false + + /@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.2.0): + resolution: {integrity: sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==} + peerDependencies: + react: '>=16.8.0' + dependencies: + react: 18.2.0 + dev: false + + /@emotion/utils@1.2.1: + resolution: {integrity: sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==} + dev: false + + /@emotion/weak-memoize@0.3.1: + resolution: {integrity: sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==} + dev: false + + /@esbuild/android-arm64@0.18.20: + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.18.20: + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.18.20: + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.18.20: + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.18.20: + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.18.20: + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.18.20: + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.18.20: + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.18.20: + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.18.20: + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.18.20: + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.18.20: + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.18.20: + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.18.20: + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.18.20: + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.18.20: + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.18.20: + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.18.20: + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.18.20: + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.18.20: + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.18.20: + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.18.20: + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@eslint-community/eslint-utils@4.4.0(eslint@8.45.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.45.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/regexpp@4.10.0: + resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/eslintrc@2.1.3: + resolution: {integrity: sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.6.1 + globals: 13.23.0 + ignore: 5.2.4 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/js@8.44.0: + resolution: {integrity: sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@floating-ui/core@1.5.0: + resolution: {integrity: sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==} + dependencies: + '@floating-ui/utils': 0.1.6 + dev: false + + /@floating-ui/dom@1.5.3: + resolution: {integrity: sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==} + dependencies: + '@floating-ui/core': 1.5.0 + '@floating-ui/utils': 0.1.6 + dev: false + + /@floating-ui/react-dom@2.0.4(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + '@floating-ui/dom': 1.5.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@floating-ui/utils@0.1.6: + resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==} + dev: false + + /@fontsource/roboto@5.0.8: + resolution: {integrity: sha512-XxPltXs5R31D6UZeLIV1td3wTXU3jzd3f2DLsXI8tytMGBkIsGcc9sIyiupRtA8y73HAhuSCeweOoBqf6DbWCA==} + dev: false + + /@humanwhocodes/config-array@0.11.13: + resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 2.0.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + + /@humanwhocodes/object-schema@2.0.1: + resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} + dev: true + + /@jridgewell/gen-mapping@0.3.3: + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.20 + dev: true + + /@jridgewell/resolve-uri@3.1.1: + resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/set-array@1.1.2: + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true + + /@jridgewell/trace-mapping@0.3.20: + resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /@mui/base@5.0.0-beta.23(@types/react@18.2.15)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-9L8SQUGAWtd/Qi7Qem26+oSSgpY7f2iQTuvcz/rsGpyZjSomMMO6lwYeQSA0CpWM7+aN7eGoSY/WV6wxJiIxXw==} + engines: {node: '>=12.0.0'} + peerDependencies: + '@types/react': ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.2 + '@floating-ui/react-dom': 2.0.4(react-dom@18.2.0)(react@18.2.0) + '@mui/types': 7.2.8(@types/react@18.2.15) + '@mui/utils': 5.14.17(@types/react@18.2.15)(react@18.2.0) + '@popperjs/core': 2.11.8 + '@types/react': 18.2.15 + clsx: 2.0.0 + prop-types: 15.8.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@mui/core-downloads-tracker@5.14.17: + resolution: {integrity: sha512-eE0uxrpJAEL2ZXkeGLKg8HQDafsiXY+6eNpP4lcv3yIjFfGbU6Hj9/P7Adt8jpU+6JIhmxvILGj2r27pX+zdrQ==} + dev: false + + /@mui/icons-material@5.14.16(@mui/material@5.14.17)(@types/react@18.2.15)(react@18.2.0): + resolution: {integrity: sha512-wmOgslMEGvbHZjFLru8uH5E+pif/ciXAvKNw16q6joK6EWVWU5rDYWFknDaZhCvz8ZE/K8ZnJQ+lMG6GgHzXbg==} + engines: {node: '>=12.0.0'} + peerDependencies: + '@mui/material': ^5.0.0 + '@types/react': ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.2 + '@mui/material': 5.14.17(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.15)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.15 + react: 18.2.0 + dev: false + + /@mui/material@5.14.17(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.15)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-+y0VeOLWfEA4Z98We/UH6KCo8+f2HLZDK45FY+sJf8kSojLy3VntadKtC/u0itqnXXb1Pr4wKB2tSIBW02zY4Q==} + engines: {node: '>=12.0.0'} + peerDependencies: + '@emotion/react': ^11.5.0 + '@emotion/styled': ^11.3.0 + '@types/react': ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@emotion/react': + optional: true + '@emotion/styled': + optional: true + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.2 + '@emotion/react': 11.11.1(@types/react@18.2.15)(react@18.2.0) + '@emotion/styled': 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.15)(react@18.2.0) + '@mui/base': 5.0.0-beta.23(@types/react@18.2.15)(react-dom@18.2.0)(react@18.2.0) + '@mui/core-downloads-tracker': 5.14.17 + '@mui/system': 5.14.17(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.15)(react@18.2.0) + '@mui/types': 7.2.8(@types/react@18.2.15) + '@mui/utils': 5.14.17(@types/react@18.2.15)(react@18.2.0) + '@types/react': 18.2.15 + '@types/react-transition-group': 4.4.9 + clsx: 2.0.0 + csstype: 3.1.2 + prop-types: 15.8.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-is: 18.2.0 + react-transition-group: 4.4.5(react-dom@18.2.0)(react@18.2.0) + dev: false + + /@mui/private-theming@5.14.17(@types/react@18.2.15)(react@18.2.0): + resolution: {integrity: sha512-u4zxsCm9xmQrlhVPug+Ccrtsjv7o2+rehvrgHoh0siSguvVgVQq5O3Hh10+tp/KWQo2JR4/nCEwquSXgITS1+g==} + engines: {node: '>=12.0.0'} + peerDependencies: + '@types/react': ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.2 + '@mui/utils': 5.14.17(@types/react@18.2.15)(react@18.2.0) + '@types/react': 18.2.15 + prop-types: 15.8.1 + react: 18.2.0 + dev: false + + /@mui/styled-engine@5.14.17(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0): + resolution: {integrity: sha512-AqpVjBEA7wnBvKPW168bNlqB6EN7HxTjLOY7oi275AzD/b1C7V0wqELy6NWoJb2yya5sRf7ENf4iNi3+T5cOgw==} + engines: {node: '>=12.0.0'} + peerDependencies: + '@emotion/react': ^11.4.1 + '@emotion/styled': ^11.3.0 + react: ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@emotion/react': + optional: true + '@emotion/styled': + optional: true + dependencies: + '@babel/runtime': 7.23.2 + '@emotion/cache': 11.11.0 + '@emotion/react': 11.11.1(@types/react@18.2.15)(react@18.2.0) + '@emotion/styled': 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.15)(react@18.2.0) + csstype: 3.1.2 + prop-types: 15.8.1 + react: 18.2.0 + dev: false + + /@mui/system@5.14.17(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.15)(react@18.2.0): + resolution: {integrity: sha512-Ccz3XlbCqka6DnbHfpL3o3TfOeWQPR+ewvNAgm8gnS9M0yVMmzzmY6z0w/C1eebb+7ZP7IoLUj9vojg/GBaTPg==} + engines: {node: '>=12.0.0'} + peerDependencies: + '@emotion/react': ^11.5.0 + '@emotion/styled': ^11.3.0 + '@types/react': ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@emotion/react': + optional: true + '@emotion/styled': + optional: true + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.2 + '@emotion/react': 11.11.1(@types/react@18.2.15)(react@18.2.0) + '@emotion/styled': 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.15)(react@18.2.0) + '@mui/private-theming': 5.14.17(@types/react@18.2.15)(react@18.2.0) + '@mui/styled-engine': 5.14.17(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + '@mui/types': 7.2.8(@types/react@18.2.15) + '@mui/utils': 5.14.17(@types/react@18.2.15)(react@18.2.0) + '@types/react': 18.2.15 + clsx: 2.0.0 + csstype: 3.1.2 + prop-types: 15.8.1 + react: 18.2.0 + dev: false + + /@mui/types@7.2.8(@types/react@18.2.15): + resolution: {integrity: sha512-9u0ji+xspl96WPqvrYJF/iO+1tQ1L5GTaDOeG3vCR893yy7VcWwRNiVMmPdPNpMDqx0WV1wtEW9OMwK9acWJzQ==} + peerDependencies: + '@types/react': ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.15 + dev: false + + /@mui/utils@5.14.17(@types/react@18.2.15)(react@18.2.0): + resolution: {integrity: sha512-yxnWgSS4J6DMFPw2Dof85yBkG02VTbEiqsikymMsnZnXDurtVGTIhlNuV24GTmFTuJMzEyTTU9UF+O7zaL8LEQ==} + engines: {node: '>=12.0.0'} + peerDependencies: + '@types/react': ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.2 + '@types/prop-types': 15.7.10 + '@types/react': 18.2.15 + prop-types: 15.8.1 + react: 18.2.0 + react-is: 18.2.0 + dev: false + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + dev: true + + /@popperjs/core@2.11.8: + resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + dev: false + + /@protobufjs/aspromise@1.1.2: + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + dev: false + + /@protobufjs/base64@1.1.2: + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + dev: false + + /@protobufjs/codegen@2.0.4: + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + dev: false + + /@protobufjs/eventemitter@1.1.0: + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + dev: false + + /@protobufjs/fetch@1.1.0: + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + dev: false + + /@protobufjs/float@1.0.2: + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + dev: false + + /@protobufjs/inquire@1.1.0: + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + dev: false + + /@protobufjs/path@1.1.2: + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + dev: false + + /@protobufjs/pool@1.1.0: + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + dev: false + + /@protobufjs/utf8@1.1.0: + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + dev: false + + /@remix-run/router@1.11.0: + resolution: {integrity: sha512-BHdhcWgeiudl91HvVa2wxqZjSHbheSgIiDvxrF1VjFzBzpTtuDPkOdOi3Iqvc08kXtFkLjhbS+ML9aM8mJS+wQ==} + engines: {node: '>=14.0.0'} + dev: false + + /@types/json-schema@7.0.15: + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + dev: true + + /@types/node@20.9.0: + resolution: {integrity: sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==} + dependencies: + undici-types: 5.26.5 + dev: false + + /@types/parse-json@4.0.2: + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + dev: false + + /@types/prop-types@15.7.10: + resolution: {integrity: sha512-mxSnDQxPqsZxmeShFH+uwQ4kO4gcJcGahjjMFeLbKE95IAZiiZyiEepGZjtXJ7hN/yfu0bu9xN2ajcU0JcxX6A==} + + /@types/react-dom@18.2.7: + resolution: {integrity: sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==} + dependencies: + '@types/react': 18.2.15 + dev: true + + /@types/react-transition-group@4.4.9: + resolution: {integrity: sha512-ZVNmWumUIh5NhH8aMD9CR2hdW0fNuYInlocZHaZ+dgk/1K49j1w/HoAuK1ki+pgscQrOFRTlXeoURtuzEkV3dg==} + dependencies: + '@types/react': 18.2.15 + dev: false + + /@types/react-window@1.8.8: + resolution: {integrity: sha512-8Ls660bHR1AUA2kuRvVG9D/4XpRC6wjAaPT9dil7Ckc76eP9TKWZwwmgfq8Q1LANX3QNDnoU4Zp48A3w+zK69Q==} + dependencies: + '@types/react': 18.2.15 + dev: false + + /@types/react@18.2.15: + resolution: {integrity: sha512-oEjE7TQt1fFTFSbf8kkNuc798ahTUzn3Le67/PWjE8MAfYAD/qB7O8hSTcromLFqHCt9bcdOg5GXMokzTjJ5SA==} + dependencies: + '@types/prop-types': 15.7.10 + '@types/scheduler': 0.16.6 + csstype: 3.1.2 + + /@types/scheduler@0.16.6: + resolution: {integrity: sha512-Vlktnchmkylvc9SnwwwozTv04L/e1NykF5vgoQ0XTmI8DD+wxfjQuHuvHS3p0r2jz2x2ghPs2h1FVeDirIteWA==} + + /@types/semver@7.5.5: + resolution: {integrity: sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==} + dev: true + + /@typescript-eslint/eslint-plugin@6.0.0(@typescript-eslint/parser@6.0.0)(eslint@8.45.0)(typescript@5.0.2): + resolution: {integrity: sha512-xuv6ghKGoiq856Bww/yVYnXGsKa588kY3M0XK7uUW/3fJNNULKRfZfSBkMTSpqGG/8ZCXCadfh8G/z/B4aqS/A==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.10.0 + '@typescript-eslint/parser': 6.0.0(eslint@8.45.0)(typescript@5.0.2) + '@typescript-eslint/scope-manager': 6.0.0 + '@typescript-eslint/type-utils': 6.0.0(eslint@8.45.0)(typescript@5.0.2) + '@typescript-eslint/utils': 6.0.0(eslint@8.45.0)(typescript@5.0.2) + '@typescript-eslint/visitor-keys': 6.0.0 + debug: 4.3.4 + eslint: 8.45.0 + grapheme-splitter: 1.0.4 + graphemer: 1.4.0 + ignore: 5.2.4 + natural-compare: 1.4.0 + natural-compare-lite: 1.4.0 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.0.2) + typescript: 5.0.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@6.0.0(eslint@8.45.0)(typescript@5.0.2): + resolution: {integrity: sha512-TNaufYSPrr1U8n+3xN+Yp9g31vQDJqhXzzPSHfQDLcaO4tU+mCfODPxCwf4H530zo7aUBE3QIdxCXamEnG04Tg==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 6.0.0 + '@typescript-eslint/types': 6.0.0 + '@typescript-eslint/typescript-estree': 6.0.0(typescript@5.0.2) + '@typescript-eslint/visitor-keys': 6.0.0 + debug: 4.3.4 + eslint: 8.45.0 + typescript: 5.0.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/scope-manager@6.0.0: + resolution: {integrity: sha512-o4q0KHlgCZTqjuaZ25nw5W57NeykZT9LiMEG4do/ovwvOcPnDO1BI5BQdCsUkjxFyrCL0cSzLjvIMfR9uo7cWg==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.0.0 + '@typescript-eslint/visitor-keys': 6.0.0 + dev: true + + /@typescript-eslint/type-utils@6.0.0(eslint@8.45.0)(typescript@5.0.2): + resolution: {integrity: sha512-ah6LJvLgkoZ/pyJ9GAdFkzeuMZ8goV6BH7eC9FPmojrnX9yNCIsfjB+zYcnex28YO3RFvBkV6rMV6WpIqkPvoQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 6.0.0(typescript@5.0.2) + '@typescript-eslint/utils': 6.0.0(eslint@8.45.0)(typescript@5.0.2) + debug: 4.3.4 + eslint: 8.45.0 + ts-api-utils: 1.0.3(typescript@5.0.2) + typescript: 5.0.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types@6.0.0: + resolution: {integrity: sha512-Zk9KDggyZM6tj0AJWYYKgF0yQyrcnievdhG0g5FqyU3Y2DRxJn4yWY21sJC0QKBckbsdKKjYDV2yVrrEvuTgxg==} + engines: {node: ^16.0.0 || >=18.0.0} + dev: true + + /@typescript-eslint/typescript-estree@6.0.0(typescript@5.0.2): + resolution: {integrity: sha512-2zq4O7P6YCQADfmJ5OTDQTP3ktajnXIRrYAtHM9ofto/CJZV3QfJ89GEaM2BNGeSr1KgmBuLhEkz5FBkS2RQhQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 6.0.0 + '@typescript-eslint/visitor-keys': 6.0.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.0.2) + typescript: 5.0.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@6.0.0(eslint@8.45.0)(typescript@5.0.2): + resolution: {integrity: sha512-SOr6l4NB6HE4H/ktz0JVVWNXqCJTOo/mHnvIte1ZhBQ0Cvd04x5uKZa3zT6tiodL06zf5xxdK8COiDvPnQ27JQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.5 + '@typescript-eslint/scope-manager': 6.0.0 + '@typescript-eslint/types': 6.0.0 + '@typescript-eslint/typescript-estree': 6.0.0(typescript@5.0.2) + eslint: 8.45.0 + eslint-scope: 5.1.1 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys@6.0.0: + resolution: {integrity: sha512-cvJ63l8c0yXdeT5POHpL0Q1cZoRcmRKFCtSjNGJxPkcP571EfZMcNbzWAc7oK3D1dRzm/V5EwtkANTZxqvuuUA==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.0.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@vitejs/plugin-react@4.0.3(vite@4.4.5): + resolution: {integrity: sha512-pwXDog5nwwvSIzwrvYYmA2Ljcd/ZNlcsSG2Q9CNDBwnsd55UGAyr2doXtB5j+2uymRCnCfExlznzzSFbBRcoCg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 + dependencies: + '@babel/core': 7.23.3 + '@babel/plugin-transform-react-jsx-self': 7.23.3(@babel/core@7.23.3) + '@babel/plugin-transform-react-jsx-source': 7.23.3(@babel/core@7.23.3) + react-refresh: 0.14.0 + vite: 4.4.5 + transitivePeerDependencies: + - supports-color + dev: true + + /abort-controller-x@0.4.3: + resolution: {integrity: sha512-VtUwTNU8fpMwvWGn4xE93ywbogTYsuT+AUxAXOeelbXuQVIwNmC5YLeho9sH4vZ4ITW8414TTAOG1nW6uIVHCA==} + dev: false + + /acorn-jsx@5.3.2(acorn@8.11.2): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.11.2 + dev: true + + /acorn@8.11.2: + resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + dev: true + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /array-buffer-byte-length@1.0.0: + resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} + dependencies: + call-bind: 1.0.5 + is-array-buffer: 3.0.2 + dev: true + + /array-includes@3.1.7: + resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + is-string: 1.0.7 + dev: true + + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: true + + /array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.tosorted@1.1.2: + resolution: {integrity: sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + get-intrinsic: 1.2.2 + dev: true + + /arraybuffer.prototype.slice@1.0.2: + resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + is-array-buffer: 3.0.2 + is-shared-array-buffer: 1.0.2 + dev: true + + /asynciterator.prototype@1.0.0: + resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==} + dependencies: + has-symbols: 1.0.3 + dev: true + + /available-typed-arrays@1.0.5: + resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + engines: {node: '>= 0.4'} + dev: true + + /babel-plugin-macros@3.1.0: + resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} + engines: {node: '>=10', npm: '>=6'} + dependencies: + '@babel/runtime': 7.23.2 + cosmiconfig: 7.1.0 + resolve: 1.22.8 + dev: false + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /browserslist@4.22.1: + resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001561 + electron-to-chromium: 1.4.581 + node-releases: 2.0.13 + update-browserslist-db: 1.0.13(browserslist@4.22.1) + dev: true + + /call-bind@1.0.5: + resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} + dependencies: + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + set-function-length: 1.1.1 + dev: true + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + /caniuse-lite@1.0.30001561: + resolution: {integrity: sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw==} + dev: true + + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /clsx@2.0.0: + resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} + engines: {node: '>=6'} + dev: false + + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + dev: false + + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + dev: true + + /cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.0 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + dev: false + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /csstype@3.1.2: + resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true + + /define-data-property@1.1.1: + resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: true + + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + has-property-descriptors: 1.0.1 + object-keys: 1.1.1 + dev: true + + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + + /doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /dom-helpers@5.2.1: + resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + dependencies: + '@babel/runtime': 7.23.2 + csstype: 3.1.2 + dev: false + + /electron-to-chromium@1.4.581: + resolution: {integrity: sha512-6uhqWBIapTJUxgPTCHH9sqdbxIMPt7oXl0VcAL1kOtlU6aECdcMncCrX5Z7sHQ/invtrC9jUQUef7+HhO8vVFw==} + dev: true + + /error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: false + + /es-abstract@1.22.3: + resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + arraybuffer.prototype.slice: 1.0.2 + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + es-set-tostringtag: 2.0.2 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.2 + get-symbol-description: 1.0.0 + globalthis: 1.0.3 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 + internal-slot: 1.0.6 + is-array-buffer: 3.0.2 + is-callable: 1.2.7 + is-negative-zero: 2.0.2 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + is-string: 1.0.7 + is-typed-array: 1.1.12 + is-weakref: 1.0.2 + object-inspect: 1.13.1 + object-keys: 1.1.1 + object.assign: 4.1.4 + regexp.prototype.flags: 1.5.1 + safe-array-concat: 1.0.1 + safe-regex-test: 1.0.0 + string.prototype.trim: 1.2.8 + string.prototype.trimend: 1.0.7 + string.prototype.trimstart: 1.0.7 + typed-array-buffer: 1.0.0 + typed-array-byte-length: 1.0.0 + typed-array-byte-offset: 1.0.0 + typed-array-length: 1.0.4 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.13 + dev: true + + /es-iterator-helpers@1.0.15: + resolution: {integrity: sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==} + dependencies: + asynciterator.prototype: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-set-tostringtag: 2.0.2 + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + globalthis: 1.0.3 + has-property-descriptors: 1.0.1 + has-proto: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.6 + iterator.prototype: 1.1.2 + safe-array-concat: 1.0.1 + dev: true + + /es-set-tostringtag@2.0.2: + resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + has-tostringtag: 1.0.0 + hasown: 2.0.0 + dev: true + + /es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + dependencies: + hasown: 2.0.0 + dev: true + + /es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + dev: true + + /esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + dev: true + + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: true + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + /eslint-plugin-react-hooks@4.6.0(eslint@8.45.0): + resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + dependencies: + eslint: 8.45.0 + dev: true + + /eslint-plugin-react-refresh@0.4.3(eslint@8.45.0): + resolution: {integrity: sha512-Hh0wv8bUNY877+sI0BlCUlsS0TYYQqvzEwJsJJPM2WF4RnTStSnSR3zdJYa2nPOJgg3UghXi54lVyMSmpCalzA==} + peerDependencies: + eslint: '>=7' + dependencies: + eslint: 8.45.0 + dev: true + + /eslint-plugin-react@7.33.2(eslint@8.45.0): + resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + dependencies: + array-includes: 3.1.7 + array.prototype.flatmap: 1.3.2 + array.prototype.tosorted: 1.1.2 + doctrine: 2.1.0 + es-iterator-helpers: 1.0.15 + eslint: 8.45.0 + estraverse: 5.3.0 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.7 + object.fromentries: 2.0.7 + object.hasown: 1.1.3 + object.values: 1.1.7 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.10 + dev: true + + /eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + dev: true + + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /eslint@8.45.0: + resolution: {integrity: sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) + '@eslint-community/regexpp': 4.10.0 + '@eslint/eslintrc': 2.1.3 + '@eslint/js': 8.44.0 + '@humanwhocodes/config-array': 0.11.13 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.23.0 + graphemer: 1.4.0 + ignore: 5.2.4 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.11.2 + acorn-jsx: 5.3.2(acorn@8.11.2) + eslint-visitor-keys: 3.4.3 + dev: true + + /esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + dev: true + + /esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + dev: true + + /estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + dev: true + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true + + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: true + + /fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true + + /fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + dev: true + + /fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + dependencies: + reusify: 1.0.4 + dev: true + + /file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: 3.1.1 + dev: true + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /find-root@1.1.0: + resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} + dev: false + + /find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + + /flat-cache@3.1.1: + resolution: {integrity: sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==} + engines: {node: '>=12.0.0'} + dependencies: + flatted: 3.2.9 + keyv: 4.5.4 + rimraf: 3.0.2 + dev: true + + /flatted@3.2.9: + resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} + dev: true + + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + dev: true + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + /function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + functions-have-names: 1.2.3 + dev: true + + /functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + dev: true + + /gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + dev: true + + /get-intrinsic@1.2.2: + resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} + dependencies: + function-bind: 1.1.2 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 + dev: true + + /get-symbol-description@1.0.0: + resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + dev: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + dev: true + + /globals@13.23.0: + resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: true + + /globalthis@1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + engines: {node: '>= 0.4'} + dependencies: + define-properties: 1.2.1 + dev: true + + /globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.2 + dev: true + + /grapheme-splitter@1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + dev: true + + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + dev: true + + /has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + dev: true + + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: true + + /has-property-descriptors@1.0.1: + resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} + dependencies: + get-intrinsic: 1.2.2 + dev: true + + /has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + dev: true + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: true + + /has-tostringtag@1.0.0: + resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + + /hasown@2.0.0: + resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + + /hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + dependencies: + react-is: 16.13.1 + dev: false + + /ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + dev: true + + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: true + + /internal-slot@1.0.6: + resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + hasown: 2.0.0 + side-channel: 1.0.4 + dev: true + + /invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + dependencies: + loose-envify: 1.4.0 + dev: false + + /is-array-buffer@3.0.2: + resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-typed-array: 1.1.12 + dev: true + + /is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: false + + /is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + dependencies: + has-bigints: 1.0.2 + dev: true + + /is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + has-tostringtag: 1.0.0 + dev: true + + /is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + dev: true + + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.0 + + /is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-finalizationregistry@1.0.2: + resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + dependencies: + call-bind: 1.0.5 + dev: true + + /is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-map@2.0.2: + resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} + dev: true + + /is-negative-zero@2.0.2: + resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} + engines: {node: '>= 0.4'} + dev: true + + /is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + + /is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + has-tostringtag: 1.0.0 + dev: true + + /is-set@2.0.2: + resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==} + dev: true + + /is-shared-array-buffer@1.0.2: + resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + dependencies: + call-bind: 1.0.5 + dev: true + + /is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + + /is-typed-array@1.1.12: + resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.13 + dev: true + + /is-weakmap@2.0.1: + resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} + dev: true + + /is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + dependencies: + call-bind: 1.0.5 + dev: true + + /is-weakset@2.0.2: + resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + dev: true + + /isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: true + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /isomorphic-ws@5.0.0(ws@8.14.2): + resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==} + peerDependencies: + ws: '*' + dependencies: + ws: 8.14.2 + dev: false + + /iterator.prototype@1.1.2: + resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} + dependencies: + define-properties: 1.2.1 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + reflect.getprototypeof: 1.0.4 + set-function-name: 2.0.1 + dev: true + + /js-base64@3.7.5: + resolution: {integrity: sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==} + dev: false + + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: true + + /json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: false + + /json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + dev: true + + /json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true + + /json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + dev: true + + /jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + dependencies: + array-includes: 3.1.7 + array.prototype.flat: 1.3.2 + object.assign: 4.1.4 + object.values: 1.1.7 + dev: true + + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + dev: true + + /levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: false + + /locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /long@5.2.3: + resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} + dev: false + + /loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + dependencies: + js-tokens: 4.0.0 + + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + dev: true + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: true + + /memoize-one@5.2.1: + resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} + dev: false + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: true + + /nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /natural-compare-lite@1.4.0: + resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} + dev: true + + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + dev: true + + /nice-grpc-common@2.0.2: + resolution: {integrity: sha512-7RNWbls5kAL1QVUOXvBsv1uO0wPQK3lHv+cY1gwkTzirnG1Nop4cBJZubpgziNbaVc/bl9QJcyvsf/NQxa3rjQ==} + dependencies: + ts-error: 1.0.6 + dev: false + + /nice-grpc-web@3.3.2(ws@8.14.2): + resolution: {integrity: sha512-qetU+H6y6jVvI5NZdtTls9UdqdCNwhr4UxqL5SfH6v8ISxucxDVPRYxnZaoZyWjMRvRgAKiQDIMu0bB0oedD0A==} + dependencies: + abort-controller-x: 0.4.3 + isomorphic-ws: 5.0.0(ws@8.14.2) + js-base64: 3.7.5 + nice-grpc-common: 2.0.2 + transitivePeerDependencies: + - ws + dev: false + + /node-releases@2.0.13: + resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + dev: true + + /object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + /object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: true + + /object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + dev: true + + /object.assign@4.1.4: + resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + dev: true + + /object.entries@1.1.7: + resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /object.fromentries@2.0.7: + resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /object.hasown@1.1.3: + resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==} + dependencies: + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /object.values@1.1.7: + resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: true + + /optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + engines: {node: '>= 0.8.0'} + dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + dev: true + + /p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: true + + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + + /parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': 7.22.13 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: false + + /path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: true + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + + /prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: true + + /prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + /protobufjs@7.2.5: + resolution: {integrity: sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==} + engines: {node: '>=12.0.0'} + requiresBuild: true + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/node': 20.9.0 + long: 5.2.3 + dev: false + + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + dev: true + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /react-dom@18.2.0(react@18.2.0): + resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} + peerDependencies: + react: ^18.2.0 + dependencies: + loose-envify: 1.4.0 + react: 18.2.0 + scheduler: 0.23.0 + dev: false + + /react-fast-compare@3.2.2: + resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==} + dev: false + + /react-helmet-async@1.3.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==} + peerDependencies: + react: ^16.6.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.6.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@babel/runtime': 7.23.2 + invariant: 2.2.4 + prop-types: 15.8.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-fast-compare: 3.2.2 + shallowequal: 1.1.0 + dev: false + + /react-hook-form@7.48.2(react@18.2.0): + resolution: {integrity: sha512-H0T2InFQb1hX7qKtDIZmvpU1Xfn/bdahWBN1fH19gSe4bBEqTfmlr7H3XWTaVtiK4/tpPaI1F3355GPMZYge+A==} + engines: {node: '>=12.22.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 + dependencies: + react: 18.2.0 + dev: false + + /react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + /react-is@18.2.0: + resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + dev: false + + /react-refresh@0.14.0: + resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} + engines: {node: '>=0.10.0'} + dev: true + + /react-router-dom@6.18.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Ubrue4+Ercc/BoDkFQfc6og5zRQ4A8YxSO3Knsne+eRbZ+IepAsK249XBH/XaFuOYOYr3L3r13CXTLvYt5JDjw==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + dependencies: + '@remix-run/router': 1.11.0 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-router: 6.18.0(react@18.2.0) + dev: false + + /react-router@6.18.0(react@18.2.0): + resolution: {integrity: sha512-vk2y7Dsy8wI02eRRaRmOs9g2o+aE72YCx5q9VasT1N9v+lrdB79tIqrjMfByHiY5+6aYkH2rUa5X839nwWGPDg==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + dependencies: + '@remix-run/router': 1.11.0 + react: 18.2.0 + dev: false + + /react-transition-group@4.4.5(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + peerDependencies: + react: '>=16.6.0' + react-dom: '>=16.6.0' + dependencies: + '@babel/runtime': 7.23.2 + dom-helpers: 5.2.1 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /react-window@1.8.9(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-+Eqx/fj1Aa5WnhRfj9dJg4VYATGwIUP2ItwItiJ6zboKWA6EX3lYDAXfGF2hyNqplEprhbtjbipiADEcwQ823Q==} + engines: {node: '>8.0.0'} + peerDependencies: + react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@babel/runtime': 7.23.2 + memoize-one: 5.2.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /react@18.2.0: + resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} + engines: {node: '>=0.10.0'} + dependencies: + loose-envify: 1.4.0 + dev: false + + /reflect.getprototypeof@1.0.4: + resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + globalthis: 1.0.3 + which-builtin-type: 1.1.3 + dev: true + + /regenerator-runtime@0.14.0: + resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} + dev: false + + /regexp.prototype.flags@1.5.1: + resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + set-function-name: 2.0.1 + dev: true + + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: false + + /resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: true + + /rollup@3.29.4: + resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /safe-array-concat@1.0.1: + resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + isarray: 2.0.5 + dev: true + + /safe-regex-test@1.0.0: + resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-regex: 1.1.4 + dev: true + + /scheduler@0.23.0: + resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} + dependencies: + loose-envify: 1.4.0 + dev: false + + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + dev: true + + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /set-function-length@1.1.1: + resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: true + + /set-function-name@2.0.1: + resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.1 + dev: true + + /shallowequal@1.1.0: + resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} + dev: false + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true + + /side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + object-inspect: 1.13.1 + dev: true + + /slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: true + + /source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + dev: true + + /source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + dev: false + + /string.prototype.matchall@4.0.10: + resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + internal-slot: 1.0.6 + regexp.prototype.flags: 1.5.1 + set-function-name: 2.0.1 + side-channel: 1.0.4 + dev: true + + /string.prototype.trim@1.2.8: + resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /string.prototype.trimend@1.0.7: + resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /string.prototype.trimstart@1.0.7: + resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + dev: true + + /stylis@4.2.0: + resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + dev: false + + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + + /to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /ts-api-utils@1.0.3(typescript@5.0.2): + resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} + engines: {node: '>=16.13.0'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.0.2 + dev: true + + /ts-error@1.0.6: + resolution: {integrity: sha512-tLJxacIQUM82IR7JO1UUkKlYuUTmoY9HBJAmNWFzheSlDS5SPMcNIepejHJa4BpPQLAcbRhRf3GDJzyj6rbKvA==} + dev: false + + /type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + dev: true + + /type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + dev: true + + /typed-array-buffer@1.0.0: + resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-length@1.0.0: + resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-offset@1.0.0: + resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-length@1.0.4: + resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + dependencies: + call-bind: 1.0.5 + for-each: 0.3.3 + is-typed-array: 1.1.12 + dev: true + + /typescript@5.0.2: + resolution: {integrity: sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==} + engines: {node: '>=12.20'} + hasBin: true + dev: true + + /unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + dependencies: + call-bind: 1.0.5 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + dev: true + + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: false + + /update-browserslist-db@1.0.13(browserslist@4.22.1): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.22.1 + escalade: 3.1.1 + picocolors: 1.0.0 + dev: true + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.1 + dev: true + + /vite@4.4.5: + resolution: {integrity: sha512-4m5kEtAWHYr0O1Fu7rZp64CfO1PsRGZlD3TAB32UmQlpd7qg15VF7ROqGN5CyqN7HFuwr7ICNM2+fDWRqFEKaA==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + esbuild: 0.18.20 + postcss: 8.4.31 + rollup: 3.29.4 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + dependencies: + is-bigint: 1.0.4 + is-boolean-object: 1.1.2 + is-number-object: 1.0.7 + is-string: 1.0.7 + is-symbol: 1.0.4 + dev: true + + /which-builtin-type@1.1.3: + resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==} + engines: {node: '>= 0.4'} + dependencies: + function.prototype.name: 1.1.6 + has-tostringtag: 1.0.0 + is-async-function: 2.0.0 + is-date-object: 1.0.5 + is-finalizationregistry: 1.0.2 + is-generator-function: 1.0.10 + is-regex: 1.1.4 + is-weakref: 1.0.2 + isarray: 2.0.5 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.1 + which-typed-array: 1.1.13 + dev: true + + /which-collection@1.0.1: + resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==} + dependencies: + is-map: 2.0.2 + is-set: 2.0.2 + is-weakmap: 2.0.1 + is-weakset: 2.0.2 + dev: true + + /which-typed-array@1.1.13: + resolution: {integrity: sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 + dev: true + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true + + /ws@8.14.2: + resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + + /yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: true + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true + + /yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + dev: false + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true diff --git a/front/public/logo.png b/front/public/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4dda6d46c8c7b9fb146cba7d0784346a713f5de8 GIT binary patch literal 7955 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 z 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%0AuLG7kqc#T-Y_7 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

fd|JD)P#pe_0 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�IBwP9vNW&I3#bDNz4a2jckps;D~&*pdZh_rg-i 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�>gT)I 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 literal 0 HcmV?d00001 diff --git a/front/src/components/ExploitUpdateForm.tsx b/front/src/components/ExploitUpdateForm.tsx new file mode 100644 index 0000000..dfa3a91 --- /dev/null +++ b/front/src/components/ExploitUpdateForm.tsx @@ -0,0 +1,152 @@ +import { ExploitState } from "@/proto/exploits/api"; +import { useExploitServiceClient } from "@/services/exploits"; +import { formatSeconds, parseDuration } from "@/utils/duration"; +import { Button, Grid, Stack, TextField, Typography } from "@mui/material"; +import { ClientError } from "nice-grpc-common"; +import { SubmitHandler, useForm } from "react-hook-form"; + +interface P { + exploit: ExploitState; + onRefresh: () => void; +} + +interface Inputs { + timeout: string; + interval: string; +} + +export default function ExploitUpdateForm(props: P) { + const { + register, + handleSubmit, + formState: { errors }, + setError, + } = useForm({ + defaultValues: { + timeout: formatSeconds( + props.exploit.config?.timeout?.seconds.toInt() || 0 + ), + interval: formatSeconds( + props.exploit.config?.runEvery?.seconds.toInt() || 0 + ), + }, + }); + + const exploitServiceClient = useExploitServiceClient(); + + const submitState = async (state: ExploitState) => { + try { + await exploitServiceClient.updateExploit({ state }); + } catch (e) { + if (e instanceof ClientError) { + setError("root", { + type: "manual", + message: e.message, + }); + } + } + props.onRefresh(); + }; + + const onSubmit: SubmitHandler = async (inputs: Inputs) => { + const newState = ExploitState.fromJSON(ExploitState.toJSON(props.exploit)); + if (!newState.config) { + return; + } + newState.config.timeout = parseDuration(inputs.timeout); + newState.config.runEvery = parseDuration(inputs.interval); + await submitState(newState); + }; + + const handleDisabledButton = async () => { + const newState = ExploitState.fromJSON(ExploitState.toJSON(props.exploit)); + if (!newState.config) { + return; + } + newState.config.disabled = !newState.config.disabled; + await submitState(newState); + }; + + const validateDuration = (value: string) => { + try { + parseDuration(value); + return true; + } catch (e) { + if (e instanceof Error) { + return e.message; + } else { + return "unknown error"; + } + } + }; + + return ( + <> +

{ + event.preventDefault(); + void handleSubmit(onSubmit)(event); + }} + > + + + + + + + + + {errors.root && ( + + {errors.root.message} + + )} + + + + + + + + + + + ); +} diff --git a/front/src/components/ExploitsView.tsx b/front/src/components/ExploitsView.tsx new file mode 100644 index 0000000..cc4ec83 --- /dev/null +++ b/front/src/components/ExploitsView.tsx @@ -0,0 +1,59 @@ +import ExploitUpdateForm from "@/components/ExploitUpdateForm"; +import { ExploitState } from "@/proto/exploits/api"; +import { formatSeconds } from "@/utils/duration"; +import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; +import { + Accordion, + AccordionDetails, + AccordionSummary, + Box, + Typography, +} from "@mui/material"; +import { useState } from "react"; + +interface P { + exploits: ExploitState[]; + onRefresh: () => void; +} + +export default function ExploitsView(props: P) { + const [expanded, setExpanded] = useState(false); + + const handleChange = + (exploit: ExploitState) => + (_event: React.SyntheticEvent, isExpanded: boolean) => { + setExpanded(isExpanded ? exploit.exploitId : false); + }; + + return ( + <> + {props.exploits.map((exploit) => ( + + }> + + {exploit.exploitId} + {" v"} + {exploit.version.toString()} + {" timeout="} + {formatSeconds(exploit.config?.timeout?.seconds.toInt() || 0)} + {" interval="} + {formatSeconds(exploit.config?.runEvery?.seconds.toInt() || 0)} + + + + + + + + + ))} + + ); +} diff --git a/front/src/components/LogsRootView.tsx b/front/src/components/LogsRootView.tsx new file mode 100644 index 0000000..0b156c0 --- /dev/null +++ b/front/src/components/LogsRootView.tsx @@ -0,0 +1,132 @@ +import { ExploitState } from "@/proto/exploits/api"; +import { LogLine } from "@/proto/logs/api"; +import { useRootContext } from "@/routes/rootContext"; +import { useExploitServiceClient } from "@/services/exploits"; +import { useLogsServiceClient } from "@/services/logs"; +import { useWindowDimensions } from "@/utils/window"; +import { + CircularProgress, + FormControl, + Grid, + InputLabel, + MenuItem, + Select, + SelectChangeEvent, + Stack, + TextField, +} from "@mui/material"; +import { useEffect, useRef, useState } from "react"; +import { unstable_batchedUpdates } from "react-dom"; +import LogsView from "./LogsView"; + +interface S { + exploitID: string; + exploitVersion: string; +} + +interface P { + exploits: ExploitState[]; +} + +export default function LogsRootView(props: P) { + const [state, setState] = useState({ exploitID: "", exploitVersion: "" }); + const [lines, setLines] = useState([]); + const [loading, setLoading] = useState(false); + + const exploitServiceClient = useExploitServiceClient(); + const logsServiceClient = useLogsServiceClient(); + + const fetchExploitData = async (exploitID: string) => { + try { + const response = await exploitServiceClient.exploit({ + exploitId: exploitID, + }); + return response.state?.version.toString() || ""; + } catch { + return ""; + } + }; + + const handleExploitIDChange = (event: SelectChangeEvent) => { + const wrapper = async () => { + const exploitVersion = await fetchExploitData(event.target.value); + setState({ exploitID: event.target.value, exploitVersion }); + }; + void wrapper(); + }; + + const handleExploitVersionChange = ( + event: React.ChangeEvent + ) => { + setState({ ...state, exploitVersion: event.target.value }); + }; + + useEffect(() => { + const tailLogs = async () => { + if (state.exploitID === "" || state.exploitVersion === "") { + return; + } + setLoading(true); + const stream = logsServiceClient.searchLogLines({ + exploit: state.exploitID, + version: state.exploitVersion, + }); + const lines: LogLine[] = []; + for await (const response of stream) { + lines.push(...response.lines); + } + unstable_batchedUpdates(() => { + setLoading(false); + setLines(lines); + }); + }; + + void tailLogs(); + }, [state.exploitID, state.exploitVersion, logsServiceClient]); + + const streamFormRef = useRef(null); + const { topbarRef } = useRootContext(); + + const { height: windowHeight } = useWindowDimensions(); + const viewSize = + windowHeight - + (topbarRef.current?.clientHeight ?? 0) - + (streamFormRef.current?.clientHeight ?? 0) - + 1; + + return ( + + + + + Exploit + + + + + + + {loading && } + {!loading && } + + + ); +} diff --git a/front/src/components/LogsView.tsx b/front/src/components/LogsView.tsx new file mode 100644 index 0000000..466cc0e --- /dev/null +++ b/front/src/components/LogsView.tsx @@ -0,0 +1,63 @@ +import { LogLine } from "@/proto/logs/api"; +import { CSSProperties } from "react"; +import { VariableSizeList } from "react-window"; + +interface P { + lines: LogLine[]; + viewHeight: number; +} + +export default function LogsView(props: P) { + const mapLevelColor = (level: string) => { + switch (level) { + case "debug": + return "grey"; + case "info": + return "black"; + case "warning": + return "orange"; + case "error": + return "red"; + default: + return "black"; + } + }; + + const lineCounts = props.lines.map((line) => line.message.split("\n").length); + + const LineRow = ({ + index, + style, + }: { + index: number; + style: CSSProperties; + }) => { + const line = props.lines[index]; + + return ( +
+        [{line.team}] [{line.level}] {line.message}
+      
+ ); + }; + + return ( + lineCounts[index] * 16} + width="100%" + > + {LineRow} + + ); +} diff --git a/front/src/config.ts b/front/src/config.ts new file mode 100644 index 0000000..9f491b3 --- /dev/null +++ b/front/src/config.ts @@ -0,0 +1,10 @@ +let grpcAddressTemp = "ws://127.0.0.1:5005"; +if (!import.meta.env.DEV) { + if (window.location.protocol === "https:") { + grpcAddressTemp = "wss://" + window.location.host; + } else { + grpcAddressTemp = "ws://" + window.location.host; + } +} + +export const grpcAddress = grpcAddressTemp; diff --git a/front/src/index.css b/front/src/index.css new file mode 100644 index 0000000..1d09d66 --- /dev/null +++ b/front/src/index.css @@ -0,0 +1,8 @@ +body > #root { + max-height: 100vh; + /* overflow: hidden; */ +} + +body { + margin: 0; +} \ No newline at end of file diff --git a/front/src/main.tsx b/front/src/main.tsx new file mode 100644 index 0000000..4d37a37 --- /dev/null +++ b/front/src/main.tsx @@ -0,0 +1,51 @@ +import "@/index.css"; +import ExploitsContainer from "@/routes/exploits"; +import Root from "@/routes/root"; +import theme from "@/theme"; +import "@fontsource/roboto/300.css"; +import "@fontsource/roboto/400.css"; +import "@fontsource/roboto/500.css"; +import "@fontsource/roboto/700.css"; +import { ThemeProvider } from "@mui/material"; +import React from "react"; +import ReactDOM from "react-dom/client"; +import { HelmetProvider } from "react-helmet-async"; +import { createBrowserRouter, RouterProvider } from "react-router-dom"; +import AuthProvider from "./routes/auth"; +import LogsContainer from "./routes/logs"; + +const router = createBrowserRouter([ + { + path: "/", + element: , + children: [ + { + index: true, + element: ( + + + + ), + }, + { + path: "/logs", + element: ( + + + + ), + }, + ], + }, +]); + +// eslint-disable-next-line @typescript-eslint/no-non-null-assertion +ReactDOM.createRoot(document.getElementById("root")!).render( + + + + + + + +); diff --git a/front/src/proto/exploits/api.ts b/front/src/proto/exploits/api.ts new file mode 100644 index 0000000..c64211b --- /dev/null +++ b/front/src/proto/exploits/api.ts @@ -0,0 +1,1963 @@ +// @ts-nocheck +/* eslint-disable */ +import Long from "long"; +import type { CallContext, CallOptions } from "nice-grpc-common"; +import _m0 from "protobufjs/minimal"; +import { FileInfo } from "../fileserver/api"; +import { Duration } from "../google/protobuf/duration"; + +export const protobufPackage = "exploits"; + +export interface TeamBucket { + teams: Map; +} + +export interface TeamBucket_TeamsEntry { + key: string; + value: string; +} + +export interface ExploitConfiguration { + entrypoint: string; + isArchive: boolean; + runEvery: Duration | undefined; + timeout: Duration | undefined; + disabled: boolean; + endless: boolean; +} + +export interface ExploitState { + exploitId: string; + version: Long; + file: FileInfo | undefined; + config: ExploitConfiguration | undefined; +} + +export interface Config { + farmUrl: string; + farmPassword: string; + flagRegexp: string; + pingEvery: Duration | undefined; + submitEvery: Duration | undefined; + environ: string[]; +} + +export interface ServerState { + /** Ping distribution by client */ + clientTeamMap: Map; + exploits: ExploitState[]; + config: Config | undefined; +} + +export interface ServerState_ClientTeamMapEntry { + key: string; + value: TeamBucket | undefined; +} + +export interface PingRequest { + clientId: string; + payload?: + | { $case: "serverInfoRequest"; serverInfoRequest: PingRequest_ServerInfo } + | { $case: "heartbeatRequest"; heartbeatRequest: PingRequest_Heartbeat } + | { $case: "leaveRequest"; leaveRequest: PingRequest_Leave } + | undefined; +} + +export interface PingRequest_ServerInfo { +} + +export interface PingRequest_Heartbeat { + weight: number; +} + +export interface PingRequest_Leave { +} + +export interface PingResponse { + state: ServerState | undefined; +} + +export interface ExploitRequest { + exploitId: string; +} + +export interface ExploitResponse { + state: ExploitState | undefined; +} + +export interface UpdateExploitRequest { + state: ExploitState | undefined; +} + +export interface UpdateExploitResponse { + state: ExploitState | undefined; +} + +export interface BroadcastRequest { + command: string; +} + +export interface BroadcastResponse { +} + +export interface BroadcastSubscribeRequest { +} + +export interface BroadcastSubscribeResponse { + command: string; +} + +export interface SingleRunRequest { + exploitId: string; +} + +export interface SingleRunResponse { +} + +export interface SingleRunSubscribeRequest { +} + +export interface SingleRunSubscribeResponse { + exploitId: string; +} + +function createBaseTeamBucket(): TeamBucket { + return { teams: new Map() }; +} + +export const TeamBucket = { + encode(message: TeamBucket, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + message.teams.forEach((value, key) => { + TeamBucket_TeamsEntry.encode({ key: key as any, value }, writer.uint32(10).fork()).ldelim(); + }); + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): TeamBucket { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseTeamBucket(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + const entry1 = TeamBucket_TeamsEntry.decode(reader, reader.uint32()); + if (entry1.value !== undefined) { + message.teams.set(entry1.key, entry1.value); + } + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): TeamBucket { + return { + teams: isObject(object.teams) + ? Object.entries(object.teams).reduce>((acc, [key, value]) => { + acc.set(key, String(value)); + return acc; + }, new Map()) + : new Map(), + }; + }, + + toJSON(message: TeamBucket): unknown { + const obj: any = {}; + if (message.teams?.size) { + obj.teams = {}; + message.teams.forEach((v, k) => { + obj.teams[k] = v; + }); + } + return obj; + }, + + create, I>>(base?: I): TeamBucket { + return TeamBucket.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): TeamBucket { + const message = createBaseTeamBucket(); + message.teams = (() => { + const m = new Map(); + (object.teams as Map ?? new Map()).forEach((value, key) => { + if (value !== undefined) { + m.set(key, globalThis.String(value)); + } + }); + return m; + })(); + return message; + }, +}; + +function createBaseTeamBucket_TeamsEntry(): TeamBucket_TeamsEntry { + return { key: "", value: "" }; +} + +export const TeamBucket_TeamsEntry = { + encode(message: TeamBucket_TeamsEntry, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.key !== "") { + writer.uint32(10).string(message.key); + } + if (message.value !== "") { + writer.uint32(18).string(message.value); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): TeamBucket_TeamsEntry { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseTeamBucket_TeamsEntry(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.key = reader.string(); + continue; + case 2: + if (tag !== 18) { + break; + } + + message.value = reader.string(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): TeamBucket_TeamsEntry { + return { + key: isSet(object.key) ? globalThis.String(object.key) : "", + value: isSet(object.value) ? globalThis.String(object.value) : "", + }; + }, + + toJSON(message: TeamBucket_TeamsEntry): unknown { + const obj: any = {}; + if (message.key !== "") { + obj.key = message.key; + } + if (message.value !== "") { + obj.value = message.value; + } + return obj; + }, + + create, I>>(base?: I): TeamBucket_TeamsEntry { + return TeamBucket_TeamsEntry.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): TeamBucket_TeamsEntry { + const message = createBaseTeamBucket_TeamsEntry(); + message.key = object.key ?? ""; + message.value = object.value ?? ""; + return message; + }, +}; + +function createBaseExploitConfiguration(): ExploitConfiguration { + return { entrypoint: "", isArchive: false, runEvery: undefined, timeout: undefined, disabled: false, endless: false }; +} + +export const ExploitConfiguration = { + encode(message: ExploitConfiguration, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.entrypoint !== "") { + writer.uint32(10).string(message.entrypoint); + } + if (message.isArchive === true) { + writer.uint32(16).bool(message.isArchive); + } + if (message.runEvery !== undefined) { + Duration.encode(message.runEvery, writer.uint32(26).fork()).ldelim(); + } + if (message.timeout !== undefined) { + Duration.encode(message.timeout, writer.uint32(34).fork()).ldelim(); + } + if (message.disabled === true) { + writer.uint32(40).bool(message.disabled); + } + if (message.endless === true) { + writer.uint32(48).bool(message.endless); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): ExploitConfiguration { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseExploitConfiguration(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.entrypoint = reader.string(); + continue; + case 2: + if (tag !== 16) { + break; + } + + message.isArchive = reader.bool(); + continue; + case 3: + if (tag !== 26) { + break; + } + + message.runEvery = Duration.decode(reader, reader.uint32()); + continue; + case 4: + if (tag !== 34) { + break; + } + + message.timeout = Duration.decode(reader, reader.uint32()); + continue; + case 5: + if (tag !== 40) { + break; + } + + message.disabled = reader.bool(); + continue; + case 6: + if (tag !== 48) { + break; + } + + message.endless = reader.bool(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): ExploitConfiguration { + return { + entrypoint: isSet(object.entrypoint) ? globalThis.String(object.entrypoint) : "", + isArchive: isSet(object.isArchive) ? globalThis.Boolean(object.isArchive) : false, + runEvery: isSet(object.runEvery) ? Duration.fromJSON(object.runEvery) : undefined, + timeout: isSet(object.timeout) ? Duration.fromJSON(object.timeout) : undefined, + disabled: isSet(object.disabled) ? globalThis.Boolean(object.disabled) : false, + endless: isSet(object.endless) ? globalThis.Boolean(object.endless) : false, + }; + }, + + toJSON(message: ExploitConfiguration): unknown { + const obj: any = {}; + if (message.entrypoint !== "") { + obj.entrypoint = message.entrypoint; + } + if (message.isArchive === true) { + obj.isArchive = message.isArchive; + } + if (message.runEvery !== undefined) { + obj.runEvery = Duration.toJSON(message.runEvery); + } + if (message.timeout !== undefined) { + obj.timeout = Duration.toJSON(message.timeout); + } + if (message.disabled === true) { + obj.disabled = message.disabled; + } + if (message.endless === true) { + obj.endless = message.endless; + } + return obj; + }, + + create, I>>(base?: I): ExploitConfiguration { + return ExploitConfiguration.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): ExploitConfiguration { + const message = createBaseExploitConfiguration(); + message.entrypoint = object.entrypoint ?? ""; + message.isArchive = object.isArchive ?? false; + message.runEvery = (object.runEvery !== undefined && object.runEvery !== null) + ? Duration.fromPartial(object.runEvery) + : undefined; + message.timeout = (object.timeout !== undefined && object.timeout !== null) + ? Duration.fromPartial(object.timeout) + : undefined; + message.disabled = object.disabled ?? false; + message.endless = object.endless ?? false; + return message; + }, +}; + +function createBaseExploitState(): ExploitState { + return { exploitId: "", version: Long.ZERO, file: undefined, config: undefined }; +} + +export const ExploitState = { + encode(message: ExploitState, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.exploitId !== "") { + writer.uint32(10).string(message.exploitId); + } + if (!message.version.isZero()) { + writer.uint32(16).int64(message.version); + } + if (message.file !== undefined) { + FileInfo.encode(message.file, writer.uint32(26).fork()).ldelim(); + } + if (message.config !== undefined) { + ExploitConfiguration.encode(message.config, writer.uint32(50).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): ExploitState { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseExploitState(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.exploitId = reader.string(); + continue; + case 2: + if (tag !== 16) { + break; + } + + message.version = reader.int64() as Long; + continue; + case 3: + if (tag !== 26) { + break; + } + + message.file = FileInfo.decode(reader, reader.uint32()); + continue; + case 6: + if (tag !== 50) { + break; + } + + message.config = ExploitConfiguration.decode(reader, reader.uint32()); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): ExploitState { + return { + exploitId: isSet(object.exploitId) ? globalThis.String(object.exploitId) : "", + version: isSet(object.version) ? Long.fromValue(object.version) : Long.ZERO, + file: isSet(object.file) ? FileInfo.fromJSON(object.file) : undefined, + config: isSet(object.config) ? ExploitConfiguration.fromJSON(object.config) : undefined, + }; + }, + + toJSON(message: ExploitState): unknown { + const obj: any = {}; + if (message.exploitId !== "") { + obj.exploitId = message.exploitId; + } + if (!message.version.isZero()) { + obj.version = (message.version || Long.ZERO).toString(); + } + if (message.file !== undefined) { + obj.file = FileInfo.toJSON(message.file); + } + if (message.config !== undefined) { + obj.config = ExploitConfiguration.toJSON(message.config); + } + return obj; + }, + + create, I>>(base?: I): ExploitState { + return ExploitState.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): ExploitState { + const message = createBaseExploitState(); + message.exploitId = object.exploitId ?? ""; + message.version = (object.version !== undefined && object.version !== null) + ? Long.fromValue(object.version) + : Long.ZERO; + message.file = (object.file !== undefined && object.file !== null) ? FileInfo.fromPartial(object.file) : undefined; + message.config = (object.config !== undefined && object.config !== null) + ? ExploitConfiguration.fromPartial(object.config) + : undefined; + return message; + }, +}; + +function createBaseConfig(): Config { + return { farmUrl: "", farmPassword: "", flagRegexp: "", pingEvery: undefined, submitEvery: undefined, environ: [] }; +} + +export const Config = { + encode(message: Config, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.farmUrl !== "") { + writer.uint32(10).string(message.farmUrl); + } + if (message.farmPassword !== "") { + writer.uint32(18).string(message.farmPassword); + } + if (message.flagRegexp !== "") { + writer.uint32(26).string(message.flagRegexp); + } + if (message.pingEvery !== undefined) { + Duration.encode(message.pingEvery, writer.uint32(34).fork()).ldelim(); + } + if (message.submitEvery !== undefined) { + Duration.encode(message.submitEvery, writer.uint32(42).fork()).ldelim(); + } + for (const v of message.environ) { + writer.uint32(50).string(v!); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): Config { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseConfig(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.farmUrl = reader.string(); + continue; + case 2: + if (tag !== 18) { + break; + } + + message.farmPassword = reader.string(); + continue; + case 3: + if (tag !== 26) { + break; + } + + message.flagRegexp = reader.string(); + continue; + case 4: + if (tag !== 34) { + break; + } + + message.pingEvery = Duration.decode(reader, reader.uint32()); + continue; + case 5: + if (tag !== 42) { + break; + } + + message.submitEvery = Duration.decode(reader, reader.uint32()); + continue; + case 6: + if (tag !== 50) { + break; + } + + message.environ.push(reader.string()); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): Config { + return { + farmUrl: isSet(object.farmUrl) ? globalThis.String(object.farmUrl) : "", + farmPassword: isSet(object.farmPassword) ? globalThis.String(object.farmPassword) : "", + flagRegexp: isSet(object.flagRegexp) ? globalThis.String(object.flagRegexp) : "", + pingEvery: isSet(object.pingEvery) ? Duration.fromJSON(object.pingEvery) : undefined, + submitEvery: isSet(object.submitEvery) ? Duration.fromJSON(object.submitEvery) : undefined, + environ: globalThis.Array.isArray(object?.environ) ? object.environ.map((e: any) => globalThis.String(e)) : [], + }; + }, + + toJSON(message: Config): unknown { + const obj: any = {}; + if (message.farmUrl !== "") { + obj.farmUrl = message.farmUrl; + } + if (message.farmPassword !== "") { + obj.farmPassword = message.farmPassword; + } + if (message.flagRegexp !== "") { + obj.flagRegexp = message.flagRegexp; + } + if (message.pingEvery !== undefined) { + obj.pingEvery = Duration.toJSON(message.pingEvery); + } + if (message.submitEvery !== undefined) { + obj.submitEvery = Duration.toJSON(message.submitEvery); + } + if (message.environ?.length) { + obj.environ = message.environ; + } + return obj; + }, + + create, I>>(base?: I): Config { + return Config.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): Config { + const message = createBaseConfig(); + message.farmUrl = object.farmUrl ?? ""; + message.farmPassword = object.farmPassword ?? ""; + message.flagRegexp = object.flagRegexp ?? ""; + message.pingEvery = (object.pingEvery !== undefined && object.pingEvery !== null) + ? Duration.fromPartial(object.pingEvery) + : undefined; + message.submitEvery = (object.submitEvery !== undefined && object.submitEvery !== null) + ? Duration.fromPartial(object.submitEvery) + : undefined; + message.environ = object.environ?.map((e) => e) || []; + return message; + }, +}; + +function createBaseServerState(): ServerState { + return { clientTeamMap: new Map(), exploits: [], config: undefined }; +} + +export const ServerState = { + encode(message: ServerState, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + message.clientTeamMap.forEach((value, key) => { + ServerState_ClientTeamMapEntry.encode({ key: key as any, value }, writer.uint32(10).fork()).ldelim(); + }); + for (const v of message.exploits) { + ExploitState.encode(v!, writer.uint32(18).fork()).ldelim(); + } + if (message.config !== undefined) { + Config.encode(message.config, writer.uint32(26).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): ServerState { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseServerState(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + const entry1 = ServerState_ClientTeamMapEntry.decode(reader, reader.uint32()); + if (entry1.value !== undefined) { + message.clientTeamMap.set(entry1.key, entry1.value); + } + continue; + case 2: + if (tag !== 18) { + break; + } + + message.exploits.push(ExploitState.decode(reader, reader.uint32())); + continue; + case 3: + if (tag !== 26) { + break; + } + + message.config = Config.decode(reader, reader.uint32()); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): ServerState { + return { + clientTeamMap: isObject(object.clientTeamMap) + ? Object.entries(object.clientTeamMap).reduce>((acc, [key, value]) => { + acc.set(key, TeamBucket.fromJSON(value)); + return acc; + }, new Map()) + : new Map(), + exploits: globalThis.Array.isArray(object?.exploits) + ? object.exploits.map((e: any) => ExploitState.fromJSON(e)) + : [], + config: isSet(object.config) ? Config.fromJSON(object.config) : undefined, + }; + }, + + toJSON(message: ServerState): unknown { + const obj: any = {}; + if (message.clientTeamMap?.size) { + obj.clientTeamMap = {}; + message.clientTeamMap.forEach((v, k) => { + obj.clientTeamMap[k] = TeamBucket.toJSON(v); + }); + } + if (message.exploits?.length) { + obj.exploits = message.exploits.map((e) => ExploitState.toJSON(e)); + } + if (message.config !== undefined) { + obj.config = Config.toJSON(message.config); + } + return obj; + }, + + create, I>>(base?: I): ServerState { + return ServerState.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): ServerState { + const message = createBaseServerState(); + message.clientTeamMap = (() => { + const m = new Map(); + (object.clientTeamMap as Map ?? new Map()).forEach((value, key) => { + if (value !== undefined) { + m.set(key, TeamBucket.fromPartial(value)); + } + }); + return m; + })(); + message.exploits = object.exploits?.map((e) => ExploitState.fromPartial(e)) || []; + message.config = (object.config !== undefined && object.config !== null) + ? Config.fromPartial(object.config) + : undefined; + return message; + }, +}; + +function createBaseServerState_ClientTeamMapEntry(): ServerState_ClientTeamMapEntry { + return { key: "", value: undefined }; +} + +export const ServerState_ClientTeamMapEntry = { + encode(message: ServerState_ClientTeamMapEntry, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.key !== "") { + writer.uint32(10).string(message.key); + } + if (message.value !== undefined) { + TeamBucket.encode(message.value, writer.uint32(18).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): ServerState_ClientTeamMapEntry { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseServerState_ClientTeamMapEntry(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.key = reader.string(); + continue; + case 2: + if (tag !== 18) { + break; + } + + message.value = TeamBucket.decode(reader, reader.uint32()); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): ServerState_ClientTeamMapEntry { + return { + key: isSet(object.key) ? globalThis.String(object.key) : "", + value: isSet(object.value) ? TeamBucket.fromJSON(object.value) : undefined, + }; + }, + + toJSON(message: ServerState_ClientTeamMapEntry): unknown { + const obj: any = {}; + if (message.key !== "") { + obj.key = message.key; + } + if (message.value !== undefined) { + obj.value = TeamBucket.toJSON(message.value); + } + return obj; + }, + + create, I>>(base?: I): ServerState_ClientTeamMapEntry { + return ServerState_ClientTeamMapEntry.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): ServerState_ClientTeamMapEntry { + const message = createBaseServerState_ClientTeamMapEntry(); + message.key = object.key ?? ""; + message.value = (object.value !== undefined && object.value !== null) + ? TeamBucket.fromPartial(object.value) + : undefined; + return message; + }, +}; + +function createBasePingRequest(): PingRequest { + return { clientId: "", payload: undefined }; +} + +export const PingRequest = { + encode(message: PingRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.clientId !== "") { + writer.uint32(10).string(message.clientId); + } + switch (message.payload?.$case) { + case "serverInfoRequest": + PingRequest_ServerInfo.encode(message.payload.serverInfoRequest, writer.uint32(18).fork()).ldelim(); + break; + case "heartbeatRequest": + PingRequest_Heartbeat.encode(message.payload.heartbeatRequest, writer.uint32(26).fork()).ldelim(); + break; + case "leaveRequest": + PingRequest_Leave.encode(message.payload.leaveRequest, writer.uint32(34).fork()).ldelim(); + break; + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): PingRequest { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBasePingRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.clientId = reader.string(); + continue; + case 2: + if (tag !== 18) { + break; + } + + message.payload = { + $case: "serverInfoRequest", + serverInfoRequest: PingRequest_ServerInfo.decode(reader, reader.uint32()), + }; + continue; + case 3: + if (tag !== 26) { + break; + } + + message.payload = { + $case: "heartbeatRequest", + heartbeatRequest: PingRequest_Heartbeat.decode(reader, reader.uint32()), + }; + continue; + case 4: + if (tag !== 34) { + break; + } + + message.payload = { $case: "leaveRequest", leaveRequest: PingRequest_Leave.decode(reader, reader.uint32()) }; + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): PingRequest { + return { + clientId: isSet(object.clientId) ? globalThis.String(object.clientId) : "", + payload: isSet(object.serverInfoRequest) + ? { $case: "serverInfoRequest", serverInfoRequest: PingRequest_ServerInfo.fromJSON(object.serverInfoRequest) } + : isSet(object.heartbeatRequest) + ? { $case: "heartbeatRequest", heartbeatRequest: PingRequest_Heartbeat.fromJSON(object.heartbeatRequest) } + : isSet(object.leaveRequest) + ? { $case: "leaveRequest", leaveRequest: PingRequest_Leave.fromJSON(object.leaveRequest) } + : undefined, + }; + }, + + toJSON(message: PingRequest): unknown { + const obj: any = {}; + if (message.clientId !== "") { + obj.clientId = message.clientId; + } + if (message.payload?.$case === "serverInfoRequest") { + obj.serverInfoRequest = PingRequest_ServerInfo.toJSON(message.payload.serverInfoRequest); + } + if (message.payload?.$case === "heartbeatRequest") { + obj.heartbeatRequest = PingRequest_Heartbeat.toJSON(message.payload.heartbeatRequest); + } + if (message.payload?.$case === "leaveRequest") { + obj.leaveRequest = PingRequest_Leave.toJSON(message.payload.leaveRequest); + } + return obj; + }, + + create, I>>(base?: I): PingRequest { + return PingRequest.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): PingRequest { + const message = createBasePingRequest(); + message.clientId = object.clientId ?? ""; + if ( + object.payload?.$case === "serverInfoRequest" && + object.payload?.serverInfoRequest !== undefined && + object.payload?.serverInfoRequest !== null + ) { + message.payload = { + $case: "serverInfoRequest", + serverInfoRequest: PingRequest_ServerInfo.fromPartial(object.payload.serverInfoRequest), + }; + } + if ( + object.payload?.$case === "heartbeatRequest" && + object.payload?.heartbeatRequest !== undefined && + object.payload?.heartbeatRequest !== null + ) { + message.payload = { + $case: "heartbeatRequest", + heartbeatRequest: PingRequest_Heartbeat.fromPartial(object.payload.heartbeatRequest), + }; + } + if ( + object.payload?.$case === "leaveRequest" && + object.payload?.leaveRequest !== undefined && + object.payload?.leaveRequest !== null + ) { + message.payload = { + $case: "leaveRequest", + leaveRequest: PingRequest_Leave.fromPartial(object.payload.leaveRequest), + }; + } + return message; + }, +}; + +function createBasePingRequest_ServerInfo(): PingRequest_ServerInfo { + return {}; +} + +export const PingRequest_ServerInfo = { + encode(_: PingRequest_ServerInfo, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): PingRequest_ServerInfo { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBasePingRequest_ServerInfo(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(_: any): PingRequest_ServerInfo { + return {}; + }, + + toJSON(_: PingRequest_ServerInfo): unknown { + const obj: any = {}; + return obj; + }, + + create, I>>(base?: I): PingRequest_ServerInfo { + return PingRequest_ServerInfo.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(_: I): PingRequest_ServerInfo { + const message = createBasePingRequest_ServerInfo(); + return message; + }, +}; + +function createBasePingRequest_Heartbeat(): PingRequest_Heartbeat { + return { weight: 0 }; +} + +export const PingRequest_Heartbeat = { + encode(message: PingRequest_Heartbeat, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.weight !== 0) { + writer.uint32(8).int32(message.weight); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): PingRequest_Heartbeat { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBasePingRequest_Heartbeat(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 8) { + break; + } + + message.weight = reader.int32(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): PingRequest_Heartbeat { + return { weight: isSet(object.weight) ? globalThis.Number(object.weight) : 0 }; + }, + + toJSON(message: PingRequest_Heartbeat): unknown { + const obj: any = {}; + if (message.weight !== 0) { + obj.weight = Math.round(message.weight); + } + return obj; + }, + + create, I>>(base?: I): PingRequest_Heartbeat { + return PingRequest_Heartbeat.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): PingRequest_Heartbeat { + const message = createBasePingRequest_Heartbeat(); + message.weight = object.weight ?? 0; + return message; + }, +}; + +function createBasePingRequest_Leave(): PingRequest_Leave { + return {}; +} + +export const PingRequest_Leave = { + encode(_: PingRequest_Leave, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): PingRequest_Leave { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBasePingRequest_Leave(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(_: any): PingRequest_Leave { + return {}; + }, + + toJSON(_: PingRequest_Leave): unknown { + const obj: any = {}; + return obj; + }, + + create, I>>(base?: I): PingRequest_Leave { + return PingRequest_Leave.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(_: I): PingRequest_Leave { + const message = createBasePingRequest_Leave(); + return message; + }, +}; + +function createBasePingResponse(): PingResponse { + return { state: undefined }; +} + +export const PingResponse = { + encode(message: PingResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.state !== undefined) { + ServerState.encode(message.state, writer.uint32(10).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): PingResponse { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBasePingResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.state = ServerState.decode(reader, reader.uint32()); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): PingResponse { + return { state: isSet(object.state) ? ServerState.fromJSON(object.state) : undefined }; + }, + + toJSON(message: PingResponse): unknown { + const obj: any = {}; + if (message.state !== undefined) { + obj.state = ServerState.toJSON(message.state); + } + return obj; + }, + + create, I>>(base?: I): PingResponse { + return PingResponse.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): PingResponse { + const message = createBasePingResponse(); + message.state = (object.state !== undefined && object.state !== null) + ? ServerState.fromPartial(object.state) + : undefined; + return message; + }, +}; + +function createBaseExploitRequest(): ExploitRequest { + return { exploitId: "" }; +} + +export const ExploitRequest = { + encode(message: ExploitRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.exploitId !== "") { + writer.uint32(10).string(message.exploitId); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): ExploitRequest { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseExploitRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.exploitId = reader.string(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): ExploitRequest { + return { exploitId: isSet(object.exploitId) ? globalThis.String(object.exploitId) : "" }; + }, + + toJSON(message: ExploitRequest): unknown { + const obj: any = {}; + if (message.exploitId !== "") { + obj.exploitId = message.exploitId; + } + return obj; + }, + + create, I>>(base?: I): ExploitRequest { + return ExploitRequest.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): ExploitRequest { + const message = createBaseExploitRequest(); + message.exploitId = object.exploitId ?? ""; + return message; + }, +}; + +function createBaseExploitResponse(): ExploitResponse { + return { state: undefined }; +} + +export const ExploitResponse = { + encode(message: ExploitResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.state !== undefined) { + ExploitState.encode(message.state, writer.uint32(10).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): ExploitResponse { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseExploitResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.state = ExploitState.decode(reader, reader.uint32()); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): ExploitResponse { + return { state: isSet(object.state) ? ExploitState.fromJSON(object.state) : undefined }; + }, + + toJSON(message: ExploitResponse): unknown { + const obj: any = {}; + if (message.state !== undefined) { + obj.state = ExploitState.toJSON(message.state); + } + return obj; + }, + + create, I>>(base?: I): ExploitResponse { + return ExploitResponse.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): ExploitResponse { + const message = createBaseExploitResponse(); + message.state = (object.state !== undefined && object.state !== null) + ? ExploitState.fromPartial(object.state) + : undefined; + return message; + }, +}; + +function createBaseUpdateExploitRequest(): UpdateExploitRequest { + return { state: undefined }; +} + +export const UpdateExploitRequest = { + encode(message: UpdateExploitRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.state !== undefined) { + ExploitState.encode(message.state, writer.uint32(10).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): UpdateExploitRequest { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseUpdateExploitRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.state = ExploitState.decode(reader, reader.uint32()); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): UpdateExploitRequest { + return { state: isSet(object.state) ? ExploitState.fromJSON(object.state) : undefined }; + }, + + toJSON(message: UpdateExploitRequest): unknown { + const obj: any = {}; + if (message.state !== undefined) { + obj.state = ExploitState.toJSON(message.state); + } + return obj; + }, + + create, I>>(base?: I): UpdateExploitRequest { + return UpdateExploitRequest.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): UpdateExploitRequest { + const message = createBaseUpdateExploitRequest(); + message.state = (object.state !== undefined && object.state !== null) + ? ExploitState.fromPartial(object.state) + : undefined; + return message; + }, +}; + +function createBaseUpdateExploitResponse(): UpdateExploitResponse { + return { state: undefined }; +} + +export const UpdateExploitResponse = { + encode(message: UpdateExploitResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.state !== undefined) { + ExploitState.encode(message.state, writer.uint32(10).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): UpdateExploitResponse { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseUpdateExploitResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.state = ExploitState.decode(reader, reader.uint32()); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): UpdateExploitResponse { + return { state: isSet(object.state) ? ExploitState.fromJSON(object.state) : undefined }; + }, + + toJSON(message: UpdateExploitResponse): unknown { + const obj: any = {}; + if (message.state !== undefined) { + obj.state = ExploitState.toJSON(message.state); + } + return obj; + }, + + create, I>>(base?: I): UpdateExploitResponse { + return UpdateExploitResponse.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): UpdateExploitResponse { + const message = createBaseUpdateExploitResponse(); + message.state = (object.state !== undefined && object.state !== null) + ? ExploitState.fromPartial(object.state) + : undefined; + return message; + }, +}; + +function createBaseBroadcastRequest(): BroadcastRequest { + return { command: "" }; +} + +export const BroadcastRequest = { + encode(message: BroadcastRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.command !== "") { + writer.uint32(10).string(message.command); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): BroadcastRequest { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseBroadcastRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.command = reader.string(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): BroadcastRequest { + return { command: isSet(object.command) ? globalThis.String(object.command) : "" }; + }, + + toJSON(message: BroadcastRequest): unknown { + const obj: any = {}; + if (message.command !== "") { + obj.command = message.command; + } + return obj; + }, + + create, I>>(base?: I): BroadcastRequest { + return BroadcastRequest.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): BroadcastRequest { + const message = createBaseBroadcastRequest(); + message.command = object.command ?? ""; + return message; + }, +}; + +function createBaseBroadcastResponse(): BroadcastResponse { + return {}; +} + +export const BroadcastResponse = { + encode(_: BroadcastResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): BroadcastResponse { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseBroadcastResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(_: any): BroadcastResponse { + return {}; + }, + + toJSON(_: BroadcastResponse): unknown { + const obj: any = {}; + return obj; + }, + + create, I>>(base?: I): BroadcastResponse { + return BroadcastResponse.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(_: I): BroadcastResponse { + const message = createBaseBroadcastResponse(); + return message; + }, +}; + +function createBaseBroadcastSubscribeRequest(): BroadcastSubscribeRequest { + return {}; +} + +export const BroadcastSubscribeRequest = { + encode(_: BroadcastSubscribeRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): BroadcastSubscribeRequest { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseBroadcastSubscribeRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(_: any): BroadcastSubscribeRequest { + return {}; + }, + + toJSON(_: BroadcastSubscribeRequest): unknown { + const obj: any = {}; + return obj; + }, + + create, I>>(base?: I): BroadcastSubscribeRequest { + return BroadcastSubscribeRequest.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(_: I): BroadcastSubscribeRequest { + const message = createBaseBroadcastSubscribeRequest(); + return message; + }, +}; + +function createBaseBroadcastSubscribeResponse(): BroadcastSubscribeResponse { + return { command: "" }; +} + +export const BroadcastSubscribeResponse = { + encode(message: BroadcastSubscribeResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.command !== "") { + writer.uint32(10).string(message.command); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): BroadcastSubscribeResponse { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseBroadcastSubscribeResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.command = reader.string(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): BroadcastSubscribeResponse { + return { command: isSet(object.command) ? globalThis.String(object.command) : "" }; + }, + + toJSON(message: BroadcastSubscribeResponse): unknown { + const obj: any = {}; + if (message.command !== "") { + obj.command = message.command; + } + return obj; + }, + + create, I>>(base?: I): BroadcastSubscribeResponse { + return BroadcastSubscribeResponse.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): BroadcastSubscribeResponse { + const message = createBaseBroadcastSubscribeResponse(); + message.command = object.command ?? ""; + return message; + }, +}; + +function createBaseSingleRunRequest(): SingleRunRequest { + return { exploitId: "" }; +} + +export const SingleRunRequest = { + encode(message: SingleRunRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.exploitId !== "") { + writer.uint32(10).string(message.exploitId); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): SingleRunRequest { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseSingleRunRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.exploitId = reader.string(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): SingleRunRequest { + return { exploitId: isSet(object.exploitId) ? globalThis.String(object.exploitId) : "" }; + }, + + toJSON(message: SingleRunRequest): unknown { + const obj: any = {}; + if (message.exploitId !== "") { + obj.exploitId = message.exploitId; + } + return obj; + }, + + create, I>>(base?: I): SingleRunRequest { + return SingleRunRequest.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): SingleRunRequest { + const message = createBaseSingleRunRequest(); + message.exploitId = object.exploitId ?? ""; + return message; + }, +}; + +function createBaseSingleRunResponse(): SingleRunResponse { + return {}; +} + +export const SingleRunResponse = { + encode(_: SingleRunResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): SingleRunResponse { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseSingleRunResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(_: any): SingleRunResponse { + return {}; + }, + + toJSON(_: SingleRunResponse): unknown { + const obj: any = {}; + return obj; + }, + + create, I>>(base?: I): SingleRunResponse { + return SingleRunResponse.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(_: I): SingleRunResponse { + const message = createBaseSingleRunResponse(); + return message; + }, +}; + +function createBaseSingleRunSubscribeRequest(): SingleRunSubscribeRequest { + return {}; +} + +export const SingleRunSubscribeRequest = { + encode(_: SingleRunSubscribeRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): SingleRunSubscribeRequest { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseSingleRunSubscribeRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(_: any): SingleRunSubscribeRequest { + return {}; + }, + + toJSON(_: SingleRunSubscribeRequest): unknown { + const obj: any = {}; + return obj; + }, + + create, I>>(base?: I): SingleRunSubscribeRequest { + return SingleRunSubscribeRequest.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(_: I): SingleRunSubscribeRequest { + const message = createBaseSingleRunSubscribeRequest(); + return message; + }, +}; + +function createBaseSingleRunSubscribeResponse(): SingleRunSubscribeResponse { + return { exploitId: "" }; +} + +export const SingleRunSubscribeResponse = { + encode(message: SingleRunSubscribeResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.exploitId !== "") { + writer.uint32(10).string(message.exploitId); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): SingleRunSubscribeResponse { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseSingleRunSubscribeResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.exploitId = reader.string(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): SingleRunSubscribeResponse { + return { exploitId: isSet(object.exploitId) ? globalThis.String(object.exploitId) : "" }; + }, + + toJSON(message: SingleRunSubscribeResponse): unknown { + const obj: any = {}; + if (message.exploitId !== "") { + obj.exploitId = message.exploitId; + } + return obj; + }, + + create, I>>(base?: I): SingleRunSubscribeResponse { + return SingleRunSubscribeResponse.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): SingleRunSubscribeResponse { + const message = createBaseSingleRunSubscribeResponse(); + message.exploitId = object.exploitId ?? ""; + return message; + }, +}; + +export type ServiceDefinition = typeof ServiceDefinition; +export const ServiceDefinition = { + name: "Service", + fullName: "exploits.Service", + methods: { + ping: { + name: "Ping", + requestType: PingRequest, + requestStream: false, + responseType: PingResponse, + responseStream: false, + options: {}, + }, + exploit: { + name: "Exploit", + requestType: ExploitRequest, + requestStream: false, + responseType: ExploitResponse, + responseStream: false, + options: {}, + }, + updateExploit: { + name: "UpdateExploit", + requestType: UpdateExploitRequest, + requestStream: false, + responseType: UpdateExploitResponse, + responseStream: false, + options: {}, + }, + broadcastCommand: { + name: "BroadcastCommand", + requestType: BroadcastRequest, + requestStream: false, + responseType: BroadcastResponse, + responseStream: false, + options: {}, + }, + broadcastSubscribe: { + name: "BroadcastSubscribe", + requestType: BroadcastSubscribeRequest, + requestStream: false, + responseType: BroadcastSubscribeResponse, + responseStream: true, + options: {}, + }, + singleRun: { + name: "SingleRun", + requestType: SingleRunRequest, + requestStream: false, + responseType: SingleRunResponse, + responseStream: false, + options: {}, + }, + singleRunSubscribe: { + name: "SingleRunSubscribe", + requestType: SingleRunSubscribeRequest, + requestStream: false, + responseType: SingleRunSubscribeResponse, + responseStream: true, + options: {}, + }, + }, +} as const; + +export interface ServiceImplementation { + ping(request: PingRequest, context: CallContext & CallContextExt): Promise>; + exploit(request: ExploitRequest, context: CallContext & CallContextExt): Promise>; + updateExploit( + request: UpdateExploitRequest, + context: CallContext & CallContextExt, + ): Promise>; + broadcastCommand( + request: BroadcastRequest, + context: CallContext & CallContextExt, + ): Promise>; + broadcastSubscribe( + request: BroadcastSubscribeRequest, + context: CallContext & CallContextExt, + ): ServerStreamingMethodResult>; + singleRun(request: SingleRunRequest, context: CallContext & CallContextExt): Promise>; + singleRunSubscribe( + request: SingleRunSubscribeRequest, + context: CallContext & CallContextExt, + ): ServerStreamingMethodResult>; +} + +export interface ServiceClient { + ping(request: DeepPartial, options?: CallOptions & CallOptionsExt): Promise; + exploit(request: DeepPartial, options?: CallOptions & CallOptionsExt): Promise; + updateExploit( + request: DeepPartial, + options?: CallOptions & CallOptionsExt, + ): Promise; + broadcastCommand( + request: DeepPartial, + options?: CallOptions & CallOptionsExt, + ): Promise; + broadcastSubscribe( + request: DeepPartial, + options?: CallOptions & CallOptionsExt, + ): AsyncIterable; + singleRun(request: DeepPartial, options?: CallOptions & CallOptionsExt): Promise; + singleRunSubscribe( + request: DeepPartial, + options?: CallOptions & CallOptionsExt, + ): AsyncIterable; +} + +type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; + +export type DeepPartial = T extends Builtin ? T + : T extends Long ? string | number | Long : T extends globalThis.Array ? globalThis.Array> + : T extends ReadonlyArray ? ReadonlyArray> + : T extends { $case: string } ? { [K in keyof Omit]?: DeepPartial } & { $case: T["$case"] } + : T extends {} ? { [K in keyof T]?: DeepPartial } + : Partial; + +type KeysOfUnion = T extends T ? keyof T : never; +export type Exact = P extends Builtin ? P + : P & { [K in keyof P]: Exact } & { [K in Exclude>]: never }; + +if (_m0.util.Long !== Long) { + _m0.util.Long = Long as any; + _m0.configure(); +} + +function isObject(value: any): boolean { + return typeof value === "object" && value !== null; +} + +function isSet(value: any): boolean { + return value !== null && value !== undefined; +} + +export type ServerStreamingMethodResult = { [Symbol.asyncIterator](): AsyncIterator }; diff --git a/front/src/proto/fileserver/api.ts b/front/src/proto/fileserver/api.ts new file mode 100644 index 0000000..0220bec --- /dev/null +++ b/front/src/proto/fileserver/api.ts @@ -0,0 +1,218 @@ +// @ts-nocheck +/* eslint-disable */ +import Long from "long"; +import type { CallContext, CallOptions } from "nice-grpc-common"; +import _m0 from "protobufjs/minimal"; + +export const protobufPackage = "fileserver"; + +export interface FileInfo { + uuid: string; +} + +export interface FileStream { + chunk: Uint8Array; +} + +function createBaseFileInfo(): FileInfo { + return { uuid: "" }; +} + +export const FileInfo = { + encode(message: FileInfo, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.uuid !== "") { + writer.uint32(10).string(message.uuid); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): FileInfo { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseFileInfo(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.uuid = reader.string(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): FileInfo { + return { uuid: isSet(object.uuid) ? globalThis.String(object.uuid) : "" }; + }, + + toJSON(message: FileInfo): unknown { + const obj: any = {}; + if (message.uuid !== "") { + obj.uuid = message.uuid; + } + return obj; + }, + + create, I>>(base?: I): FileInfo { + return FileInfo.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): FileInfo { + const message = createBaseFileInfo(); + message.uuid = object.uuid ?? ""; + return message; + }, +}; + +function createBaseFileStream(): FileStream { + return { chunk: new Uint8Array(0) }; +} + +export const FileStream = { + encode(message: FileStream, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.chunk.length !== 0) { + writer.uint32(10).bytes(message.chunk); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): FileStream { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseFileStream(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.chunk = reader.bytes(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): FileStream { + return { chunk: isSet(object.chunk) ? bytesFromBase64(object.chunk) : new Uint8Array(0) }; + }, + + toJSON(message: FileStream): unknown { + const obj: any = {}; + if (message.chunk.length !== 0) { + obj.chunk = base64FromBytes(message.chunk); + } + return obj; + }, + + create, I>>(base?: I): FileStream { + return FileStream.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): FileStream { + const message = createBaseFileStream(); + message.chunk = object.chunk ?? new Uint8Array(0); + return message; + }, +}; + +export type ServiceDefinition = typeof ServiceDefinition; +export const ServiceDefinition = { + name: "Service", + fullName: "fileserver.Service", + methods: { + uploadFile: { + name: "UploadFile", + requestType: FileStream, + requestStream: true, + responseType: FileInfo, + responseStream: false, + options: {}, + }, + downloadFile: { + name: "DownloadFile", + requestType: FileInfo, + requestStream: false, + responseType: FileStream, + responseStream: true, + options: {}, + }, + }, +} as const; + +export interface ServiceImplementation { + uploadFile(request: AsyncIterable, context: CallContext & CallContextExt): Promise>; + downloadFile( + request: FileInfo, + context: CallContext & CallContextExt, + ): ServerStreamingMethodResult>; +} + +export interface ServiceClient { + uploadFile( + request: AsyncIterable>, + options?: CallOptions & CallOptionsExt, + ): Promise; + downloadFile(request: DeepPartial, options?: CallOptions & CallOptionsExt): AsyncIterable; +} + +function bytesFromBase64(b64: string): Uint8Array { + if (globalThis.Buffer) { + return Uint8Array.from(globalThis.Buffer.from(b64, "base64")); + } else { + const bin = globalThis.atob(b64); + const arr = new Uint8Array(bin.length); + for (let i = 0; i < bin.length; ++i) { + arr[i] = bin.charCodeAt(i); + } + return arr; + } +} + +function base64FromBytes(arr: Uint8Array): string { + if (globalThis.Buffer) { + return globalThis.Buffer.from(arr).toString("base64"); + } else { + const bin: string[] = []; + arr.forEach((byte) => { + bin.push(globalThis.String.fromCharCode(byte)); + }); + return globalThis.btoa(bin.join("")); + } +} + +type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; + +export type DeepPartial = T extends Builtin ? T + : T extends Long ? string | number | Long : T extends globalThis.Array ? globalThis.Array> + : T extends ReadonlyArray ? ReadonlyArray> + : T extends { $case: string } ? { [K in keyof Omit]?: DeepPartial } & { $case: T["$case"] } + : T extends {} ? { [K in keyof T]?: DeepPartial } + : Partial; + +type KeysOfUnion = T extends T ? keyof T : never; +export type Exact = P extends Builtin ? P + : P & { [K in keyof P]: Exact } & { [K in Exclude>]: never }; + +if (_m0.util.Long !== Long) { + _m0.util.Long = Long as any; + _m0.configure(); +} + +function isSet(value: any): boolean { + return value !== null && value !== undefined; +} + +export type ServerStreamingMethodResult = { [Symbol.asyncIterator](): AsyncIterator }; diff --git a/front/src/proto/google/protobuf/duration.ts b/front/src/proto/google/protobuf/duration.ts new file mode 100644 index 0000000..56fe8f3 --- /dev/null +++ b/front/src/proto/google/protobuf/duration.ts @@ -0,0 +1,182 @@ +// @ts-nocheck +/* eslint-disable */ +import Long from "long"; +import _m0 from "protobufjs/minimal"; + +export const protobufPackage = "google.protobuf"; + +/** + * A Duration represents a signed, fixed-length span of time represented + * as a count of seconds and fractions of seconds at nanosecond + * resolution. It is independent of any calendar and concepts like "day" + * or "month". It is related to Timestamp in that the difference between + * two Timestamp values is a Duration and it can be added or subtracted + * from a Timestamp. Range is approximately +-10,000 years. + * + * # Examples + * + * Example 1: Compute Duration from two Timestamps in pseudo code. + * + * Timestamp start = ...; + * Timestamp end = ...; + * Duration duration = ...; + * + * duration.seconds = end.seconds - start.seconds; + * duration.nanos = end.nanos - start.nanos; + * + * if (duration.seconds < 0 && duration.nanos > 0) { + * duration.seconds += 1; + * duration.nanos -= 1000000000; + * } else if (duration.seconds > 0 && duration.nanos < 0) { + * duration.seconds -= 1; + * duration.nanos += 1000000000; + * } + * + * Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. + * + * Timestamp start = ...; + * Duration duration = ...; + * Timestamp end = ...; + * + * end.seconds = start.seconds + duration.seconds; + * end.nanos = start.nanos + duration.nanos; + * + * if (end.nanos < 0) { + * end.seconds -= 1; + * end.nanos += 1000000000; + * } else if (end.nanos >= 1000000000) { + * end.seconds += 1; + * end.nanos -= 1000000000; + * } + * + * Example 3: Compute Duration from datetime.timedelta in Python. + * + * td = datetime.timedelta(days=3, minutes=10) + * duration = Duration() + * duration.FromTimedelta(td) + * + * # JSON Mapping + * + * In JSON format, the Duration type is encoded as a string rather than an + * object, where the string ends in the suffix "s" (indicating seconds) and + * is preceded by the number of seconds, with nanoseconds expressed as + * fractional seconds. For example, 3 seconds with 0 nanoseconds should be + * encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should + * be expressed in JSON format as "3.000000001s", and 3 seconds and 1 + * microsecond should be expressed in JSON format as "3.000001s". + */ +export interface Duration { + /** + * Signed seconds of the span of time. Must be from -315,576,000,000 + * to +315,576,000,000 inclusive. Note: these bounds are computed from: + * 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years + */ + seconds: Long; + /** + * Signed fractions of a second at nanosecond resolution of the span + * of time. Durations less than one second are represented with a 0 + * `seconds` field and a positive or negative `nanos` field. For durations + * of one second or more, a non-zero value for the `nanos` field must be + * of the same sign as the `seconds` field. Must be from -999,999,999 + * to +999,999,999 inclusive. + */ + nanos: number; +} + +function createBaseDuration(): Duration { + return { seconds: Long.ZERO, nanos: 0 }; +} + +export const Duration = { + encode(message: Duration, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (!message.seconds.isZero()) { + writer.uint32(8).int64(message.seconds); + } + if (message.nanos !== 0) { + writer.uint32(16).int32(message.nanos); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): Duration { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseDuration(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 8) { + break; + } + + message.seconds = reader.int64() as Long; + continue; + case 2: + if (tag !== 16) { + break; + } + + message.nanos = reader.int32(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): Duration { + return { + seconds: isSet(object.seconds) ? Long.fromValue(object.seconds) : Long.ZERO, + nanos: isSet(object.nanos) ? globalThis.Number(object.nanos) : 0, + }; + }, + + toJSON(message: Duration): unknown { + const obj: any = {}; + if (!message.seconds.isZero()) { + obj.seconds = (message.seconds || Long.ZERO).toString(); + } + if (message.nanos !== 0) { + obj.nanos = Math.round(message.nanos); + } + return obj; + }, + + create, I>>(base?: I): Duration { + return Duration.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): Duration { + const message = createBaseDuration(); + message.seconds = (object.seconds !== undefined && object.seconds !== null) + ? Long.fromValue(object.seconds) + : Long.ZERO; + message.nanos = object.nanos ?? 0; + return message; + }, +}; + +type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; + +export type DeepPartial = T extends Builtin ? T + : T extends Long ? string | number | Long : T extends globalThis.Array ? globalThis.Array> + : T extends ReadonlyArray ? ReadonlyArray> + : T extends { $case: string } ? { [K in keyof Omit]?: DeepPartial } & { $case: T["$case"] } + : T extends {} ? { [K in keyof T]?: DeepPartial } + : Partial; + +type KeysOfUnion = T extends T ? keyof T : never; +export type Exact = P extends Builtin ? P + : P & { [K in keyof P]: Exact } & { [K in Exclude>]: never }; + +if (_m0.util.Long !== Long) { + _m0.util.Long = Long as any; + _m0.configure(); +} + +function isSet(value: any): boolean { + return value !== null && value !== undefined; +} diff --git a/front/src/proto/google/protobuf/empty.ts b/front/src/proto/google/protobuf/empty.ts new file mode 100644 index 0000000..cd73836 --- /dev/null +++ b/front/src/proto/google/protobuf/empty.ts @@ -0,0 +1,79 @@ +// @ts-nocheck +/* eslint-disable */ +import Long from "long"; +import _m0 from "protobufjs/minimal"; + +export const protobufPackage = "google.protobuf"; + +/** + * A generic empty message that you can re-use to avoid defining duplicated + * empty messages in your APIs. A typical example is to use it as the request + * or the response type of an API method. For instance: + * + * service Foo { + * rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); + * } + */ +export interface Empty { +} + +function createBaseEmpty(): Empty { + return {}; +} + +export const Empty = { + encode(_: Empty, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): Empty { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseEmpty(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(_: any): Empty { + return {}; + }, + + toJSON(_: Empty): unknown { + const obj: any = {}; + return obj; + }, + + create, I>>(base?: I): Empty { + return Empty.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(_: I): Empty { + const message = createBaseEmpty(); + return message; + }, +}; + +type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; + +export type DeepPartial = T extends Builtin ? T + : T extends Long ? string | number | Long : T extends globalThis.Array ? globalThis.Array> + : T extends ReadonlyArray ? ReadonlyArray> + : T extends { $case: string } ? { [K in keyof Omit]?: DeepPartial } & { $case: T["$case"] } + : T extends {} ? { [K in keyof T]?: DeepPartial } + : Partial; + +type KeysOfUnion = T extends T ? keyof T : never; +export type Exact = P extends Builtin ? P + : P & { [K in keyof P]: Exact } & { [K in Exclude>]: never }; + +if (_m0.util.Long !== Long) { + _m0.util.Long = Long as any; + _m0.configure(); +} diff --git a/front/src/proto/logs/api.ts b/front/src/proto/logs/api.ts new file mode 100644 index 0000000..ff020cb --- /dev/null +++ b/front/src/proto/logs/api.ts @@ -0,0 +1,404 @@ +// @ts-nocheck +/* eslint-disable */ +import Long from "long"; +import type { CallContext, CallOptions } from "nice-grpc-common"; +import _m0 from "protobufjs/minimal"; +import { Empty } from "../google/protobuf/empty"; + +export const protobufPackage = "logs"; + +export interface LogLine { + exploit: string; + version: Long; + message: string; + level: string; + team: string; +} + +export interface AddLogLinesRequest { + lines: LogLine[]; +} + +export interface SearchLogLinesRequest { + exploit: string; + version: Long; +} + +export interface SearchLogLinesResponse { + lines: LogLine[]; +} + +function createBaseLogLine(): LogLine { + return { exploit: "", version: Long.ZERO, message: "", level: "", team: "" }; +} + +export const LogLine = { + encode(message: LogLine, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.exploit !== "") { + writer.uint32(10).string(message.exploit); + } + if (!message.version.isZero()) { + writer.uint32(16).int64(message.version); + } + if (message.message !== "") { + writer.uint32(26).string(message.message); + } + if (message.level !== "") { + writer.uint32(34).string(message.level); + } + if (message.team !== "") { + writer.uint32(42).string(message.team); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): LogLine { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseLogLine(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.exploit = reader.string(); + continue; + case 2: + if (tag !== 16) { + break; + } + + message.version = reader.int64() as Long; + continue; + case 3: + if (tag !== 26) { + break; + } + + message.message = reader.string(); + continue; + case 4: + if (tag !== 34) { + break; + } + + message.level = reader.string(); + continue; + case 5: + if (tag !== 42) { + break; + } + + message.team = reader.string(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): LogLine { + return { + exploit: isSet(object.exploit) ? globalThis.String(object.exploit) : "", + version: isSet(object.version) ? Long.fromValue(object.version) : Long.ZERO, + message: isSet(object.message) ? globalThis.String(object.message) : "", + level: isSet(object.level) ? globalThis.String(object.level) : "", + team: isSet(object.team) ? globalThis.String(object.team) : "", + }; + }, + + toJSON(message: LogLine): unknown { + const obj: any = {}; + if (message.exploit !== "") { + obj.exploit = message.exploit; + } + if (!message.version.isZero()) { + obj.version = (message.version || Long.ZERO).toString(); + } + if (message.message !== "") { + obj.message = message.message; + } + if (message.level !== "") { + obj.level = message.level; + } + if (message.team !== "") { + obj.team = message.team; + } + return obj; + }, + + create, I>>(base?: I): LogLine { + return LogLine.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): LogLine { + const message = createBaseLogLine(); + message.exploit = object.exploit ?? ""; + message.version = (object.version !== undefined && object.version !== null) + ? Long.fromValue(object.version) + : Long.ZERO; + message.message = object.message ?? ""; + message.level = object.level ?? ""; + message.team = object.team ?? ""; + return message; + }, +}; + +function createBaseAddLogLinesRequest(): AddLogLinesRequest { + return { lines: [] }; +} + +export const AddLogLinesRequest = { + encode(message: AddLogLinesRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + for (const v of message.lines) { + LogLine.encode(v!, writer.uint32(10).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): AddLogLinesRequest { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseAddLogLinesRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.lines.push(LogLine.decode(reader, reader.uint32())); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): AddLogLinesRequest { + return { lines: globalThis.Array.isArray(object?.lines) ? object.lines.map((e: any) => LogLine.fromJSON(e)) : [] }; + }, + + toJSON(message: AddLogLinesRequest): unknown { + const obj: any = {}; + if (message.lines?.length) { + obj.lines = message.lines.map((e) => LogLine.toJSON(e)); + } + return obj; + }, + + create, I>>(base?: I): AddLogLinesRequest { + return AddLogLinesRequest.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): AddLogLinesRequest { + const message = createBaseAddLogLinesRequest(); + message.lines = object.lines?.map((e) => LogLine.fromPartial(e)) || []; + return message; + }, +}; + +function createBaseSearchLogLinesRequest(): SearchLogLinesRequest { + return { exploit: "", version: Long.ZERO }; +} + +export const SearchLogLinesRequest = { + encode(message: SearchLogLinesRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.exploit !== "") { + writer.uint32(10).string(message.exploit); + } + if (!message.version.isZero()) { + writer.uint32(16).int64(message.version); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): SearchLogLinesRequest { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseSearchLogLinesRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.exploit = reader.string(); + continue; + case 2: + if (tag !== 16) { + break; + } + + message.version = reader.int64() as Long; + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): SearchLogLinesRequest { + return { + exploit: isSet(object.exploit) ? globalThis.String(object.exploit) : "", + version: isSet(object.version) ? Long.fromValue(object.version) : Long.ZERO, + }; + }, + + toJSON(message: SearchLogLinesRequest): unknown { + const obj: any = {}; + if (message.exploit !== "") { + obj.exploit = message.exploit; + } + if (!message.version.isZero()) { + obj.version = (message.version || Long.ZERO).toString(); + } + return obj; + }, + + create, I>>(base?: I): SearchLogLinesRequest { + return SearchLogLinesRequest.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): SearchLogLinesRequest { + const message = createBaseSearchLogLinesRequest(); + message.exploit = object.exploit ?? ""; + message.version = (object.version !== undefined && object.version !== null) + ? Long.fromValue(object.version) + : Long.ZERO; + return message; + }, +}; + +function createBaseSearchLogLinesResponse(): SearchLogLinesResponse { + return { lines: [] }; +} + +export const SearchLogLinesResponse = { + encode(message: SearchLogLinesResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + for (const v of message.lines) { + LogLine.encode(v!, writer.uint32(10).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): SearchLogLinesResponse { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseSearchLogLinesResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.lines.push(LogLine.decode(reader, reader.uint32())); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): SearchLogLinesResponse { + return { lines: globalThis.Array.isArray(object?.lines) ? object.lines.map((e: any) => LogLine.fromJSON(e)) : [] }; + }, + + toJSON(message: SearchLogLinesResponse): unknown { + const obj: any = {}; + if (message.lines?.length) { + obj.lines = message.lines.map((e) => LogLine.toJSON(e)); + } + return obj; + }, + + create, I>>(base?: I): SearchLogLinesResponse { + return SearchLogLinesResponse.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): SearchLogLinesResponse { + const message = createBaseSearchLogLinesResponse(); + message.lines = object.lines?.map((e) => LogLine.fromPartial(e)) || []; + return message; + }, +}; + +export type ServiceDefinition = typeof ServiceDefinition; +export const ServiceDefinition = { + name: "Service", + fullName: "logs.Service", + methods: { + addLogLines: { + name: "AddLogLines", + requestType: AddLogLinesRequest, + requestStream: false, + responseType: Empty, + responseStream: false, + options: {}, + }, + searchLogLines: { + name: "SearchLogLines", + requestType: SearchLogLinesRequest, + requestStream: false, + responseType: SearchLogLinesResponse, + responseStream: true, + options: {}, + }, + }, +} as const; + +export interface ServiceImplementation { + addLogLines(request: AddLogLinesRequest, context: CallContext & CallContextExt): Promise>; + searchLogLines( + request: SearchLogLinesRequest, + context: CallContext & CallContextExt, + ): ServerStreamingMethodResult>; +} + +export interface ServiceClient { + addLogLines(request: DeepPartial, options?: CallOptions & CallOptionsExt): Promise; + searchLogLines( + request: DeepPartial, + options?: CallOptions & CallOptionsExt, + ): AsyncIterable; +} + +type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; + +export type DeepPartial = T extends Builtin ? T + : T extends Long ? string | number | Long : T extends globalThis.Array ? globalThis.Array> + : T extends ReadonlyArray ? ReadonlyArray> + : T extends { $case: string } ? { [K in keyof Omit]?: DeepPartial } & { $case: T["$case"] } + : T extends {} ? { [K in keyof T]?: DeepPartial } + : Partial; + +type KeysOfUnion = T extends T ? keyof T : never; +export type Exact = P extends Builtin ? P + : P & { [K in keyof P]: Exact } & { [K in Exclude>]: never }; + +if (_m0.util.Long !== Long) { + _m0.util.Long = Long as any; + _m0.configure(); +} + +function isSet(value: any): boolean { + return value !== null && value !== undefined; +} + +export type ServerStreamingMethodResult = { [Symbol.asyncIterator](): AsyncIterator }; diff --git a/front/src/routes/auth.tsx b/front/src/routes/auth.tsx new file mode 100644 index 0000000..48bd701 --- /dev/null +++ b/front/src/routes/auth.tsx @@ -0,0 +1,86 @@ +import { rawExploitServiceClient } from "@/services/exploits"; +import { usePersistentStorageValue } from "@/utils/storage"; +import { Box, TextField } from "@mui/material"; +import { ClientError, Metadata } from "nice-grpc-web"; +import { useEffect, useState } from "react"; +import ReactDOM from "react-dom"; +import { Helmet } from "react-helmet-async"; +import { AuthContext } from "./authContext"; + +export default function AuthProvider({ + children, +}: { + children: React.ReactNode; +}) { + const [error, setError] = useState(null); + const [token, setToken] = usePersistentStorageValue("token"); + const [checkedToken, setCheckedToken] = useState(false); + + useEffect(() => { + const checkToken = async (token: string) => { + try { + await rawExploitServiceClient.ping( + { + payload: { $case: "serverInfoRequest", serverInfoRequest: {} }, + }, + { metadata: new Metadata({ authorization: token }) } + ); + ReactDOM.unstable_batchedUpdates(() => { + setToken(token); + setCheckedToken(true); + setError(null); + }); + } catch (e) { + let message = "Unknown error"; + if (e instanceof ClientError) { + message = e.message; + } else if (e instanceof Error) { + message = e.message; + } + + ReactDOM.unstable_batchedUpdates(() => { + setCheckedToken(false); + setError(message); + }); + } + }; + + if (token) { + void checkToken(token); + } + }, [token, setToken]); + + const handleTokenChange = (event: React.ChangeEvent) => { + setToken(event.target.value); + }; + + if (!token || !checkedToken) { + return ( + <> + + Neo + + + + + + ); + } + + return ( + + {children} + + ); +} diff --git a/front/src/routes/authContext.ts b/front/src/routes/authContext.ts new file mode 100644 index 0000000..1c3ac8a --- /dev/null +++ b/front/src/routes/authContext.ts @@ -0,0 +1,14 @@ +import { Metadata } from "nice-grpc-common"; +import { createContext, useContext } from "react"; + +type AuthContextType = { metadata: Metadata }; + +export const AuthContext = createContext(null); + +export function useAuthContext(): AuthContextType { + const ctx = useContext(AuthContext); + if (!ctx) { + throw new Error("useAuthContext must be used within AuthContext.Provider"); + } + return ctx; +} diff --git a/front/src/routes/exploits.tsx b/front/src/routes/exploits.tsx new file mode 100644 index 0000000..4838157 --- /dev/null +++ b/front/src/routes/exploits.tsx @@ -0,0 +1,50 @@ +import ExploitsView from "@/components/ExploitsView"; +import { ExploitState } from "@/proto/exploits/api"; +import { useExploitServiceClient } from "@/services/exploits"; +import { Box } from "@mui/material"; +import { useCallback, useEffect, useState } from "react"; +import { Helmet } from "react-helmet-async"; + +interface S { + exploits: ExploitState[]; +} + +export default function ExploitsContainer() { + const [state, setState] = useState(); + + const exploitServiceClient = useExploitServiceClient(); + + const fetchExploits = useCallback(async () => { + const response = await exploitServiceClient.ping({ + payload: { $case: "serverInfoRequest", serverInfoRequest: {} }, + }); + setState({ + exploits: + response.state?.exploits.sort((e1: ExploitState, e2: ExploitState) => { + return e1.exploitId.localeCompare(e2.exploitId); + }) || [], + }); + }, [exploitServiceClient]); + + useEffect(() => { + void fetchExploits(); + }, [exploitServiceClient, fetchExploits]); + + return ( + <> + + Neo Exploits + + + {state && ( + { + void fetchExploits(); + }} + /> + )} + + + ); +} diff --git a/front/src/routes/logs.tsx b/front/src/routes/logs.tsx new file mode 100644 index 0000000..727c672 --- /dev/null +++ b/front/src/routes/logs.tsx @@ -0,0 +1,40 @@ +import LogsRootView from "@/components/LogsRootView"; +import { ExploitState } from "@/proto/exploits/api"; +import { useExploitServiceClient } from "@/services/exploits"; +import { useEffect, useState } from "react"; +import { Helmet } from "react-helmet-async"; + +interface S { + exploits: ExploitState[]; +} + +export default function LogsContainer() { + const exploitServiceClient = useExploitServiceClient(); + const [state, setState] = useState(); + + useEffect(() => { + const fetchExploits = async () => { + const response = await exploitServiceClient.ping({ + payload: { $case: "serverInfoRequest", serverInfoRequest: {} }, + }); + setState({ + exploits: + response.state?.exploits.sort( + (e1: ExploitState, e2: ExploitState) => { + return e1.exploitId.localeCompare(e2.exploitId); + } + ) || [], + }); + }; + void fetchExploits(); + }, [exploitServiceClient]); + + return ( + <> + + Neo Logs + + {state && } + + ); +} diff --git a/front/src/routes/root.tsx b/front/src/routes/root.tsx new file mode 100644 index 0000000..3f9a1f9 --- /dev/null +++ b/front/src/routes/root.tsx @@ -0,0 +1,36 @@ +import { AppBar, Box, Button, Toolbar } from "@mui/material"; +import { useRef } from "react"; +import { Link, Outlet } from "react-router-dom"; +import { RootContext } from "./rootContext"; + +export default function Root() { + const topbarRef = useRef(null); + + return ( + <> + + + + + + + + + + + + + + ); +} diff --git a/front/src/routes/rootContext.ts b/front/src/routes/rootContext.ts new file mode 100644 index 0000000..1f260f6 --- /dev/null +++ b/front/src/routes/rootContext.ts @@ -0,0 +1,13 @@ +import { createContext, useContext } from "react"; + +type RootContextType = { topbarRef: React.RefObject }; + +export const RootContext = createContext(null); + +export function useRootContext(): RootContextType { + const ctx = useContext(RootContext); + if (!ctx) { + throw new Error("useRootContext must be used within RootContext.Provider"); + } + return ctx; +} diff --git a/front/src/services/exploits.ts b/front/src/services/exploits.ts new file mode 100644 index 0000000..31809f7 --- /dev/null +++ b/front/src/services/exploits.ts @@ -0,0 +1,38 @@ +import { grpcAddress } from "@/config.ts"; +import { ServiceClient, ServiceDefinition } from "@/proto/exploits/api.ts"; +import { useAuthContext } from "@/routes/authContext"; +import { + WebsocketTransport, + createChannel, + createClient, + createClientFactory, +} from "nice-grpc-web"; +import { useMemo } from "react"; + +const channel = createChannel(grpcAddress, WebsocketTransport()); + +export type ExploitServiceClient = ServiceClient; + +export const rawExploitServiceClient: ExploitServiceClient = createClient( + ServiceDefinition, + channel +); + +export function useExploitServiceClient(): ExploitServiceClient { + const authContext = useAuthContext(); + return useMemo( + () => + createClientFactory() + .use((call, options) => + call.next(call.request, { + ...options, + metadata: { + ...options.metadata, + ...authContext.metadata, + }, + }) + ) + .create(ServiceDefinition, channel), + [authContext] + ); +} diff --git a/front/src/services/logs.ts b/front/src/services/logs.ts new file mode 100644 index 0000000..7c72a15 --- /dev/null +++ b/front/src/services/logs.ts @@ -0,0 +1,32 @@ +import { grpcAddress } from "@/config.ts"; +import { ServiceClient, ServiceDefinition } from "@/proto/logs/api.ts"; +import { useAuthContext } from "@/routes/authContext"; +import { + WebsocketTransport, + createChannel, + createClientFactory, +} from "nice-grpc-web"; +import { useMemo } from "react"; + +const channel = createChannel(grpcAddress, WebsocketTransport()); + +export type LogsServiceClient = ServiceClient; + +export function useLogsServiceClient(): LogsServiceClient { + const authContext = useAuthContext(); + return useMemo( + () => + createClientFactory() + .use((call, options) => + call.next(call.request, { + ...options, + metadata: { + ...options.metadata, + ...authContext.metadata, + }, + }) + ) + .create(ServiceDefinition, channel), + [authContext] + ); +} diff --git a/front/src/theme.ts b/front/src/theme.ts new file mode 100644 index 0000000..dd390e0 --- /dev/null +++ b/front/src/theme.ts @@ -0,0 +1,28 @@ +import { createTheme } from "@mui/material/styles"; + +declare module "@mui/material/styles" { + interface Theme { + typography: { + fontFamily: string; + }; + palette: { + primary: { + main: string; + contrastText: string; + }; + }; + } +} + +const theme = createTheme({ + typography: { + fontFamily: "Monospace", + }, + palette: { + primary: { + main: "#333333", + }, + }, +}); + +export default theme; diff --git a/front/src/utils/duration.ts b/front/src/utils/duration.ts new file mode 100644 index 0000000..303b86c --- /dev/null +++ b/front/src/utils/duration.ts @@ -0,0 +1,60 @@ +import { Duration } from "@/proto/google/protobuf/duration"; +import Long from "long"; + +export function formatDuration(d: Duration): string { + return formatSeconds(d.seconds.toInt()); +} + +export function formatSeconds(s: number): string { + const hours = Math.floor(s / 3600); + const minutes = Math.floor((s % 3600) / 60); + const seconds = Math.floor(s % 60); + + let res = ""; + if (hours > 0) { + res += `${hours}h`; + } + if (minutes > 0) { + res += `${minutes}m`; + } + if (seconds > 0) { + res += `${seconds}s`; + } + if (res.length === 0) { + res = "0s"; + } + return res; +} + +export function parseDuration(s: string): Duration { + const numRegex = /^\d+$/; + if (numRegex.test(s)) { + return Duration.create({ + seconds: Long.fromNumber(parseInt(s)), + nanos: 0, + }); + } + + const regex = + /^(?(\d+)h)?\s*(?(\d+)m)?\s*(?(\d+)s)?$/; + const match = regex.exec(s); + if (match === null) { + throw new Error(`invalid duration: ${s}`); + } + + interface Parsed { + hours: string; + minutes: string; + seconds: string; + } + const parsed: Partial | undefined = match.groups; + + const hours = parsed?.hours === undefined ? 0 : parseInt(parsed.hours); + const minutes = parsed?.minutes === undefined ? 0 : parseInt(parsed.minutes); + const seconds = parsed?.seconds === undefined ? 0 : parseInt(parsed.seconds); + + return Duration.create({ + seconds: Long.fromNumber(hours * 3600 + minutes * 60 + seconds), + nanos: 0, + }); +} diff --git a/front/src/utils/storage.ts b/front/src/utils/storage.ts new file mode 100644 index 0000000..b846c36 --- /dev/null +++ b/front/src/utils/storage.ts @@ -0,0 +1,19 @@ +import { useEffect, useState } from "react"; + +export function usePersistentStorageValue(key: string, initialValue?: T) { + const [value, setValue] = useState(() => { + const valueFromStorage = window.localStorage.getItem(key); + if (valueFromStorage) { + return JSON.parse(valueFromStorage) as unknown as T; + } + return initialValue; + }); + + useEffect(() => { + if (value) { + window.localStorage.setItem(key, JSON.stringify(value)); + } + }, [key, value]); + + return [value, setValue] as const; +} diff --git a/front/src/utils/window.ts b/front/src/utils/window.ts new file mode 100644 index 0000000..dcb90b3 --- /dev/null +++ b/front/src/utils/window.ts @@ -0,0 +1,34 @@ +import { useSyncExternalStore } from "react"; + +export function useWindowDimensions() { + return useSyncExternalStore(subscribe, getSnapshot); +} + +function subscribe(callback: { + (this: Window, ev: UIEvent): void; + (this: Window, ev: UIEvent): void; +}) { + window.addEventListener("resize", callback); + return () => { + window.removeEventListener("resize", callback); + }; +} + +interface Snapshot { + width: number; + height: number; +} + +let lastSnapshot: Snapshot | null = null; + +function getSnapshot() { + const newSnapshot = { width: window.innerWidth, height: window.innerHeight }; + if ( + lastSnapshot == null || + newSnapshot.width != lastSnapshot.width || + newSnapshot.height != lastSnapshot.height + ) { + lastSnapshot = newSnapshot; + } + return lastSnapshot; +} diff --git a/front/src/vite-env.d.ts b/front/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/front/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/front/tsconfig.json b/front/tsconfig.json new file mode 100644 index 0000000..8775be2 --- /dev/null +++ b/front/tsconfig.json @@ -0,0 +1,40 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": [ + "ES2020", + "DOM", + "DOM.Iterable" + ], + "module": "ESNext", + "skipLibCheck": true, + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + /* Linting */ + "strict": true, + "strictNullChecks": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "baseUrl": ".", + "paths": { + "@/*": [ + "src/*", + ] + }, + }, + "include": [ + "src" + ], + "references": [ + { + "path": "./tsconfig.node.json" + } + ] +} \ No newline at end of file diff --git a/front/tsconfig.node.json b/front/tsconfig.node.json new file mode 100644 index 0000000..7f5d1a8 --- /dev/null +++ b/front/tsconfig.node.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "strictNullChecks": true, + "allowSyntheticDefaultImports": true + }, + "include": [ + "vite.config.ts" + ] +} \ No newline at end of file diff --git a/front/vite.config.ts b/front/vite.config.ts new file mode 100644 index 0000000..e8e2bf8 --- /dev/null +++ b/front/vite.config.ts @@ -0,0 +1,10 @@ +import react from "@vitejs/plugin-react"; +import { defineConfig } from "vite"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + resolve: { + alias: [{ find: "@", replacement: "/src" }], + }, +}); From d7e0c50040b1d840e7251fc8f677f56385c99312 Mon Sep 17 00:00:00 2001 From: Roman Nikitin Date: Fri, 17 Nov 2023 15:46:33 +0300 Subject: [PATCH 04/18] Serving static in neo --- .dockerignore | 1 + Dockerfile | 18 ++++++++++++++++-- Makefile | 1 + cmd/server/main.go | 5 +++++ compose.yml | 3 +++ configs/server/config.yml | 6 +----- internal/server/config/config.go | 1 + 7 files changed, 28 insertions(+), 7 deletions(-) diff --git a/.dockerignore b/.dockerignore index 58ce30a..cb44ba9 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,4 @@ dist data volumes +/front/node_modules diff --git a/Dockerfile b/Dockerfile index 2cdbdc9..e118b19 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,8 +15,22 @@ RUN --mount=type=cache,target=/root/.cache/go-build \ -o neo_server \ cmd/server/main.go +FROM node:20-slim AS front-base +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +RUN corepack enable + +COPY front /app +WORKDIR /app + +FROM front-base AS front-build +RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile +RUN pnpm run build + FROM alpine -COPY --from=build /app/neo_server /neo_server +WORKDIR /app +COPY --from=build /app/neo_server neo_server +COPY --from=front-build /app/dist front/dist -CMD ["/neo_server", "--config", "/config.yml"] +CMD ["./neo_server", "--config", "/config.yml"] diff --git a/Makefile b/Makefile index f1b987e..1e159ef 100644 --- a/Makefile +++ b/Makefile @@ -32,6 +32,7 @@ validate: lint test .PHONY: proto proto: cd proto && buf generate + cd front && ./add_ts_ignore.sh .PHONY: test-cov test-cov: diff --git a/cmd/server/main.go b/cmd/server/main.go index d4cb814..1d910ac 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -89,6 +89,10 @@ func main() { httpMux := http.NewServeMux() httpMux.Handle("/metrics", promhttp.Handler()) + + staticFS := http.FileServer(http.Dir(cfg.StaticDir)) + httpMux.Handle("/", staticFS) + muHandler := mu.NewHandler(s, mu.WithHTTPHandler(httpMux)) httpServer := &http.Server{ Handler: muHandler, @@ -158,6 +162,7 @@ func setupConfig() error { viper.SetDefault("ping_every", time.Second*5) viper.SetDefault("submit_every", time.Second*2) viper.SetDefault("address", ":5005") + viper.SetDefault("static_dir", "front/dist") return nil } diff --git a/compose.yml b/compose.yml index 40a7677..815cc8d 100644 --- a/compose.yml +++ b/compose.yml @@ -8,6 +8,9 @@ services: NEO_GRPC_AUTH_KEY: ${GRPC_AUTH_KEY} NEO_FARM_PASSWORD: ${FARM_PASSWORD} NEO_FARM_URL: ${FARM_URL} + NEO_DB_PATH: /data/db.db + NEO_REDIS_URL: 'redis://redis:6379/0' + NEO_BASE_DIR: '/data/exploits' ports: - '5005:5005' restart: unless-stopped diff --git a/configs/server/config.yml b/configs/server/config.yml index 48f3387..1ab550d 100644 --- a/configs/server/config.yml +++ b/configs/server/config.yml @@ -1,13 +1,9 @@ -db_path: "data/db.db" -redis_url: 'redis://redis:6379/0' -base_dir: "data/exploits" ping_every: "5s" submit_every: "2s" grpc_auth_key: "s3cret_t0ken_pls_d0nt_leak" farm: - # url: "http://127.0.0.1:5137" - url: "http://192.168.82.252:5137" + url: "http://127.0.0.1:5137" password: "1234" env: diff --git a/internal/server/config/config.go b/internal/server/config/config.go index 1957128..56fc618 100644 --- a/internal/server/config/config.go +++ b/internal/server/config/config.go @@ -10,6 +10,7 @@ import ( type Config struct { Debug bool `mapstructure:"debug"` Address string `mapstructure:"address"` + StaticDir string `mapstructure:"static_dir"` DBPath string `mapstructure:"db_path"` RedisURL string `mapstructure:"redis_url"` BaseDir string `mapstructure:"base_dir"` From 117073065ba7374cab4ff9595a0a4d73af9eef49 Mon Sep 17 00:00:00 2001 From: Roman Nikitin Date: Fri, 17 Nov 2023 15:52:04 +0300 Subject: [PATCH 05/18] Better server config --- cmd/server/main.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmd/server/main.go b/cmd/server/main.go index 1d910ac..2927731 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -157,12 +157,18 @@ func setupConfig() error { viper.MustBindEnv("grpc_auth_key") viper.MustBindEnv("farm.password") viper.MustBindEnv("farm.url") + viper.MustBindEnv("db_path") + viper.MustBindEnv("redis_url") + viper.MustBindEnv("base_dir") viper.SetDefault("config", "server_config.yml") viper.SetDefault("ping_every", time.Second*5) viper.SetDefault("submit_every", time.Second*2) viper.SetDefault("address", ":5005") viper.SetDefault("static_dir", "front/dist") + viper.SetDefault("redis_url", "redis://127.0.0.1:6379/0") + viper.SetDefault("db_path", "data/db.db") + viper.SetDefault("base_dir", "data/exploits") return nil } From c0ce8295c92b5680e9166a42e12a47f5f62b43ad Mon Sep 17 00:00:00 2001 From: Roman Nikitin Date: Fri, 17 Nov 2023 20:16:37 +0300 Subject: [PATCH 06/18] Fix static handler --- cmd/server/main.go | 5 ++--- pkg/neohttp/static.go | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 pkg/neohttp/static.go diff --git a/cmd/server/main.go b/cmd/server/main.go index 2927731..f4bcd17 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -26,6 +26,7 @@ import ( logs "github.com/c4t-but-s4d/neo/v2/internal/server/logs" "github.com/c4t-but-s4d/neo/v2/pkg/grpcauth" "github.com/c4t-but-s4d/neo/v2/pkg/mu" + "github.com/c4t-but-s4d/neo/v2/pkg/neohttp" "github.com/c4t-but-s4d/neo/v2/pkg/neosync" epb "github.com/c4t-but-s4d/neo/v2/proto/go/exploits" fspb "github.com/c4t-but-s4d/neo/v2/proto/go/fileserver" @@ -89,9 +90,7 @@ func main() { httpMux := http.NewServeMux() httpMux.Handle("/metrics", promhttp.Handler()) - - staticFS := http.FileServer(http.Dir(cfg.StaticDir)) - httpMux.Handle("/", staticFS) + httpMux.Handle("/", neohttp.StaticHandler(cfg.StaticDir)) muHandler := mu.NewHandler(s, mu.WithHTTPHandler(httpMux)) httpServer := &http.Server{ diff --git a/pkg/neohttp/static.go b/pkg/neohttp/static.go new file mode 100644 index 0000000..5c858c0 --- /dev/null +++ b/pkg/neohttp/static.go @@ -0,0 +1,21 @@ +package neohttp + +import ( + "net/http" + "os" + "path/filepath" +) + +func StaticHandler(dir string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + filePath := filepath.Join(dir, r.URL.Path) + + if r.URL.Path == "" || r.URL.Path == "/" { + filePath = filepath.Join(dir, "index.html") + } else if _, err := os.Stat(filePath); err != nil { + filePath = filepath.Join(dir, "index.html") + } + + http.ServeFile(w, r, filePath) + } +} From 0818e9b9b07c1c27ac468d4356bd963eec3b62d2 Mon Sep 17 00:00:00 2001 From: Roman Nikitin Date: Fri, 17 Nov 2023 20:51:58 +0300 Subject: [PATCH 07/18] Fix websockets --- go.mod | 4 +- go.sum | 229 +++++------------------------------------------ pkg/mu/server.go | 2 + 3 files changed, 28 insertions(+), 207 deletions(-) diff --git a/go.mod b/go.mod index 9809c07..c501944 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( ) require ( - github.com/improbable-eng/grpc-web v0.15.0 + github.com/improbable-eng/grpc-web v0.15.1-0.20230209220825-1d9bbb09a099 github.com/prometheus/client_golang v1.17.0 github.com/prometheus/common v0.44.0 github.com/samber/lo v1.38.1 @@ -60,5 +60,5 @@ require ( golang.org/x/text v0.13.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c // indirect gopkg.in/ini.v1 v1.67.0 // indirect - nhooyr.io/websocket v1.8.6 // indirect + nhooyr.io/websocket v1.8.7 // indirect ) diff --git a/go.sum b/go.sum index bd308fc..959cdf2 100644 --- a/go.sum +++ b/go.sum @@ -38,54 +38,30 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= -github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= -github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -94,30 +70,18 @@ github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMS github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= -github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= @@ -127,7 +91,7 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -140,7 +104,6 @@ github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1 github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= @@ -148,12 +111,9 @@ github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -179,9 +139,9 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -211,69 +171,35 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= -github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= -github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/improbable-eng/grpc-web v0.15.1-0.20230209220825-1d9bbb09a099 h1:k07oXM8RqIaaSEF09Frr/iRMlwx2qvx6vRo2XuPIeW8= +github.com/improbable-eng/grpc-web v0.15.1-0.20230209220825-1d9bbb09a099/go.mod h1:Vkb7Iy2LTlRGIAubpODgfeKPzu8nsh1gO+vvZAiZrcs= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= @@ -295,29 +221,14 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= -github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -331,110 +242,66 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod h1:x5OoJHDHqxHS801UIuhqGl6QdSAEJvtausosHSdazIo= -github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= -github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= -github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= -github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= -github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= -github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= -github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ= github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= -github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= @@ -443,17 +310,12 @@ github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY= github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI= github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -469,48 +331,33 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= @@ -553,13 +400,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -570,7 +412,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -591,8 +432,9 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -604,6 +446,7 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -614,14 +457,9 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -631,11 +469,9 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -661,16 +497,21 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -681,19 +522,16 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -703,8 +541,6 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -712,7 +548,6 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -742,7 +577,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -763,7 +597,6 @@ google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= @@ -775,7 +608,6 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= @@ -811,15 +643,10 @@ google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c h1:jHkCUWkseRf+W+edG5hMzr/Uh1xkDREY4caybAq4dpY= google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -847,6 +674,7 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -855,17 +683,11 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -878,7 +700,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -886,10 +707,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= -nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= +nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/pkg/mu/server.go b/pkg/mu/server.go index 706a38d..3f7260b 100644 --- a/pkg/mu/server.go +++ b/pkg/mu/server.go @@ -7,6 +7,7 @@ import ( "golang.org/x/net/http2" "golang.org/x/net/http2/h2c" "google.golang.org/grpc" + "nhooyr.io/websocket" ) func NewHandler(grpcServer *grpc.Server, opts ...Option) http.Handler { @@ -30,6 +31,7 @@ func NewHandler(grpcServer *grpc.Server, opts ...Option) http.Handler { grpcweb.WithWebsocketOriginFunc(func(*http.Request) bool { return true }), + grpcweb.WithWebsocketCompressionMode(websocket.CompressionDisabled), ), httpHandler: cfg.httpHandler, }, From 18dbe9209cf5e3f6528e018eda2db0d379ea8629 Mon Sep 17 00:00:00 2001 From: Roman Nikitin Date: Fri, 17 Nov 2023 20:54:58 +0300 Subject: [PATCH 08/18] Go mod tidy --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index c501944..aba3999 100644 --- a/go.mod +++ b/go.mod @@ -29,6 +29,7 @@ require ( github.com/samber/lo v1.38.1 golang.org/x/net v0.17.0 golang.org/x/sys v0.13.0 + nhooyr.io/websocket v1.8.7 ) require ( @@ -60,5 +61,4 @@ require ( golang.org/x/text v0.13.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c // indirect gopkg.in/ini.v1 v1.67.0 // indirect - nhooyr.io/websocket v1.8.7 // indirect ) From 98745f72ce29b664c13d0dead1073310b141e3a4 Mon Sep 17 00:00:00 2001 From: Roman Nikitin Date: Sat, 18 Nov 2023 01:23:13 +0300 Subject: [PATCH 09/18] Fix tests --- internal/server/exploits/server_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/internal/server/exploits/server_test.go b/internal/server/exploits/server_test.go index 26deb2b..a25eec2 100644 --- a/internal/server/exploits/server_test.go +++ b/internal/server/exploits/server_test.go @@ -10,6 +10,7 @@ import ( "github.com/google/uuid" "github.com/stretchr/testify/require" "google.golang.org/protobuf/testing/protocmp" + "google.golang.org/protobuf/types/known/durationpb" "github.com/c4t-but-s4d/neo/v2/internal/server/config" "github.com/c4t-but-s4d/neo/v2/pkg/hostbucket" @@ -40,6 +41,8 @@ func TestServer_UpdateExploit(t *testing.T) { cfg := &epb.ExploitConfiguration{ Entrypoint: "bin", IsArchive: false, + Timeout: durationpb.New(time.Minute), + RunEvery: durationpb.New(time.Minute), } r := &epb.UpdateExploitRequest{ State: &epb.ExploitState{ @@ -50,6 +53,9 @@ func TestServer_UpdateExploit(t *testing.T) { } resp, err := es.UpdateExploit(context.Background(), r) require.NoError(t, err) + + cfg.Timeout = durationpb.New(2 * time.Minute) + cfg.RunEvery = durationpb.New(2 * time.Minute) want := &epb.ExploitState{ ExploitId: "1", Version: 1, @@ -67,6 +73,8 @@ func TestServer_Exploit(t *testing.T) { cfg := &epb.ExploitConfiguration{ Entrypoint: "bin", IsArchive: false, + Timeout: durationpb.New(time.Minute), + RunEvery: durationpb.New(time.Minute), } state := &epb.ExploitState{ ExploitId: "1", @@ -99,6 +107,8 @@ func TestServer_Ping(t *testing.T) { cfg := &epb.ExploitConfiguration{ Entrypoint: "bin", IsArchive: false, + Timeout: durationpb.New(time.Minute), + RunEvery: durationpb.New(time.Minute), } state := &epb.ExploitState{ ExploitId: "1", From 7654f655e84907053b5e0a44f168e9af0658c802 Mon Sep 17 00:00:00 2001 From: Roman Nikitin Date: Sat, 18 Nov 2023 01:42:05 +0300 Subject: [PATCH 10/18] Move go proto to pkg/proto, add .gitattributes --- .gitattributes | 2 ++ cmd/client/cli/add.go | 2 +- cmd/client/cli/tail.go | 2 +- cmd/client/cli/update.go | 2 +- cmd/client/cli/utils.go | 2 +- cmd/server/main.go | 6 +++--- internal/client/client.go | 6 +++--- internal/config/config.go | 2 +- internal/exploit/cache.go | 2 +- internal/exploit/cache_test.go | 2 +- internal/exploit/runner.go | 2 +- internal/exploit/storage.go | 2 +- internal/exploit/storage_test.go | 2 +- internal/server/exploits/server.go | 2 +- internal/server/exploits/server_test.go | 4 ++-- internal/server/exploits/storage.go | 2 +- internal/server/exploits/storage_test.go | 4 ++-- internal/server/fs/server.go | 2 +- internal/server/logs/logline.go | 2 +- internal/server/logs/server.go | 2 +- pkg/filestream/filestream.go | 2 +- pkg/filestream/filestream_test.go | 2 +- pkg/hostbucket/hostbucket.go | 2 +- pkg/joblogger/logger.go | 2 +- pkg/joblogger/sender.go | 2 +- {proto/go => pkg/proto}/exploits/api.pb.go | 20 +++++++++---------- .../go => pkg/proto}/exploits/api_grpc.pb.go | 0 {proto/go => pkg/proto}/fileserver/api.pb.go | 18 ++++++++--------- .../proto}/fileserver/api_grpc.pb.go | 0 {proto/go => pkg/proto}/logs/api.pb.go | 14 ++++++------- {proto/go => pkg/proto}/logs/api_grpc.pb.go | 0 proto/buf.gen.yaml | 6 +++--- 32 files changed, 61 insertions(+), 59 deletions(-) create mode 100644 .gitattributes rename {proto/go => pkg/proto}/exploits/api.pb.go (98%) rename {proto/go => pkg/proto}/exploits/api_grpc.pb.go (100%) rename {proto/go => pkg/proto}/fileserver/api.pb.go (90%) rename {proto/go => pkg/proto}/fileserver/api_grpc.pb.go (100%) rename {proto/go => pkg/proto}/logs/api.pb.go (96%) rename {proto/go => pkg/proto}/logs/api_grpc.pb.go (100%) diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..84afbe0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +pkg/proto/** linguist-vendored +front/src/proto/** linguist-vendored diff --git a/cmd/client/cli/add.go b/cmd/client/cli/add.go index 53b6061..2bd611c 100644 --- a/cmd/client/cli/add.go +++ b/cmd/client/cli/add.go @@ -19,7 +19,7 @@ import ( "github.com/c4t-but-s4d/neo/v2/internal/client" "github.com/c4t-but-s4d/neo/v2/pkg/archive" - epb "github.com/c4t-but-s4d/neo/v2/proto/go/exploits" + epb "github.com/c4t-but-s4d/neo/v2/pkg/proto/exploits" ) type addCLI struct { diff --git a/cmd/client/cli/tail.go b/cmd/client/cli/tail.go index 946384e..112ceeb 100644 --- a/cmd/client/cli/tail.go +++ b/cmd/client/cli/tail.go @@ -8,7 +8,7 @@ import ( "github.com/spf13/cobra" "github.com/c4t-but-s4d/neo/v2/internal/client" - logspb "github.com/c4t-but-s4d/neo/v2/proto/go/logs" + logspb "github.com/c4t-but-s4d/neo/v2/pkg/proto/logs" ) type tailCLI struct { diff --git a/cmd/client/cli/update.go b/cmd/client/cli/update.go index 040b2a3..72d9d6f 100644 --- a/cmd/client/cli/update.go +++ b/cmd/client/cli/update.go @@ -12,7 +12,7 @@ import ( "github.com/c4t-but-s4d/neo/v2/internal/client" - epb "github.com/c4t-but-s4d/neo/v2/proto/go/exploits" + epb "github.com/c4t-but-s4d/neo/v2/pkg/proto/exploits" ) type updateCLI struct { diff --git a/cmd/client/cli/utils.go b/cmd/client/cli/utils.go index 8cb9246..46a029b 100644 --- a/cmd/client/cli/utils.go +++ b/cmd/client/cli/utils.go @@ -5,7 +5,7 @@ import ( "github.com/samber/lo" - "github.com/c4t-but-s4d/neo/v2/proto/go/exploits" + "github.com/c4t-but-s4d/neo/v2/pkg/proto/exploits" ) func isBinary(data []byte) bool { diff --git a/cmd/server/main.go b/cmd/server/main.go index f4bcd17..42d87a3 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -28,9 +28,9 @@ import ( "github.com/c4t-but-s4d/neo/v2/pkg/mu" "github.com/c4t-but-s4d/neo/v2/pkg/neohttp" "github.com/c4t-but-s4d/neo/v2/pkg/neosync" - epb "github.com/c4t-but-s4d/neo/v2/proto/go/exploits" - fspb "github.com/c4t-but-s4d/neo/v2/proto/go/fileserver" - logspb "github.com/c4t-but-s4d/neo/v2/proto/go/logs" + epb "github.com/c4t-but-s4d/neo/v2/pkg/proto/exploits" + fspb "github.com/c4t-but-s4d/neo/v2/pkg/proto/fileserver" + logspb "github.com/c4t-but-s4d/neo/v2/pkg/proto/logs" ) func main() { diff --git a/internal/client/client.go b/internal/client/client.go index 0a8e4fe..ee7b217 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -10,9 +10,9 @@ import ( "google.golang.org/grpc" "github.com/c4t-but-s4d/neo/v2/pkg/filestream" - epb "github.com/c4t-but-s4d/neo/v2/proto/go/exploits" - fspb "github.com/c4t-but-s4d/neo/v2/proto/go/fileserver" - logspb "github.com/c4t-but-s4d/neo/v2/proto/go/logs" + epb "github.com/c4t-but-s4d/neo/v2/pkg/proto/exploits" + fspb "github.com/c4t-but-s4d/neo/v2/pkg/proto/fileserver" + logspb "github.com/c4t-but-s4d/neo/v2/pkg/proto/logs" ) func New(cc grpc.ClientConnInterface, id string) *Client { diff --git a/internal/config/config.go b/internal/config/config.go index 7f666e3..4e01476 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -7,7 +7,7 @@ import ( "google.golang.org/protobuf/types/known/durationpb" - epb "github.com/c4t-but-s4d/neo/v2/proto/go/exploits" + epb "github.com/c4t-but-s4d/neo/v2/pkg/proto/exploits" ) type ExploitsConfig struct { diff --git a/internal/exploit/cache.go b/internal/exploit/cache.go index b368256..a6f9251 100644 --- a/internal/exploit/cache.go +++ b/internal/exploit/cache.go @@ -4,7 +4,7 @@ import ( "sync" "time" - epb "github.com/c4t-but-s4d/neo/v2/proto/go/exploits" + epb "github.com/c4t-but-s4d/neo/v2/pkg/proto/exploits" ) func NewCache() *Cache { diff --git a/internal/exploit/cache_test.go b/internal/exploit/cache_test.go index 1cd1812..a3e5d77 100644 --- a/internal/exploit/cache_test.go +++ b/internal/exploit/cache_test.go @@ -7,7 +7,7 @@ import ( "github.com/google/go-cmp/cmp/cmpopts" "google.golang.org/protobuf/testing/protocmp" - epb "github.com/c4t-but-s4d/neo/v2/proto/go/exploits" + epb "github.com/c4t-but-s4d/neo/v2/pkg/proto/exploits" ) func TestCache_Diff(t *testing.T) { diff --git a/internal/exploit/runner.go b/internal/exploit/runner.go index 0493931..97850db 100644 --- a/internal/exploit/runner.go +++ b/internal/exploit/runner.go @@ -21,7 +21,7 @@ import ( "github.com/c4t-but-s4d/neo/v2/internal/models" "github.com/c4t-but-s4d/neo/v2/internal/queue" "github.com/c4t-but-s4d/neo/v2/pkg/joblogger" - epb "github.com/c4t-but-s4d/neo/v2/proto/go/exploits" + epb "github.com/c4t-but-s4d/neo/v2/pkg/proto/exploits" ) var ( diff --git a/internal/exploit/storage.go b/internal/exploit/storage.go index b2397cd..d99bd8f 100644 --- a/internal/exploit/storage.go +++ b/internal/exploit/storage.go @@ -12,7 +12,7 @@ import ( "github.com/c4t-but-s4d/neo/v2/internal/client" "github.com/c4t-but-s4d/neo/v2/pkg/archive" - epb "github.com/c4t-but-s4d/neo/v2/proto/go/exploits" + epb "github.com/c4t-but-s4d/neo/v2/pkg/proto/exploits" ) func NewStorage(cache *Cache, exploitDir string, client *client.Client) *Storage { diff --git a/internal/exploit/storage_test.go b/internal/exploit/storage_test.go index 5fb8c86..74cefc8 100644 --- a/internal/exploit/storage_test.go +++ b/internal/exploit/storage_test.go @@ -14,7 +14,7 @@ import ( "github.com/stretchr/testify/require" "github.com/c4t-but-s4d/neo/v2/pkg/archive" - epb "github.com/c4t-but-s4d/neo/v2/proto/go/exploits" + epb "github.com/c4t-but-s4d/neo/v2/pkg/proto/exploits" ) func mockStorage() (*Storage, func() error) { diff --git a/internal/server/exploits/server.go b/internal/server/exploits/server.go index 15b9562..8a6ab24 100644 --- a/internal/server/exploits/server.go +++ b/internal/server/exploits/server.go @@ -14,8 +14,8 @@ import ( serverConfig "github.com/c4t-but-s4d/neo/v2/internal/server/config" "github.com/c4t-but-s4d/neo/v2/pkg/gstream" "github.com/c4t-but-s4d/neo/v2/pkg/hostbucket" + epb "github.com/c4t-but-s4d/neo/v2/pkg/proto/exploits" "github.com/c4t-but-s4d/neo/v2/pkg/pubsub" - epb "github.com/c4t-but-s4d/neo/v2/proto/go/exploits" ) func New(cfg *serverConfig.Config, storage *CachedStorage) *Server { diff --git a/internal/server/exploits/server_test.go b/internal/server/exploits/server_test.go index a25eec2..1dec111 100644 --- a/internal/server/exploits/server_test.go +++ b/internal/server/exploits/server_test.go @@ -14,8 +14,8 @@ import ( "github.com/c4t-but-s4d/neo/v2/internal/server/config" "github.com/c4t-but-s4d/neo/v2/pkg/hostbucket" - epb "github.com/c4t-but-s4d/neo/v2/proto/go/exploits" - fspb "github.com/c4t-but-s4d/neo/v2/proto/go/fileserver" + epb "github.com/c4t-but-s4d/neo/v2/pkg/proto/exploits" + fspb "github.com/c4t-but-s4d/neo/v2/pkg/proto/fileserver" ) func testServer(t *testing.T) (*Server, func()) { diff --git a/internal/server/exploits/storage.go b/internal/server/exploits/storage.go index c47b1a1..6a61a11 100644 --- a/internal/server/exploits/storage.go +++ b/internal/server/exploits/storage.go @@ -10,7 +10,7 @@ import ( bolt "go.etcd.io/bbolt" "google.golang.org/protobuf/proto" - epb "github.com/c4t-but-s4d/neo/v2/proto/go/exploits" + epb "github.com/c4t-but-s4d/neo/v2/pkg/proto/exploits" ) const ( diff --git a/internal/server/exploits/storage_test.go b/internal/server/exploits/storage_test.go index 4fc987b..d69a9a5 100644 --- a/internal/server/exploits/storage_test.go +++ b/internal/server/exploits/storage_test.go @@ -12,8 +12,8 @@ import ( "google.golang.org/protobuf/proto" "google.golang.org/protobuf/testing/protocmp" - epb "github.com/c4t-but-s4d/neo/v2/proto/go/exploits" - fspb "github.com/c4t-but-s4d/neo/v2/proto/go/fileserver" + epb "github.com/c4t-but-s4d/neo/v2/pkg/proto/exploits" + fspb "github.com/c4t-but-s4d/neo/v2/pkg/proto/fileserver" ) func testDB() (*bolt.DB, func()) { diff --git a/internal/server/fs/server.go b/internal/server/fs/server.go index 79325a0..2286dfc 100644 --- a/internal/server/fs/server.go +++ b/internal/server/fs/server.go @@ -12,7 +12,7 @@ import ( serverConfig "github.com/c4t-but-s4d/neo/v2/internal/server/config" "github.com/c4t-but-s4d/neo/v2/internal/server/utils" "github.com/c4t-but-s4d/neo/v2/pkg/filestream" - fspb "github.com/c4t-but-s4d/neo/v2/proto/go/fileserver" + fspb "github.com/c4t-but-s4d/neo/v2/pkg/proto/fileserver" ) func New(cfg *serverConfig.Config) (*Server, error) { diff --git a/internal/server/logs/logline.go b/internal/server/logs/logline.go index f2659c4..f6f913d 100644 --- a/internal/server/logs/logline.go +++ b/internal/server/logs/logline.go @@ -6,7 +6,7 @@ import ( "github.com/mitchellh/mapstructure" - logspb "github.com/c4t-but-s4d/neo/v2/proto/go/logs" + logspb "github.com/c4t-but-s4d/neo/v2/pkg/proto/logs" ) func NewLogLineFromValues(vals map[string]interface{}) (*LogLine, error) { diff --git a/internal/server/logs/server.go b/internal/server/logs/server.go index 3812923..064d805 100644 --- a/internal/server/logs/server.go +++ b/internal/server/logs/server.go @@ -10,7 +10,7 @@ import ( "github.com/c4t-but-s4d/neo/v2/internal/server/common" "github.com/c4t-but-s4d/neo/v2/internal/server/utils" "github.com/c4t-but-s4d/neo/v2/pkg/gstream" - logspb "github.com/c4t-but-s4d/neo/v2/proto/go/logs" + logspb "github.com/c4t-but-s4d/neo/v2/pkg/proto/logs" ) const ( diff --git a/pkg/filestream/filestream.go b/pkg/filestream/filestream.go index 3bed68a..c6a2105 100644 --- a/pkg/filestream/filestream.go +++ b/pkg/filestream/filestream.go @@ -5,7 +5,7 @@ import ( "fmt" "io" - fspb "github.com/c4t-but-s4d/neo/v2/proto/go/fileserver" + fspb "github.com/c4t-but-s4d/neo/v2/pkg/proto/fileserver" ) const ( diff --git a/pkg/filestream/filestream_test.go b/pkg/filestream/filestream_test.go index cda51bc..cff0d16 100644 --- a/pkg/filestream/filestream_test.go +++ b/pkg/filestream/filestream_test.go @@ -11,7 +11,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/require" - fspb "github.com/c4t-but-s4d/neo/v2/proto/go/fileserver" + fspb "github.com/c4t-but-s4d/neo/v2/pkg/proto/fileserver" ) type failedReadWriter struct { diff --git a/pkg/hostbucket/hostbucket.go b/pkg/hostbucket/hostbucket.go index 30e5ccf..33a46a9 100644 --- a/pkg/hostbucket/hostbucket.go +++ b/pkg/hostbucket/hostbucket.go @@ -6,8 +6,8 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" + epb "github.com/c4t-but-s4d/neo/v2/pkg/proto/exploits" "github.com/c4t-but-s4d/neo/v2/pkg/rendezvous" - epb "github.com/c4t-but-s4d/neo/v2/proto/go/exploits" ) func New(teams map[string]string) *HostBucket { diff --git a/pkg/joblogger/logger.go b/pkg/joblogger/logger.go index dd5e3e1..7ab968d 100644 --- a/pkg/joblogger/logger.go +++ b/pkg/joblogger/logger.go @@ -8,7 +8,7 @@ import ( "github.com/sirupsen/logrus" "github.com/c4t-but-s4d/neo/v2/internal/logger" - logspb "github.com/c4t-but-s4d/neo/v2/proto/go/logs" + logspb "github.com/c4t-but-s4d/neo/v2/pkg/proto/logs" ) // 1 MB. diff --git a/pkg/joblogger/sender.go b/pkg/joblogger/sender.go index faccce5..3a8c67b 100644 --- a/pkg/joblogger/sender.go +++ b/pkg/joblogger/sender.go @@ -9,7 +9,7 @@ import ( "github.com/sirupsen/logrus" "github.com/c4t-but-s4d/neo/v2/internal/client" - logspb "github.com/c4t-but-s4d/neo/v2/proto/go/logs" + logspb "github.com/c4t-but-s4d/neo/v2/pkg/proto/logs" ) const ( diff --git a/proto/go/exploits/api.pb.go b/pkg/proto/exploits/api.pb.go similarity index 98% rename from proto/go/exploits/api.pb.go rename to pkg/proto/exploits/api.pb.go index 76e67b5..42bd408 100644 --- a/proto/go/exploits/api.pb.go +++ b/pkg/proto/exploits/api.pb.go @@ -7,7 +7,7 @@ package exploits import ( - fileserver "github.com/c4t-but-s4d/neo/v2/proto/go/fileserver" + fileserver "github.com/c4t-but-s4d/neo/v2/pkg/proto/fileserver" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" durationpb "google.golang.org/protobuf/types/known/durationpb" @@ -1351,17 +1351,17 @@ var file_exploits_api_proto_rawDesc = []byte{ 0x65, 0x52, 0x75, 0x6e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x73, 0x2e, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x52, 0x75, 0x6e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x42, 0x89, + 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x42, 0x8a, 0x01, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x73, 0x42, - 0x08, 0x41, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x74, + 0x08, 0x41, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x34, 0x74, 0x2d, 0x62, 0x75, 0x74, 0x2d, - 0x73, 0x34, 0x64, 0x2f, 0x6e, 0x65, 0x6f, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2f, 0x67, 0x6f, 0x2f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x45, - 0x58, 0x58, 0xaa, 0x02, 0x08, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x73, 0xca, 0x02, 0x08, - 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x73, 0xe2, 0x02, 0x14, 0x45, 0x78, 0x70, 0x6c, 0x6f, - 0x69, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, - 0x02, 0x08, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x73, 0x34, 0x64, 0x2f, 0x6e, 0x65, 0x6f, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x73, 0xa2, 0x02, 0x03, + 0x45, 0x58, 0x58, 0xaa, 0x02, 0x08, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x73, 0xca, 0x02, + 0x08, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x73, 0xe2, 0x02, 0x14, 0x45, 0x78, 0x70, 0x6c, + 0x6f, 0x69, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0xea, 0x02, 0x08, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( diff --git a/proto/go/exploits/api_grpc.pb.go b/pkg/proto/exploits/api_grpc.pb.go similarity index 100% rename from proto/go/exploits/api_grpc.pb.go rename to pkg/proto/exploits/api_grpc.pb.go diff --git a/proto/go/fileserver/api.pb.go b/pkg/proto/fileserver/api.pb.go similarity index 90% rename from proto/go/fileserver/api.pb.go rename to pkg/proto/fileserver/api.pb.go index 5be2053..97b5bb0 100644 --- a/proto/go/fileserver/api.pb.go +++ b/pkg/proto/fileserver/api.pb.go @@ -132,17 +132,17 @@ var file_fileserver_api_proto_rawDesc = []byte{ 0x6c, 0x65, 0x12, 0x14, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x16, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x22, 0x00, 0x30, 0x01, 0x42, 0x95, 0x01, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x66, 0x69, 0x6c, + 0x22, 0x00, 0x30, 0x01, 0x42, 0x96, 0x01, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42, 0x08, 0x41, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x6f, 0x50, 0x01, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x34, 0x74, 0x2d, 0x62, 0x75, 0x74, 0x2d, 0x73, 0x34, 0x64, 0x2f, 0x6e, 0x65, 0x6f, 0x2f, - 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x66, 0x69, 0x6c, 0x65, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0xa2, 0x02, 0x03, 0x46, 0x58, 0x58, 0xaa, 0x02, 0x0a, 0x46, - 0x69, 0x6c, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0xca, 0x02, 0x0a, 0x46, 0x69, 0x6c, 0x65, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0xe2, 0x02, 0x16, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, - 0x02, 0x0a, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x76, 0x32, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x66, 0x69, 0x6c, + 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0xa2, 0x02, 0x03, 0x46, 0x58, 0x58, 0xaa, 0x02, 0x0a, + 0x46, 0x69, 0x6c, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0xca, 0x02, 0x0a, 0x46, 0x69, 0x6c, + 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0xe2, 0x02, 0x16, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0xea, 0x02, 0x0a, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/go/fileserver/api_grpc.pb.go b/pkg/proto/fileserver/api_grpc.pb.go similarity index 100% rename from proto/go/fileserver/api_grpc.pb.go rename to pkg/proto/fileserver/api_grpc.pb.go diff --git a/proto/go/logs/api.pb.go b/pkg/proto/logs/api.pb.go similarity index 96% rename from proto/go/logs/api.pb.go rename to pkg/proto/logs/api.pb.go index b9757c8..0798adb 100644 --- a/proto/go/logs/api.pb.go +++ b/pkg/proto/logs/api.pb.go @@ -285,15 +285,15 @@ var file_logs_api_proto_rawDesc = []byte{ 0x1b, 0x2e, 0x6c, 0x6f, 0x67, 0x73, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4c, 0x6f, 0x67, 0x4c, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6f, 0x67, 0x73, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4c, 0x6f, 0x67, 0x4c, 0x69, 0x6e, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x42, 0x71, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x42, 0x72, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x2e, 0x6c, 0x6f, 0x67, 0x73, 0x42, 0x08, 0x41, 0x70, 0x69, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x34, 0x74, 0x2d, 0x62, 0x75, 0x74, 0x2d, 0x73, 0x34, 0x64, 0x2f, 0x6e, - 0x65, 0x6f, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x6c, - 0x6f, 0x67, 0x73, 0xa2, 0x02, 0x03, 0x4c, 0x58, 0x58, 0xaa, 0x02, 0x04, 0x4c, 0x6f, 0x67, 0x73, - 0xca, 0x02, 0x04, 0x4c, 0x6f, 0x67, 0x73, 0xe2, 0x02, 0x10, 0x4c, 0x6f, 0x67, 0x73, 0x5c, 0x47, - 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x04, 0x4c, 0x6f, 0x67, - 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x6f, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, + 0x6c, 0x6f, 0x67, 0x73, 0xa2, 0x02, 0x03, 0x4c, 0x58, 0x58, 0xaa, 0x02, 0x04, 0x4c, 0x6f, 0x67, + 0x73, 0xca, 0x02, 0x04, 0x4c, 0x6f, 0x67, 0x73, 0xe2, 0x02, 0x10, 0x4c, 0x6f, 0x67, 0x73, 0x5c, + 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x04, 0x4c, 0x6f, + 0x67, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/go/logs/api_grpc.pb.go b/pkg/proto/logs/api_grpc.pb.go similarity index 100% rename from proto/go/logs/api_grpc.pb.go rename to pkg/proto/logs/api_grpc.pb.go diff --git a/proto/buf.gen.yaml b/proto/buf.gen.yaml index 2d9dae1..d17b9fa 100644 --- a/proto/buf.gen.yaml +++ b/proto/buf.gen.yaml @@ -2,15 +2,15 @@ version: v1 managed: enabled: true go_package_prefix: - default: github.com/c4t-but-s4d/neo/v2/proto/go + default: github.com/c4t-but-s4d/neo/v2/pkg/proto plugins: # Go - name: go - out: go + out: ../pkg/proto opt: - paths=source_relative - name: go-grpc - out: go + out: ../pkg/proto opt: - paths=source_relative From 4c639e8e5cbea96051d1e543e8bf5cd0095a7ea6 Mon Sep 17 00:00:00 2001 From: Roman Nikitin Date: Sat, 18 Nov 2023 01:47:32 +0300 Subject: [PATCH 11/18] Fix images & releases --- .goreleaser.yml | 1 - Dockerfile | 1 - client_env/Dockerfile | 1 - 3 files changed, 3 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index f82861b..6ef19cb 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -44,7 +44,6 @@ archives: - cmd - internal - pkg - - proto/go - monitoring - id: "client_env" diff --git a/Dockerfile b/Dockerfile index e118b19..6733263 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,6 @@ WORKDIR /app COPY go.* ./ COPY cmd cmd COPY internal internal -COPY proto/go proto/go COPY pkg pkg RUN --mount=type=cache,target=/root/.cache/go-build \ --mount=type=cache,target=/go/pkg/mod \ diff --git a/client_env/Dockerfile b/client_env/Dockerfile index 967f6d6..808d8e4 100644 --- a/client_env/Dockerfile +++ b/client_env/Dockerfile @@ -6,7 +6,6 @@ WORKDIR /app COPY go.* ./ COPY cmd cmd COPY internal internal -COPY proto/go proto/go COPY pkg pkg RUN --mount=type=cache,target=/root/.cache/go-build \ --mount=type=cache,target=/go/pkg/mod \ From 731c31d2a9a2e0a102bd379db7bdbd730e2eb768 Mon Sep 17 00:00:00 2001 From: Roman Nikitin Date: Sat, 18 Nov 2023 12:28:56 +0300 Subject: [PATCH 12/18] Add tooling & CI for frontend linting --- .github/workflows/tests.yml | 16 ++++++++++++++++ Makefile | 8 ++++++-- cmd/client/cli/update.go | 1 - 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 85d9764..5e24eea 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -37,6 +37,22 @@ jobs: input: proto config: proto/buf.yaml + front: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'pnpm' + cache-dependency-path: 'front/pnpm-lock.yaml' + + - name: run linter + run: make lint-front + image: runs-on: ubuntu-latest steps: diff --git a/Makefile b/Makefile index 1e159ef..a556955 100644 --- a/Makefile +++ b/Makefile @@ -15,12 +15,16 @@ lint-go: lint-proto: cd proto && buf lint +.PHONY: lint-front +lint-front: + cd front && pnpm lint + .PHONY: lint -lint: lint-go lint-proto +lint: lint-go lint-proto lint-front .PHONY: goimports goimports: - gofancyimports fix --local github.com/c4t-but-s4d/neo -w $(shell find . -type f -name '*.go' -not -path "./proto/*") + gofancyimports fix --local github.com/c4t-but-s4d/neo/v2 -w $(shell find . -type f -name '*.go' -not -path "./pkg/proto/*") .PHONY: test test: diff --git a/cmd/client/cli/update.go b/cmd/client/cli/update.go index 72d9d6f..1c9b99b 100644 --- a/cmd/client/cli/update.go +++ b/cmd/client/cli/update.go @@ -11,7 +11,6 @@ import ( "google.golang.org/protobuf/types/known/durationpb" "github.com/c4t-but-s4d/neo/v2/internal/client" - epb "github.com/c4t-but-s4d/neo/v2/pkg/proto/exploits" ) From 556cf56e2e7f695c9d219f83950dcf7572a59614 Mon Sep 17 00:00:00 2001 From: Roman Nikitin Date: Sat, 18 Nov 2023 12:33:06 +0300 Subject: [PATCH 13/18] Fix front CI --- .github/workflows/tests.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5e24eea..bb950ae 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -43,6 +43,11 @@ jobs: - name: Checkout uses: actions/checkout@v3 + - name: Install pnpm + uses: pnpm/action-setup@v2 + with: + version: 'latest' + - name: Set up Node.js uses: actions/setup-node@v4 with: @@ -50,6 +55,9 @@ jobs: cache: 'pnpm' cache-dependency-path: 'front/pnpm-lock.yaml' + - name: Install deps + run: cd front && pnpm install + - name: run linter run: make lint-front From 086f8d57826e0228e30793b0d612ea7502658c1b Mon Sep 17 00:00:00 2001 From: Roman Nikitin Date: Sat, 18 Nov 2023 12:59:32 +0300 Subject: [PATCH 14/18] Add front to server release --- .goreleaser.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.goreleaser.yml b/.goreleaser.yml index 6ef19cb..ecceda5 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -45,6 +45,7 @@ archives: - internal - pkg - monitoring + - front - id: "client_env" format: zip From 6d0aa68a769317d0949bc0eabf79f2f9bc74575a Mon Sep 17 00:00:00 2001 From: Roman Nikitin Date: Sat, 23 Dec 2023 18:13:15 +0300 Subject: [PATCH 15/18] Make metrics secure --- cmd/client/cmd/root.go | 2 -- cmd/server/main.go | 23 +++++++++++++++++++--- compose.yml | 14 +++++++++++-- configs/client/config.yml | 6 +++++- configs/server/config.yml | 2 +- internal/client/config.go | 9 ++++++++- internal/exploit/runner.go | 3 ++- internal/server/config/config.go | 26 +++++++++++++------------ monitoring/cfg/prometheus/config.yml | 6 +++--- monitoring/cfg/victoria-proxy/Caddyfile | 9 +++++++++ 10 files changed, 74 insertions(+), 26 deletions(-) create mode 100644 monitoring/cfg/victoria-proxy/Caddyfile diff --git a/cmd/client/cmd/root.go b/cmd/client/cmd/root.go index d0f5812..71e60ab 100644 --- a/cmd/client/cmd/root.go +++ b/cmd/client/cmd/root.go @@ -33,12 +33,10 @@ func init() { rootCmd.PersistentFlags().StringP("config", "c", "client_config.yml", "config file") rootCmd.PersistentFlags().BoolP("verbose", "v", true, "enable debug logging") rootCmd.PersistentFlags().String("host", "127.0.0.1:5005", "server host") - rootCmd.PersistentFlags().String("metrics_host", "127.0.0.1:9091", "pushgateway host") mustBindPersistent(rootCmd, "config") mustBindPersistent(rootCmd, "host") mustBindPersistent(rootCmd, "verbose") - mustBindPersistent(rootCmd, "metrics_host") } func mustBindPersistent(c *cobra.Command, flag string) { diff --git a/cmd/server/main.go b/cmd/server/main.go index 42d87a3..aa77937 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -89,7 +89,6 @@ func main() { reflection.Register(s) httpMux := http.NewServeMux() - httpMux.Handle("/metrics", promhttp.Handler()) httpMux.Handle("/", neohttp.StaticHandler(cfg.StaticDir)) muHandler := mu.NewHandler(s, mu.WithHTTPHandler(httpMux)) @@ -98,12 +97,20 @@ func main() { Addr: cfg.Address, } + // Separate server to make it private. + metricsMux := http.NewServeMux() + metricsMux.Handle("/metrics", promhttp.Handler()) + metricsServer := &http.Server{ + Handler: metricsMux, + Addr: cfg.MetricsAddress, + } + runCtx, cancel := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT) defer cancel() wg := sync.WaitGroup{} - wg.Add(3) + wg.Add(4) go func() { defer wg.Done() exploitsServer.HeartBeat(runCtx) @@ -119,12 +126,21 @@ func main() { shutdownCtx, shutdownCancel := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT) defer shutdownCancel() - shutdownCtx, shutdownCancel = context.WithTimeout(shutdownCtx, 10*time.Second) + shutdownCtx, shutdownCancel = context.WithTimeout(shutdownCtx, 5*time.Second) defer shutdownCancel() if err := httpServer.Shutdown(shutdownCtx); err != nil { logrus.Errorf("Failed to shutdown http server: %v", err) } + if err := metricsServer.Shutdown(shutdownCtx); err != nil { + logrus.Errorf("Failed to shutdown metrics server: %v", err) + } + }() + go func() { + defer wg.Done() + if err := metricsServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { + logrus.Fatalf("Failed to serve metrics: %v", err) + } }() logrus.Infof("Starting multiproto server on %s", cfg.Address) @@ -164,6 +180,7 @@ func setupConfig() error { viper.SetDefault("ping_every", time.Second*5) viper.SetDefault("submit_every", time.Second*2) viper.SetDefault("address", ":5005") + viper.SetDefault("metrics_address", ":3000") viper.SetDefault("static_dir", "front/dist") viper.SetDefault("redis_url", "redis://127.0.0.1:6379/0") viper.SetDefault("db_path", "data/db.db") diff --git a/compose.yml b/compose.yml index 815cc8d..af276f1 100644 --- a/compose.yml +++ b/compose.yml @@ -4,6 +4,8 @@ services: volumes: - "./configs/server/config.yml:/config.yml:ro" - "./volumes/data:/data" + extra_hosts: + - "host.docker.internal:host-gateway" environment: NEO_GRPC_AUTH_KEY: ${GRPC_AUTH_KEY} NEO_FARM_PASSWORD: ${FARM_PASSWORD} @@ -47,7 +49,15 @@ services: - "-storageDataPath=/victoria-metrics-data" - "-promscrape.config=/etc/prometheus/config.yml" restart: unless-stopped - cpus: 2 - mem_limit: 4gb + + victoria-proxy: + image: caddy:2.6.1-alpine + restart: unless-stopped + environment: + HTTP_BASIC_AUTH_USER: "${VICTORIA_USER:-admin}" + HTTP_BASIC_AUTH_PASSWORD: "${VICTORIA_PASSWORD:-1234}" + command: "/bin/sh -c 'export HTTP_BASIC_AUTH_PASSWORD_HASH=$(caddy hash-password --plaintext $$HTTP_BASIC_AUTH_PASSWORD) && caddy run --config /etc/caddy/Caddyfile'" ports: - "8428:8428" + volumes: + - "./monitoring/cfg/victoria-proxy:/etc/caddy" diff --git a/configs/client/config.yml b/configs/client/config.yml index 26a0376..d76b093 100644 --- a/configs/client/config.yml +++ b/configs/client/config.yml @@ -1,4 +1,8 @@ host: "localhost:5005" -metrics_host: "localhost:8428/api/v1/import/prometheus" exploit_dir: "exploits" grpc_auth_key: "s3cret_t0ken_pls_d0nt_leak" + +metrics: + url: "localhost:8428/api/v1/import/prometheus" + user: "admin" + password: "1234" \ No newline at end of file diff --git a/configs/server/config.yml b/configs/server/config.yml index 1ab550d..86819f5 100644 --- a/configs/server/config.yml +++ b/configs/server/config.yml @@ -3,7 +3,7 @@ submit_every: "2s" grpc_auth_key: "s3cret_t0ken_pls_d0nt_leak" farm: - url: "http://127.0.0.1:5137" + url: "http://host.docker.internal:5137" password: "1234" env: diff --git a/internal/client/config.go b/internal/client/config.go index 94dc63c..15ae678 100644 --- a/internal/client/config.go +++ b/internal/client/config.go @@ -14,10 +14,17 @@ func MustUnmarshalConfig() *Config { return cfg } +type Metrics struct { + URL string `mapstructure:"url"` + User string `mapstructure:"user"` + Password string `mapstructure:"password"` +} + type Config struct { Host string `mapstructure:"host"` - MetricsHost string `mapstructure:"metrics_host"` ExploitDir string `mapstructure:"exploit_dir"` GrpcAuthKey string `mapstructure:"grpc_auth_key"` UseTLS bool `mapstructure:"use_tls"` + + Metrics *Metrics `mapstructure:"metrics"` } diff --git a/internal/exploit/runner.go b/internal/exploit/runner.go index 97850db..a89eac9 100644 --- a/internal/exploit/runner.go +++ b/internal/exploit/runner.go @@ -49,7 +49,8 @@ func NewRunner( restarts: make(chan struct{}, 1), logSender: logSender, metricsPusher: push. - New(clientConfig.MetricsHost, "neo_runner"). + New(clientConfig.Metrics.URL, "neo_runner"). + BasicAuth(clientConfig.Metrics.User, clientConfig.Metrics.Password). Grouping("client_id", clientID). Format(expfmt.FmtOpenMetrics_1_0_0). Gatherer(prometheus.DefaultGatherer), diff --git a/internal/server/config/config.go b/internal/server/config/config.go index 56fc618..b2da314 100644 --- a/internal/server/config/config.go +++ b/internal/server/config/config.go @@ -8,18 +8,20 @@ import ( ) type Config struct { - Debug bool `mapstructure:"debug"` - Address string `mapstructure:"address"` - StaticDir string `mapstructure:"static_dir"` - DBPath string `mapstructure:"db_path"` - RedisURL string `mapstructure:"redis_url"` - BaseDir string `mapstructure:"base_dir"` - PingEvery time.Duration `mapstructure:"ping_every"` - SubmitEvery time.Duration `mapstructure:"submit_every"` - FarmConfig FarmConfig `mapstructure:"farm"` - GrpcAuthKey string `mapstructure:"grpc_auth_key"` - Environ map[string]string `mapstructure:"env"` - MetricsNamespace string `mapstructure:"metrics_namespace"` + Debug bool `mapstructure:"debug"` + Address string `mapstructure:"address"` + StaticDir string `mapstructure:"static_dir"` + DBPath string `mapstructure:"db_path"` + RedisURL string `mapstructure:"redis_url"` + BaseDir string `mapstructure:"base_dir"` + PingEvery time.Duration `mapstructure:"ping_every"` + SubmitEvery time.Duration `mapstructure:"submit_every"` + FarmConfig FarmConfig `mapstructure:"farm"` + GrpcAuthKey string `mapstructure:"grpc_auth_key"` + Environ map[string]string `mapstructure:"env"` + + MetricsAddress string `mapstructure:"metrics_address"` + MetricsNamespace string `mapstructure:"metrics_namespace"` } type FarmConfig struct { diff --git a/monitoring/cfg/prometheus/config.yml b/monitoring/cfg/prometheus/config.yml index 50af731..7c5e269 100644 --- a/monitoring/cfg/prometheus/config.yml +++ b/monitoring/cfg/prometheus/config.yml @@ -3,18 +3,18 @@ scrape_configs: scrape_interval: 10s scrape_timeout: 3s static_configs: - - targets: ['server:3000'] + - targets: [ 'server:3000' ] - job_name: 's4d_farm_api' scrape_interval: 10s scrape_timeout: 3s metrics_path: '/api/metrics' static_configs: - - targets: ['host.docker.internal:5137'] + - targets: [ 'host.docker.internal:5137' ] - job_name: 's4d_farm_celery' scrape_interval: 10s scrape_timeout: 3s metrics_path: '/celery/metrics' static_configs: - - targets: ['host.docker.internal:5137'] + - targets: [ 'host.docker.internal:5137' ] diff --git a/monitoring/cfg/victoria-proxy/Caddyfile b/monitoring/cfg/victoria-proxy/Caddyfile new file mode 100644 index 0000000..d856017 --- /dev/null +++ b/monitoring/cfg/victoria-proxy/Caddyfile @@ -0,0 +1,9 @@ +http://:8428 { + handle { + basicauth { + {$HTTP_BASIC_AUTH_USER} {$HTTP_BASIC_AUTH_PASSWORD_HASH} + } + + reverse_proxy victoria:8428 + } +} From 02a4af11615bc4ba140346017ae25d7ffd0fc3d1 Mon Sep 17 00:00:00 2001 From: Roman Nikitin Date: Mon, 25 Dec 2023 11:35:06 +0300 Subject: [PATCH 16/18] Add dynamic virtualized scroll --- cmd/client/cli/run.go | 2 +- cmd/server/main.go | 3 +- front/package.json | 4 +- front/pnpm-lock.yaml | 25 ++- front/src/components/LogsRootView.tsx | 62 ++++- front/src/components/LogsView.tsx | 70 +++++- front/src/proto/google/protobuf/timestamp.ts | 211 ++++++++++++++++++ front/src/proto/logs/api.ts | 103 ++++++++- internal/logstor/interface.go | 43 ++++ internal/logstor/line.go | 72 ++++++ .../logs/storage.go => logstor/redis.go} | 54 ++--- internal/server/logs/logline.go | 72 ------ internal/server/logs/server.go | 52 +++-- pkg/joblogger/logger.go | 14 +- pkg/joblogger/sender.go | 3 + pkg/proto/logs/api.pb.go | 128 +++++++---- proto/logs/api.proto | 27 ++- 17 files changed, 734 insertions(+), 211 deletions(-) create mode 100644 front/src/proto/google/protobuf/timestamp.ts create mode 100644 internal/logstor/interface.go create mode 100644 internal/logstor/line.go rename internal/{server/logs/storage.go => logstor/redis.go} (53%) delete mode 100644 internal/server/logs/logline.go diff --git a/cmd/client/cli/run.go b/cmd/client/cli/run.go index cf25b38..96c52f5 100644 --- a/cmd/client/cli/run.go +++ b/cmd/client/cli/run.go @@ -17,7 +17,7 @@ const JobsPerCPU = 5 type runCLI struct { *baseCLI run *exploit.Runner - sender *joblogger.RemoteSender + sender joblogger.Sender } func parseJobsFlag(cmd *cobra.Command, name string) int { diff --git a/cmd/server/main.go b/cmd/server/main.go index aa77937..15feb35 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -20,6 +20,7 @@ import ( "google.golang.org/grpc/reflection" "github.com/c4t-but-s4d/neo/v2/internal/logger" + "github.com/c4t-but-s4d/neo/v2/internal/logstor" "github.com/c4t-but-s4d/neo/v2/internal/server/config" "github.com/c4t-but-s4d/neo/v2/internal/server/exploits" "github.com/c4t-but-s4d/neo/v2/internal/server/fs" @@ -58,7 +59,7 @@ func main() { logrus.Fatalf("Failed to create bolt storage: %v", err) } - logStore, err := logs.NewLogStorage(initCtx, cfg.RedisURL) + logStore, err := logstor.NewRedisStorage(initCtx, cfg.RedisURL) if err != nil { logrus.Fatalf("Failed to create log storage: %v", err) } diff --git a/front/package.json b/front/package.json index 54396d0..57e875f 100644 --- a/front/package.json +++ b/front/package.json @@ -25,11 +25,13 @@ "react-helmet-async": "^1.3.0", "react-hook-form": "^7.48.2", "react-router-dom": "^6.18.0", - "react-window": "^1.8.9" + "react-window": "^1.8.9", + "react-window-infinite-loader": "^1.0.9" }, "devDependencies": { "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", + "@types/react-window-infinite-loader": "^1.0.9", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "@vitejs/plugin-react": "^4.0.3", diff --git a/front/pnpm-lock.yaml b/front/pnpm-lock.yaml index 2a7467f..939c902 100644 --- a/front/pnpm-lock.yaml +++ b/front/pnpm-lock.yaml @@ -53,6 +53,9 @@ dependencies: react-window: specifier: ^1.8.9 version: 1.8.9(react-dom@18.2.0)(react@18.2.0) + react-window-infinite-loader: + specifier: ^1.0.9 + version: 1.0.9(react-dom@18.2.0)(react@18.2.0) devDependencies: '@types/react': @@ -61,6 +64,9 @@ devDependencies: '@types/react-dom': specifier: ^18.2.7 version: 18.2.7 + '@types/react-window-infinite-loader': + specifier: ^1.0.9 + version: 1.0.9 '@typescript-eslint/eslint-plugin': specifier: ^6.0.0 version: 6.0.0(@typescript-eslint/parser@6.0.0)(eslint@8.45.0)(typescript@5.0.2) @@ -1034,11 +1040,17 @@ packages: '@types/react': 18.2.15 dev: false + /@types/react-window-infinite-loader@1.0.9: + resolution: {integrity: sha512-gEInTjQwURCnDOFyIEK2+fWB5gTjqwx30O62QfxA9stE5aiB6EWkGj4UMhc0axq7/FV++Gs/TGW8FtgEx0S6Tw==} + dependencies: + '@types/react': 18.2.15 + '@types/react-window': 1.8.8 + dev: true + /@types/react-window@1.8.8: resolution: {integrity: sha512-8Ls660bHR1AUA2kuRvVG9D/4XpRC6wjAaPT9dil7Ckc76eP9TKWZwwmgfq8Q1LANX3QNDnoU4Zp48A3w+zK69Q==} dependencies: '@types/react': 18.2.15 - dev: false /@types/react@18.2.15: resolution: {integrity: sha512-oEjE7TQt1fFTFSbf8kkNuc798ahTUzn3Le67/PWjE8MAfYAD/qB7O8hSTcromLFqHCt9bcdOg5GXMokzTjJ5SA==} @@ -2715,6 +2727,17 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /react-window-infinite-loader@1.0.9(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-5Hg89IdU4Vrp0RT8kZYKeTIxWZYhNkVXeI1HbKo01Vm/Z7qztDvXljwx16sMzsa9yapRJQW3ODZfMUw38SOWHw==} + engines: {node: '>8.0.0'} + peerDependencies: + react: ^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0 + react-dom: ^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /react-window@1.8.9(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-+Eqx/fj1Aa5WnhRfj9dJg4VYATGwIUP2ItwItiJ6zboKWA6EX3lYDAXfGF2hyNqplEprhbtjbipiADEcwQ823Q==} engines: {node: '>8.0.0'} diff --git a/front/src/components/LogsRootView.tsx b/front/src/components/LogsRootView.tsx index 0b156c0..9d841b4 100644 --- a/front/src/components/LogsRootView.tsx +++ b/front/src/components/LogsRootView.tsx @@ -5,7 +5,6 @@ import { useExploitServiceClient } from "@/services/exploits"; import { useLogsServiceClient } from "@/services/logs"; import { useWindowDimensions } from "@/utils/window"; import { - CircularProgress, FormControl, Grid, InputLabel, @@ -31,7 +30,12 @@ interface P { export default function LogsRootView(props: P) { const [state, setState] = useState({ exploitID: "", exploitVersion: "" }); const [lines, setLines] = useState([]); + const [linesToken, setLinesToken] = useState(""); const [loading, setLoading] = useState(false); + const [hasMoreLines, setHasMoreLines] = useState(true); + const [linesRequested, setLinesRequested] = useState(false); + + const prevStateRef = useRef(state); const exploitServiceClient = useExploitServiceClient(); const logsServiceClient = useLogsServiceClient(); @@ -62,27 +66,54 @@ export default function LogsRootView(props: P) { }; useEffect(() => { - const tailLogs = async () => { - if (state.exploitID === "" || state.exploitVersion === "") { - return; - } - setLoading(true); + const prevState = prevStateRef.current; + if ( + state.exploitID !== prevState.exploitID || + state.exploitVersion !== prevState.exploitVersion + ) { + unstable_batchedUpdates(() => { + setLines([]); + setLinesToken(""); + setLoading(false); + setHasMoreLines(true); + }); + prevStateRef.current = state; + } + + if ( + !state.exploitID || + !state.exploitVersion || + loading || + !linesRequested + ) { + return; + } + + setLoading(true); + const wrapper = async () => { const stream = logsServiceClient.searchLogLines({ exploit: state.exploitID, version: state.exploitVersion, + lastToken: linesToken, }); + const lines: LogLine[] = []; + let nextToken = ""; for await (const response of stream) { lines.push(...response.lines); + nextToken = response.lastToken; } + unstable_batchedUpdates(() => { + setLines((prevLines) => [...prevLines, ...lines]); + setLinesToken(nextToken); setLoading(false); - setLines(lines); + setHasMoreLines(lines.length > 0); + setLinesRequested(false); }); }; - - void tailLogs(); - }, [state.exploitID, state.exploitVersion, logsServiceClient]); + void wrapper(); + }, [state, logsServiceClient, loading, linesToken, linesRequested]); const streamFormRef = useRef(null); const { topbarRef } = useRootContext(); @@ -124,8 +155,15 @@ export default function LogsRootView(props: P) { - {loading && } - {!loading && } + { + setLinesRequested(true); + }} + /> ); diff --git a/front/src/components/LogsView.tsx b/front/src/components/LogsView.tsx index 466cc0e..0e9d58e 100644 --- a/front/src/components/LogsView.tsx +++ b/front/src/components/LogsView.tsx @@ -1,10 +1,14 @@ import { LogLine } from "@/proto/logs/api"; import { CSSProperties } from "react"; -import { VariableSizeList } from "react-window"; +import { ListOnItemsRenderedProps, VariableSizeList } from "react-window"; +import InfiniteLoader from "react-window-infinite-loader"; interface P { lines: LogLine[]; viewHeight: number; + hasMoreLines: boolean; + isLoading: boolean; + loadNext: () => void; } export default function LogsView(props: P) { @@ -25,6 +29,15 @@ export default function LogsView(props: P) { const lineCounts = props.lines.map((line) => line.message.split("\n").length); + const isLineLoaded = (index: number) => + !props.hasMoreLines || index < props.lines.length; + + const lineCount = props.hasMoreLines + ? props.lines.length + 1 + : props.lines.length; + + const loadMoreLines = props.isLoading ? () => {} : props.loadNext; + const LineRow = ({ index, style, @@ -32,6 +45,22 @@ export default function LogsView(props: P) { index: number; style: CSSProperties; }) => { + if (!isLineLoaded(index)) { + return ( +
+ Loading... +
+ ); + } + const line = props.lines[index]; return ( @@ -49,15 +78,38 @@ export default function LogsView(props: P) { ); }; + const lineHeight = (index: number): number => { + if (!isLineLoaded(index)) { + return 16; + } + return lineCounts[index] * 16; + }; + return ( - lineCounts[index] * 16} - width="100%" + - {LineRow} - + {({ + onItemsRendered, + ref, + }: { + onItemsRendered: (props: ListOnItemsRenderedProps) => unknown; + ref: (ref: unknown) => void; + }) => ( + + {LineRow} + + )} + ); } diff --git a/front/src/proto/google/protobuf/timestamp.ts b/front/src/proto/google/protobuf/timestamp.ts new file mode 100644 index 0000000..0947940 --- /dev/null +++ b/front/src/proto/google/protobuf/timestamp.ts @@ -0,0 +1,211 @@ +// @ts-nocheck +/* eslint-disable */ +import Long from "long"; +import _m0 from "protobufjs/minimal"; + +export const protobufPackage = "google.protobuf"; + +/** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at + * nanosecond resolution. The count is relative to an epoch at UTC midnight on + * January 1, 1970, in the proleptic Gregorian calendar which extends the + * Gregorian calendar backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a [24-hour linear + * smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from [RFC + * 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the + * format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" + * where {year} is always expressed using four digits while {month}, {day}, + * {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional + * seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), + * are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone + * is required. A proto3 JSON serializer should always use UTC (as indicated by + * "Z") when printing the Timestamp type and a proto3 JSON parser should be + * able to accept both UTC and other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past + * 01:30 UTC on January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the + * standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted + * to this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with + * the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use + * the Joda Time's [`ISODateTimeFormat.dateTime()`]( + * http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D + * ) to obtain a formatter capable of generating timestamps in this format. + */ +export interface Timestamp { + /** + * Represents seconds of UTC time since Unix epoch + * 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + * 9999-12-31T23:59:59Z inclusive. + */ + seconds: Long; + /** + * Non-negative fractions of a second at nanosecond resolution. Negative + * second values with fractions must still have non-negative nanos values + * that count forward in time. Must be from 0 to 999,999,999 + * inclusive. + */ + nanos: number; +} + +function createBaseTimestamp(): Timestamp { + return { seconds: Long.ZERO, nanos: 0 }; +} + +export const Timestamp = { + encode(message: Timestamp, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (!message.seconds.isZero()) { + writer.uint32(8).int64(message.seconds); + } + if (message.nanos !== 0) { + writer.uint32(16).int32(message.nanos); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): Timestamp { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseTimestamp(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 8) { + break; + } + + message.seconds = reader.int64() as Long; + continue; + case 2: + if (tag !== 16) { + break; + } + + message.nanos = reader.int32(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): Timestamp { + return { + seconds: isSet(object.seconds) ? Long.fromValue(object.seconds) : Long.ZERO, + nanos: isSet(object.nanos) ? globalThis.Number(object.nanos) : 0, + }; + }, + + toJSON(message: Timestamp): unknown { + const obj: any = {}; + if (!message.seconds.isZero()) { + obj.seconds = (message.seconds || Long.ZERO).toString(); + } + if (message.nanos !== 0) { + obj.nanos = Math.round(message.nanos); + } + return obj; + }, + + create, I>>(base?: I): Timestamp { + return Timestamp.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): Timestamp { + const message = createBaseTimestamp(); + message.seconds = (object.seconds !== undefined && object.seconds !== null) + ? Long.fromValue(object.seconds) + : Long.ZERO; + message.nanos = object.nanos ?? 0; + return message; + }, +}; + +type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; + +export type DeepPartial = T extends Builtin ? T + : T extends Long ? string | number | Long : T extends globalThis.Array ? globalThis.Array> + : T extends ReadonlyArray ? ReadonlyArray> + : T extends { $case: string } ? { [K in keyof Omit]?: DeepPartial } & { $case: T["$case"] } + : T extends {} ? { [K in keyof T]?: DeepPartial } + : Partial; + +type KeysOfUnion = T extends T ? keyof T : never; +export type Exact = P extends Builtin ? P + : P & { [K in keyof P]: Exact } & { [K in Exclude>]: never }; + +if (_m0.util.Long !== Long) { + _m0.util.Long = Long as any; + _m0.configure(); +} + +function isSet(value: any): boolean { + return value !== null && value !== undefined; +} diff --git a/front/src/proto/logs/api.ts b/front/src/proto/logs/api.ts index ff020cb..b3c12ef 100644 --- a/front/src/proto/logs/api.ts +++ b/front/src/proto/logs/api.ts @@ -4,6 +4,7 @@ import Long from "long"; import type { CallContext, CallOptions } from "nice-grpc-common"; import _m0 from "protobufjs/minimal"; import { Empty } from "../google/protobuf/empty"; +import { Timestamp } from "../google/protobuf/timestamp"; export const protobufPackage = "logs"; @@ -13,6 +14,7 @@ export interface LogLine { message: string; level: string; team: string; + timestamp: Timestamp | undefined; } export interface AddLogLinesRequest { @@ -22,14 +24,17 @@ export interface AddLogLinesRequest { export interface SearchLogLinesRequest { exploit: string; version: Long; + limit: Long; + lastToken: string; } export interface SearchLogLinesResponse { lines: LogLine[]; + lastToken: string; } function createBaseLogLine(): LogLine { - return { exploit: "", version: Long.ZERO, message: "", level: "", team: "" }; + return { exploit: "", version: Long.ZERO, message: "", level: "", team: "", timestamp: undefined }; } export const LogLine = { @@ -49,6 +54,9 @@ export const LogLine = { if (message.team !== "") { writer.uint32(42).string(message.team); } + if (message.timestamp !== undefined) { + Timestamp.encode(message.timestamp, writer.uint32(50).fork()).ldelim(); + } return writer; }, @@ -94,6 +102,13 @@ export const LogLine = { message.team = reader.string(); continue; + case 6: + if (tag !== 50) { + break; + } + + message.timestamp = Timestamp.decode(reader, reader.uint32()); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -110,6 +125,7 @@ export const LogLine = { message: isSet(object.message) ? globalThis.String(object.message) : "", level: isSet(object.level) ? globalThis.String(object.level) : "", team: isSet(object.team) ? globalThis.String(object.team) : "", + timestamp: isSet(object.timestamp) ? fromJsonTimestamp(object.timestamp) : undefined, }; }, @@ -130,6 +146,9 @@ export const LogLine = { if (message.team !== "") { obj.team = message.team; } + if (message.timestamp !== undefined) { + obj.timestamp = fromTimestamp(message.timestamp).toISOString(); + } return obj; }, @@ -145,6 +164,9 @@ export const LogLine = { message.message = object.message ?? ""; message.level = object.level ?? ""; message.team = object.team ?? ""; + message.timestamp = (object.timestamp !== undefined && object.timestamp !== null) + ? Timestamp.fromPartial(object.timestamp) + : undefined; return message; }, }; @@ -207,7 +229,7 @@ export const AddLogLinesRequest = { }; function createBaseSearchLogLinesRequest(): SearchLogLinesRequest { - return { exploit: "", version: Long.ZERO }; + return { exploit: "", version: Long.ZERO, limit: Long.ZERO, lastToken: "" }; } export const SearchLogLinesRequest = { @@ -218,6 +240,12 @@ export const SearchLogLinesRequest = { if (!message.version.isZero()) { writer.uint32(16).int64(message.version); } + if (!message.limit.isZero()) { + writer.uint32(24).int64(message.limit); + } + if (message.lastToken !== "") { + writer.uint32(34).string(message.lastToken); + } return writer; }, @@ -242,6 +270,20 @@ export const SearchLogLinesRequest = { message.version = reader.int64() as Long; continue; + case 3: + if (tag !== 24) { + break; + } + + message.limit = reader.int64() as Long; + continue; + case 4: + if (tag !== 34) { + break; + } + + message.lastToken = reader.string(); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -255,6 +297,8 @@ export const SearchLogLinesRequest = { return { exploit: isSet(object.exploit) ? globalThis.String(object.exploit) : "", version: isSet(object.version) ? Long.fromValue(object.version) : Long.ZERO, + limit: isSet(object.limit) ? Long.fromValue(object.limit) : Long.ZERO, + lastToken: isSet(object.lastToken) ? globalThis.String(object.lastToken) : "", }; }, @@ -266,6 +310,12 @@ export const SearchLogLinesRequest = { if (!message.version.isZero()) { obj.version = (message.version || Long.ZERO).toString(); } + if (!message.limit.isZero()) { + obj.limit = (message.limit || Long.ZERO).toString(); + } + if (message.lastToken !== "") { + obj.lastToken = message.lastToken; + } return obj; }, @@ -278,12 +328,14 @@ export const SearchLogLinesRequest = { message.version = (object.version !== undefined && object.version !== null) ? Long.fromValue(object.version) : Long.ZERO; + message.limit = (object.limit !== undefined && object.limit !== null) ? Long.fromValue(object.limit) : Long.ZERO; + message.lastToken = object.lastToken ?? ""; return message; }, }; function createBaseSearchLogLinesResponse(): SearchLogLinesResponse { - return { lines: [] }; + return { lines: [], lastToken: "" }; } export const SearchLogLinesResponse = { @@ -291,6 +343,9 @@ export const SearchLogLinesResponse = { for (const v of message.lines) { LogLine.encode(v!, writer.uint32(10).fork()).ldelim(); } + if (message.lastToken !== "") { + writer.uint32(18).string(message.lastToken); + } return writer; }, @@ -308,6 +363,13 @@ export const SearchLogLinesResponse = { message.lines.push(LogLine.decode(reader, reader.uint32())); continue; + case 2: + if (tag !== 18) { + break; + } + + message.lastToken = reader.string(); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -318,7 +380,10 @@ export const SearchLogLinesResponse = { }, fromJSON(object: any): SearchLogLinesResponse { - return { lines: globalThis.Array.isArray(object?.lines) ? object.lines.map((e: any) => LogLine.fromJSON(e)) : [] }; + return { + lines: globalThis.Array.isArray(object?.lines) ? object.lines.map((e: any) => LogLine.fromJSON(e)) : [], + lastToken: isSet(object.lastToken) ? globalThis.String(object.lastToken) : "", + }; }, toJSON(message: SearchLogLinesResponse): unknown { @@ -326,6 +391,9 @@ export const SearchLogLinesResponse = { if (message.lines?.length) { obj.lines = message.lines.map((e) => LogLine.toJSON(e)); } + if (message.lastToken !== "") { + obj.lastToken = message.lastToken; + } return obj; }, @@ -335,6 +403,7 @@ export const SearchLogLinesResponse = { fromPartial, I>>(object: I): SearchLogLinesResponse { const message = createBaseSearchLogLinesResponse(); message.lines = object.lines?.map((e) => LogLine.fromPartial(e)) || []; + message.lastToken = object.lastToken ?? ""; return message; }, }; @@ -392,6 +461,32 @@ type KeysOfUnion = T extends T ? keyof T : never; export type Exact = P extends Builtin ? P : P & { [K in keyof P]: Exact } & { [K in Exclude>]: never }; +function toTimestamp(date: Date): Timestamp { + const seconds = numberToLong(date.getTime() / 1_000); + const nanos = (date.getTime() % 1_000) * 1_000_000; + return { seconds, nanos }; +} + +function fromTimestamp(t: Timestamp): Date { + let millis = (t.seconds.toNumber() || 0) * 1_000; + millis += (t.nanos || 0) / 1_000_000; + return new globalThis.Date(millis); +} + +function fromJsonTimestamp(o: any): Timestamp { + if (o instanceof globalThis.Date) { + return toTimestamp(o); + } else if (typeof o === "string") { + return toTimestamp(new globalThis.Date(o)); + } else { + return Timestamp.fromJSON(o); + } +} + +function numberToLong(number: number) { + return Long.fromNumber(number); +} + if (_m0.util.Long !== Long) { _m0.util.Long = Long as any; _m0.configure(); diff --git a/internal/logstor/interface.go b/internal/logstor/interface.go new file mode 100644 index 0000000..267a071 --- /dev/null +++ b/internal/logstor/interface.go @@ -0,0 +1,43 @@ +package logstor + +import ( + "context" +) + +const defaultLimit = 10000 + +type SearchConfig struct { + limit int + lastToken string +} + +type SearchOption func(cfg *SearchConfig) + +func SearchWithLimit(limit int) SearchOption { + return func(cfg *SearchConfig) { + cfg.limit = limit + } +} + +func SearchWithLastToken(lastToken string) SearchOption { + return func(cfg *SearchConfig) { + cfg.lastToken = lastToken + } +} + +func GetSearchConfig(opts ...SearchOption) *SearchConfig { + cfg := &SearchConfig{ + limit: defaultLimit, + } + + for _, opt := range opts { + opt(cfg) + } + + return cfg +} + +type Storage interface { + Add(ctx context.Context, lines ...*Line) error + Search(ctx context.Context, exploit string, version int64, opts ...SearchOption) ([]*Line, error) +} diff --git a/internal/logstor/line.go b/internal/logstor/line.go new file mode 100644 index 0000000..c0175f4 --- /dev/null +++ b/internal/logstor/line.go @@ -0,0 +1,72 @@ +package logstor + +import ( + "fmt" + "time" + + "github.com/mitchellh/mapstructure" + "google.golang.org/protobuf/types/known/timestamppb" + + logspb "github.com/c4t-but-s4d/neo/v2/pkg/proto/logs" +) + +func NewLineFromRedis(vals map[string]any) (*Line, error) { + var line Line + if err := mapstructure.Decode(vals, &line); err != nil { + return nil, fmt.Errorf("decoding structure: %w", err) + } + return &line, nil +} + +func NewLineFromProto(p *logspb.LogLine) *Line { + return &Line{ + Timestamp: p.Timestamp.AsTime(), + Exploit: p.Exploit, + Version: p.Version, + Message: p.Message, + Level: p.Level, + Team: p.Team, + } +} + +type Line struct { + Timestamp time.Time `mapstructure:"timestamp"` + Exploit string `mapstructure:"exploit"` + Version int64 `mapstructure:"version"` + Message string `mapstructure:"message"` + Level string `mapstructure:"level"` + Team string `mapstructure:"team"` +} + +func (l *Line) String() string { + return fmt.Sprintf("Line(%s.v%s)", l.Exploit, l.Version) +} + +func (l *Line) EstimateSize() int { + const ( + estNum = 5 + estDenom = 4 + structSize = 8*4 + 32 + 8 + ) + sizeEst := structSize + len(l.Exploit) + len(l.Message) + len(l.Level) + len(l.Team) + return sizeEst * estNum / estDenom +} + +func (l *Line) ToRedis() (map[string]any, error) { + res := make(map[string]any) + if err := mapstructure.Decode(l, &res); err != nil { + return nil, fmt.Errorf("encoding structure: %w", err) + } + return res, nil +} + +func (l *Line) ToProto() *logspb.LogLine { + return &logspb.LogLine{ + Timestamp: timestamppb.New(l.Timestamp), + Exploit: l.Exploit, + Version: l.Version, + Message: l.Message, + Level: l.Level, + Team: l.Team, + } +} diff --git a/internal/server/logs/storage.go b/internal/logstor/redis.go similarity index 53% rename from internal/server/logs/storage.go rename to internal/logstor/redis.go index 2050e98..8535f41 100644 --- a/internal/server/logs/storage.go +++ b/internal/logstor/redis.go @@ -1,19 +1,26 @@ -package server +package logstor import ( "context" "fmt" - "strconv" "github.com/go-redis/redis/v8" ) const ( - linesPerSploitLimit = 100000 + maxRedisStreamLength = 100000 ) -func NewLogStorage(ctx context.Context, redisURL string) (*LogStorage, error) { - opts, err := redis.ParseURL(redisURL) +var ( + _ Storage = (*RedisStorage)(nil) +) + +type RedisStorage struct { + rdb *redis.Client +} + +func NewRedisStorage(ctx context.Context, url string) (*RedisStorage, error) { + opts, err := redis.ParseURL(url) if err != nil { return nil, fmt.Errorf("invalid redis url: %w", err) } @@ -21,24 +28,20 @@ func NewLogStorage(ctx context.Context, redisURL string) (*LogStorage, error) { if err := c.Ping(ctx).Err(); err != nil { return nil, fmt.Errorf("connecting to redis: %w", err) } - return &LogStorage{rdb: c}, nil -} - -type LogStorage struct { - rdb *redis.Client + return &RedisStorage{rdb: c}, nil } -func (s *LogStorage) Add(ctx context.Context, lines []LogLine) error { +func (s *RedisStorage) Add(ctx context.Context, lines ...*Line) error { if _, err := s.rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error { for _, line := range lines { key := getRedisStream(line.Exploit, line.Version) - vals, err := line.DumpValues() + vals, err := line.ToRedis() if err != nil { return fmt.Errorf("serializing %v: %w", line, err) } args := redis.XAddArgs{ Stream: key, - MaxLen: linesPerSploitLimit, + MaxLen: maxRedisStreamLength, Approx: true, Values: vals, } @@ -53,15 +56,21 @@ func (s *LogStorage) Add(ctx context.Context, lines []LogLine) error { return nil } -func (s *LogStorage) Get(ctx context.Context, opts GetOptions) ([]*LogLine, error) { - key := getRedisStream(opts.Exploit, strconv.FormatInt(opts.Version, 10)) - res, err := s.rdb.XRange(ctx, key, "-", "+").Result() +func (s *RedisStorage) Search(ctx context.Context, exploit string, version int64, opts ...SearchOption) ([]*Line, error) { + cfg := GetSearchConfig(opts...) + key := getRedisStream(exploit, version) + + start := "-" + if cfg.lastToken != "" { + start = fmt.Sprintf("(%s", cfg.lastToken) + } + res, err := s.rdb.XRangeN(ctx, key, start, "+", int64(cfg.limit)).Result() if err != nil { return nil, fmt.Errorf("querying stream %s: %w", key, err) } - lines := make([]*LogLine, 0, len(res)) + lines := make([]*Line, 0, len(res)) for _, msg := range res { - line, err := NewLogLineFromValues(msg.Values) + line, err := NewLineFromRedis(msg.Values) if err != nil { return nil, fmt.Errorf("decoding line from %+v: %w", msg.Values, err) } @@ -70,11 +79,6 @@ func (s *LogStorage) Get(ctx context.Context, opts GetOptions) ([]*LogLine, erro return lines, nil } -type GetOptions struct { - Exploit string - Version int64 -} - -func getRedisStream(exploit string, version string) string { - return fmt.Sprintf("logs:%s:%s", exploit, version) +func getRedisStream(exploit string, version int64) string { + return fmt.Sprintf("logs:%s:%d", exploit, version) } diff --git a/internal/server/logs/logline.go b/internal/server/logs/logline.go deleted file mode 100644 index f6f913d..0000000 --- a/internal/server/logs/logline.go +++ /dev/null @@ -1,72 +0,0 @@ -package server - -import ( - "fmt" - "strconv" - - "github.com/mitchellh/mapstructure" - - logspb "github.com/c4t-but-s4d/neo/v2/pkg/proto/logs" -) - -func NewLogLineFromValues(vals map[string]interface{}) (*LogLine, error) { - var line LogLine - if err := mapstructure.Decode(vals, &line); err != nil { - return nil, fmt.Errorf("decoding structure: %w", err) - } - return &line, nil -} - -func NewLogLineFromProto(p *logspb.LogLine) *LogLine { - return &LogLine{ - Exploit: p.Exploit, - Version: strconv.FormatInt(p.Version, 10), - Message: p.Message, - Level: p.Level, - Team: p.Team, - } -} - -type LogLine struct { - Exploit string `mapstructure:"exploit"` - Version string `mapstructure:"version"` - Message string `mapstructure:"message"` - Level string `mapstructure:"level"` - Team string `mapstructure:"team"` -} - -func (l *LogLine) String() string { - return fmt.Sprintf("Line(%s.v%s)", l.Exploit, l.Version) -} - -func (l *LogLine) DumpValues() (map[string]interface{}, error) { - res := make(map[string]interface{}) - if err := mapstructure.Decode(l, &res); err != nil { - return nil, fmt.Errorf("encoding structure: %w", err) - } - return res, nil -} - -func (l *LogLine) EstimateSize() int { - const ( - estNum = 5 - estDenom = 4 - structSize = 8 * 5 - ) - sizeEst := structSize + len(l.Exploit) + len(l.Version) + len(l.Message) + len(l.Level) + len(l.Team) - return sizeEst * estNum / estDenom -} - -func (l *LogLine) ToProto() (*logspb.LogLine, error) { - version, err := strconv.ParseInt(l.Version, 10, 64) - if err != nil { - return nil, fmt.Errorf("converting version (%v): %w", l.Version, err) - } - return &logspb.LogLine{ - Exploit: l.Exploit, - Version: version, - Message: l.Message, - Level: l.Level, - Team: l.Team, - }, nil -} diff --git a/internal/server/logs/server.go b/internal/server/logs/server.go index 064d805..c828230 100644 --- a/internal/server/logs/server.go +++ b/internal/server/logs/server.go @@ -2,11 +2,12 @@ package server import ( "context" - "fmt" + "github.com/samber/lo" "google.golang.org/grpc/codes" "google.golang.org/protobuf/types/known/emptypb" + "github.com/c4t-but-s4d/neo/v2/internal/logstor" "github.com/c4t-but-s4d/neo/v2/internal/server/common" "github.com/c4t-but-s4d/neo/v2/internal/server/utils" "github.com/c4t-but-s4d/neo/v2/pkg/gstream" @@ -18,7 +19,7 @@ const ( maxMsgSize = 4 * 1024 * 1024 ) -func New(storage *LogStorage) *Server { +func New(storage logstor.Storage) *Server { return &Server{ LoggingServer: common.NewLoggingServer("logs"), @@ -30,17 +31,16 @@ type Server struct { logspb.UnimplementedServiceServer common.LoggingServer - storage *LogStorage + storage logstor.Storage } -func (s *Server) AddLogLines(ctx context.Context, lines *logspb.AddLogLinesRequest) (*emptypb.Empty, error) { - s.GetMethodLogger(ctx).Infof("New request with %d lines", len(lines.Lines)) +func (s *Server) AddLogLines(ctx context.Context, request *logspb.AddLogLinesRequest) (*emptypb.Empty, error) { + s.GetMethodLogger(ctx).Infof("New request with %d lines", len(request.Lines)) - decoded := make([]LogLine, 0, len(lines.Lines)) - for _, line := range lines.Lines { - decoded = append(decoded, *NewLogLineFromProto(line)) - } - if err := s.storage.Add(ctx, decoded); err != nil { + decoded := lo.Map(request.Lines, func(line *logspb.LogLine, _ int) *logstor.Line { + return logstor.NewLineFromProto(line) + }) + if err := s.storage.Add(ctx, decoded...); err != nil { return nil, utils.WrapErrorf(codes.Internal, "adding log lines: %v", err) } return &emptypb.Empty{}, nil @@ -49,30 +49,28 @@ func (s *Server) AddLogLines(ctx context.Context, lines *logspb.AddLogLinesReque func (s *Server) SearchLogLines(req *logspb.SearchLogLinesRequest, stream logspb.Service_SearchLogLinesServer) error { s.LogRequest(stream.Context(), req) - opts := GetOptions{ - Exploit: req.Exploit, - Version: req.Version, + var opts []logstor.SearchOption + if req.Limit != 0 { + opts = append(opts, logstor.SearchWithLimit(int(req.Limit))) + } + if req.LastToken != "" { + opts = append(opts, logstor.SearchWithLastToken(req.LastToken)) } - lines, err := s.storage.Get(stream.Context(), opts) + + lines, err := s.storage.Search(stream.Context(), req.Exploit, req.Version, opts...) if err != nil { return utils.WrapErrorf(codes.Internal, "searching log lines: %v", err) } - cache := gstream.NewDynamicSizeCache[*LogLine, logspb.SearchLogLinesResponse]( + cache := gstream.NewDynamicSizeCache[*logstor.Line, logspb.SearchLogLinesResponse]( stream, maxMsgSize, - func(lines []*LogLine) (*logspb.SearchLogLinesResponse, error) { - resp := &logspb.SearchLogLinesResponse{ - Lines: make([]*logspb.LogLine, 0, len(lines)), - } - for _, line := range lines { - protoLine, err := line.ToProto() - if err != nil { - return nil, fmt.Errorf("converting line to proto: %w", err) - } - resp.Lines = append(resp.Lines, protoLine) - } - return resp, nil + func(lines []*logstor.Line) (*logspb.SearchLogLinesResponse, error) { + return &logspb.SearchLogLinesResponse{ + Lines: lo.Map(lines, func(line *logstor.Line, _ int) *logspb.LogLine { + return line.ToProto() + }), + }, nil }, ) diff --git a/pkg/joblogger/logger.go b/pkg/joblogger/logger.go index 7ab968d..e8213f9 100644 --- a/pkg/joblogger/logger.go +++ b/pkg/joblogger/logger.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/sirupsen/logrus" + "google.golang.org/protobuf/types/known/timestamppb" "github.com/c4t-but-s4d/neo/v2/internal/logger" logspb "github.com/c4t-but-s4d/neo/v2/pkg/proto/logs" @@ -56,11 +57,12 @@ func (l *JobLogger) Errorf(format string, args ...interface{}) { func (l *JobLogger) newLine(msg, level string) *logspb.LogLine { return &logspb.LogLine{ - Exploit: l.exploit, - Version: l.version, - Message: sanitizeMessage(msg), - Level: level, - Team: l.team, + Exploit: l.exploit, + Version: l.version, + Message: sanitizeMessage(msg), + Level: level, + Team: l.team, + Timestamp: timestamppb.Now(), } } @@ -72,7 +74,7 @@ func (l *JobLogger) getLogger() *logrus.Entry { }) } -func (l *JobLogger) logProxy(level logrus.Level, format string, args ...interface{}) { +func (l *JobLogger) logProxy(level logrus.Level, format string, args ...any) { if logrus.IsLevelEnabled(level) { l. getLogger(). diff --git a/pkg/joblogger/sender.go b/pkg/joblogger/sender.go index 3a8c67b..ed4cb99 100644 --- a/pkg/joblogger/sender.go +++ b/pkg/joblogger/sender.go @@ -17,6 +17,7 @@ const ( ) type Sender interface { + Start(ctx context.Context) Add(lines ...*logspb.LogLine) } @@ -26,6 +27,8 @@ func NewDummySender() *DummySender { type DummySender struct{} +func (s *DummySender) Start(context.Context) {} + func (s *DummySender) Add(...*logspb.LogLine) { } diff --git a/pkg/proto/logs/api.pb.go b/pkg/proto/logs/api.pb.go index 0798adb..bb98b68 100644 --- a/pkg/proto/logs/api.pb.go +++ b/pkg/proto/logs/api.pb.go @@ -10,6 +10,7 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" emptypb "google.golang.org/protobuf/types/known/emptypb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" ) @@ -26,11 +27,12 @@ type LogLine struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Exploit string `protobuf:"bytes,1,opt,name=exploit,proto3" json:"exploit,omitempty"` - Version int64 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` - Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` - Level string `protobuf:"bytes,4,opt,name=level,proto3" json:"level,omitempty"` - Team string `protobuf:"bytes,5,opt,name=team,proto3" json:"team,omitempty"` + Exploit string `protobuf:"bytes,1,opt,name=exploit,proto3" json:"exploit,omitempty"` + Version int64 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` + Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` + Level string `protobuf:"bytes,4,opt,name=level,proto3" json:"level,omitempty"` + Team string `protobuf:"bytes,5,opt,name=team,proto3" json:"team,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=timestamp,proto3" json:"timestamp,omitempty"` } func (x *LogLine) Reset() { @@ -100,6 +102,13 @@ func (x *LogLine) GetTeam() string { return "" } +func (x *LogLine) GetTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.Timestamp + } + return nil +} + type AddLogLinesRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -152,8 +161,10 @@ type SearchLogLinesRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Exploit string `protobuf:"bytes,1,opt,name=exploit,proto3" json:"exploit,omitempty"` - Version int64 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` + Exploit string `protobuf:"bytes,1,opt,name=exploit,proto3" json:"exploit,omitempty"` + Version int64 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` + Limit int64 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` + LastToken string `protobuf:"bytes,4,opt,name=last_token,json=lastToken,proto3" json:"last_token,omitempty"` } func (x *SearchLogLinesRequest) Reset() { @@ -202,12 +213,27 @@ func (x *SearchLogLinesRequest) GetVersion() int64 { return 0 } +func (x *SearchLogLinesRequest) GetLimit() int64 { + if x != nil { + return x.Limit + } + return 0 +} + +func (x *SearchLogLinesRequest) GetLastToken() string { + if x != nil { + return x.LastToken + } + return "" +} + type SearchLogLinesResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Lines []*LogLine `protobuf:"bytes,1,rep,name=lines,proto3" json:"lines,omitempty"` + Lines []*LogLine `protobuf:"bytes,1,rep,name=lines,proto3" json:"lines,omitempty"` + LastToken string `protobuf:"bytes,2,opt,name=last_token,json=lastToken,proto3" json:"last_token,omitempty"` } func (x *SearchLogLinesResponse) Reset() { @@ -249,33 +275,51 @@ func (x *SearchLogLinesResponse) GetLines() []*LogLine { return nil } +func (x *SearchLogLinesResponse) GetLastToken() string { + if x != nil { + return x.LastToken + } + return "" +} + var File_logs_api_proto protoreflect.FileDescriptor var file_logs_api_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x6c, 0x6f, 0x67, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x6c, 0x6f, 0x67, 0x73, 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, 0x81, 0x01, 0x0a, 0x07, 0x4c, 0x6f, 0x67, 0x4c, 0x69, 0x6e, 0x65, 0x12, - 0x18, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x65, - 0x76, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x22, 0x39, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x4c, 0x6f, - 0x67, 0x4c, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, - 0x05, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6c, - 0x6f, 0x67, 0x73, 0x2e, 0x4c, 0x6f, 0x67, 0x4c, 0x69, 0x6e, 0x65, 0x52, 0x05, 0x6c, 0x69, 0x6e, - 0x65, 0x73, 0x22, 0x4b, 0x0a, 0x15, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4c, 0x6f, 0x67, 0x4c, - 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x65, - 0x78, 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x78, - 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, - 0x3d, 0x0a, 0x16, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4c, 0x6f, 0x67, 0x4c, 0x69, 0x6e, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x05, 0x6c, 0x69, 0x6e, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6c, 0x6f, 0x67, 0x73, 0x2e, - 0x4c, 0x6f, 0x67, 0x4c, 0x69, 0x6e, 0x65, 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x32, 0x9d, + 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xbb, 0x01, 0x0a, 0x07, 0x4c, 0x6f, 0x67, 0x4c, 0x69, 0x6e, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, + 0x65, 0x76, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x22, 0x39, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x4c, 0x6f, 0x67, 0x4c, 0x69, 0x6e, 0x65, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x05, 0x6c, 0x69, 0x6e, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6c, 0x6f, 0x67, 0x73, 0x2e, 0x4c, + 0x6f, 0x67, 0x4c, 0x69, 0x6e, 0x65, 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x22, 0x80, 0x01, + 0x0a, 0x15, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4c, 0x6f, 0x67, 0x4c, 0x69, 0x6e, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x6c, 0x6f, + 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x69, + 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6c, + 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, + 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x22, 0x5c, 0x0a, 0x16, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4c, 0x6f, 0x67, 0x4c, 0x69, 0x6e, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x05, 0x6c, 0x69, + 0x6e, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6c, 0x6f, 0x67, 0x73, + 0x2e, 0x4c, 0x6f, 0x67, 0x4c, 0x69, 0x6e, 0x65, 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x12, + 0x1d, 0x0a, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x32, 0x9d, 0x01, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x4c, 0x6f, 0x67, 0x4c, 0x69, 0x6e, 0x65, 0x73, 0x12, 0x18, 0x2e, 0x6c, 0x6f, 0x67, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x4c, 0x6f, 0x67, 0x4c, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, @@ -314,20 +358,22 @@ var file_logs_api_proto_goTypes = []interface{}{ (*AddLogLinesRequest)(nil), // 1: logs.AddLogLinesRequest (*SearchLogLinesRequest)(nil), // 2: logs.SearchLogLinesRequest (*SearchLogLinesResponse)(nil), // 3: logs.SearchLogLinesResponse - (*emptypb.Empty)(nil), // 4: google.protobuf.Empty + (*timestamppb.Timestamp)(nil), // 4: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 5: google.protobuf.Empty } var file_logs_api_proto_depIdxs = []int32{ - 0, // 0: logs.AddLogLinesRequest.lines:type_name -> logs.LogLine - 0, // 1: logs.SearchLogLinesResponse.lines:type_name -> logs.LogLine - 1, // 2: logs.Service.AddLogLines:input_type -> logs.AddLogLinesRequest - 2, // 3: logs.Service.SearchLogLines:input_type -> logs.SearchLogLinesRequest - 4, // 4: logs.Service.AddLogLines:output_type -> google.protobuf.Empty - 3, // 5: logs.Service.SearchLogLines:output_type -> logs.SearchLogLinesResponse - 4, // [4:6] is the sub-list for method output_type - 2, // [2:4] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 4, // 0: logs.LogLine.timestamp:type_name -> google.protobuf.Timestamp + 0, // 1: logs.AddLogLinesRequest.lines:type_name -> logs.LogLine + 0, // 2: logs.SearchLogLinesResponse.lines:type_name -> logs.LogLine + 1, // 3: logs.Service.AddLogLines:input_type -> logs.AddLogLinesRequest + 2, // 4: logs.Service.SearchLogLines:input_type -> logs.SearchLogLinesRequest + 5, // 5: logs.Service.AddLogLines:output_type -> google.protobuf.Empty + 3, // 6: logs.Service.SearchLogLines:output_type -> logs.SearchLogLinesResponse + 5, // [5:7] is the sub-list for method output_type + 3, // [3:5] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name } func init() { file_logs_api_proto_init() } diff --git a/proto/logs/api.proto b/proto/logs/api.proto index 0dafb6a..8c96692 100644 --- a/proto/logs/api.proto +++ b/proto/logs/api.proto @@ -4,29 +4,34 @@ package logs; option go_package = "logs"; import "google/protobuf/empty.proto"; +import "google/protobuf/timestamp.proto"; message LogLine { - string exploit = 1; - int64 version = 2; - string message = 3; - string level = 4; - string team = 5; + string exploit = 1; + int64 version = 2; + string message = 3; + string level = 4; + string team = 5; + google.protobuf.Timestamp timestamp = 6; } message AddLogLinesRequest { - repeated LogLine lines = 1; + repeated LogLine lines = 1; } message SearchLogLinesRequest { - string exploit = 1; - int64 version = 2; + string exploit = 1; + int64 version = 2; + int64 limit = 3; + string last_token = 4; } message SearchLogLinesResponse { - repeated LogLine lines = 1; + repeated LogLine lines = 1; + string last_token = 2; } service Service { - rpc AddLogLines(AddLogLinesRequest) returns (google.protobuf.Empty) {} - rpc SearchLogLines(SearchLogLinesRequest) returns (stream SearchLogLinesResponse) {} + rpc AddLogLines(AddLogLinesRequest) returns (google.protobuf.Empty) {} + rpc SearchLogLines(SearchLogLinesRequest) returns (stream SearchLogLinesResponse) {} } From cad8e5c1f77ecbe5012bb79772c7a296fd47e544 Mon Sep 17 00:00:00 2001 From: Roman Nikitin Date: Mon, 25 Dec 2023 11:36:22 +0300 Subject: [PATCH 17/18] Minor refactoring in logs storage --- internal/logstor/line.go | 56 ++++++++++++++++++++++++++++++++++----- internal/logstor/redis.go | 6 +---- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/internal/logstor/line.go b/internal/logstor/line.go index c0175f4..730489c 100644 --- a/internal/logstor/line.go +++ b/internal/logstor/line.go @@ -2,6 +2,8 @@ package logstor import ( "fmt" + "reflect" + "strconv" "time" "github.com/mitchellh/mapstructure" @@ -10,9 +12,48 @@ import ( logspb "github.com/c4t-but-s4d/neo/v2/pkg/proto/logs" ) +func LineDecodeHook(from, to reflect.Type, data any) (any, error) { + switch { + case from.Kind() == reflect.String && to == reflect.TypeOf(time.Time{}): + str, ok := data.(string) + if !ok { + return data, nil + } + + res, err := time.Parse(time.RFC3339Nano, str) + if err != nil { + return nil, fmt.Errorf("parsing time: %w", err) + } + return res, nil + + case from.Kind() == reflect.String && to.Kind() == reflect.Int64: + str, ok := data.(string) + if !ok { + return data, nil + } + + res, err := strconv.ParseInt(str, 10, 64) + if err != nil { + return nil, fmt.Errorf("parsing int64: %w", err) + } + return res, nil + + default: + return data, nil + } +} + func NewLineFromRedis(vals map[string]any) (*Line, error) { var line Line - if err := mapstructure.Decode(vals, &line); err != nil { + decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ + DecodeHook: LineDecodeHook, + Result: &line, + }) + if err != nil { + return nil, fmt.Errorf("creating decoder: %w", err) + } + + if err := decoder.Decode(vals); err != nil { return nil, fmt.Errorf("decoding structure: %w", err) } return &line, nil @@ -52,12 +93,15 @@ func (l *Line) EstimateSize() int { return sizeEst * estNum / estDenom } -func (l *Line) ToRedis() (map[string]any, error) { - res := make(map[string]any) - if err := mapstructure.Decode(l, &res); err != nil { - return nil, fmt.Errorf("encoding structure: %w", err) +func (l *Line) ToRedis() map[string]any { + return map[string]any{ + "timestamp": l.Timestamp.Format(time.RFC3339Nano), + "exploit": l.Exploit, + "version": strconv.FormatInt(l.Version, 10), + "message": l.Message, + "level": l.Level, + "team": l.Team, } - return res, nil } func (l *Line) ToProto() *logspb.LogLine { diff --git a/internal/logstor/redis.go b/internal/logstor/redis.go index 8535f41..0df43c0 100644 --- a/internal/logstor/redis.go +++ b/internal/logstor/redis.go @@ -35,15 +35,11 @@ func (s *RedisStorage) Add(ctx context.Context, lines ...*Line) error { if _, err := s.rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error { for _, line := range lines { key := getRedisStream(line.Exploit, line.Version) - vals, err := line.ToRedis() - if err != nil { - return fmt.Errorf("serializing %v: %w", line, err) - } args := redis.XAddArgs{ Stream: key, MaxLen: maxRedisStreamLength, Approx: true, - Values: vals, + Values: line.ToRedis(), } if err := pipe.XAdd(ctx, &args).Err(); err != nil { return fmt.Errorf("adding %v: %w", line, err) From fbb8620f2704f5d9ad85e7309da54035d22f908d Mon Sep 17 00:00:00 2001 From: Roman Nikitin Date: Sat, 10 Aug 2024 20:00:35 +0300 Subject: [PATCH 18/18] Fix --- internal/logstor/line.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/logstor/line.go b/internal/logstor/line.go index 730489c..c1cfd82 100644 --- a/internal/logstor/line.go +++ b/internal/logstor/line.go @@ -80,7 +80,7 @@ type Line struct { } func (l *Line) String() string { - return fmt.Sprintf("Line(%s.v%s)", l.Exploit, l.Version) + return fmt.Sprintf("Line(%s.v%d)", l.Exploit, l.Version) } func (l *Line) EstimateSize() int {