diff --git a/CHANGELOG.md b/CHANGELOG.md index e7f3de4f4a..f5754130f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,13 @@ For details about compatibility between different releases, see the **Commitment ### Security +## [3.29.1] - unreleased + +### Added + +- Option to store rate limits in Redis. When used, the rate limits are applied over the entire cluster instead of per-instance. +- Field `complement_collaborators` was added to `SearchAccounts`. Allows an user to request the accounts that are not already attached to the entity's collaborator list. + ## [3.29.0] - 2024-02-06 ### Added @@ -2766,7 +2773,8 @@ For details about compatibility between different releases, see the **Commitment NOTE: These links should respect backports. See https://github.com/TheThingsNetwork/lorawan-stack/pull/1444/files#r333379706. --> -[unreleased]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.29.0...v3.29 +[unreleased]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.29.1...v3.29 +[3.29.1]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.29.0...v3.29.1 [3.29.0]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.28.2...v3.29.0 [3.28.2]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.28.1...v3.28.2 [3.28.1]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.28.0...v3.28.1 diff --git a/api/ttn/lorawan/v3/api.md b/api/ttn/lorawan/v3/api.md index 61cbca85b2..b0955178a5 100644 --- a/api/ttn/lorawan/v3/api.md +++ b/api/ttn/lorawan/v3/api.md @@ -10157,6 +10157,7 @@ Right is the enum that defines all the different rights to do something in the n | `client_ids` | [`ClientIdentifiers`](#ttn.lorawan.v3.ClientIdentifiers) | | | | `gateway_ids` | [`GatewayIdentifiers`](#ttn.lorawan.v3.GatewayIdentifiers) | | | | `organization_ids` | [`OrganizationIdentifiers`](#ttn.lorawan.v3.OrganizationIdentifiers) | | | +| `complement_collaborators` | [`bool`](#bool) | | | #### Field Rules diff --git a/api/ttn/lorawan/v3/api.swagger.json b/api/ttn/lorawan/v3/api.swagger.json index c8032a6909..6f44936803 100644 --- a/api/ttn/lorawan/v3/api.swagger.json +++ b/api/ttn/lorawan/v3/api.swagger.json @@ -941,6 +941,12 @@ "in": "query", "required": false, "type": "string" + }, + { + "name": "complement_collaborators", + "in": "query", + "required": false, + "type": "boolean" } ], "tags": [ @@ -4242,6 +4248,12 @@ "in": "query", "required": false, "type": "string" + }, + { + "name": "complement_collaborators", + "in": "query", + "required": false, + "type": "boolean" } ], "tags": [ @@ -7484,6 +7496,12 @@ "in": "query", "required": false, "type": "string" + }, + { + "name": "complement_collaborators", + "in": "query", + "required": false, + "type": "boolean" } ], "tags": [ @@ -10582,6 +10600,12 @@ "required": false, "type": "string", "format": "string" + }, + { + "name": "complement_collaborators", + "in": "query", + "required": false, + "type": "boolean" } ], "tags": [ @@ -11869,6 +11893,12 @@ "in": "query", "required": false, "type": "string" + }, + { + "name": "complement_collaborators", + "in": "query", + "required": false, + "type": "boolean" } ], "tags": [ diff --git a/api/ttn/lorawan/v3/search_services.proto b/api/ttn/lorawan/v3/search_services.proto index 109ed6da19..2e0222ac88 100644 --- a/api/ttn/lorawan/v3/search_services.proto +++ b/api/ttn/lorawan/v3/search_services.proto @@ -341,6 +341,8 @@ message SearchAccountsRequest { OrganizationIdentifiers organization_ids = 6; } + bool complement_collaborators = 7; + // NOTE: This request intentionally does not support pagination. } diff --git a/cmd/internal/shared/config.go b/cmd/internal/shared/config.go index 453da1562f..6f7310596b 100644 --- a/cmd/internal/shared/config.go +++ b/cmd/internal/shared/config.go @@ -145,6 +145,11 @@ var DefaultKeyVaultConfig = config.KeyVault{ Provider: "static", } +// DefaultRateLimitingConfig is the default config for rate limiting. +var DefaultRateLimitingConfig = config.RateLimiting{ + Provider: "memory", +} + // DefaultTracingConfig is the default config for telemetry tracing. var DefaultTracingConfig = tracing.Config{ Enable: false, @@ -184,6 +189,7 @@ var DefaultServiceBase = config.ServiceBase{ FrequencyPlans: DefaultFrequencyPlansConfig, Rights: DefaultRightsConfig, KeyVault: DefaultKeyVaultConfig, + RateLimiting: DefaultRateLimitingConfig, Tracing: DefaultTracingConfig, Telemetry: DefaultTelemetryConfig, } diff --git a/cmd/ttn-lw-stack/commands/start.go b/cmd/ttn-lw-stack/commands/start.go index a6f16c559b..c2988bdbff 100644 --- a/cmd/ttn-lw-stack/commands/start.go +++ b/cmd/ttn-lw-stack/commands/start.go @@ -103,6 +103,14 @@ func NewJoinServerSessionKeyRegistryRedis(conf *Config) *redis.Client { return redis.New(conf.Redis.WithNamespace("js", "keys")) } +// NewRateLimitingRedis instantiates a new redis client with the Rate Limiting namespace. +func NewRateLimitingRedis(conf *Config) *redis.Client { + if conf.RateLimiting.Provider != "redis" { + return nil + } + return redis.New(conf.Cache.Redis.WithNamespace("rate-limiting")) +} + var errUnknownComponent = errors.DefineInvalidArgument("unknown_component", "unknown component `{component}`") var startCommand = &cobra.Command{ @@ -218,6 +226,7 @@ var startCommand = &cobra.Command{ logger.Warn("No cookie block key configured, generated a random one") } + config.RateLimiting.Redis.Client = NewRateLimitingRedis(config) c, err := component.New(logger, &component.Config{ServiceBase: config.ServiceBase}, componentOptions...) if err != nil { return shared.ErrInitializeBaseComponent.WithCause(err) diff --git a/config/messages.json b/config/messages.json index 5c34dbc48f..2367999020 100644 --- a/config/messages.json +++ b/config/messages.json @@ -5903,6 +5903,15 @@ "file": "client_access.go" } }, + "error:pkg/identityserver:collaborator_is_contact": { + "translations": { + "en": "collaborator `{collaborator_id}` is used as a contact" + }, + "description": { + "package": "pkg/identityserver", + "file": "errors.go" + } + }, "error:pkg/identityserver:common_password": { "translations": { "en": "must not be too common" diff --git a/go.mod b/go.mod index 1bb6ad73f2..a7ae6e261d 100644 --- a/go.mod +++ b/go.mod @@ -2,9 +2,6 @@ module go.thethings.network/lorawan-stack/v3 go 1.21 -// Use our fork of throttled/throttled/v2. -replace github.com/throttled/throttled/v2 => github.com/TheThingsIndustries/throttled/v2 v2.7.1-noredis - // See https://github.com/mitchellh/mapstructure/pull/278 replace github.com/mitchellh/mapstructure => github.com/TheThingsIndustries/mapstructure v0.0.0-20230413130846-941bcd1deec3 @@ -16,7 +13,7 @@ require ( github.com/TheThingsIndustries/protoc-gen-go-flags v1.2.0 github.com/TheThingsIndustries/protoc-gen-go-json v1.6.0 github.com/TheThingsNetwork/go-cayenne-lib v1.2.0 - github.com/aws/aws-sdk-go v1.50.11 + github.com/aws/aws-sdk-go v1.50.26 github.com/blang/semver v3.5.1+incompatible github.com/blevesearch/bleve v1.0.14 github.com/bluele/gcache v0.0.2 @@ -27,7 +24,7 @@ require ( github.com/emersion/go-smtp v0.20.2 github.com/envoyproxy/protoc-gen-validate v1.0.4 github.com/felixge/httpsnoop v1.0.4 - github.com/getsentry/sentry-go v0.26.0 + github.com/getsentry/sentry-go v0.27.0 github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f github.com/google/go-cmp v0.6.0 github.com/google/uuid v1.6.0 @@ -52,20 +49,20 @@ require ( github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 github.com/json-iterator/go v1.1.12 github.com/jtacoma/uritemplates v1.0.0 - github.com/klauspost/compress v1.17.6 + github.com/klauspost/compress v1.17.7 github.com/kr/pretty v0.3.1 github.com/lib/pq v1.10.9 github.com/mileusna/useragent v1.3.4 github.com/mitchellh/mapstructure v1.5.0 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 - github.com/nats-io/nats-server/v2 v2.10.10 - github.com/nats-io/nats.go v1.32.0 + github.com/nats-io/nats-server/v2 v2.10.11 + github.com/nats-io/nats.go v1.33.0 github.com/oklog/ulid/v2 v2.1.0 github.com/openshift/osin v1.0.2-0.20220317075346-0f4d38c6e53f github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.18.0 - github.com/redis/go-redis/v9 v9.4.0 + github.com/redis/go-redis/v9 v9.5.1 github.com/sendgrid/sendgrid-go v3.14.0+incompatible github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/smarty/assertions v1.15.1 @@ -73,21 +70,20 @@ require ( github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.18.2 - github.com/throttled/throttled v2.2.5+incompatible github.com/throttled/throttled/v2 v2.12.0 github.com/uptrace/bun v1.1.17 github.com/uptrace/bun/dialect/pgdialect v1.1.17 github.com/uptrace/bun/driver/pgdriver v1.1.17 github.com/vmihailenco/msgpack/v5 v5.4.1 go.opencensus.io v0.24.0 - go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.47.0 - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 - go.opentelemetry.io/otel v1.22.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0 - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.22.0 - go.opentelemetry.io/otel/sdk v1.22.0 - go.opentelemetry.io/otel/trace v1.22.0 + go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.49.0 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 + go.opentelemetry.io/otel v1.24.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 + go.opentelemetry.io/otel/sdk v1.24.0 + go.opentelemetry.io/otel/trace v1.24.0 go.packetbroker.org/api/iam v1.8.2 go.packetbroker.org/api/iam/v2 v2.9.1 go.packetbroker.org/api/mapping/v2 v2.3.1 @@ -96,18 +92,18 @@ require ( go.thethings.network/lorawan-application-payload v0.0.0-20220125153912-1198ff1e403e go.thethings.network/lorawan-stack-legacy/v2 v2.1.0 go.uber.org/automaxprocs v1.5.3 - go.uber.org/zap v1.26.0 + go.uber.org/zap v1.27.0 gocloud.dev v0.36.0 gocloud.dev/pubsub/natspubsub v0.36.0 - golang.org/x/crypto v0.18.0 + golang.org/x/crypto v0.20.0 golang.org/x/exp v0.0.0-20240119083558-1b970713d09a - golang.org/x/net v0.20.0 - golang.org/x/oauth2 v0.16.0 + golang.org/x/net v0.21.0 + golang.org/x/oauth2 v0.17.0 golang.org/x/sync v0.6.0 google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe - google.golang.org/grpc v1.61.0 + google.golang.org/grpc v1.61.1 google.golang.org/protobuf v1.32.0 gopkg.in/mail.v2 v2.3.1 gopkg.in/square/go-jose.v2 v2.6.0 @@ -186,7 +182,6 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/gomodule/redigo v1.8.9 // indirect github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/google/wire v0.5.0 // indirect @@ -249,13 +244,13 @@ require ( github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/willf/bitset v1.1.10 // indirect go.etcd.io/bbolt v1.3.5 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0 // indirect - go.opentelemetry.io/otel/metric v1.22.0 // indirect - go.opentelemetry.io/proto/otlp v1.0.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/proto/otlp v1.1.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/image v0.14.0 // indirect - golang.org/x/sys v0.16.0 // indirect - golang.org/x/term v0.16.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/term v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect diff --git a/go.sum b/go.sum index 68f5a710e7..24b9038a32 100644 --- a/go.sum +++ b/go.sum @@ -82,8 +82,6 @@ github.com/TheThingsIndustries/protoc-gen-go-flags v1.2.0 h1:QkFMT0vLDH4jzcnsbQh github.com/TheThingsIndustries/protoc-gen-go-flags v1.2.0/go.mod h1:MgevoYLHRx/KP6LZeY7uMyoQPxD+11ed4eJMN5+faD4= github.com/TheThingsIndustries/protoc-gen-go-json v1.6.0 h1:FTaVxiDPoV9o6k2OFBijhQO8zWZf6uYHIAc/cRYsCSA= github.com/TheThingsIndustries/protoc-gen-go-json v1.6.0/go.mod h1:6ourNr6TBk/2SB2V4In+o2eqZd/DIdiBLnoxvQ3UyWk= -github.com/TheThingsIndustries/throttled/v2 v2.7.1-noredis h1:uashKgjy7XCNZNb00+3GheWtJXnS9DnAkYQ1X89cAIg= -github.com/TheThingsIndustries/throttled/v2 v2.7.1-noredis/go.mod h1:XC/YhKcHsxRy8shbYICwf+oWeYTCC2kpL5/clSJbt+U= github.com/TheThingsNetwork/go-cayenne-lib v1.2.0 h1:yW4x7mNk2vyNTUYNRhda9oV8caLePMNR7Z5QbaG5Ifs= github.com/TheThingsNetwork/go-cayenne-lib v1.2.0/go.mod h1:HTTus7UIBhXKvLIeNGybbG1o7wr4zwwVbbUXwFqrtp0= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -93,8 +91,8 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/aws/aws-sdk-go v1.50.11 h1:BxUqMbkzKzzQ6FXLlZFNFkFjHnv6utbc4PItVs5SvaE= -github.com/aws/aws-sdk-go v1.50.11/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go v1.50.26 h1:tuv8+dje59DBK1Pj65tSCdD36oamBxKYJgbng4bFylc= +github.com/aws/aws-sdk-go v1.50.26/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/aws-sdk-go-v2 v1.24.0 h1:890+mqQ+hTpNuw0gGP6/4akolQkSToDJgHfQE7AwGuk= github.com/aws/aws-sdk-go-v2 v1.24.0/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 h1:OCs21ST2LrepDfD3lwlQiOqIGp6JiEUqG84GzTDoyJs= @@ -170,8 +168,10 @@ github.com/blevesearch/zap/v15 v15.0.3/go.mod h1:iuwQrImsh1WjWJ0Ue2kBqY83a0rFtJT github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw= github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0= github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= +github.com/bsm/ginkgo/v2 v2.7.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= @@ -192,8 +192,6 @@ github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnx 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-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= -github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/containerd/cgroups/v3 v3.0.1 h1:4hfGvu8rfGIwVIDd+nLzn/B9ZXx4BcCjzt5ToenJRaE= github.com/containerd/cgroups/v3 v3.0.1/go.mod h1:/vtwk1VXrtoa5AaZLkypuOJgA/6DyPMZHJPGQNtlHnw= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -258,11 +256,12 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.3-0.20170329110642-4da3e2cfbabc/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/garyburd/redigo v1.1.1-0.20170914051019-70e1b1943d4f/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= -github.com/getsentry/sentry-go v0.26.0 h1:IX3++sF6/4B5JcevhdZfdKIHfyvMmAq/UnqcyT2H6mA= -github.com/getsentry/sentry-go v0.26.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= +github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 h1:Ujru1hufTHVb++eG6OuNDKMxZnGIvF6o/u8q/8h2+I4= github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31 h1:gclg6gY70GLy3PbkQ1AERPfmLMMagS60DKF78eWwLn8= @@ -288,6 +287,8 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-redis/redis/v8 v8.4.2/go.mod h1:A1tbYoHSa1fXwN+//ljcCYYJeLmVrwL9hbQN45Jdy0M= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -497,8 +498,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= -github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= +github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kljensen/snowball v0.6.0/go.mod h1:27N7E8fVU5H68RlUmnWwZCfxgt4POBJfENGMvNRhldw= 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= @@ -555,21 +556,27 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/jwt/v2 v2.5.3 h1:/9SWvzc6hTfamcgXJ3uYRpgj+QuY2aLNqRiqrKcrpEo= github.com/nats-io/jwt/v2 v2.5.3/go.mod h1:iysuPemFcc7p4IoYots3IuELSI4EDe9Y0bQMe+I3Bf4= -github.com/nats-io/nats-server/v2 v2.10.10 h1:g1Wd64J5SGsoqWSx1qoNu9/At7a2x+jE7Qtf2XpEx/I= -github.com/nats-io/nats-server/v2 v2.10.10/go.mod h1:/TE61Dos8NlwZnjzyE3ZlOnM6dgl7tf937dnf4VclrA= -github.com/nats-io/nats.go v1.32.0 h1:Bx9BZS+aXYlxW08k8Gd3yR2s73pV5XSoAQUyp1Kwvp0= -github.com/nats-io/nats.go v1.32.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= +github.com/nats-io/nats-server/v2 v2.10.11 h1:yKUiLVincZISpo3A4YljJQ+HfLltGAgoNNJl99KL8I0= +github.com/nats-io/nats-server/v2 v2.10.11/go.mod h1:dXtOqVWzbMTEj+tUyC/itXjJhW37xh0tUBrTAlqAfx8= +github.com/nats-io/nats.go v1.33.0 h1:rRg0l2F29B30n6EPl0j50hl8eYp7rA2ecoJ74E62US8= +github.com/nats-io/nats.go v1.33.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU= github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= 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.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/openshift/build-machinery-go v0.0.0-20200917070002-f171684f77ab/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE= @@ -636,8 +643,9 @@ github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3c github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT1pX2CziuyQR0= github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwyKk= -github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= +github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8= +github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= @@ -720,8 +728,8 @@ github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpP github.com/tebeka/snowball v0.4.2/go.mod h1:4IfL14h1lvwZcp1sfXuuc7/7yCsvVffTWxWxCLfFpYg= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= -github.com/throttled/throttled v2.2.5+incompatible h1:65UB52X0qNTYiT0Sohp8qLYVFwZQPDw85uSa65OljjQ= -github.com/throttled/throttled v2.2.5+incompatible/go.mod h1:0BjlrEGQmvxps+HuXLsyRdqpSRvJpq0PNIsOtqP9Nos= +github.com/throttled/throttled/v2 v2.12.0 h1:IezKE1uHlYC/0Al05oZV6Ar+uN/znw3cy9J8banxhEY= +github.com/throttled/throttled/v2 v2.12.0/go.mod h1:+EAvrG2hZAQTx8oMpBu8fq6Xmm+d1P2luKK7fIY1Esc= github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU= github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= @@ -757,28 +765,29 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.47.0 h1:yPWywmjyhn5C64Z7OLdIfjnbwOQF/Xz89HNqSVquC2E= -go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.47.0/go.mod h1:jk2INQzOTr9e27FwMs2JVXXttZc/3bucJX/7l3YVfbw= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 h1:UNQQKPfTDe1J81ViolILjTKPr9WetKW6uei2hFgJmFs= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= -go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= -go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0 h1:9M3+rhx7kZCIQQhQRYaZCdNu1V73tm4TvXs2ntl98C4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0/go.mod h1:noq80iT8rrHP1SfybmPiRGc9dc5M8RPmGvtwo7Oo7tc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0 h1:H2JFgRcGiyHg7H7bwcwaQJYrNFqCqrbTQ8K4p1OvDu8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0/go.mod h1:WfCWp1bGoYK8MeULtI15MmQVczfR+bFkk0DF3h06QmQ= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.22.0 h1:zr8ymM5OWWjjiWRzwTfZ67c905+2TMHYp2lMJ52QTyM= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.22.0/go.mod h1:sQs7FT2iLVJ+67vYngGJkPe1qr39IzaBzaj9IDNNY8k= -go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= -go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= -go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= -go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= -go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= -go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= -go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.49.0 h1:h+c4WbSjBBc3j+IsxwB2mWvkm2nDh0SyGLa5Y5+V9cw= +go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.49.0/go.mod h1:FObmJ0epY1FcwMR7aq7sRkrCfwwV3d0GBGFfyV5JUBg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v0.14.0/go.mod h1:vH5xEuwy7Rts0GNtsCW3HYQoZDY+OmBJ6t1bFGGlxgw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 h1:s0PHtIkN+3xrbDOpt2M8OTG92cWqUESvzh2MxiR5xY8= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0/go.mod h1:hZlFbDbRt++MMPCCfSJfmhkGIWnX1h3XjkfxZUjLrIA= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= +go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= +go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= go.packetbroker.org/api/iam v1.8.2 h1:XQ0ViBP5+6PikRNLPZi0u+bi8STdQ0Xb9poLyiXwj8k= go.packetbroker.org/api/iam v1.8.2/go.mod h1:r3J5NKOVuvtnJxk/nZl9y/nqznReg/kjte2CFNsG08o= go.packetbroker.org/api/iam/v2 v2.9.1 h1:YUkM3w5EmYr0N35IGrhlCQXKewZLkCu+F0Mj8/zrMo8= @@ -803,8 +812,8 @@ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9i 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/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= gocloud.dev v0.36.0 h1:q5zoXux4xkOZP473e1EZbG8Gq9f0vlg1VNH5Du/ybus= gocloud.dev v0.36.0/go.mod h1:bLxah6JQVKBaIxzsr5BQLYB4IYdWHkMZdzCXlo6F0gg= gocloud.dev/pubsub/natspubsub v0.36.0 h1:QGBT53UN7VO7zttlGhAcLrwXjv0BKUbMET7hIlq5ehs= @@ -818,8 +827,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg= +golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -881,10 +890,12 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ 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= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -894,8 +905,8 @@ golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -905,8 +916,8 @@ golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= -golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= +golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= golang.org/x/sync v0.0.0-20170517211232-f52d1811a629/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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= @@ -939,7 +950,10 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w 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-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/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= @@ -954,6 +968,7 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w 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-20200519105757-fe76b779f299/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= @@ -974,13 +989,13 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= 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= @@ -1129,8 +1144,8 @@ google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.31.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.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= -google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= +google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY= +google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/grpc/examples v0.0.0-20210424002626-9572fd6faeae/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= diff --git a/package.json b/package.json index 8b8286a336..b3c1b2df49 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "wait-on": "^7.2.0", "webpack": "^5.90.1", "webpack-cli": "^5.1.4", - "webpack-dev-server": "^4.15.1", + "webpack-dev-server": "^5.0.0", "webpack-shell-plugin": "https://github.com/cdeutsch/webpack-shell-plugin.git#bee537d", "yargs": "^17.7.2" }, diff --git a/pkg/config/shared.go b/pkg/config/shared.go index d64fed7415..dcafec25e8 100644 --- a/pkg/config/shared.go +++ b/pkg/config/shared.go @@ -549,6 +549,11 @@ func (f MQTTConfigProviderFunc) GetMQTTConfig(ctx context.Context) (*MQTT, error return f(ctx) } +// RateLimitingRedis represents configuration for the in-Redis rate limiting store. +type RateLimitingRedis struct { + Client *redis.Client `name:"-"` +} + // RateLimitingProfile represents configuration for a rate limiting class. type RateLimitingProfile struct { Name string `name:"name" description:"Rate limiting class name"` @@ -569,7 +574,9 @@ type RateLimiting struct { URL string `name:"url" description:"URL, which contains rate limiting configuration"` Blob BlobPathConfig `name:"blob"` + Provider string `name:"provider" description:"Rate limiting store provider (memory, redis)"` Memory RateLimitingMemory `name:"memory" description:"In-memory rate limiting store configuration"` + Redis RateLimitingRedis `name:"redis" description:"In-Redis rate limiting store configuration"` Profiles []RateLimitingProfile `name:"profiles" description:"Rate limiting profiles"` } diff --git a/pkg/gatewayserver/io/udp/config.go b/pkg/gatewayserver/io/udp/config.go index 0cacdc5ad6..5ec36a60d4 100644 --- a/pkg/gatewayserver/io/udp/config.go +++ b/pkg/gatewayserver/io/udp/config.go @@ -14,14 +14,20 @@ package udp -import "time" +import ( + "time" + + "go.thethings.network/lorawan-stack/v3/pkg/config" +) // RateLimitingConfig contains configuration settings for the rate limiting // capabilities of the UDP gateway frontend firewall. type RateLimitingConfig struct { - Enable bool `name:"enable" description:"Enable rate limiting for gateways"` - Messages int `name:"messages" description:"Number of past messages to check timestamp for"` - Threshold time.Duration `name:"threshold" description:"Filter packet if timestamp is not newer than the older timestamps of the previous messages by this threshold"` + Enable bool `name:"enable" description:"Enable rate limiting for gateways"` + Messages int `name:"messages" description:"Number of past messages to check timestamp for"` + Threshold time.Duration `name:"threshold" description:"Filter packet if timestamp is not newer than the older timestamps of the previous messages by this threshold"` //nolint:lll + Provider string `name:"provider" description:"Rate limiting store provider (memory, redis)"` + Redis config.RateLimitingRedis `name:"redis" description:"In-Redis rate limiting store configuration"` } // Config contains configuration settings for the UDP gateway frontend. diff --git a/pkg/gatewayserver/io/udp/udp.go b/pkg/gatewayserver/io/udp/udp.go index 45a0c003f2..f1b63e868e 100644 --- a/pkg/gatewayserver/io/udp/udp.go +++ b/pkg/gatewayserver/io/udp/udp.go @@ -71,7 +71,10 @@ func Serve(ctx context.Context, server io.Server, conn *net.UDPConn, conf Config if conf.RateLimiting.Enable { firewall = NewRateLimitingFirewall(firewall, conf.RateLimiting.Messages, conf.RateLimiting.Threshold) } - limitLogs, err := ratelimit.NewProfile(ctx, limitLogsConfig, limitLogsSize) + limitLogs, err := ratelimit.NewProfile(ctx, limitLogsConfig, ratelimit.StoreConfig{ + Provider: conf.RateLimiting.Provider, + Redis: conf.RateLimiting.Redis.Client, + }) if err != nil { return err } diff --git a/pkg/identityserver/application_access.go b/pkg/identityserver/application_access.go index 39af07aecb..1ad3ea2a44 100644 --- a/pkg/identityserver/application_access.go +++ b/pkg/identityserver/application_access.go @@ -23,6 +23,7 @@ import ( "go.thethings.network/lorawan-stack/v3/pkg/identityserver/store" "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" "go.thethings.network/lorawan-stack/v3/pkg/unique" + "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/emptypb" ) @@ -434,10 +435,24 @@ func (is *IdentityServer) deleteApplicationCollaborator( return nil, err } err = is.store.Transact(ctx, func(ctx context.Context, st store.Store) error { - removedRights, err := st.GetMember(ctx, req.GetCollaboratorIds(), req.GetApplicationIds().GetEntityIdentifiers()) + removedRights, err := st.GetMember( + ctx, req.GetCollaboratorIds(), req.GetApplicationIds().GetEntityIdentifiers(), + ) if err != nil { return err } + app, err := st.GetApplication( + ctx, + req.GetApplicationIds(), + store.FieldMask([]string{"administrative_contact", "technical_contact"}), + ) + if err != nil { + return err + } + if proto.Equal(app.GetAdministrativeContact(), req.GetCollaboratorIds()) || + proto.Equal(app.GetTechnicalContact(), req.GetCollaboratorIds()) { + return errCollaboratorIsContact.WithAttributes("collaborator_id", req.GetCollaboratorIds().IDString()) + } if removedRights.Implied().IncludesAll(ttnpb.Right_RIGHT_APPLICATION_ALL) { memberRights, err := st.FindMembers(ctx, req.GetApplicationIds().GetEntityIdentifiers()) if err != nil { diff --git a/pkg/identityserver/application_access_test.go b/pkg/identityserver/application_access_test.go index 1cd6d20645..e5f24407a1 100644 --- a/pkg/identityserver/application_access_test.go +++ b/pkg/identityserver/application_access_test.go @@ -532,3 +532,54 @@ func TestApplicationAccessClusterAuth(t *testing.T) { } }, withPrivateTestDatabase(p)) } + +func TestApplicationContactRestrictions(t *testing.T) { + p := &storetest.Population{} + + usr1 := p.NewUser() + usr1Key, _ := p.NewAPIKey(usr1.GetEntityIdentifiers(), ttnpb.Right_RIGHT_ALL) + usr1Creds := rpcCreds(usr1Key) + + app1 := p.NewApplication(usr1.GetOrganizationOrUserIdentifiers()) + + usr2 := p.NewUser() + p.NewMembership( + usr2.GetOrganizationOrUserIdentifiers(), + app1.GetEntityIdentifiers(), + ttnpb.Right_RIGHT_APPLICATION_INFO, + ) + // Set the user as administrative contact for the application. + app1.AdministrativeContact = usr2.GetOrganizationOrUserIdentifiers() + + t.Parallel() + a, ctx := test.New(t) + + testWithIdentityServer(t, func(is *IdentityServer, cc *grpc.ClientConn) { + regClt := ttnpb.NewApplicationRegistryClient(cc) + accessClt := ttnpb.NewApplicationAccessClient(cc) + + // Attempt to delete a collaborator that is an administrative contact. + _, err := accessClt.DeleteCollaborator(ctx, &ttnpb.DeleteApplicationCollaboratorRequest{ + ApplicationIds: app1.Ids, + CollaboratorIds: usr2.GetOrganizationOrUserIdentifiers(), + }, usr1Creds) + a.So(errors.IsFailedPrecondition(err), should.BeTrue) + + // Change the administrative contact. + _, err = regClt.Update(ctx, &ttnpb.UpdateApplicationRequest{ + Application: &ttnpb.Application{ + Ids: app1.Ids, + AdministrativeContact: usr1.GetOrganizationOrUserIdentifiers(), + }, + FieldMask: ttnpb.FieldMask("administrative_contact"), + }, usr1Creds) + a.So(err, should.BeNil) + + // Attempt to delete a collaborator that is an administrative contact. + _, err = accessClt.DeleteCollaborator(ctx, &ttnpb.DeleteApplicationCollaboratorRequest{ + ApplicationIds: app1.Ids, + CollaboratorIds: usr2.GetOrganizationOrUserIdentifiers(), + }, usr1Creds) + a.So(err, should.BeNil) + }, withPrivateTestDatabase(p)) +} diff --git a/pkg/identityserver/bunstore/entity_search.go b/pkg/identityserver/bunstore/entity_search.go index b3825c76de..7f36e62908 100644 --- a/pkg/identityserver/bunstore/entity_search.go +++ b/pkg/identityserver/bunstore/entity_search.go @@ -370,6 +370,8 @@ func (s *entitySearch) SearchAccounts( defer span.End() var selectQuery *bun.SelectQuery + var count int + var err error if entityID := req.GetEntityIdentifiers(); entityID != nil { entityType, entityUUID, err := s.getEntity(ctx, entityID) @@ -388,23 +390,47 @@ func (s *entitySearch) SearchAccounts( if q := req.GetQuery(); q != "" { selectQuery = selectQuery.Where(ilike("account_friendly_id"), q) } + + count, err = selectQuery.Count(ctx) + if err != nil { + return nil, storeutil.WrapDriverError(err) + } + if req.ComplementCollaborators { + accountQuery := s.newSelectModel(ctx, &Account{}). + Column("account_type"). + ColumnExpr("uid AS account_friendly_id") + if req.OnlyUsers { + accountQuery = accountQuery.Where(`account_type = 'user'`) + } + if q := req.GetQuery(); q != "" { + accountQuery = accountQuery.Where(ilike("uid"), q) + } + // Count the total number of results. + c, err := accountQuery.Count(ctx) + if err != nil { + return nil, storeutil.WrapDriverError(err) + } + + count = c - count + selectQuery = accountQuery.Except(selectQuery) + } } else { selectQuery = s.newSelectModel(ctx, &Account{}). - ColumnExpr("account_type, uid AS account_friendly_id"). - Order("uid") + Column("account_type"). + ColumnExpr("uid AS account_friendly_id") if req.OnlyUsers { selectQuery = selectQuery.Where(`account_type = 'user'`) } if q := req.GetQuery(); q != "" { selectQuery = selectQuery.Where(ilike("uid"), q) } + // Count the total number of results. + count, err = selectQuery.Count(ctx) + if err != nil { + return nil, storeutil.WrapDriverError(err) + } } - // Count the total number of results. - count, err := selectQuery.Count(ctx) - if err != nil { - return nil, storeutil.WrapDriverError(err) - } store.SetTotal(ctx, uint64(count)) // Apply paging. diff --git a/pkg/identityserver/client_access.go b/pkg/identityserver/client_access.go index 113fdd0650..ad9770cb45 100644 --- a/pkg/identityserver/client_access.go +++ b/pkg/identityserver/client_access.go @@ -23,6 +23,7 @@ import ( "go.thethings.network/lorawan-stack/v3/pkg/identityserver/store" "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" "go.thethings.network/lorawan-stack/v3/pkg/unique" + "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/emptypb" ) @@ -241,6 +242,18 @@ func (is *IdentityServer) deleteClientCollaborator( if err != nil { return err } + clt, err := st.GetClient( + ctx, + req.GetClientIds(), + store.FieldMask([]string{"administrative_contact", "technical_contact"}), + ) + if err != nil { + return err + } + if proto.Equal(clt.GetAdministrativeContact(), req.GetCollaboratorIds()) || + proto.Equal(clt.GetTechnicalContact(), req.GetCollaboratorIds()) { + return errCollaboratorIsContact.WithAttributes("collaborator_id", req.GetCollaboratorIds().IDString()) + } if removedRights.Implied().IncludesAll(ttnpb.Right_RIGHT_CLIENT_ALL) { memberRights, err := st.FindMembers(ctx, req.GetClientIds().GetEntityIdentifiers()) if err != nil { diff --git a/pkg/identityserver/client_access_test.go b/pkg/identityserver/client_access_test.go index f4eea518ad..624750d5b6 100644 --- a/pkg/identityserver/client_access_test.go +++ b/pkg/identityserver/client_access_test.go @@ -246,3 +246,54 @@ func TestClientAccessClusterAuth(t *testing.T) { } }, withPrivateTestDatabase(p)) } + +func TestClientContactRestrictions(t *testing.T) { + p := &storetest.Population{} + + usr1 := p.NewUser() + usr1Key, _ := p.NewAPIKey(usr1.GetEntityIdentifiers(), ttnpb.Right_RIGHT_ALL) + usr1Creds := rpcCreds(usr1Key) + + gtw1 := p.NewClient(usr1.GetOrganizationOrUserIdentifiers()) + + usr2 := p.NewUser() + p.NewMembership( + usr2.GetOrganizationOrUserIdentifiers(), + gtw1.GetEntityIdentifiers(), + ttnpb.Right_RIGHT_CLIENT_INFO, + ) + // Set the user as administrative contact for the client. + gtw1.AdministrativeContact = usr2.GetOrganizationOrUserIdentifiers() + + t.Parallel() + a, ctx := test.New(t) + + testWithIdentityServer(t, func(is *IdentityServer, cc *grpc.ClientConn) { + regClt := ttnpb.NewClientRegistryClient(cc) + accessClt := ttnpb.NewClientAccessClient(cc) + + // Attempt to delete a collaborator that is an administrative contact. + _, err := accessClt.DeleteCollaborator(ctx, &ttnpb.DeleteClientCollaboratorRequest{ + ClientIds: gtw1.Ids, + CollaboratorIds: usr2.GetOrganizationOrUserIdentifiers(), + }, usr1Creds) + a.So(errors.IsFailedPrecondition(err), should.BeTrue) + + // Change the administrative contact. + _, err = regClt.Update(ctx, &ttnpb.UpdateClientRequest{ + Client: &ttnpb.Client{ + Ids: gtw1.Ids, + AdministrativeContact: usr1.GetOrganizationOrUserIdentifiers(), + }, + FieldMask: ttnpb.FieldMask("administrative_contact"), + }, usr1Creds) + a.So(err, should.BeNil) + + // Attempt to delete a collaborator that is an administrative contact. + _, err = accessClt.DeleteCollaborator(ctx, &ttnpb.DeleteClientCollaboratorRequest{ + ClientIds: gtw1.Ids, + CollaboratorIds: usr2.GetOrganizationOrUserIdentifiers(), + }, usr1Creds) + a.So(err, should.BeNil) + }, withPrivateTestDatabase(p)) +} diff --git a/pkg/identityserver/errors.go b/pkg/identityserver/errors.go new file mode 100644 index 0000000000..0a81aca2df --- /dev/null +++ b/pkg/identityserver/errors.go @@ -0,0 +1,21 @@ +// Copyright © 2024 The Things Network Foundation, The Things Industries B.V. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package identityserver + +import "go.thethings.network/lorawan-stack/v3/pkg/errors" + +var errCollaboratorIsContact = errors.DefineFailedPrecondition( + "collaborator_is_contact", "collaborator `{collaborator_id}` is used as a contact", +) diff --git a/pkg/identityserver/gateway_access.go b/pkg/identityserver/gateway_access.go index 5c4ad4c6d0..7bf451a8c9 100644 --- a/pkg/identityserver/gateway_access.go +++ b/pkg/identityserver/gateway_access.go @@ -23,6 +23,7 @@ import ( "go.thethings.network/lorawan-stack/v3/pkg/identityserver/store" "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" "go.thethings.network/lorawan-stack/v3/pkg/unique" + "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/emptypb" ) @@ -427,6 +428,18 @@ func (is *IdentityServer) deleteGatewayCollaborator( if err != nil { return err } + gtw, err := st.GetGateway( + ctx, + req.GetGatewayIds(), + store.FieldMask([]string{"administrative_contact", "technical_contact"}), + ) + if err != nil { + return err + } + if proto.Equal(gtw.GetAdministrativeContact(), req.GetCollaboratorIds()) || + proto.Equal(gtw.GetTechnicalContact(), req.GetCollaboratorIds()) { + return errCollaboratorIsContact.WithAttributes("collaborator_id", req.GetCollaboratorIds().IDString()) + } if removedRights.Implied().IncludesAll(ttnpb.Right_RIGHT_GATEWAY_ALL) { memberRights, err := st.FindMembers(ctx, req.GetGatewayIds().GetEntityIdentifiers()) if err != nil { diff --git a/pkg/identityserver/gateway_access_test.go b/pkg/identityserver/gateway_access_test.go index b666c731e0..75a265b9b0 100644 --- a/pkg/identityserver/gateway_access_test.go +++ b/pkg/identityserver/gateway_access_test.go @@ -524,6 +524,57 @@ func TestGatewayAccessClusterAuth(t *testing.T) { }, withPrivateTestDatabase(p)) } +func TestGatewayContactRestrictions(t *testing.T) { + p := &storetest.Population{} + + usr1 := p.NewUser() + usr1Key, _ := p.NewAPIKey(usr1.GetEntityIdentifiers(), ttnpb.Right_RIGHT_ALL) + usr1Creds := rpcCreds(usr1Key) + + gtw1 := p.NewGateway(usr1.GetOrganizationOrUserIdentifiers()) + + usr2 := p.NewUser() + p.NewMembership( + usr2.GetOrganizationOrUserIdentifiers(), + gtw1.GetEntityIdentifiers(), + ttnpb.Right_RIGHT_GATEWAY_INFO, + ) + // Set the user as administrative contact for the gateway. + gtw1.AdministrativeContact = usr2.GetOrganizationOrUserIdentifiers() + + t.Parallel() + a, ctx := test.New(t) + + testWithIdentityServer(t, func(is *IdentityServer, cc *grpc.ClientConn) { + regClt := ttnpb.NewGatewayRegistryClient(cc) + accessClt := ttnpb.NewGatewayAccessClient(cc) + + // Attempt to delete a collaborator that is an administrative contact. + _, err := accessClt.DeleteCollaborator(ctx, &ttnpb.DeleteGatewayCollaboratorRequest{ + GatewayIds: gtw1.Ids, + CollaboratorIds: usr2.GetOrganizationOrUserIdentifiers(), + }, usr1Creds) + a.So(errors.IsFailedPrecondition(err), should.BeTrue) + + // Change the administrative contact. + _, err = regClt.Update(ctx, &ttnpb.UpdateGatewayRequest{ + Gateway: &ttnpb.Gateway{ + Ids: gtw1.Ids, + AdministrativeContact: usr1.GetOrganizationOrUserIdentifiers(), + }, + FieldMask: ttnpb.FieldMask("administrative_contact"), + }, usr1Creds) + a.So(err, should.BeNil) + + // Attempt to delete a collaborator that is an administrative contact. + _, err = accessClt.DeleteCollaborator(ctx, &ttnpb.DeleteGatewayCollaboratorRequest{ + GatewayIds: gtw1.Ids, + CollaboratorIds: usr2.GetOrganizationOrUserIdentifiers(), + }, usr1Creds) + a.So(err, should.BeNil) + }, withPrivateTestDatabase(p)) +} + func TestGatewayBatchAccess(t *testing.T) { p := &storetest.Population{} diff --git a/pkg/identityserver/organization_access.go b/pkg/identityserver/organization_access.go index ce361a0fe5..d3f76e362b 100644 --- a/pkg/identityserver/organization_access.go +++ b/pkg/identityserver/organization_access.go @@ -23,6 +23,7 @@ import ( "go.thethings.network/lorawan-stack/v3/pkg/identityserver/store" "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" "go.thethings.network/lorawan-stack/v3/pkg/unique" + "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/emptypb" ) @@ -63,6 +64,10 @@ var ( events.WithAuthFromContext(), events.WithClientInfoFromContext(), ) + + errOrganizationNeedsCollaborator = errors.DefineFailedPrecondition( + "organization_needs_collaborator", "every organization needs at least one collaborator with all rights", + ) ) func (*IdentityServer) listOrganizationRights( @@ -282,10 +287,6 @@ func (is *IdentityServer) getOrganizationCollaborator( return res, nil } -var errOrganizationNeedsCollaborator = errors.DefineFailedPrecondition( - "organization_needs_collaborator", "every organization needs at least one collaborator with all rights", -) - func (is *IdentityServer) setOrganizationCollaborator( //nolint:gocyclo ctx context.Context, req *ttnpb.SetOrganizationCollaboratorRequest, ) (_ *emptypb.Empty, err error) { @@ -440,6 +441,18 @@ func (is *IdentityServer) deleteOrganizationCollaborator( if err != nil { return err } + org, err := st.GetOrganization( + ctx, + req.GetOrganizationIds(), + store.FieldMask([]string{"administrative_contact", "technical_contact"}), + ) + if err != nil { + return err + } + if proto.Equal(org.GetAdministrativeContact(), req.GetCollaboratorIds()) || + proto.Equal(org.GetTechnicalContact(), req.GetCollaboratorIds()) { + return errCollaboratorIsContact.WithAttributes("collaborator_id", req.GetCollaboratorIds().IDString()) + } if r.Implied().IncludesAll(ttnpb.Right_RIGHT_ORGANIZATION_ALL) { memberRights, err := st.FindMembers(ctx, req.GetOrganizationIds().GetEntityIdentifiers()) if err != nil { diff --git a/pkg/identityserver/organization_access_test.go b/pkg/identityserver/organization_access_test.go index 581cf3745e..b11c511d0d 100644 --- a/pkg/identityserver/organization_access_test.go +++ b/pkg/identityserver/organization_access_test.go @@ -528,3 +528,54 @@ func TestOrganizationAccessClusterAuth(t *testing.T) { } }, withPrivateTestDatabase(p)) } + +func TestOrganizationContactRestrictions(t *testing.T) { + p := &storetest.Population{} + + usr1 := p.NewUser() + usr1Key, _ := p.NewAPIKey(usr1.GetEntityIdentifiers(), ttnpb.Right_RIGHT_ALL) + usr1Creds := rpcCreds(usr1Key) + + gtw1 := p.NewOrganization(usr1.GetOrganizationOrUserIdentifiers()) + + usr2 := p.NewUser() + p.NewMembership( + usr2.GetOrganizationOrUserIdentifiers(), + gtw1.GetEntityIdentifiers(), + ttnpb.Right_RIGHT_ORGANIZATION_INFO, + ) + // Set the user as administrative contact for the organization. + gtw1.AdministrativeContact = usr2.GetOrganizationOrUserIdentifiers() + + t.Parallel() + a, ctx := test.New(t) + + testWithIdentityServer(t, func(is *IdentityServer, cc *grpc.ClientConn) { + regClt := ttnpb.NewOrganizationRegistryClient(cc) + accessClt := ttnpb.NewOrganizationAccessClient(cc) + + // Attempt to delete a collaborator that is an administrative contact. + _, err := accessClt.DeleteCollaborator(ctx, &ttnpb.DeleteOrganizationCollaboratorRequest{ + OrganizationIds: gtw1.Ids, + CollaboratorIds: usr2.GetOrganizationOrUserIdentifiers(), + }, usr1Creds) + a.So(errors.IsFailedPrecondition(err), should.BeTrue) + + // Change the administrative contact. + _, err = regClt.Update(ctx, &ttnpb.UpdateOrganizationRequest{ + Organization: &ttnpb.Organization{ + Ids: gtw1.Ids, + AdministrativeContact: usr1.GetOrganizationOrUserIdentifiers(), + }, + FieldMask: ttnpb.FieldMask("administrative_contact"), + }, usr1Creds) + a.So(err, should.BeNil) + + // Attempt to delete a collaborator that is an administrative contact. + _, err = accessClt.DeleteCollaborator(ctx, &ttnpb.DeleteOrganizationCollaboratorRequest{ + OrganizationIds: gtw1.Ids, + CollaboratorIds: usr2.GetOrganizationOrUserIdentifiers(), + }, usr1Creds) + a.So(err, should.BeNil) + }, withPrivateTestDatabase(p)) +} diff --git a/pkg/identityserver/storetest/entity_search.go b/pkg/identityserver/storetest/entity_search.go index 9c34992ddc..e44501a30e 100644 --- a/pkg/identityserver/storetest/entity_search.go +++ b/pkg/identityserver/storetest/entity_search.go @@ -560,6 +560,14 @@ func (st *StoreTest) TestEntitySearch(t *T) { if a.So(err, should.BeNil) && a.So(ids, should.NotBeNil) && a.So(ids, should.HaveLength, 1) { a.So(ids[0], should.Resemble, usr1.GetIds().GetOrganizationOrUserIdentifiers()) } + + // Exclude app1 collaborator. + ids, err = s.SearchAccounts(ctx, &ttnpb.SearchAccountsRequest{ + CollaboratorOf: &ttnpb.SearchAccountsRequest_ApplicationIds{ApplicationIds: app1.GetIds()}, + ComplementCollaborators: true, + }) + a.So(err, should.BeNil) + a.So(ids, should.HaveLength, 3) }) t.Run("Client", func(t *T) { @@ -571,6 +579,14 @@ func (st *StoreTest) TestEntitySearch(t *T) { if a.So(err, should.BeNil) && a.So(ids, should.NotBeNil) && a.So(ids, should.HaveLength, 1) { a.So(ids[0], should.Resemble, usr1.GetIds().GetOrganizationOrUserIdentifiers()) } + + // Exclude cli1 collaborator. + ids, err = s.SearchAccounts(ctx, &ttnpb.SearchAccountsRequest{ + CollaboratorOf: &ttnpb.SearchAccountsRequest_ClientIds{ClientIds: cli1.GetIds()}, + ComplementCollaborators: true, + }) + a.So(err, should.BeNil) + a.So(ids, should.HaveLength, 3) }) t.Run("Gateway", func(t *T) { @@ -582,6 +598,14 @@ func (st *StoreTest) TestEntitySearch(t *T) { if a.So(err, should.BeNil) && a.So(ids, should.NotBeNil) && a.So(ids, should.HaveLength, 1) { a.So(ids[0], should.Resemble, usr1.GetIds().GetOrganizationOrUserIdentifiers()) } + + // Exclude gtw1 collaborator. + ids, err = s.SearchAccounts(ctx, &ttnpb.SearchAccountsRequest{ + CollaboratorOf: &ttnpb.SearchAccountsRequest_GatewayIds{GatewayIds: gtw1.GetIds()}, + ComplementCollaborators: true, + }) + a.So(err, should.BeNil) + a.So(ids, should.HaveLength, 3) }) t.Run("Organization", func(t *T) { @@ -593,6 +617,14 @@ func (st *StoreTest) TestEntitySearch(t *T) { if a.So(err, should.BeNil) && a.So(ids, should.NotBeNil) && a.So(ids, should.HaveLength, 1) { a.So(ids[0], should.Resemble, usr1.GetIds().GetOrganizationOrUserIdentifiers()) } + + // Exclude org1 collaborator. + ids, err = s.SearchAccounts(ctx, &ttnpb.SearchAccountsRequest{ + CollaboratorOf: &ttnpb.SearchAccountsRequest_OrganizationIds{OrganizationIds: org1.GetIds()}, + ComplementCollaborators: true, + }) + a.So(err, should.BeNil) + a.So(ids, should.HaveLength, 3) }) }) } diff --git a/pkg/ratelimit/config.go b/pkg/ratelimit/config.go index 37237c8fc1..62b02d716e 100644 --- a/pkg/ratelimit/config.go +++ b/pkg/ratelimit/config.go @@ -17,11 +17,13 @@ package ratelimit import ( "context" - "github.com/throttled/throttled" + "github.com/throttled/throttled/v2" + redisstore "github.com/throttled/throttled/v2/store/goredisstore.v9" "github.com/throttled/throttled/v2/store/memstore" "go.thethings.network/lorawan-stack/v3/pkg/config" "go.thethings.network/lorawan-stack/v3/pkg/errors" "go.thethings.network/lorawan-stack/v3/pkg/httpclient" + ttnredis "go.thethings.network/lorawan-stack/v3/pkg/redis" "gopkg.in/yaml.v2" ) @@ -30,6 +32,13 @@ const defaultMaxSize = 1 << 12 var errRateLimitExceeded = errors.DefineResourceExhausted("rate_limit_exceeded", "rate limit of `{rate}` accesses per minute exceeded for resource `{key}`") +// StoreConfig represents configuration for rate limiting stores. +type StoreConfig struct { + Provider string + Memory config.RateLimitingMemory + Redis *ttnredis.Client +} + // New creates a new ratelimit.Interface from configuration. func New(ctx context.Context, conf config.RateLimiting, blobConf config.BlobConfig, httpClientProvider httpclient.Provider) (Interface, error) { defaultLimiter := &NoopRateLimiter{} @@ -64,7 +73,11 @@ func New(ctx context.Context, conf config.RateLimiting, blobConf config.BlobConf if len(profile.Associations) == 0 { continue } - limiter, err := NewProfile(ctx, profile, conf.Memory.MaxSize) + limiter, err := NewProfile(ctx, profile, StoreConfig{ + Provider: conf.Provider, + Memory: conf.Memory, + Redis: conf.Redis.Client, + }) if err != nil { return nil, err } @@ -77,15 +90,25 @@ func New(ctx context.Context, conf config.RateLimiting, blobConf config.BlobConf var errInvalidRate = errors.DefineInvalidArgument("invalid_rate", "invalid rate `{rate}` for profile `{name}`") +func newStore(conf StoreConfig) (store throttled.GCRAStoreCtx, err error) { + switch conf.Provider { + case "redis": + return redisstore.NewCtx(conf.Redis, conf.Redis.Key("")) + + default: + return memstore.NewCtx(int(conf.Memory.MaxSize)) + } +} + // NewProfile returns a new ratelimit.Interface from profile configuration. -func NewProfile(ctx context.Context, conf config.RateLimitingProfile, size uint) (Interface, error) { - if size == 0 { - size = defaultMaxSize +func NewProfile(ctx context.Context, conf config.RateLimitingProfile, storeConf StoreConfig) (Interface, error) { + if s := &storeConf.Memory.MaxSize; *s == 0 { + *s = defaultMaxSize } if conf.MaxPerMin == 0 { return nil, errInvalidRate.WithAttributes("rate", conf.MaxPerMin, "name", conf.Name) } - store, err := memstore.New(int(size)) + store, err := newStore(storeConf) if err != nil { return nil, err } @@ -96,7 +119,7 @@ func NewProfile(ctx context.Context, conf config.RateLimitingProfile, size uint) MaxRate: throttled.PerMin(int(conf.MaxPerMin)), MaxBurst: int(conf.MaxBurst - 1), } - limiter, err := throttled.NewGCRARateLimiter(store, quota) + limiter, err := throttled.NewGCRARateLimiterCtx(store, quota) if err != nil { return nil, err } diff --git a/pkg/ratelimit/rate_limit.go b/pkg/ratelimit/rate_limit.go index 46b336d464..a054206bd6 100644 --- a/pkg/ratelimit/rate_limit.go +++ b/pkg/ratelimit/rate_limit.go @@ -17,7 +17,7 @@ package ratelimit import ( "context" - "github.com/throttled/throttled" + "github.com/throttled/throttled/v2" "go.thethings.network/lorawan-stack/v3/pkg/log" ) diff --git a/pkg/ratelimit/rate_limit_test.go b/pkg/ratelimit/rate_limit_test.go index 62549a3442..b1d927bc26 100644 --- a/pkg/ratelimit/rate_limit_test.go +++ b/pkg/ratelimit/rate_limit_test.go @@ -151,6 +151,7 @@ func TestRateLimit(t *testing.T) { conf := config.RateLimiting{ ConfigSource: "directory", Directory: "testdata", + Provider: "memory", Memory: config.RateLimitingMemory{ MaxSize: 1024, }, diff --git a/pkg/ttnpb/search_services.pb.go b/pkg/ttnpb/search_services.pb.go index 30d4386975..bcb896ff46 100644 --- a/pkg/ttnpb/search_services.pb.go +++ b/pkg/ttnpb/search_services.pb.go @@ -727,7 +727,8 @@ type SearchAccountsRequest struct { // *SearchAccountsRequest_ClientIds // *SearchAccountsRequest_GatewayIds // *SearchAccountsRequest_OrganizationIds - CollaboratorOf isSearchAccountsRequest_CollaboratorOf `protobuf_oneof:"collaborator_of"` + CollaboratorOf isSearchAccountsRequest_CollaboratorOf `protobuf_oneof:"collaborator_of"` + ComplementCollaborators bool `protobuf:"varint,7,opt,name=complement_collaborators,json=complementCollaborators,proto3" json:"complement_collaborators,omitempty"` } func (x *SearchAccountsRequest) Reset() { @@ -811,6 +812,13 @@ func (x *SearchAccountsRequest) GetOrganizationIds() *OrganizationIdentifiers { return nil } +func (x *SearchAccountsRequest) GetComplementCollaborators() bool { + if x != nil { + return x.ComplementCollaborators + } + return false +} + type isSearchAccountsRequest_CollaboratorOf interface { isSearchAccountsRequest_CollaboratorOf() } @@ -1302,7 +1310,7 @@ var file_ttn_lorawan_v3_search_services_proto_rawDesc = []byte{ 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, - 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x01, 0x22, 0xa6, 0x03, 0x0a, 0x15, 0x53, 0x65, 0x61, + 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x01, 0x22, 0xe1, 0x03, 0x0a, 0x15, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, @@ -1327,154 +1335,158 @@ var file_ttn_lorawan_v3_search_services_proto_rawDesc = []byte{ 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x0f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x73, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x01, 0x42, 0x11, - 0x0a, 0x0f, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x6f, - 0x66, 0x22, 0x68, 0x0a, 0x16, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0b, 0x61, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x2d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x72, - 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, - 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x22, 0xe9, 0x07, 0x0a, 0x17, - 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x59, 0x0a, 0x0f, 0x61, 0x70, 0x70, 0x6c, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, - 0x10, 0x01, 0x52, 0x0e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x73, 0x12, 0x1d, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x0d, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, - 0x79, 0x12, 0x28, 0x0a, 0x0b, 0x69, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, - 0x0a, 0x69, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x2c, 0x0a, 0x0d, 0x6e, - 0x61, 0x6d, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, 0x0c, 0x6e, 0x61, 0x6d, - 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x3a, 0x0a, 0x14, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, - 0x52, 0x13, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x73, 0x12, 0xa3, 0x01, 0x0a, 0x12, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, - 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x42, 0x34, 0xfa, 0x42, 0x31, 0x9a, 0x01, 0x2e, 0x10, 0x0a, 0x22, 0x24, 0x72, 0x22, - 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x3f, 0x3a, - 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x7b, 0x32, 0x2c, - 0x7d, 0x24, 0x2a, 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, 0x11, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x65, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x12, 0x31, 0x0a, 0x10, 0x64, - 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x10, 0x52, 0x0e, - 0x64, 0x65, 0x76, 0x45, 0x75, 0x69, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x33, - 0x0a, 0x11, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x65, 0x75, 0x69, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, - 0x69, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, - 0x18, 0x10, 0x52, 0x0f, 0x6a, 0x6f, 0x69, 0x6e, 0x45, 0x75, 0x69, 0x43, 0x6f, 0x6e, 0x74, 0x61, - 0x69, 0x6e, 0x73, 0x12, 0x33, 0x0a, 0x11, 0x64, 0x65, 0x76, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x5f, - 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, - 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x08, 0x52, 0x0f, 0x64, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, - 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, - 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, - 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, - 0x61, 0x73, 0x6b, 0x12, 0xbd, 0x01, 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x09, 0x42, 0xa6, 0x01, 0xfa, 0x42, 0xa2, 0x01, 0x72, 0x9f, 0x01, 0x52, 0x00, 0x52, - 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x52, 0x0a, 0x2d, 0x64, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x52, 0x08, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x65, 0x75, 0x69, - 0x52, 0x09, 0x2d, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x65, 0x75, 0x69, 0x52, 0x07, 0x64, 0x65, 0x76, - 0x5f, 0x65, 0x75, 0x69, 0x52, 0x08, 0x2d, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x05, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x2d, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, - 0x61, 0x74, 0x52, 0x0b, 0x2d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, - 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x61, 0x74, 0x52, 0x0d, 0x2d, - 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x61, 0x74, 0x52, 0x05, 0x6f, 0x72, - 0x64, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x0b, 0x20, 0x01, - 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x05, 0x6c, 0x69, - 0x6d, 0x69, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x1a, 0x44, 0x0a, 0x16, 0x41, 0x74, 0x74, 0x72, 0x69, - 0x62, 0x75, 0x74, 0x65, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, - 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x01, 0x32, 0xcd, 0x07, 0x0a, 0x14, 0x45, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x12, 0x7b, 0x0a, 0x12, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x29, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, - 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, - 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x67, 0x0a, - 0x0d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x24, + 0x6e, 0x49, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x3a, + 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x01, 0x42, 0x11, 0x0a, 0x0f, 0x63, 0x6f, 0x6c, + 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x6f, 0x66, 0x22, 0x68, 0x0a, 0x16, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, + 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x22, 0xe9, 0x07, 0x0a, 0x17, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x59, 0x0a, 0x0f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0e, 0x61, + 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x1d, 0x0a, + 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, + 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x28, 0x0a, 0x0b, + 0x69, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, 0x0a, 0x69, 0x64, 0x43, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x2c, 0x0a, 0x0d, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, + 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, 0x0c, 0x6e, 0x61, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x73, 0x12, 0x3a, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, 0x13, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, + 0x12, 0xa3, 0x01, 0x0a, 0x12, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, + 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x34, 0xfa, + 0x42, 0x31, 0x9a, 0x01, 0x2e, 0x10, 0x0a, 0x22, 0x24, 0x72, 0x22, 0x18, 0x24, 0x32, 0x1e, 0x5e, + 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x3f, 0x3a, 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, + 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x7b, 0x32, 0x2c, 0x7d, 0x24, 0x2a, 0x04, 0x72, + 0x02, 0x18, 0x32, 0x52, 0x11, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x43, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x12, 0x31, 0x0a, 0x10, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, + 0x69, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x10, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x45, 0x75, + 0x69, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x33, 0x0a, 0x11, 0x6a, 0x6f, 0x69, + 0x6e, 0x5f, 0x65, 0x75, 0x69, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x10, 0x52, 0x0f, 0x6a, + 0x6f, 0x69, 0x6e, 0x45, 0x75, 0x69, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x33, + 0x0a, 0x11, 0x64, 0x65, 0x76, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, + 0x18, 0x08, 0x52, 0x0f, 0x64, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, + 0x6b, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, + 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0xbd, + 0x01, 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x42, 0xa6, + 0x01, 0xfa, 0x42, 0xa2, 0x01, 0x72, 0x9f, 0x01, 0x52, 0x00, 0x52, 0x09, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x52, 0x0a, 0x2d, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, + 0x64, 0x52, 0x08, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x65, 0x75, 0x69, 0x52, 0x09, 0x2d, 0x6a, 0x6f, + 0x69, 0x6e, 0x5f, 0x65, 0x75, 0x69, 0x52, 0x07, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x52, + 0x08, 0x2d, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, + 0x05, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x2d, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x0b, 0x2d, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, + 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x61, 0x74, 0x52, 0x0d, 0x2d, 0x6c, 0x61, 0x73, 0x74, 0x5f, + 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x61, 0x74, 0x52, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x1e, + 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, + 0x42, 0x05, 0x2a, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x61, + 0x67, 0x65, 0x1a, 0x44, 0x0a, 0x16, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, + 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, + 0x10, 0x01, 0x32, 0xcd, 0x07, 0x0a, 0x14, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x79, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x7b, 0x0a, 0x12, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x29, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x16, 0x12, 0x14, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x61, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x67, 0x0a, 0x0d, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, + 0x12, 0x0f, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x73, 0x12, 0x6b, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x73, 0x12, 0x25, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x47, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x73, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x73, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x12, 0x7f, + 0x0a, 0x13, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4f, 0x72, 0x67, + 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x2f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x5f, 0x0a, 0x0b, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, - 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, - 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x17, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x6b, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x12, 0x25, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x12, 0x12, 0x10, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, - 0x61, 0x79, 0x73, 0x12, 0x7f, 0x0a, 0x13, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4f, 0x72, 0x67, - 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2a, 0x2e, 0x74, 0x74, 0x6e, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x73, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x0f, 0x12, 0x0d, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, + 0x12, 0xff, 0x02, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x73, 0x12, 0x25, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, - 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x5f, 0x0a, 0x0b, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, - 0x65, 0x72, 0x73, 0x12, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, - 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, - 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x73, 0x22, 0x15, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x12, 0x0d, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, - 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0xff, 0x02, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x25, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x9d, 0x02, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x96, - 0x02, 0x5a, 0x45, 0x12, 0x43, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x2f, 0x7b, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x69, 0x64, 0x73, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x69, 0x64, 0x7d, 0x2f, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, - 0x73, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5a, 0x36, 0x12, 0x34, 0x2f, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x73, - 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x63, 0x6f, 0x6c, 0x6c, + 0x63, 0x68, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x9d, 0x02, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x96, 0x02, 0x5a, 0x45, 0x12, 0x43, + 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x61, + 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x2e, 0x61, + 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x63, + 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x73, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x5a, 0x36, 0x12, 0x34, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x2f, + 0x7b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5a, 0x39, 0x12, 0x37, 0x2f, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x2f, 0x7b, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x5f, 0x69, 0x64, 0x73, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x69, 0x64, + 0x7d, 0x2f, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, + 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5a, 0x48, 0x12, 0x46, 0x2f, 0x6f, 0x72, 0x67, 0x61, 0x6e, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x2e, 0x6f, 0x72, 0x67, 0x61, 0x6e, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x5a, 0x39, 0x12, 0x37, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x2f, 0x7b, 0x67, - 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x69, 0x64, 0x73, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, - 0x61, 0x79, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, - 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5a, 0x48, 0x12, 0x46, 0x2f, - 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x6f, - 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x2e, - 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x7d, - 0x2f, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x73, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x10, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x61, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x32, 0xba, 0x01, 0x0a, 0x17, 0x45, 0x6e, 0x64, 0x44, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x53, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x12, 0x9e, 0x01, 0x0a, 0x10, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x45, 0x6e, - 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x22, 0x45, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x3f, 0x12, 0x3d, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x61, - 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x61, 0x70, 0x70, - 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x2e, 0x61, 0x70, 0x70, - 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x64, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, - 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, - 0x67, 0x2f, 0x74, 0x74, 0x6e, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x12, 0x10, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x73, 0x32, 0xba, 0x01, 0x0a, 0x17, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x9e, + 0x01, 0x0a, 0x10, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x12, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x45, 0x6e, 0x64, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, + 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x22, 0x45, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3f, + 0x12, 0x3d, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x42, + 0x31, 0x5a, 0x2f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d, + 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x74, 0x6e, + 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/pkg/ttnpb/search_services.pb.paths.fm.go b/pkg/ttnpb/search_services.pb.paths.fm.go index c588d29ca2..b8f7465a90 100644 --- a/pkg/ttnpb/search_services.pb.paths.fm.go +++ b/pkg/ttnpb/search_services.pb.paths.fm.go @@ -144,12 +144,14 @@ var SearchAccountsRequestFieldPathsNested = []string{ "collaborator_of.gateway_ids.gateway_id", "collaborator_of.organization_ids", "collaborator_of.organization_ids.organization_id", + "complement_collaborators", "only_users", "query", } var SearchAccountsRequestFieldPathsTopLevel = []string{ "collaborator_of", + "complement_collaborators", "only_users", "query", } diff --git a/pkg/ttnpb/search_services.pb.setters.fm.go b/pkg/ttnpb/search_services.pb.setters.fm.go index 23e3ce029f..0917c877dc 100644 --- a/pkg/ttnpb/search_services.pb.setters.fm.go +++ b/pkg/ttnpb/search_services.pb.setters.fm.go @@ -600,6 +600,16 @@ func (dst *SearchAccountsRequest) SetFields(src *SearchAccountsRequest, paths .. var zero bool dst.OnlyUsers = zero } + case "complement_collaborators": + if len(subs) > 0 { + return fmt.Errorf("'complement_collaborators' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.ComplementCollaborators = src.ComplementCollaborators + } else { + var zero bool + dst.ComplementCollaborators = zero + } case "collaborator_of": if len(subs) == 0 && src == nil { diff --git a/pkg/ttnpb/search_services.pb.validate.go b/pkg/ttnpb/search_services.pb.validate.go index b85070c496..35421320ef 100644 --- a/pkg/ttnpb/search_services.pb.validate.go +++ b/pkg/ttnpb/search_services.pb.validate.go @@ -1117,6 +1117,8 @@ func (m *SearchAccountsRequest) ValidateFields(paths ...string) error { case "only_users": // no validation rules for OnlyUsers + case "complement_collaborators": + // no validation rules for ComplementCollaborators case "collaborator_of": if len(subs) == 0 { subs = []string{ diff --git a/pkg/ttnpb/search_services_flags.pb.go b/pkg/ttnpb/search_services_flags.pb.go index ca45b8a657..1d3979fc32 100644 --- a/pkg/ttnpb/search_services_flags.pb.go +++ b/pkg/ttnpb/search_services_flags.pb.go @@ -450,6 +450,7 @@ func AddSetFlagsForSearchAccountsRequest(flags *pflag.FlagSet, prefix string, hi AddSetFlagsForClientIdentifiers(flags, flagsplugin.Prefix("collaborator-of.client-ids", prefix), hidden) AddSetFlagsForGatewayIdentifiers(flags, flagsplugin.Prefix("collaborator-of.gateway-ids", prefix), hidden) AddSetFlagsForOrganizationIdentifiers(flags, flagsplugin.Prefix("collaborator-of.organization-ids", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("complement-collaborators", prefix), "", flagsplugin.WithHidden(hidden))) } // SetFromFlags sets the SearchAccountsRequest message from flags. @@ -514,6 +515,12 @@ func (m *SearchAccountsRequest) SetFromFlags(flags *pflag.FlagSet, prefix string } m.CollaboratorOf = ov } + if val, changed, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("complement_collaborators", prefix)); err != nil { + return nil, err + } else if changed { + m.ComplementCollaborators = val + paths = append(paths, flagsplugin.Prefix("complement_collaborators", prefix)) + } return paths, nil } diff --git a/pkg/ttnpb/search_services_json.pb.go b/pkg/ttnpb/search_services_json.pb.go index 88c22107b9..83cf89a3b9 100644 --- a/pkg/ttnpb/search_services_json.pb.go +++ b/pkg/ttnpb/search_services_json.pb.go @@ -804,6 +804,11 @@ func (x *SearchAccountsRequest) MarshalProtoJSON(s *jsonplugin.MarshalState) { golang.MarshalMessage(s, ov.OrganizationIds) } } + if x.ComplementCollaborators || s.HasField("complement_collaborators") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("complement_collaborators") + s.WriteBool(x.ComplementCollaborators) + } s.WriteObjectEnd() } @@ -872,6 +877,9 @@ func (x *SearchAccountsRequest) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) var v OrganizationIdentifiers golang.UnmarshalMessage(s, &v) ov.OrganizationIds = &v + case "complement_collaborators", "complementCollaborators": + s.AddField("complement_collaborators") + x.ComplementCollaborators = s.ReadBool() } }) } diff --git a/pkg/webui/components/footer/index.js b/pkg/webui/components/footer/index.js index 546ee2d564..d2ed252314 100644 --- a/pkg/webui/components/footer/index.js +++ b/pkg/webui/components/footer/index.js @@ -147,15 +147,7 @@ const Footer = ({