From 567b3d267e61d829e316cbf91b4f26159f33fb73 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sun, 10 Dec 2023 19:15:32 -0800 Subject: [PATCH] Move auth, metrics, meters to transitland-mw repo (#194) * Move auth, metrics, meters to transitland-mw repo --- .github/workflows/test.yml | 4 +- actions/fetch.go | 11 +- actions/fetch_test.go | 2 +- actions/fv.go | 11 +- actions/validate.go | 3 +- auth/ancheck/gatekeeper.go | 169 - auth/ancheck/gatekeeper_test.go | 297 -- auth/ancheck/jwt.go | 78 - auth/ancheck/jwt_test.go | 7 - auth/ancheck/mw.go | 92 - auth/ancheck/mw_test.go | 98 - auth/ancheck/user_header.go | 20 - auth/ancheck/user_header_test.go | 34 - auth/auth0/auth0.go | 56 - auth/auth0/auth0_test.go | 15 - auth/authn/authn.go | 35 - auth/authn/user.go | 108 - auth/authn/user_test.go | 39 - auth/authz/azpb.pb.go | 4414 --------------------- auth/authz/azpb.proto | 332 -- auth/authz/azpb_gen.go | 3 - auth/authz/azpb_grpc.pb.go | 1041 ----- auth/authz/tk.go | 248 -- auth/azcheck/checker.go | 948 ----- auth/azcheck/checker_test.go | 1890 --------- auth/azcheck/mock.go | 79 - auth/azcheck/server.go | 224 -- auth/azcheck/server_test.go | 466 --- auth/fga/fga.go | 288 -- auth/fga/fga_test.go | 1086 ----- cmd/tlserver/main.go | 2 +- finders/dbfinder/feed_select.go | 2 +- finders/dbfinder/feed_version_select.go | 2 +- finders/dbfinder/finder.go | 4 +- finders/rtfinder/finder.go | 2 +- finders/rtfinder/lookup.go | 2 +- finders/rtfinder/redis.go | 2 +- finders/rtfinder/source.go | 2 +- go.mod | 94 +- go.sum | 219 +- internal/dbutil/dbutil.go | 2 +- internal/directions/aws_router.go | 2 +- internal/directions/directions.go | 2 +- internal/directions/valhalla_router.go | 2 +- internal/ecache/ecache.go | 2 +- internal/gbfs/fetch.go | 2 +- internal/jobs/local_jobs.go | 2 +- internal/jobs/log.go | 2 +- internal/jobs/redis_jobs.go | 2 +- internal/testfinder/testfinder.go | 4 +- internal/testutil/db.go | 2 +- internal/testutil/recorder.go | 2 +- meters/amberflo.go | 246 -- meters/amberflo_test.go | 57 - meters/default.go | 126 - meters/default_test.go | 17 - meters/limit.go | 129 - meters/limit_test.go | 162 - meters/meters.go | 108 - meters/meters_test.go | 127 - metrics/default.go | 33 - metrics/http.go | 61 - metrics/jobs.go | 32 - metrics/metrics.go | 32 - metrics/prom.go | 130 - model/finders.go | 2 +- server/gql/agency_resolver_test.go | 4 +- server/gql/fvsl_cache.go | 2 +- server/gql/loaders.go | 2 +- server/gql/mutation_resolver.go | 11 +- server/gql/mutation_resolver_test.go | 2 +- server/gql/query_resolver.go | 4 +- server/gql/resolver_test.go | 4 +- server/gql/server.go | 2 +- server/rest/feed_version_download.go | 2 +- server/rest/feed_version_download_test.go | 4 +- server/rest/filecache.go | 2 +- server/rest/map.go | 2 +- server/rest/rest.go | 6 +- server/server.go | 123 - server/server_cmd.go | 42 +- test_setup.sh | 1 + workers/static_fetch_worker.go | 2 +- 83 files changed, 244 insertions(+), 13688 deletions(-) delete mode 100644 auth/ancheck/gatekeeper.go delete mode 100644 auth/ancheck/gatekeeper_test.go delete mode 100644 auth/ancheck/jwt.go delete mode 100644 auth/ancheck/jwt_test.go delete mode 100644 auth/ancheck/mw.go delete mode 100644 auth/ancheck/mw_test.go delete mode 100644 auth/ancheck/user_header.go delete mode 100644 auth/ancheck/user_header_test.go delete mode 100644 auth/auth0/auth0.go delete mode 100644 auth/auth0/auth0_test.go delete mode 100644 auth/authn/authn.go delete mode 100644 auth/authn/user.go delete mode 100644 auth/authn/user_test.go delete mode 100644 auth/authz/azpb.pb.go delete mode 100644 auth/authz/azpb.proto delete mode 100644 auth/authz/azpb_gen.go delete mode 100644 auth/authz/azpb_grpc.pb.go delete mode 100644 auth/authz/tk.go delete mode 100644 auth/azcheck/checker.go delete mode 100644 auth/azcheck/checker_test.go delete mode 100644 auth/azcheck/mock.go delete mode 100644 auth/azcheck/server.go delete mode 100644 auth/azcheck/server_test.go delete mode 100644 auth/fga/fga.go delete mode 100644 auth/fga/fga_test.go delete mode 100644 meters/amberflo.go delete mode 100644 meters/amberflo_test.go delete mode 100644 meters/default.go delete mode 100644 meters/default_test.go delete mode 100644 meters/limit.go delete mode 100644 meters/limit_test.go delete mode 100644 meters/meters.go delete mode 100644 meters/meters_test.go delete mode 100644 metrics/default.go delete mode 100644 metrics/http.go delete mode 100644 metrics/jobs.go delete mode 100644 metrics/metrics.go delete mode 100644 metrics/prom.go delete mode 100644 server/server.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1449dc22..cfd2c1d6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -49,13 +49,13 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v4 with: - go-version: '^1.20.7' + go-version: '1.20.12' - run: sudo apt-get install -y gdal-bin - run: go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest - run: git clone https://github.com/interline-io/transitland-lib.git - run: dropdb --if-exists ${PGDATABASE} - run: ${PWD}/transitland-lib/internal/schema/postgres/bootstrap.sh - - run: (cd cmd/tlserver && go install .) + - run: (cd cmd/tlserver && go version && go install .) - run: ./test_setup.sh - run: go test -v -count=1 ./... diff --git a/actions/fetch.go b/actions/fetch.go index 1f178bee..25406e25 100644 --- a/actions/fetch.go +++ b/actions/fetch.go @@ -11,13 +11,13 @@ import ( "time" sq "github.com/Masterminds/squirrel" + "github.com/interline-io/log" "github.com/interline-io/transitland-lib/dmfr/fetch" - "github.com/interline-io/transitland-lib/log" "github.com/interline-io/transitland-lib/rt/pb" "github.com/interline-io/transitland-lib/tl/tt" "github.com/interline-io/transitland-lib/tldb" - "github.com/interline-io/transitland-server/auth/authn" - "github.com/interline-io/transitland-server/auth/authz" + "github.com/interline-io/transitland-mw/auth/authn" + "github.com/interline-io/transitland-mw/auth/authz" "github.com/interline-io/transitland-server/config" "github.com/interline-io/transitland-server/internal/dbutil" "github.com/interline-io/transitland-server/model" @@ -25,7 +25,7 @@ import ( "google.golang.org/protobuf/proto" ) -func StaticFetch(ctx context.Context, cfg config.Config, dbf model.Finder, feedId string, feedSrc io.Reader, feedUrl string, user authn.User, checker model.Checker) (*model.FeedVersionFetchResult, error) { +func StaticFetch(ctx context.Context, cfg config.Config, dbf model.Finder, feedId string, feedSrc io.Reader, feedUrl string, checker model.Checker) (*model.FeedVersionFetchResult, error) { urlType := "static_current" feed, err := fetchCheckFeed(ctx, dbf, checker, feedId, urlType, feedUrl) if err != nil { @@ -45,7 +45,8 @@ func StaticFetch(ctx context.Context, cfg config.Config, dbf model.Finder, feedI FetchedAt: time.Now().In(time.UTC), AllowFTPFetch: true, } - if user != nil { + + if user := authn.ForContext(ctx); user != nil { fetchOpts.CreatedBy = tt.NewString(user.ID()) } diff --git a/actions/fetch_test.go b/actions/fetch_test.go index fc3a9bd5..c1b0d98b 100644 --- a/actions/fetch_test.go +++ b/actions/fetch_test.go @@ -112,7 +112,7 @@ func TestStaticFetchWorker(t *testing.T) { feedUrl := ts.URL + "/" + tc.serveFile testfinder.FindersTxRollback(t, nil, nil, func(te model.Finders) { // Run job - if result, err := StaticFetch(context.Background(), te.Config, te.Finder, tc.feedId, nil, feedUrl, nil, nil); err != nil && !tc.expectError { + if result, err := StaticFetch(context.Background(), te.Config, te.Finder, tc.feedId, nil, feedUrl, nil); err != nil && !tc.expectError { _ = result t.Fatal("unexpected error", err) } else if err == nil && tc.expectError { diff --git a/actions/fv.go b/actions/fv.go index bc135df8..a5956d5a 100644 --- a/actions/fv.go +++ b/actions/fv.go @@ -9,13 +9,12 @@ import ( "github.com/interline-io/transitland-lib/tl" "github.com/interline-io/transitland-lib/tl/tt" "github.com/interline-io/transitland-lib/tldb" - "github.com/interline-io/transitland-server/auth/authn" - "github.com/interline-io/transitland-server/auth/authz" + "github.com/interline-io/transitland-mw/auth/authz" "github.com/interline-io/transitland-server/config" "github.com/interline-io/transitland-server/model" ) -func FeedVersionImport(ctx context.Context, cfg config.Config, dbf model.Finder, checker model.Checker, user authn.User, fvid int) (*model.FeedVersionImportResult, error) { +func FeedVersionImport(ctx context.Context, cfg config.Config, dbf model.Finder, checker model.Checker, fvid int) (*model.FeedVersionImportResult, error) { if checker == nil { return nil, authz.ErrUnauthorized } @@ -39,7 +38,7 @@ func FeedVersionImport(ctx context.Context, cfg config.Config, dbf model.Finder, return &mr, nil } -func FeedVersionUnimport(ctx context.Context, cfg config.Config, dbf model.Finder, checker model.Checker, user authn.User, fvid int) (*model.FeedVersionUnimportResult, error) { +func FeedVersionUnimport(ctx context.Context, cfg config.Config, dbf model.Finder, checker model.Checker, fvid int) (*model.FeedVersionUnimportResult, error) { if checker == nil { return nil, authz.ErrUnauthorized } @@ -60,7 +59,7 @@ func FeedVersionUnimport(ctx context.Context, cfg config.Config, dbf model.Finde return &mr, nil } -func FeedVersionUpdate(ctx context.Context, cfg config.Config, dbf model.Finder, checker model.Checker, user authn.User, fvid int, values model.FeedVersionSetInput) error { +func FeedVersionUpdate(ctx context.Context, cfg config.Config, dbf model.Finder, checker model.Checker, fvid int, values model.FeedVersionSetInput) error { if checker == nil { return authz.ErrUnauthorized } @@ -94,7 +93,7 @@ func FeedVersionUpdate(ctx context.Context, cfg config.Config, dbf model.Finder, return nil } -func FeedVersionDelete(ctx context.Context, cfg config.Config, dbf model.Finder, checker model.Checker, user authn.User, fvid int) (*model.FeedVersionDeleteResult, error) { +func FeedVersionDelete(ctx context.Context, cfg config.Config, dbf model.Finder, checker model.Checker, fvid int) (*model.FeedVersionDeleteResult, error) { if checker == nil { return nil, authz.ErrUnauthorized } diff --git a/actions/validate.go b/actions/validate.go index 6365da7d..bdf8826f 100644 --- a/actions/validate.go +++ b/actions/validate.go @@ -12,7 +12,6 @@ import ( "github.com/interline-io/transitland-lib/tl/tt" "github.com/interline-io/transitland-lib/tlcsv" "github.com/interline-io/transitland-lib/validator" - "github.com/interline-io/transitland-server/auth/authn" "github.com/interline-io/transitland-server/config" "github.com/interline-io/transitland-server/model" ) @@ -22,7 +21,7 @@ type hasGeometries interface { } // ValidateUpload takes a file Reader and produces a validation package containing errors, warnings, file infos, service levels, etc. -func ValidateUpload(ctx context.Context, cfg config.Config, src io.Reader, feedURL *string, rturls []string, user authn.User) (*model.ValidationResult, error) { +func ValidateUpload(ctx context.Context, cfg config.Config, src io.Reader, feedURL *string, rturls []string) (*model.ValidationResult, error) { // Check inputs rturlsok := []string{} for _, rturl := range rturls { diff --git a/auth/ancheck/gatekeeper.go b/auth/ancheck/gatekeeper.go deleted file mode 100644 index bfeb81de..00000000 --- a/auth/ancheck/gatekeeper.go +++ /dev/null @@ -1,169 +0,0 @@ -package ancheck - -import ( - "context" - "errors" - "fmt" - "io" - "net/http" - "net/url" - "time" - - "github.com/go-redis/redis/v8" - "github.com/interline-io/transitland-lib/log" - "github.com/interline-io/transitland-server/auth/authn" - "github.com/interline-io/transitland-server/internal/ecache" - "github.com/interline-io/transitland-server/internal/util" - "github.com/tidwall/gjson" -) - -// GatekeeperMiddleware checks an external endpoint for a list of roles -func GatekeeperMiddleware(client *redis.Client, endpoint string, param string, roleKey string, eidKey string, allowError bool) (MiddlewareFunc, error) { - gk := NewGatekeeper(client, endpoint, param, roleKey, eidKey) - gk.Start(60 * time.Second) - return newGatekeeperMiddleware(gk, allowError), nil -} - -func newGatekeeperMiddleware(gk *Gatekeeper, allowError bool) MiddlewareFunc { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Check context for a user name; if it is present, replace user context with gatekeeper user - ctx := r.Context() - if user := authn.ForContext(ctx); user != nil && user.ID() != "" { - checkUser, err := gk.GetUser(ctx, user.ID()) - if err != nil { - log.Error().Err(err).Msg("gatekeeper error") - if !allowError { - http.Error(w, util.MakeJsonError(http.StatusText(http.StatusUnauthorized)), http.StatusUnauthorized) - return - } - } else if checkUser.ID() != "" { - r = r.WithContext(authn.WithUser(r.Context(), checkUser)) - } - } - next.ServeHTTP(w, r) - }) - } -} - -type Gatekeeper struct { - RequestTimeout time.Duration - endpoint string - roleKey string - eidKey string - param string - recheckTtl time.Duration - cache *ecache.Cache[gkCacheItem] -} - -func NewGatekeeper(client *redis.Client, endpoint string, param string, roleKey string, eidKey string) *Gatekeeper { - gk := &Gatekeeper{ - RequestTimeout: 1 * time.Second, - endpoint: endpoint, - roleKey: roleKey, - eidKey: eidKey, - param: param, - recheckTtl: 5 * 60 * time.Second, - cache: ecache.NewCache[gkCacheItem](client, "gatekeeper"), - } - return gk -} - -func (gk *Gatekeeper) GetUser(ctx context.Context, userKey string) (authn.User, error) { - gkUser, ok := gk.cache.Get(ctx, userKey) - if !ok { - var err error - gkUser, err = gk.updateUser(ctx, userKey) - if err != nil { - return nil, err - } - } - user := authn.NewCtxUser(gkUser.ID, "", "").WithRoles(gkUser.Roles...).WithExternalData(gkUser.ExternalData) - return user, nil -} - -func (gk *Gatekeeper) Start(t time.Duration) { - ticker := time.NewTicker(t) - go func() { - for t := range ticker.C { - _ = t - gk.updateUsers(context.Background()) - } - }() -} - -func (gk *Gatekeeper) updateUsers(ctx context.Context) { - // This can be improved to avoid races - keys := gk.cache.GetRecheckKeys(ctx) - for _, userKey := range keys { - gk.updateUser(ctx, userKey) - } -} - -func (gk *Gatekeeper) updateUser(ctx context.Context, userKey string) (gkCacheItem, error) { - gkUser, err := gk.requestUser(ctx, userKey) - if err != nil { - log.Error().Err(err).Str("user", userKey).Msg("gatekeeper requestUser failed") - return gkUser, err - } - log.Trace().Str("user", userKey).Strs("roles", gkUser.Roles).Any("external_data", gkUser.ExternalData).Msg("gatekeeper requestUser ok") - gk.cache.SetTTL(ctx, userKey, gkUser, gk.recheckTtl, 24*time.Hour) - return gkUser, nil -} - -func (gk *Gatekeeper) requestUser(ctx context.Context, userKey string) (gkCacheItem, error) { - u, _ := url.Parse(gk.endpoint) - rq := u.Query() - rq.Set(gk.param, userKey) - u.RawQuery = rq.Encode() - rctx, cf := context.WithTimeout(ctx, gk.RequestTimeout) - defer cf() - req, err := http.NewRequestWithContext(rctx, "GET", u.String(), nil) - if err != nil { - return gkCacheItem{}, errors.New("invalid request") - } - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - return gkCacheItem{}, err - } - defer resp.Body.Close() - if resp.StatusCode >= 400 { - return gkCacheItem{}, fmt.Errorf("response status code: %d", resp.StatusCode) - } - // Read response - body, err := io.ReadAll(resp.Body) - if err != nil { - return gkCacheItem{}, err - } - if !gjson.Valid(string(body)) { - return gkCacheItem{}, errors.New("invalid json") - } - parsed := gjson.ParseBytes(body) - - // Process roles and external IDs - item := gkCacheItem{ - ID: userKey, - Roles: []string{}, - ExternalData: map[string]string{}, - } - item.ExternalData["gatekeeper"] = string(body) - for _, r := range parsed.Get(gk.roleKey).Array() { - item.Roles = append(item.Roles, r.String()) - // TODO: temporarily map "tl_admin" role to "admin" role. - if r.String() == "tl_admin" { - item.Roles = append(item.Roles, "admin") - } - } - for k, v := range parsed.Get(gk.eidKey).Map() { - item.ExternalData[k] = v.String() - } - return item, nil -} - -// gkCacheItem needed for internal cached representation of ctxUser (Roles/ExternalData as exported fields) -type gkCacheItem struct { - ID string - Roles []string - ExternalData map[string]string -} diff --git a/auth/ancheck/gatekeeper_test.go b/auth/ancheck/gatekeeper_test.go deleted file mode 100644 index d375572f..00000000 --- a/auth/ancheck/gatekeeper_test.go +++ /dev/null @@ -1,297 +0,0 @@ -package ancheck - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - "net/http/httptest" - "sync" - "testing" - "time" - - "github.com/go-redis/redismock/v8" - "github.com/interline-io/transitland-server/auth/authn" - "github.com/interline-io/transitland-server/internal/ecache" - "github.com/stretchr/testify/assert" -) - -func TestGatekeeper(t *testing.T) { - // Mock users - testEmail := "test@transit.land" - testRole := "test_role" - - // Test server - gkts := GatekeeperTestServer{} - gkts.AddUser(testEmail, newCtxUser(testEmail).WithRoles(testRole)) - gkts.AddUser("refresh@transit.land", newCtxUser("refresh@transit.land").WithRoles("refresh_test")) - - // Mock gatekeeper api interface - ts200 := httptest.NewServer(&gkts) - defer ts200.Close() - - // Invalid response with error - tsInvalid := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - t.Log("gatekeeper mock invalid get:", r.URL) - http.Error(w, "error", 500) - })) - defer tsInvalid.Close() - - // Invalid response with 200 OK - tsInvalidOk := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - t.Log("gatekeeper mock invalid 200 get:", r.URL) - w.WriteHeader(200) - w.Write([]byte("not json data")) - })) - defer tsInvalidOk.Close() - - // Close after 10 seconds with no response - tsTimeout := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - t.Log("gatekeeper mock timeout get:", r.URL) - ctx := r.Context() - select { - case <-ctx.Done(): - t.Log("gatekeeper mock timeout: client closed connection") - case <-time.After(10 * time.Second): - t.Log("gatekeeper mock timeout: closing after timeout") - } - })) - defer tsTimeout.Close() - - // Middleware create helpers - gkHelper := func(next http.Handler, em string, endpoint string, param string, roleKey string, eidKey string, allowError bool) http.Handler { - // Does not start update process - gk := NewGatekeeper(nil, endpoint, param, roleKey, eidKey) - return UserDefaultMiddleware(em)(newGatekeeperMiddleware(gk, allowError)(next)) - } - - // Tests - testStartTime := time.Now() - tcs := []struct { - name string - mwf MiddlewareFunc - code int - user authn.User - after func(*testing.T) - }{ - { - "endpoint returns specified roles", - func(next http.Handler) http.Handler { - return gkHelper(next, testEmail, ts200.URL, "user", "roles", "external_ids", false) - }, - 200, - newCtxUser(testEmail).WithRoles(testRole), - nil, - }, - { - "unknown user returns 401", - func(next http.Handler) http.Handler { - return gkHelper(next, "unknown@transit.land", ts200.URL, "user", "roles", "external_ids", false) - }, - 401, - nil, - nil, - }, - { - "locally cached value ok when endpoint available", - func(next http.Handler) http.Handler { - u := gkCacheItem{ID: testEmail, Roles: []string{testRole}} - gk := NewGatekeeper(nil, ts200.URL, "user", "roles", "external_ids") - gk.cache.SetTTL(context.Background(), testEmail, u, 0, 0) - return UserDefaultMiddleware(testEmail)(newGatekeeperMiddleware(gk, false)(next)) - }, - 200, - newCtxUser(testEmail).WithRoles(testRole), - nil, - }, - { - "locally cached value ok when endpoint down", - func(next http.Handler) http.Handler { - u := gkCacheItem{ID: testEmail, Roles: []string{testRole}} - gk := NewGatekeeper(nil, tsTimeout.URL, "user", "roles", "external_ids") - gk.RequestTimeout = 100 * time.Millisecond - gk.cache.SetTTL(context.Background(), testEmail, u, 0, 0) - return UserDefaultMiddleware(testEmail)(newGatekeeperMiddleware(gk, false)(next)) - }, - 200, - newCtxUser(testEmail).WithRoles(testRole), - nil, - }, - { - "unknown user skipped when allowFail = true", - func(next http.Handler) http.Handler { - return gkHelper(next, "other@transit.land", ts200.URL, "user", "roles", "external_ids", true) - }, - 200, - newCtxUser("other@transit.land"), - nil, - }, - { - "invalid data returns 401", - func(next http.Handler) http.Handler { - return gkHelper(next, testEmail, tsInvalidOk.URL, "user", "roles", "external_ids", false) - }, - 401, - nil, - nil, - }, - { - "invalid data allowed when allowFail = true", - func(next http.Handler) http.Handler { - return gkHelper(next, testEmail, tsInvalidOk.URL, "user", "roles", "external_ids", true) - }, - 200, - newCtxUser(testEmail), - nil, - }, - { - "invalid response allowed when allowFail = true", - func(next http.Handler) http.Handler { - return gkHelper(next, "other@transit.land", tsInvalid.URL, "user", "roles", "external_ids", true) - }, - 200, - newCtxUser("other@transit.land"), - nil, - }, - { - "invalid response returns 401", - func(next http.Handler) http.Handler { - return gkHelper(next, "other@transit.land", tsInvalid.URL, "user", "roles", "external_ids", false) - }, - 401, - nil, - nil, - }, - { - "endpoint down, returns 401 after request timeout", - func(next http.Handler) http.Handler { - testStartTime = time.Now() - gk := NewGatekeeper(nil, tsTimeout.URL, "user", "roles", "external_ids") - gk.RequestTimeout = 100 * time.Millisecond - return UserDefaultMiddleware(testEmail)(newGatekeeperMiddleware(gk, false)(next)) - }, - 401, - nil, - func(t *testing.T) { - // Check at least 100ms have elapsed - elapsedTime := time.Now().UnixNano() - testStartTime.UnixNano() - assert.GreaterOrEqual(t, elapsedTime, int64(100*1e6)) // 100*1e6 = 100ms in nanoseconds - t.Log("elapsedTime:", elapsedTime) - }, - }, - { - "endpoint down, ignored when allowFail = true", - func(next http.Handler) http.Handler { - gk := NewGatekeeper(nil, tsTimeout.URL, "user", "roles", "external_ids") - gk.RequestTimeout = 100 * time.Millisecond - return UserDefaultMiddleware(testEmail)(newGatekeeperMiddleware(gk, true)(next)) - }, - 200, - newCtxUser(testEmail), - nil, - }, - { - "redis cached value ok when endpoint down", - func(next http.Handler) http.Handler { - u := gkCacheItem{ID: testEmail, Roles: []string{testRole}} - db, mock := redismock.NewClientMock() - mock.ExpectGet(cacheRedisKey("gatekeeper", testEmail)).SetVal(cacheItemJson(u, 0)) - gk := NewGatekeeper(db, tsTimeout.URL, "user", "roles", "external_ids") - gk.RequestTimeout = 100 * time.Millisecond - return UserDefaultMiddleware(testEmail)(newGatekeeperMiddleware(gk, false)(next)) - }, - 200, - newCtxUser(testEmail).WithRoles(testRole), - nil, - }, - { - "gatekeeper refreshes contexts in background", - func(next http.Handler) http.Handler { - gk := NewGatekeeper(nil, ts200.URL, "user", "roles", "external_ids") - gk.recheckTtl = 1 * time.Millisecond - gk.Start(10 * time.Millisecond) - return UserDefaultMiddleware("refresh@transit.land")(newGatekeeperMiddleware(gk, false)(next)) - }, - 200, - newCtxUser("refresh@transit.land").WithRoles("refresh_test"), - func(t *testing.T) { - // Request count should be at least 10 - time.Sleep(100 * time.Millisecond) - a := gkts.counts["refresh@transit.land"] - assert.GreaterOrEqual(t, a, 10) - }, - }, - } - for _, tc := range tcs { - t.Run(tc.name, func(t *testing.T) { - req := httptest.NewRequest(http.MethodGet, "/", nil) - testAuthMiddleware(t, req, tc.mwf, tc.code, tc.user) - if tc.after != nil { - tc.after(t) - } - }) - } -} - -// Must be the same as ecache -func cacheItemJson(user gkCacheItem, ttl time.Duration) string { - a := ecache.Item[gkCacheItem]{Value: user, ExpiresAt: time.Now().Add(ttl), RecheckAt: time.Now().Add(ttl)} - b, err := json.Marshal(&a) - if err != nil { - panic(err) - } - return string(b) -} - -// This must be the same as ecache.redisKey -func cacheRedisKey(topic string, key string) string { - return fmt.Sprintf("ecache:%s:%s", topic, key) -} - -////////// - -// Trivial implementation of Gatekeeper for testing purposes -type GatekeeperTestServer struct { - users map[string]authn.User - counts map[string]int - lock sync.Mutex -} - -func (gk *GatekeeperTestServer) AddUser(key string, user authn.User) { - gk.lock.Lock() - defer gk.lock.Unlock() - if gk.users == nil { - gk.users = map[string]authn.User{} - } - gk.users[key] = newCtxUser(user.ID()).WithRoles(user.Roles()...) -} - -func (gk *GatekeeperTestServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { - gk.lock.Lock() - defer gk.lock.Unlock() - u := r.URL.Query() - var user authn.User - if a := u["user"]; len(a) > 0 { - user = gk.users[a[0]] - } - if user != nil { - if gk.counts == nil { - gk.counts = map[string]int{} - } - gk.counts[user.ID()] += 1 - umap := map[string]any{ - "id": user.ID(), - "name": user.Name(), - "email": user.Email(), - "roles": user.Roles(), - } - jb, err := json.Marshal(umap) - if err != nil { - http.Error(w, "json error", 500) - } - w.WriteHeader(200) - w.Write(jb) - return - } - http.Error(w, "error", 404) -} diff --git a/auth/ancheck/jwt.go b/auth/ancheck/jwt.go deleted file mode 100644 index 5eb6ba44..00000000 --- a/auth/ancheck/jwt.go +++ /dev/null @@ -1,78 +0,0 @@ -package ancheck - -import ( - "crypto/rsa" - "errors" - "io/ioutil" - "net/http" - "strings" - - "github.com/form3tech-oss/jwt-go" - "github.com/interline-io/transitland-lib/log" - "github.com/interline-io/transitland-server/auth/authn" - "github.com/interline-io/transitland-server/internal/util" -) - -// JWTMiddleware checks and pulls user information from JWT in Authorization header. -func JWTMiddleware(jwtAudience string, jwtIssuer string, pubKeyPath string, useEmailAsId bool) (func(http.Handler) http.Handler, error) { - var verifyKey *rsa.PublicKey - verifyBytes, err := ioutil.ReadFile(pubKeyPath) - if err != nil { - return nil, err - } - verifyKey, err = jwt.ParseRSAPublicKeyFromPEM(verifyBytes) - if err != nil { - return nil, err - } - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if tokenString := strings.Split(r.Header.Get("Authorization"), "Bearer "); len(tokenString) == 2 { - claims, err := validateJwt(verifyKey, jwtAudience, jwtIssuer, tokenString[1]) - if err != nil { - log.Error().Err(err).Msgf("invalid jwt token") - http.Error(w, util.MakeJsonError(http.StatusText(http.StatusUnauthorized)), http.StatusUnauthorized) - return - } - if claims == nil { - log.Error().Err(err).Msgf("no claims") - http.Error(w, util.MakeJsonError(http.StatusText(http.StatusUnauthorized)), http.StatusUnauthorized) - return - } - userId := claims.Subject - if useEmailAsId { - userId = claims.Email - } - jwtUser := authn.NewCtxUser(userId, claims.Subject, claims.Email) - r = r.WithContext(authn.WithUser(r.Context(), jwtUser)) - } - next.ServeHTTP(w, r) - }) - }, nil -} - -type CustomClaimsExample struct { - Email string - jwt.StandardClaims -} - -func (c *CustomClaimsExample) Valid() error { - return nil -} - -func validateJwt(rsaPublicKey *rsa.PublicKey, jwtAudience string, jwtIssuer string, tokenString string) (*CustomClaimsExample, error) { - // Parse the token - token, err := jwt.ParseWithClaims(tokenString, &CustomClaimsExample{}, func(token *jwt.Token) (interface{}, error) { - return rsaPublicKey, nil - }) - if err != nil { - return nil, err - } - claims := token.Claims.(*CustomClaimsExample) - if !claims.VerifyAudience(jwtAudience, true) { - return nil, errors.New("invalid audience") - } - if !claims.VerifyIssuer(jwtIssuer, true) { - return nil, errors.New("invalid issuer") - } - return claims, nil -} diff --git a/auth/ancheck/jwt_test.go b/auth/ancheck/jwt_test.go deleted file mode 100644 index feea0a63..00000000 --- a/auth/ancheck/jwt_test.go +++ /dev/null @@ -1,7 +0,0 @@ -package ancheck - -import "testing" - -func TestJWTMiddleware(t *testing.T) { - // TODO -} diff --git a/auth/ancheck/mw.go b/auth/ancheck/mw.go deleted file mode 100644 index 5b7ab121..00000000 --- a/auth/ancheck/mw.go +++ /dev/null @@ -1,92 +0,0 @@ -package ancheck - -import ( - "net/http" - - "github.com/go-redis/redis/v8" - "github.com/interline-io/transitland-server/auth/authn" - "github.com/interline-io/transitland-server/internal/util" -) - -type MiddlewareFunc func(http.Handler) http.Handler - -type AuthConfig struct { - DefaultUsername string - GatekeeperEndpoint string - GatekeeperParam string - GatekeeperRoleSelector string - GatekeeperExternalIDSelector string - GatekeeperAllowError bool - JwtAudience string - JwtIssuer string - JwtPublicKeyFile string - JwtUseEmailAsId bool - UserHeader string -} - -// GetUserMiddleware returns a middleware that sets user details. -func GetUserMiddleware(authType string, cfg AuthConfig, client *redis.Client) (MiddlewareFunc, error) { - // Setup auth; default is all users will be anonymous. - switch authType { - case "admin": - return AdminDefaultMiddleware(cfg.DefaultUsername), nil - case "user": - return UserDefaultMiddleware(cfg.DefaultUsername), nil - case "jwt": - return JWTMiddleware(cfg.JwtAudience, cfg.JwtIssuer, cfg.JwtPublicKeyFile, cfg.JwtUseEmailAsId) - case "header": - return UserHeaderMiddleware(cfg.UserHeader) - case "kong": - return UserHeaderMiddleware("x-consumer-username") - case "gatekeeper": - return GatekeeperMiddleware(client, cfg.GatekeeperEndpoint, cfg.GatekeeperParam, cfg.GatekeeperRoleSelector, cfg.GatekeeperExternalIDSelector, cfg.GatekeeperAllowError) - } - return func(next http.Handler) http.Handler { - return next - }, nil -} - -// AdminDefaultMiddleware uses a default "admin" context. -func AdminDefaultMiddleware(defaultName string) func(http.Handler) http.Handler { - return NewUserDefaultMiddleware(func() authn.User { return authn.NewCtxUser(defaultName, "", "").WithRoles("admin") }) -} - -// UserDefaultMiddleware uses a default "user" context. -func UserDefaultMiddleware(defaultName string) func(http.Handler) http.Handler { - return NewUserDefaultMiddleware(func() authn.User { return authn.NewCtxUser(defaultName, "", "") }) -} - -// NewUserDefaultMiddleware uses a default "user" context. -func NewUserDefaultMiddleware(cb func() authn.User) func(http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - user := cb() - r = r.WithContext(authn.WithUser(r.Context(), user)) - next.ServeHTTP(w, r) - }) - } -} - -// AdminRequired limits a request to admin privileges. -func AdminRequired(next http.Handler) http.Handler { - return RoleRequired("admin")(next) -} - -// UserRequired limits a request to user privileges. -func UserRequired(next http.Handler) http.Handler { - return RoleRequired("user")(next) -} - -func RoleRequired(role string) func(http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - user := authn.ForContext(ctx) - if user == nil || !user.HasRole(role) { - http.Error(w, util.MakeJsonError(http.StatusText(http.StatusUnauthorized)), http.StatusUnauthorized) - return - } - next.ServeHTTP(w, r) - }) - } -} diff --git a/auth/ancheck/mw_test.go b/auth/ancheck/mw_test.go deleted file mode 100644 index db95c4e5..00000000 --- a/auth/ancheck/mw_test.go +++ /dev/null @@ -1,98 +0,0 @@ -package ancheck - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/interline-io/transitland-server/auth/authn" - "github.com/stretchr/testify/assert" -) - -func newCtxUser(id string) authn.CtxUser { - return authn.NewCtxUser(id, "", "") -} - -func TestUserMiddleware(t *testing.T) { - a := UserDefaultMiddleware("test") - req := httptest.NewRequest(http.MethodGet, "/", nil) - testAuthMiddleware(t, req, a, 200, authn.NewCtxUser("test", "", "")) -} - -func TestAdminMiddleware(t *testing.T) { - a := AdminDefaultMiddleware("test") - req := httptest.NewRequest(http.MethodGet, "/", nil) - testAuthMiddleware(t, req, a, 200, authn.NewCtxUser("test", "", "").WithRoles("admin")) -} - -func TestNoMiddleware(t *testing.T) { - a, err := GetUserMiddleware("", AuthConfig{}, nil) - if err != nil { - t.Fatal(err) - } - req := httptest.NewRequest(http.MethodGet, "/", nil) - testAuthMiddleware(t, req, a, 200, nil) -} - -func testAuthMiddleware(t *testing.T, req *http.Request, mwf MiddlewareFunc, expectCode int, expectUser authn.User) { - var user authn.User - testHandler := func(w http.ResponseWriter, r *http.Request) { - user = authn.ForContext(r.Context()) - } - router := http.NewServeMux() - router.HandleFunc("/", testHandler) - // - a := mwf(router) - w := httptest.NewRecorder() - a.ServeHTTP(w, req) - // - assert.Equal(t, expectCode, w.Result().StatusCode) - if expectUser != nil && user != nil { - assert.Equal(t, expectUser.ID(), user.ID()) - for _, checkRole := range expectUser.Roles() { - assert.Equalf(t, true, user.HasRole(checkRole), "checking role '%s'", checkRole) - } - } else if expectUser == nil && user != nil { - t.Errorf("got user, expected none") - } else if expectUser != nil && user == nil { - t.Errorf("got no user, expected user") - } -} - -func TestUserRequired(t *testing.T) { - tcs := []struct { - name string - mwf MiddlewareFunc - code int - user authn.User - }{ - {"with user", func(next http.Handler) http.Handler { return AdminDefaultMiddleware("test")(UserRequired(next)) }, 200, newCtxUser("test").WithRoles("admin")}, - {"with user", func(next http.Handler) http.Handler { return UserDefaultMiddleware("test")(UserRequired(next)) }, 200, newCtxUser("test")}, - {"no user", func(next http.Handler) http.Handler { return UserRequired(next) }, 401, nil}, - } - for _, tc := range tcs { - t.Run(tc.name, func(t *testing.T) { - req := httptest.NewRequest(http.MethodGet, "/", nil) - testAuthMiddleware(t, req, tc.mwf, tc.code, tc.user) - }) - } -} - -func TestAdminRequired(t *testing.T) { - tcs := []struct { - name string - mwf MiddlewareFunc - code int - user authn.User - }{ - {"with admin", func(next http.Handler) http.Handler { return AdminDefaultMiddleware("test")(AdminRequired(next)) }, 200, newCtxUser("test").WithRoles("admin")}, - {"with user", func(next http.Handler) http.Handler { return UserDefaultMiddleware("test")(AdminRequired(next)) }, 401, nil}, // mw kills request before handler - {"no user", func(next http.Handler) http.Handler { return AdminRequired(next) }, 401, nil}, - } - for _, tc := range tcs { - t.Run(tc.name, func(t *testing.T) { - req := httptest.NewRequest(http.MethodGet, "/", nil) - testAuthMiddleware(t, req, tc.mwf, tc.code, tc.user) - }) - } -} diff --git a/auth/ancheck/user_header.go b/auth/ancheck/user_header.go deleted file mode 100644 index 0362a698..00000000 --- a/auth/ancheck/user_header.go +++ /dev/null @@ -1,20 +0,0 @@ -package ancheck - -import ( - "net/http" - - "github.com/interline-io/transitland-server/auth/authn" -) - -// UserHeaderMiddleware checks and pulls user ID from specified headers. -func UserHeaderMiddleware(header string) (func(http.Handler) http.Handler, error) { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if v := r.Header.Get(header); v != "" { - user := authn.NewCtxUser(v, "", "") - r = r.WithContext(authn.WithUser(r.Context(), user)) - } - next.ServeHTTP(w, r) - }) - }, nil -} diff --git a/auth/ancheck/user_header_test.go b/auth/ancheck/user_header_test.go deleted file mode 100644 index 4a5f2eb7..00000000 --- a/auth/ancheck/user_header_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package ancheck - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/interline-io/transitland-server/auth/authn" -) - -func TestKongMiddleware(t *testing.T) { - tcs := []struct { - name string - consumerId string - code int - user authn.User - }{ - {"test", "test@transitland", 200, newCtxUser("test@transitland")}, - {"no user", "", 200, nil}, - } - for _, tc := range tcs { - t.Run(tc.name, func(t *testing.T) { - mf, err := UserHeaderMiddleware("x-consumer-username") - if err != nil { - t.Fatal(err) - } - req := httptest.NewRequest(http.MethodGet, "/", nil) - if tc.consumerId != "" { - req.Header.Add("x-consumer-username", tc.consumerId) - } - testAuthMiddleware(t, req, mf, tc.code, tc.user) - }) - } -} diff --git a/auth/auth0/auth0.go b/auth/auth0/auth0.go deleted file mode 100644 index 13bac11c..00000000 --- a/auth/auth0/auth0.go +++ /dev/null @@ -1,56 +0,0 @@ -package auth0 - -import ( - "context" - "fmt" - - "github.com/auth0/go-auth0/management" - "github.com/interline-io/transitland-server/auth/authn" -) - -type Auth0Client struct { - client *management.Management - Connection string -} - -func NewAuth0Client(domain string, clientId string, clientSecret string) (*Auth0Client, error) { - auth0API, err := management.New( - domain, - management.WithClientCredentials(clientId, clientSecret), - ) - if err != nil { - return nil, err - } - return &Auth0Client{client: auth0API}, nil -} - -func (c *Auth0Client) UserByID(ctx context.Context, id string) (authn.User, error) { - user, err := c.client.User.Read(id) - if err != nil { - return nil, err - } - u := authn.NewCtxUser(user.GetID(), user.GetName(), user.GetEmail()) - return u, nil -} - -func (c *Auth0Client) Users(ctx context.Context, userQuery string) ([]authn.User, error) { - if userQuery != "" { - userQuery = fmt.Sprintf(`*%s*`, userQuery) - } - if c.Connection != "" { - if userQuery != "" { - userQuery = fmt.Sprintf(`identities.connection:"%s" AND %s`, c.Connection, userQuery) - } else { - userQuery = fmt.Sprintf(`identities.connection:"%s"`, c.Connection) - } - } - ul, err := c.client.User.List(management.Query(userQuery)) - if err != nil { - return nil, err - } - var ret []authn.User - for _, user := range ul.Users { - ret = append(ret, authn.NewCtxUser(user.GetID(), user.GetName(), user.GetEmail())) - } - return ret, nil -} diff --git a/auth/auth0/auth0_test.go b/auth/auth0/auth0_test.go deleted file mode 100644 index 951122c8..00000000 --- a/auth/auth0/auth0_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package auth0 - -import ( - "testing" - - "github.com/interline-io/transitland-server/internal/testutil" -) - -func TestAuth0Client(t *testing.T) { - _, a, ok := testutil.CheckEnv("TL_TEST_AUTH0_DOMAIN") - if !ok { - t.Skip(a) - return - } -} diff --git a/auth/authn/authn.go b/auth/authn/authn.go deleted file mode 100644 index c156de42..00000000 --- a/auth/authn/authn.go +++ /dev/null @@ -1,35 +0,0 @@ -package authn - -import "context" - -// User provides access to key user metadata and roles. -type User interface { - ID() string - Name() string - Email() string - Roles() []string - HasRole(string) bool - GetExternalData(string) (string, bool) -} - -// A private key for context that only this package can access. This is important -// to prevent collisions between different context uses -var ctxUserKey = &contextKey{"user"} - -type contextKey struct { - name string -} - -// ForContext finds the user from the context. REQUIRES Middleware to have run. -func ForContext(ctx context.Context) User { - raw, ok := ctx.Value(ctxUserKey).(User) - if !ok { - return nil - } - return raw -} - -func WithUser(ctx context.Context, user User) context.Context { - r := context.WithValue(ctx, ctxUserKey, user) - return r -} diff --git a/auth/authn/user.go b/auth/authn/user.go deleted file mode 100644 index 8e086d49..00000000 --- a/auth/authn/user.go +++ /dev/null @@ -1,108 +0,0 @@ -package authn - -import ( - "strings" -) - -// User is the base user implementation. -type CtxUser struct { - id string - name string - email string - valid bool - roles map[string]bool - externalData map[string]string -} - -func NewCtxUser(id string, name string, email string) CtxUser { - a := newCtxUserWith(id, name, email, nil, nil) - return a -} - -func newCtxUserWith(id string, name string, email string, roles map[string]bool, externalData map[string]string) CtxUser { - u := CtxUser{ - id: id, - name: name, - email: email, - valid: true, - roles: map[string]bool{}, - externalData: map[string]string{}, - } - for k, v := range roles { - u.roles[k] = v - } - for k, v := range externalData { - u.externalData[k] = v - } - return u -} - -func (user CtxUser) clone() CtxUser { - return newCtxUserWith(user.id, user.name, user.email, user.roles, user.externalData) -} - -func (user CtxUser) Name() string { - return user.name -} - -func (user CtxUser) ID() string { - return user.id -} - -func (user CtxUser) Email() string { - return user.email -} - -func (user CtxUser) IsValid() bool { - return user.valid -} - -func (user CtxUser) GetExternalData(eid string) (string, bool) { - a, ok := user.externalData[eid] - return a, ok -} - -func (user CtxUser) WithExternalData(m map[string]string) CtxUser { - newUser := user.clone() - for k, v := range m { - newUser.externalData[k] = v - } - return newUser -} - -func (user CtxUser) WithRoles(roles ...string) CtxUser { - newUser := user.clone() - for _, v := range roles { - newUser.roles[v] = true - } - return newUser -} - -// HasRole checks if a User is allowed to use a defined role. -func (user CtxUser) HasRole(role string) bool { - if user.hasRole("admin") { - return true - } - checkRole := strings.ToLower(role) - // Check for original roles - switch checkRole { - case "anon": - return true - case "user": - return user.id != "" - } - // Check all other roles - return user.hasRole(checkRole) -} - -func (user CtxUser) hasRole(checkRole string) bool { - return user.roles[checkRole] -} - -func (user CtxUser) Roles() []string { - var keys []string - for k := range user.roles { - keys = append(keys, k) - } - return keys -} diff --git a/auth/authn/user_test.go b/auth/authn/user_test.go deleted file mode 100644 index 331d2be0..00000000 --- a/auth/authn/user_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package authn - -import ( - "testing" - - "github.com/interline-io/transitland-server/model" -) - -func TestUser_HasRole(t *testing.T) { - testcases := []struct { - name string - user User - role model.Role - hasRole bool - }{ - {"anon", NewCtxUser("", "", ""), model.RoleAnon, true}, - {"anon", NewCtxUser("test", "", ""), model.RoleAnon, true}, - {"anon", NewCtxUser("test", "", "").WithRoles("admin"), model.RoleAnon, true}, - - {"user", NewCtxUser("", "", ""), model.RoleUser, false}, - {"user", NewCtxUser("test", "", ""), model.RoleUser, true}, - {"user", NewCtxUser("test", "", "").WithRoles("admin"), model.RoleUser, true}, - - {"admin", NewCtxUser("", "", ""), model.RoleAdmin, false}, - {"admin", NewCtxUser("", "", ""), model.RoleAdmin, false}, - {"admin", NewCtxUser("test", "", ""), model.RoleAdmin, false}, - {"admin", NewCtxUser("test", "", ""), model.RoleAdmin, false}, - {"admin", NewCtxUser("test", "", "").WithRoles("admin"), model.RoleAdmin, true}, - - {"other roles", NewCtxUser("test", "", "").WithRoles("tlv2-admin"), model.Role("tlv2-admin"), true}, - } - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - if tc.user.HasRole(string(tc.role)) != tc.hasRole { - t.Errorf("expected role %s to be %t", tc.role, tc.hasRole) - } - }) - } -} diff --git a/auth/authz/azpb.pb.go b/auth/authz/azpb.pb.go deleted file mode 100644 index 390170f6..00000000 --- a/auth/authz/azpb.pb.go +++ /dev/null @@ -1,4414 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.30.0 -// protoc v4.23.3 -// source: azpb.proto - -package authz - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type Action int32 - -const ( - Action_empty_action Action = 0 - Action_can_view Action = 1 - Action_can_edit Action = 2 - Action_can_edit_members Action = 3 - Action_can_create_org Action = 4 - Action_can_delete_org Action = 5 - Action_can_create_feed_version Action = 6 - Action_can_delete_feed_version Action = 7 - Action_can_create_feed Action = 8 - Action_can_delete_feed Action = 9 - Action_can_set_group Action = 10 - Action_can_set_tenant Action = 11 -) - -// Enum value maps for Action. -var ( - Action_name = map[int32]string{ - 0: "empty_action", - 1: "can_view", - 2: "can_edit", - 3: "can_edit_members", - 4: "can_create_org", - 5: "can_delete_org", - 6: "can_create_feed_version", - 7: "can_delete_feed_version", - 8: "can_create_feed", - 9: "can_delete_feed", - 10: "can_set_group", - 11: "can_set_tenant", - } - Action_value = map[string]int32{ - "empty_action": 0, - "can_view": 1, - "can_edit": 2, - "can_edit_members": 3, - "can_create_org": 4, - "can_delete_org": 5, - "can_create_feed_version": 6, - "can_delete_feed_version": 7, - "can_create_feed": 8, - "can_delete_feed": 9, - "can_set_group": 10, - "can_set_tenant": 11, - } -) - -func (x Action) Enum() *Action { - p := new(Action) - *p = x - return p -} - -func (x Action) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (Action) Descriptor() protoreflect.EnumDescriptor { - return file_azpb_proto_enumTypes[0].Descriptor() -} - -func (Action) Type() protoreflect.EnumType { - return &file_azpb_proto_enumTypes[0] -} - -func (x Action) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use Action.Descriptor instead. -func (Action) EnumDescriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{0} -} - -type ObjectType int32 - -const ( - ObjectType_empty_object ObjectType = 0 - ObjectType_tenant ObjectType = 1 - ObjectType_org ObjectType = 2 - ObjectType_feed ObjectType = 3 - ObjectType_feed_version ObjectType = 4 - ObjectType_user ObjectType = 5 -) - -// Enum value maps for ObjectType. -var ( - ObjectType_name = map[int32]string{ - 0: "empty_object", - 1: "tenant", - 2: "org", - 3: "feed", - 4: "feed_version", - 5: "user", - } - ObjectType_value = map[string]int32{ - "empty_object": 0, - "tenant": 1, - "org": 2, - "feed": 3, - "feed_version": 4, - "user": 5, - } -) - -func (x ObjectType) Enum() *ObjectType { - p := new(ObjectType) - *p = x - return p -} - -func (x ObjectType) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (ObjectType) Descriptor() protoreflect.EnumDescriptor { - return file_azpb_proto_enumTypes[1].Descriptor() -} - -func (ObjectType) Type() protoreflect.EnumType { - return &file_azpb_proto_enumTypes[1] -} - -func (x ObjectType) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use ObjectType.Descriptor instead. -func (ObjectType) EnumDescriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{1} -} - -type Relation int32 - -const ( - Relation_empty_relation Relation = 0 - Relation_admin Relation = 1 - Relation_member Relation = 2 - Relation_manager Relation = 3 - Relation_viewer Relation = 4 - Relation_editor Relation = 5 - Relation_parent Relation = 6 -) - -// Enum value maps for Relation. -var ( - Relation_name = map[int32]string{ - 0: "empty_relation", - 1: "admin", - 2: "member", - 3: "manager", - 4: "viewer", - 5: "editor", - 6: "parent", - } - Relation_value = map[string]int32{ - "empty_relation": 0, - "admin": 1, - "member": 2, - "manager": 3, - "viewer": 4, - "editor": 5, - "parent": 6, - } -) - -func (x Relation) Enum() *Relation { - p := new(Relation) - *p = x - return p -} - -func (x Relation) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (Relation) Descriptor() protoreflect.EnumDescriptor { - return file_azpb_proto_enumTypes[2].Descriptor() -} - -func (Relation) Type() protoreflect.EnumType { - return &file_azpb_proto_enumTypes[2] -} - -func (x Relation) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use Relation.Descriptor instead. -func (Relation) EnumDescriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{2} -} - -type EntityRelation struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Type ObjectType `protobuf:"varint,1,opt,name=type,proto3,enum=azpb.ObjectType" json:"type,omitempty"` - Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` - RefRelation Relation `protobuf:"varint,4,opt,name=ref_relation,json=refRelation,proto3,enum=azpb.Relation" json:"ref_relation,omitempty"` - Relation Relation `protobuf:"varint,5,opt,name=relation,proto3,enum=azpb.Relation" json:"relation,omitempty"` -} - -func (x *EntityRelation) Reset() { - *x = EntityRelation{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *EntityRelation) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*EntityRelation) ProtoMessage() {} - -func (x *EntityRelation) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use EntityRelation.ProtoReflect.Descriptor instead. -func (*EntityRelation) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{0} -} - -func (x *EntityRelation) GetType() ObjectType { - if x != nil { - return x.Type - } - return ObjectType_empty_object -} - -func (x *EntityRelation) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *EntityRelation) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *EntityRelation) GetRefRelation() Relation { - if x != nil { - return x.RefRelation - } - return Relation_empty_relation -} - -func (x *EntityRelation) GetRelation() Relation { - if x != nil { - return x.Relation - } - return Relation_empty_relation -} - -type User struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` -} - -func (x *User) Reset() { - *x = User{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *User) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*User) ProtoMessage() {} - -func (x *User) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use User.ProtoReflect.Descriptor instead. -func (*User) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{1} -} - -func (x *User) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *User) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *User) GetEmail() string { - if x != nil { - return x.Email - } - return "" -} - -type UserListRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Q string `protobuf:"bytes,1,opt,name=q,proto3" json:"q,omitempty"` -} - -func (x *UserListRequest) Reset() { - *x = UserListRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UserListRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UserListRequest) ProtoMessage() {} - -func (x *UserListRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UserListRequest.ProtoReflect.Descriptor instead. -func (*UserListRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{2} -} - -func (x *UserListRequest) GetQ() string { - if x != nil { - return x.Q - } - return "" -} - -type UserRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` -} - -func (x *UserRequest) Reset() { - *x = UserRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UserRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UserRequest) ProtoMessage() {} - -func (x *UserRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UserRequest.ProtoReflect.Descriptor instead. -func (*UserRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{3} -} - -func (x *UserRequest) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -type UserListResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Users []*User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"` -} - -func (x *UserListResponse) Reset() { - *x = UserListResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UserListResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UserListResponse) ProtoMessage() {} - -func (x *UserListResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UserListResponse.ProtoReflect.Descriptor instead. -func (*UserListResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{4} -} - -func (x *UserListResponse) GetUsers() []*User { - if x != nil { - return x.Users - } - return nil -} - -type UserResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` -} - -func (x *UserResponse) Reset() { - *x = UserResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UserResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UserResponse) ProtoMessage() {} - -func (x *UserResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UserResponse.ProtoReflect.Descriptor instead. -func (*UserResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{5} -} - -func (x *UserResponse) GetUser() *User { - if x != nil { - return x.User - } - return nil -} - -type MeRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *MeRequest) Reset() { - *x = MeRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *MeRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MeRequest) ProtoMessage() {} - -func (x *MeRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MeRequest.ProtoReflect.Descriptor instead. -func (*MeRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{6} -} - -type MeResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` - Groups []*Group `protobuf:"bytes,2,rep,name=groups,proto3" json:"groups,omitempty"` - ExpandedGroups []*Group `protobuf:"bytes,3,rep,name=expanded_groups,json=expandedGroups,proto3" json:"expanded_groups,omitempty"` - ExternalData map[string]string `protobuf:"bytes,4,rep,name=external_data,json=externalData,proto3" json:"external_data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - Roles []string `protobuf:"bytes,5,rep,name=roles,proto3" json:"roles,omitempty"` -} - -func (x *MeResponse) Reset() { - *x = MeResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *MeResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MeResponse) ProtoMessage() {} - -func (x *MeResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MeResponse.ProtoReflect.Descriptor instead. -func (*MeResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{7} -} - -func (x *MeResponse) GetUser() *User { - if x != nil { - return x.User - } - return nil -} - -func (x *MeResponse) GetGroups() []*Group { - if x != nil { - return x.Groups - } - return nil -} - -func (x *MeResponse) GetExpandedGroups() []*Group { - if x != nil { - return x.ExpandedGroups - } - return nil -} - -func (x *MeResponse) GetExternalData() map[string]string { - if x != nil { - return x.ExternalData - } - return nil -} - -func (x *MeResponse) GetRoles() []string { - if x != nil { - return x.Roles - } - return nil -} - -type Tenant struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` -} - -func (x *Tenant) Reset() { - *x = Tenant{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Tenant) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Tenant) ProtoMessage() {} - -func (x *Tenant) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Tenant.ProtoReflect.Descriptor instead. -func (*Tenant) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{8} -} - -func (x *Tenant) GetId() int64 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *Tenant) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -type TenantSaveRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Tenant *Tenant `protobuf:"bytes,1,opt,name=tenant,proto3" json:"tenant,omitempty"` -} - -func (x *TenantSaveRequest) Reset() { - *x = TenantSaveRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TenantSaveRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TenantSaveRequest) ProtoMessage() {} - -func (x *TenantSaveRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TenantSaveRequest.ProtoReflect.Descriptor instead. -func (*TenantSaveRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{9} -} - -func (x *TenantSaveRequest) GetTenant() *Tenant { - if x != nil { - return x.Tenant - } - return nil -} - -type TenantRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` -} - -func (x *TenantRequest) Reset() { - *x = TenantRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TenantRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TenantRequest) ProtoMessage() {} - -func (x *TenantRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TenantRequest.ProtoReflect.Descriptor instead. -func (*TenantRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{10} -} - -func (x *TenantRequest) GetId() int64 { - if x != nil { - return x.Id - } - return 0 -} - -type TenantListRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *TenantListRequest) Reset() { - *x = TenantListRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TenantListRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TenantListRequest) ProtoMessage() {} - -func (x *TenantListRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TenantListRequest.ProtoReflect.Descriptor instead. -func (*TenantListRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{11} -} - -type TenantResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Tenant *Tenant `protobuf:"bytes,1,opt,name=tenant,proto3" json:"tenant,omitempty"` -} - -func (x *TenantResponse) Reset() { - *x = TenantResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TenantResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TenantResponse) ProtoMessage() {} - -func (x *TenantResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TenantResponse.ProtoReflect.Descriptor instead. -func (*TenantResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{12} -} - -func (x *TenantResponse) GetTenant() *Tenant { - if x != nil { - return x.Tenant - } - return nil -} - -type TenantListResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Tenants []*Tenant `protobuf:"bytes,1,rep,name=tenants,proto3" json:"tenants,omitempty"` -} - -func (x *TenantListResponse) Reset() { - *x = TenantListResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TenantListResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TenantListResponse) ProtoMessage() {} - -func (x *TenantListResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TenantListResponse.ProtoReflect.Descriptor instead. -func (*TenantListResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{13} -} - -func (x *TenantListResponse) GetTenants() []*Tenant { - if x != nil { - return x.Tenants - } - return nil -} - -type TenantPermissionsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Tenant *Tenant `protobuf:"bytes,1,opt,name=tenant,proto3" json:"tenant,omitempty"` - Groups []*Group `protobuf:"bytes,2,rep,name=groups,proto3" json:"groups,omitempty"` - Actions *TenantPermissionsResponse_Actions `protobuf:"bytes,3,opt,name=actions,proto3" json:"actions,omitempty"` - Users *TenantPermissionsResponse_Users `protobuf:"bytes,4,opt,name=users,proto3" json:"users,omitempty"` -} - -func (x *TenantPermissionsResponse) Reset() { - *x = TenantPermissionsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TenantPermissionsResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TenantPermissionsResponse) ProtoMessage() {} - -func (x *TenantPermissionsResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TenantPermissionsResponse.ProtoReflect.Descriptor instead. -func (*TenantPermissionsResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{14} -} - -func (x *TenantPermissionsResponse) GetTenant() *Tenant { - if x != nil { - return x.Tenant - } - return nil -} - -func (x *TenantPermissionsResponse) GetGroups() []*Group { - if x != nil { - return x.Groups - } - return nil -} - -func (x *TenantPermissionsResponse) GetActions() *TenantPermissionsResponse_Actions { - if x != nil { - return x.Actions - } - return nil -} - -func (x *TenantPermissionsResponse) GetUsers() *TenantPermissionsResponse_Users { - if x != nil { - return x.Users - } - return nil -} - -type TenantCreateRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *TenantCreateRequest) Reset() { - *x = TenantCreateRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TenantCreateRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TenantCreateRequest) ProtoMessage() {} - -func (x *TenantCreateRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TenantCreateRequest.ProtoReflect.Descriptor instead. -func (*TenantCreateRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{15} -} - -type TenantCreateGroupRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - Group *Group `protobuf:"bytes,2,opt,name=group,proto3" json:"group,omitempty"` -} - -func (x *TenantCreateGroupRequest) Reset() { - *x = TenantCreateGroupRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[16] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TenantCreateGroupRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TenantCreateGroupRequest) ProtoMessage() {} - -func (x *TenantCreateGroupRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[16] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TenantCreateGroupRequest.ProtoReflect.Descriptor instead. -func (*TenantCreateGroupRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{16} -} - -func (x *TenantCreateGroupRequest) GetId() int64 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *TenantCreateGroupRequest) GetGroup() *Group { - if x != nil { - return x.Group - } - return nil -} - -type TenantCreateGroupResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Group *Group `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` -} - -func (x *TenantCreateGroupResponse) Reset() { - *x = TenantCreateGroupResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[17] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TenantCreateGroupResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TenantCreateGroupResponse) ProtoMessage() {} - -func (x *TenantCreateGroupResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[17] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TenantCreateGroupResponse.ProtoReflect.Descriptor instead. -func (*TenantCreateGroupResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{17} -} - -func (x *TenantCreateGroupResponse) GetGroup() *Group { - if x != nil { - return x.Group - } - return nil -} - -type TenantModifyPermissionRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - EntityRelation *EntityRelation `protobuf:"bytes,2,opt,name=entity_relation,json=entityRelation,proto3" json:"entity_relation,omitempty"` -} - -func (x *TenantModifyPermissionRequest) Reset() { - *x = TenantModifyPermissionRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[18] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TenantModifyPermissionRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TenantModifyPermissionRequest) ProtoMessage() {} - -func (x *TenantModifyPermissionRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[18] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TenantModifyPermissionRequest.ProtoReflect.Descriptor instead. -func (*TenantModifyPermissionRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{18} -} - -func (x *TenantModifyPermissionRequest) GetId() int64 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *TenantModifyPermissionRequest) GetEntityRelation() *EntityRelation { - if x != nil { - return x.EntityRelation - } - return nil -} - -type TenantSaveResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *TenantSaveResponse) Reset() { - *x = TenantSaveResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[19] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TenantSaveResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TenantSaveResponse) ProtoMessage() {} - -func (x *TenantSaveResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[19] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TenantSaveResponse.ProtoReflect.Descriptor instead. -func (*TenantSaveResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{19} -} - -type Group struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` -} - -func (x *Group) Reset() { - *x = Group{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[20] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Group) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Group) ProtoMessage() {} - -func (x *Group) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[20] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Group.ProtoReflect.Descriptor instead. -func (*Group) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{20} -} - -func (x *Group) GetId() int64 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *Group) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -type GroupRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` -} - -func (x *GroupRequest) Reset() { - *x = GroupRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[21] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GroupRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupRequest) ProtoMessage() {} - -func (x *GroupRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[21] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GroupRequest.ProtoReflect.Descriptor instead. -func (*GroupRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{21} -} - -func (x *GroupRequest) GetId() int64 { - if x != nil { - return x.Id - } - return 0 -} - -type GroupSaveRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Group *Group `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` -} - -func (x *GroupSaveRequest) Reset() { - *x = GroupSaveRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[22] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GroupSaveRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupSaveRequest) ProtoMessage() {} - -func (x *GroupSaveRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[22] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GroupSaveRequest.ProtoReflect.Descriptor instead. -func (*GroupSaveRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{22} -} - -func (x *GroupSaveRequest) GetGroup() *Group { - if x != nil { - return x.Group - } - return nil -} - -type GroupListRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *GroupListRequest) Reset() { - *x = GroupListRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[23] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GroupListRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupListRequest) ProtoMessage() {} - -func (x *GroupListRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[23] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GroupListRequest.ProtoReflect.Descriptor instead. -func (*GroupListRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{23} -} - -type GroupModifyPermissionRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - EntityRelation *EntityRelation `protobuf:"bytes,2,opt,name=entity_relation,json=entityRelation,proto3" json:"entity_relation,omitempty"` -} - -func (x *GroupModifyPermissionRequest) Reset() { - *x = GroupModifyPermissionRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[24] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GroupModifyPermissionRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupModifyPermissionRequest) ProtoMessage() {} - -func (x *GroupModifyPermissionRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[24] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GroupModifyPermissionRequest.ProtoReflect.Descriptor instead. -func (*GroupModifyPermissionRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{24} -} - -func (x *GroupModifyPermissionRequest) GetId() int64 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *GroupModifyPermissionRequest) GetEntityRelation() *EntityRelation { - if x != nil { - return x.EntityRelation - } - return nil -} - -type GroupResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Group *Group `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` -} - -func (x *GroupResponse) Reset() { - *x = GroupResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[25] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GroupResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupResponse) ProtoMessage() {} - -func (x *GroupResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[25] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GroupResponse.ProtoReflect.Descriptor instead. -func (*GroupResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{25} -} - -func (x *GroupResponse) GetGroup() *Group { - if x != nil { - return x.Group - } - return nil -} - -type GroupListResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Groups []*Group `protobuf:"bytes,1,rep,name=groups,proto3" json:"groups,omitempty"` -} - -func (x *GroupListResponse) Reset() { - *x = GroupListResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[26] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GroupListResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupListResponse) ProtoMessage() {} - -func (x *GroupListResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[26] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GroupListResponse.ProtoReflect.Descriptor instead. -func (*GroupListResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{26} -} - -func (x *GroupListResponse) GetGroups() []*Group { - if x != nil { - return x.Groups - } - return nil -} - -type GroupPermissionsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Group *Group `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` - Tenant *Tenant `protobuf:"bytes,2,opt,name=tenant,proto3" json:"tenant,omitempty"` - Feeds []*Feed `protobuf:"bytes,3,rep,name=feeds,proto3" json:"feeds,omitempty"` - Actions *GroupPermissionsResponse_Actions `protobuf:"bytes,4,opt,name=actions,proto3" json:"actions,omitempty"` - Users *GroupPermissionsResponse_Users `protobuf:"bytes,5,opt,name=users,proto3" json:"users,omitempty"` -} - -func (x *GroupPermissionsResponse) Reset() { - *x = GroupPermissionsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[27] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GroupPermissionsResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupPermissionsResponse) ProtoMessage() {} - -func (x *GroupPermissionsResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[27] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GroupPermissionsResponse.ProtoReflect.Descriptor instead. -func (*GroupPermissionsResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{27} -} - -func (x *GroupPermissionsResponse) GetGroup() *Group { - if x != nil { - return x.Group - } - return nil -} - -func (x *GroupPermissionsResponse) GetTenant() *Tenant { - if x != nil { - return x.Tenant - } - return nil -} - -func (x *GroupPermissionsResponse) GetFeeds() []*Feed { - if x != nil { - return x.Feeds - } - return nil -} - -func (x *GroupPermissionsResponse) GetActions() *GroupPermissionsResponse_Actions { - if x != nil { - return x.Actions - } - return nil -} - -func (x *GroupPermissionsResponse) GetUsers() *GroupPermissionsResponse_Users { - if x != nil { - return x.Users - } - return nil -} - -type GroupSaveResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Group *Group `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` -} - -func (x *GroupSaveResponse) Reset() { - *x = GroupSaveResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[28] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GroupSaveResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupSaveResponse) ProtoMessage() {} - -func (x *GroupSaveResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[28] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GroupSaveResponse.ProtoReflect.Descriptor instead. -func (*GroupSaveResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{28} -} - -func (x *GroupSaveResponse) GetGroup() *Group { - if x != nil { - return x.Group - } - return nil -} - -type GroupSetTenantRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - TenantId int64 `protobuf:"varint,2,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"` -} - -func (x *GroupSetTenantRequest) Reset() { - *x = GroupSetTenantRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[29] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GroupSetTenantRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupSetTenantRequest) ProtoMessage() {} - -func (x *GroupSetTenantRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[29] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GroupSetTenantRequest.ProtoReflect.Descriptor instead. -func (*GroupSetTenantRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{29} -} - -func (x *GroupSetTenantRequest) GetId() int64 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *GroupSetTenantRequest) GetTenantId() int64 { - if x != nil { - return x.TenantId - } - return 0 -} - -type GroupSetTenantResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *GroupSetTenantResponse) Reset() { - *x = GroupSetTenantResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[30] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GroupSetTenantResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupSetTenantResponse) ProtoMessage() {} - -func (x *GroupSetTenantResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[30] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GroupSetTenantResponse.ProtoReflect.Descriptor instead. -func (*GroupSetTenantResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{30} -} - -type Feed struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - OnestopId string `protobuf:"bytes,2,opt,name=onestop_id,json=onestopId,proto3" json:"onestop_id,omitempty"` - Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` -} - -func (x *Feed) Reset() { - *x = Feed{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[31] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Feed) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Feed) ProtoMessage() {} - -func (x *Feed) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[31] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Feed.ProtoReflect.Descriptor instead. -func (*Feed) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{31} -} - -func (x *Feed) GetId() int64 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *Feed) GetOnestopId() string { - if x != nil { - return x.OnestopId - } - return "" -} - -func (x *Feed) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -type FeedRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` -} - -func (x *FeedRequest) Reset() { - *x = FeedRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[32] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FeedRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FeedRequest) ProtoMessage() {} - -func (x *FeedRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[32] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FeedRequest.ProtoReflect.Descriptor instead. -func (*FeedRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{32} -} - -func (x *FeedRequest) GetId() int64 { - if x != nil { - return x.Id - } - return 0 -} - -type FeedListRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *FeedListRequest) Reset() { - *x = FeedListRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[33] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FeedListRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FeedListRequest) ProtoMessage() {} - -func (x *FeedListRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[33] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FeedListRequest.ProtoReflect.Descriptor instead. -func (*FeedListRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{33} -} - -type FeedPermissionsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Feed *Feed `protobuf:"bytes,1,opt,name=feed,proto3" json:"feed,omitempty"` - Group *Group `protobuf:"bytes,2,opt,name=group,proto3" json:"group,omitempty"` - Actions *FeedPermissionsResponse_Actions `protobuf:"bytes,3,opt,name=actions,proto3" json:"actions,omitempty"` -} - -func (x *FeedPermissionsResponse) Reset() { - *x = FeedPermissionsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[34] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FeedPermissionsResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FeedPermissionsResponse) ProtoMessage() {} - -func (x *FeedPermissionsResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[34] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FeedPermissionsResponse.ProtoReflect.Descriptor instead. -func (*FeedPermissionsResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{34} -} - -func (x *FeedPermissionsResponse) GetFeed() *Feed { - if x != nil { - return x.Feed - } - return nil -} - -func (x *FeedPermissionsResponse) GetGroup() *Group { - if x != nil { - return x.Group - } - return nil -} - -func (x *FeedPermissionsResponse) GetActions() *FeedPermissionsResponse_Actions { - if x != nil { - return x.Actions - } - return nil -} - -type FeedResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Feed *Feed `protobuf:"bytes,1,opt,name=feed,proto3" json:"feed,omitempty"` -} - -func (x *FeedResponse) Reset() { - *x = FeedResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[35] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FeedResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FeedResponse) ProtoMessage() {} - -func (x *FeedResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[35] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FeedResponse.ProtoReflect.Descriptor instead. -func (*FeedResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{35} -} - -func (x *FeedResponse) GetFeed() *Feed { - if x != nil { - return x.Feed - } - return nil -} - -type FeedListResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Feeds []*Feed `protobuf:"bytes,1,rep,name=feeds,proto3" json:"feeds,omitempty"` -} - -func (x *FeedListResponse) Reset() { - *x = FeedListResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[36] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FeedListResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FeedListResponse) ProtoMessage() {} - -func (x *FeedListResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[36] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FeedListResponse.ProtoReflect.Descriptor instead. -func (*FeedListResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{36} -} - -func (x *FeedListResponse) GetFeeds() []*Feed { - if x != nil { - return x.Feeds - } - return nil -} - -type FeedSetGroupRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - GroupId int64 `protobuf:"varint,2,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` -} - -func (x *FeedSetGroupRequest) Reset() { - *x = FeedSetGroupRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[37] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FeedSetGroupRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FeedSetGroupRequest) ProtoMessage() {} - -func (x *FeedSetGroupRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[37] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FeedSetGroupRequest.ProtoReflect.Descriptor instead. -func (*FeedSetGroupRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{37} -} - -func (x *FeedSetGroupRequest) GetId() int64 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *FeedSetGroupRequest) GetGroupId() int64 { - if x != nil { - return x.GroupId - } - return 0 -} - -type FeedSaveResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *FeedSaveResponse) Reset() { - *x = FeedSaveResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[38] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FeedSaveResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FeedSaveResponse) ProtoMessage() {} - -func (x *FeedSaveResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[38] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FeedSaveResponse.ProtoReflect.Descriptor instead. -func (*FeedSaveResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{38} -} - -type FeedVersion struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Sha1 string `protobuf:"bytes,3,opt,name=sha1,proto3" json:"sha1,omitempty"` - FeedId int64 `protobuf:"varint,4,opt,name=feed_id,json=feedId,proto3" json:"feed_id,omitempty"` -} - -func (x *FeedVersion) Reset() { - *x = FeedVersion{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[39] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FeedVersion) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FeedVersion) ProtoMessage() {} - -func (x *FeedVersion) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[39] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FeedVersion.ProtoReflect.Descriptor instead. -func (*FeedVersion) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{39} -} - -func (x *FeedVersion) GetId() int64 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *FeedVersion) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *FeedVersion) GetSha1() string { - if x != nil { - return x.Sha1 - } - return "" -} - -func (x *FeedVersion) GetFeedId() int64 { - if x != nil { - return x.FeedId - } - return 0 -} - -type FeedVersionListRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *FeedVersionListRequest) Reset() { - *x = FeedVersionListRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[40] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FeedVersionListRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FeedVersionListRequest) ProtoMessage() {} - -func (x *FeedVersionListRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[40] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FeedVersionListRequest.ProtoReflect.Descriptor instead. -func (*FeedVersionListRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{40} -} - -type FeedVersionResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - FeedVersion *FeedVersion `protobuf:"bytes,1,opt,name=feed_version,json=feedVersion,proto3" json:"feed_version,omitempty"` -} - -func (x *FeedVersionResponse) Reset() { - *x = FeedVersionResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[41] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FeedVersionResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FeedVersionResponse) ProtoMessage() {} - -func (x *FeedVersionResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[41] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FeedVersionResponse.ProtoReflect.Descriptor instead. -func (*FeedVersionResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{41} -} - -func (x *FeedVersionResponse) GetFeedVersion() *FeedVersion { - if x != nil { - return x.FeedVersion - } - return nil -} - -type FeedVersionRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` -} - -func (x *FeedVersionRequest) Reset() { - *x = FeedVersionRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[42] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FeedVersionRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FeedVersionRequest) ProtoMessage() {} - -func (x *FeedVersionRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[42] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FeedVersionRequest.ProtoReflect.Descriptor instead. -func (*FeedVersionRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{42} -} - -func (x *FeedVersionRequest) GetId() int64 { - if x != nil { - return x.Id - } - return 0 -} - -type FeedVersionListResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - FeedVersions []*FeedVersion `protobuf:"bytes,1,rep,name=feed_versions,json=feedVersions,proto3" json:"feed_versions,omitempty"` -} - -func (x *FeedVersionListResponse) Reset() { - *x = FeedVersionListResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[43] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FeedVersionListResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FeedVersionListResponse) ProtoMessage() {} - -func (x *FeedVersionListResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[43] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FeedVersionListResponse.ProtoReflect.Descriptor instead. -func (*FeedVersionListResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{43} -} - -func (x *FeedVersionListResponse) GetFeedVersions() []*FeedVersion { - if x != nil { - return x.FeedVersions - } - return nil -} - -type FeedVersionPermissionsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - FeedVersion *FeedVersion `protobuf:"bytes,1,opt,name=feed_version,json=feedVersion,proto3" json:"feed_version,omitempty"` - Feed *Feed `protobuf:"bytes,2,opt,name=feed,proto3" json:"feed,omitempty"` - Group *Group `protobuf:"bytes,3,opt,name=group,proto3" json:"group,omitempty"` - Actions *FeedVersionPermissionsResponse_Actions `protobuf:"bytes,4,opt,name=actions,proto3" json:"actions,omitempty"` - Users *FeedVersionPermissionsResponse_Users `protobuf:"bytes,5,opt,name=users,proto3" json:"users,omitempty"` -} - -func (x *FeedVersionPermissionsResponse) Reset() { - *x = FeedVersionPermissionsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[44] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FeedVersionPermissionsResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FeedVersionPermissionsResponse) ProtoMessage() {} - -func (x *FeedVersionPermissionsResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[44] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FeedVersionPermissionsResponse.ProtoReflect.Descriptor instead. -func (*FeedVersionPermissionsResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{44} -} - -func (x *FeedVersionPermissionsResponse) GetFeedVersion() *FeedVersion { - if x != nil { - return x.FeedVersion - } - return nil -} - -func (x *FeedVersionPermissionsResponse) GetFeed() *Feed { - if x != nil { - return x.Feed - } - return nil -} - -func (x *FeedVersionPermissionsResponse) GetGroup() *Group { - if x != nil { - return x.Group - } - return nil -} - -func (x *FeedVersionPermissionsResponse) GetActions() *FeedVersionPermissionsResponse_Actions { - if x != nil { - return x.Actions - } - return nil -} - -func (x *FeedVersionPermissionsResponse) GetUsers() *FeedVersionPermissionsResponse_Users { - if x != nil { - return x.Users - } - return nil -} - -type FeedVersionModifyPermissionRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - EntityRelation *EntityRelation `protobuf:"bytes,2,opt,name=entity_relation,json=entityRelation,proto3" json:"entity_relation,omitempty"` -} - -func (x *FeedVersionModifyPermissionRequest) Reset() { - *x = FeedVersionModifyPermissionRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[45] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FeedVersionModifyPermissionRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FeedVersionModifyPermissionRequest) ProtoMessage() {} - -func (x *FeedVersionModifyPermissionRequest) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[45] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FeedVersionModifyPermissionRequest.ProtoReflect.Descriptor instead. -func (*FeedVersionModifyPermissionRequest) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{45} -} - -func (x *FeedVersionModifyPermissionRequest) GetId() int64 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *FeedVersionModifyPermissionRequest) GetEntityRelation() *EntityRelation { - if x != nil { - return x.EntityRelation - } - return nil -} - -type FeedVersionSaveResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *FeedVersionSaveResponse) Reset() { - *x = FeedVersionSaveResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[46] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FeedVersionSaveResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FeedVersionSaveResponse) ProtoMessage() {} - -func (x *FeedVersionSaveResponse) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[46] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FeedVersionSaveResponse.ProtoReflect.Descriptor instead. -func (*FeedVersionSaveResponse) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{46} -} - -type TenantPermissionsResponse_Actions struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - CanEditMembers bool `protobuf:"varint,1,opt,name=can_edit_members,json=canEditMembers,proto3" json:"can_edit_members,omitempty"` - CanView bool `protobuf:"varint,2,opt,name=can_view,json=canView,proto3" json:"can_view,omitempty"` - CanEdit bool `protobuf:"varint,3,opt,name=can_edit,json=canEdit,proto3" json:"can_edit,omitempty"` - CanCreateOrg bool `protobuf:"varint,4,opt,name=can_create_org,json=canCreateOrg,proto3" json:"can_create_org,omitempty"` - CanDeleteOrg bool `protobuf:"varint,5,opt,name=can_delete_org,json=canDeleteOrg,proto3" json:"can_delete_org,omitempty"` -} - -func (x *TenantPermissionsResponse_Actions) Reset() { - *x = TenantPermissionsResponse_Actions{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[48] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TenantPermissionsResponse_Actions) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TenantPermissionsResponse_Actions) ProtoMessage() {} - -func (x *TenantPermissionsResponse_Actions) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[48] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TenantPermissionsResponse_Actions.ProtoReflect.Descriptor instead. -func (*TenantPermissionsResponse_Actions) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{14, 0} -} - -func (x *TenantPermissionsResponse_Actions) GetCanEditMembers() bool { - if x != nil { - return x.CanEditMembers - } - return false -} - -func (x *TenantPermissionsResponse_Actions) GetCanView() bool { - if x != nil { - return x.CanView - } - return false -} - -func (x *TenantPermissionsResponse_Actions) GetCanEdit() bool { - if x != nil { - return x.CanEdit - } - return false -} - -func (x *TenantPermissionsResponse_Actions) GetCanCreateOrg() bool { - if x != nil { - return x.CanCreateOrg - } - return false -} - -func (x *TenantPermissionsResponse_Actions) GetCanDeleteOrg() bool { - if x != nil { - return x.CanDeleteOrg - } - return false -} - -type TenantPermissionsResponse_Users struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Admins []*EntityRelation `protobuf:"bytes,1,rep,name=admins,proto3" json:"admins,omitempty"` - Members []*EntityRelation `protobuf:"bytes,2,rep,name=members,proto3" json:"members,omitempty"` -} - -func (x *TenantPermissionsResponse_Users) Reset() { - *x = TenantPermissionsResponse_Users{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[49] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TenantPermissionsResponse_Users) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TenantPermissionsResponse_Users) ProtoMessage() {} - -func (x *TenantPermissionsResponse_Users) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[49] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TenantPermissionsResponse_Users.ProtoReflect.Descriptor instead. -func (*TenantPermissionsResponse_Users) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{14, 1} -} - -func (x *TenantPermissionsResponse_Users) GetAdmins() []*EntityRelation { - if x != nil { - return x.Admins - } - return nil -} - -func (x *TenantPermissionsResponse_Users) GetMembers() []*EntityRelation { - if x != nil { - return x.Members - } - return nil -} - -type GroupPermissionsResponse_Actions struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - CanView bool `protobuf:"varint,1,opt,name=can_view,json=canView,proto3" json:"can_view,omitempty"` - CanEditMembers bool `protobuf:"varint,2,opt,name=can_edit_members,json=canEditMembers,proto3" json:"can_edit_members,omitempty"` - CanCreateFeed bool `protobuf:"varint,3,opt,name=can_create_feed,json=canCreateFeed,proto3" json:"can_create_feed,omitempty"` - CanDeleteFeed bool `protobuf:"varint,4,opt,name=can_delete_feed,json=canDeleteFeed,proto3" json:"can_delete_feed,omitempty"` - CanEdit bool `protobuf:"varint,5,opt,name=can_edit,json=canEdit,proto3" json:"can_edit,omitempty"` - CanSetTenant bool `protobuf:"varint,6,opt,name=can_set_tenant,json=canSetTenant,proto3" json:"can_set_tenant,omitempty"` -} - -func (x *GroupPermissionsResponse_Actions) Reset() { - *x = GroupPermissionsResponse_Actions{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[50] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GroupPermissionsResponse_Actions) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupPermissionsResponse_Actions) ProtoMessage() {} - -func (x *GroupPermissionsResponse_Actions) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[50] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GroupPermissionsResponse_Actions.ProtoReflect.Descriptor instead. -func (*GroupPermissionsResponse_Actions) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{27, 0} -} - -func (x *GroupPermissionsResponse_Actions) GetCanView() bool { - if x != nil { - return x.CanView - } - return false -} - -func (x *GroupPermissionsResponse_Actions) GetCanEditMembers() bool { - if x != nil { - return x.CanEditMembers - } - return false -} - -func (x *GroupPermissionsResponse_Actions) GetCanCreateFeed() bool { - if x != nil { - return x.CanCreateFeed - } - return false -} - -func (x *GroupPermissionsResponse_Actions) GetCanDeleteFeed() bool { - if x != nil { - return x.CanDeleteFeed - } - return false -} - -func (x *GroupPermissionsResponse_Actions) GetCanEdit() bool { - if x != nil { - return x.CanEdit - } - return false -} - -func (x *GroupPermissionsResponse_Actions) GetCanSetTenant() bool { - if x != nil { - return x.CanSetTenant - } - return false -} - -type GroupPermissionsResponse_Users struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Managers []*EntityRelation `protobuf:"bytes,1,rep,name=managers,proto3" json:"managers,omitempty"` - Editors []*EntityRelation `protobuf:"bytes,2,rep,name=editors,proto3" json:"editors,omitempty"` - Viewers []*EntityRelation `protobuf:"bytes,3,rep,name=viewers,proto3" json:"viewers,omitempty"` -} - -func (x *GroupPermissionsResponse_Users) Reset() { - *x = GroupPermissionsResponse_Users{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[51] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GroupPermissionsResponse_Users) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupPermissionsResponse_Users) ProtoMessage() {} - -func (x *GroupPermissionsResponse_Users) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[51] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GroupPermissionsResponse_Users.ProtoReflect.Descriptor instead. -func (*GroupPermissionsResponse_Users) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{27, 1} -} - -func (x *GroupPermissionsResponse_Users) GetManagers() []*EntityRelation { - if x != nil { - return x.Managers - } - return nil -} - -func (x *GroupPermissionsResponse_Users) GetEditors() []*EntityRelation { - if x != nil { - return x.Editors - } - return nil -} - -func (x *GroupPermissionsResponse_Users) GetViewers() []*EntityRelation { - if x != nil { - return x.Viewers - } - return nil -} - -type FeedPermissionsResponse_Actions struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - CanView bool `protobuf:"varint,1,opt,name=can_view,json=canView,proto3" json:"can_view,omitempty"` - CanEdit bool `protobuf:"varint,2,opt,name=can_edit,json=canEdit,proto3" json:"can_edit,omitempty"` - CanSetGroup bool `protobuf:"varint,3,opt,name=can_set_group,json=canSetGroup,proto3" json:"can_set_group,omitempty"` - CanCreateFeedVersion bool `protobuf:"varint,4,opt,name=can_create_feed_version,json=canCreateFeedVersion,proto3" json:"can_create_feed_version,omitempty"` - CanDeleteFeedVersion bool `protobuf:"varint,5,opt,name=can_delete_feed_version,json=canDeleteFeedVersion,proto3" json:"can_delete_feed_version,omitempty"` -} - -func (x *FeedPermissionsResponse_Actions) Reset() { - *x = FeedPermissionsResponse_Actions{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[52] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FeedPermissionsResponse_Actions) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FeedPermissionsResponse_Actions) ProtoMessage() {} - -func (x *FeedPermissionsResponse_Actions) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[52] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FeedPermissionsResponse_Actions.ProtoReflect.Descriptor instead. -func (*FeedPermissionsResponse_Actions) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{34, 0} -} - -func (x *FeedPermissionsResponse_Actions) GetCanView() bool { - if x != nil { - return x.CanView - } - return false -} - -func (x *FeedPermissionsResponse_Actions) GetCanEdit() bool { - if x != nil { - return x.CanEdit - } - return false -} - -func (x *FeedPermissionsResponse_Actions) GetCanSetGroup() bool { - if x != nil { - return x.CanSetGroup - } - return false -} - -func (x *FeedPermissionsResponse_Actions) GetCanCreateFeedVersion() bool { - if x != nil { - return x.CanCreateFeedVersion - } - return false -} - -func (x *FeedPermissionsResponse_Actions) GetCanDeleteFeedVersion() bool { - if x != nil { - return x.CanDeleteFeedVersion - } - return false -} - -type FeedVersionPermissionsResponse_Actions struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - CanView bool `protobuf:"varint,1,opt,name=can_view,json=canView,proto3" json:"can_view,omitempty"` - CanEditMembers bool `protobuf:"varint,2,opt,name=can_edit_members,json=canEditMembers,proto3" json:"can_edit_members,omitempty"` - CanEdit bool `protobuf:"varint,3,opt,name=can_edit,json=canEdit,proto3" json:"can_edit,omitempty"` -} - -func (x *FeedVersionPermissionsResponse_Actions) Reset() { - *x = FeedVersionPermissionsResponse_Actions{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[53] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FeedVersionPermissionsResponse_Actions) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FeedVersionPermissionsResponse_Actions) ProtoMessage() {} - -func (x *FeedVersionPermissionsResponse_Actions) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[53] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FeedVersionPermissionsResponse_Actions.ProtoReflect.Descriptor instead. -func (*FeedVersionPermissionsResponse_Actions) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{44, 0} -} - -func (x *FeedVersionPermissionsResponse_Actions) GetCanView() bool { - if x != nil { - return x.CanView - } - return false -} - -func (x *FeedVersionPermissionsResponse_Actions) GetCanEditMembers() bool { - if x != nil { - return x.CanEditMembers - } - return false -} - -func (x *FeedVersionPermissionsResponse_Actions) GetCanEdit() bool { - if x != nil { - return x.CanEdit - } - return false -} - -type FeedVersionPermissionsResponse_Users struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Editors []*EntityRelation `protobuf:"bytes,1,rep,name=editors,proto3" json:"editors,omitempty"` - Viewers []*EntityRelation `protobuf:"bytes,2,rep,name=viewers,proto3" json:"viewers,omitempty"` -} - -func (x *FeedVersionPermissionsResponse_Users) Reset() { - *x = FeedVersionPermissionsResponse_Users{} - if protoimpl.UnsafeEnabled { - mi := &file_azpb_proto_msgTypes[54] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FeedVersionPermissionsResponse_Users) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FeedVersionPermissionsResponse_Users) ProtoMessage() {} - -func (x *FeedVersionPermissionsResponse_Users) ProtoReflect() protoreflect.Message { - mi := &file_azpb_proto_msgTypes[54] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FeedVersionPermissionsResponse_Users.ProtoReflect.Descriptor instead. -func (*FeedVersionPermissionsResponse_Users) Descriptor() ([]byte, []int) { - return file_azpb_proto_rawDescGZIP(), []int{44, 1} -} - -func (x *FeedVersionPermissionsResponse_Users) GetEditors() []*EntityRelation { - if x != nil { - return x.Editors - } - return nil -} - -func (x *FeedVersionPermissionsResponse_Users) GetViewers() []*EntityRelation { - if x != nil { - return x.Viewers - } - return nil -} - -var File_azpb_proto protoreflect.FileDescriptor - -var file_azpb_proto_rawDesc = []byte{ - 0x0a, 0x0a, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x61, 0x7a, - 0x70, 0x62, 0x22, 0xb9, 0x01, 0x0a, 0x0e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, - 0x31, 0x0a, 0x0c, 0x72, 0x65, 0x66, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x72, 0x65, 0x66, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x6c, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x40, - 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, - 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, - 0x22, 0x1f, 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x0c, 0x0a, 0x01, 0x71, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x01, - 0x71, 0x22, 0x1d, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, - 0x22, 0x34, 0x0a, 0x10, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, - 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x2e, 0x0a, 0x0c, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, - 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x0b, 0x0a, 0x09, 0x4d, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x22, 0xa7, 0x02, 0x0a, 0x0a, 0x4d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0a, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, - 0x65, 0x72, 0x12, 0x23, 0x0a, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, - 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x34, 0x0a, 0x0f, 0x65, 0x78, 0x70, 0x61, 0x6e, - 0x64, 0x65, 0x64, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x0b, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x0e, 0x65, - 0x78, 0x70, 0x61, 0x6e, 0x64, 0x65, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x47, 0x0a, - 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, - 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, - 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x1a, 0x3f, 0x0a, 0x11, - 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x61, 0x74, 0x61, 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, 0x22, 0x2c, 0x0a, - 0x06, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x39, 0x0a, 0x11, 0x54, - 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x24, 0x0a, 0x06, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0c, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x52, 0x06, - 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x22, 0x1f, 0x0a, 0x0d, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x22, 0x13, 0x0a, 0x11, 0x54, 0x65, 0x6e, 0x61, 0x6e, - 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x36, 0x0a, 0x0e, - 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, - 0x0a, 0x06, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, - 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x52, 0x06, 0x74, 0x65, - 0x6e, 0x61, 0x6e, 0x74, 0x22, 0x3c, 0x0a, 0x12, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x07, 0x74, 0x65, - 0x6e, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x7a, - 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x52, 0x07, 0x74, 0x65, 0x6e, 0x61, 0x6e, - 0x74, 0x73, 0x22, 0x85, 0x04, 0x0a, 0x19, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x50, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x24, 0x0a, 0x06, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0c, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x52, 0x06, - 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x12, 0x23, 0x0a, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x52, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x41, 0x0a, 0x07, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, - 0x7a, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3b, - 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, - 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x55, - 0x73, 0x65, 0x72, 0x73, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x1a, 0xb5, 0x01, 0x0a, 0x07, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x63, 0x61, 0x6e, 0x5f, 0x65, - 0x64, 0x69, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0e, 0x63, 0x61, 0x6e, 0x45, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x61, 0x6e, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x07, 0x63, 0x61, 0x6e, 0x56, 0x69, 0x65, 0x77, 0x12, 0x19, 0x0a, 0x08, - 0x63, 0x61, 0x6e, 0x5f, 0x65, 0x64, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, - 0x63, 0x61, 0x6e, 0x45, 0x64, 0x69, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x63, 0x61, 0x6e, 0x5f, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x6f, 0x72, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0c, 0x63, 0x61, 0x6e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x67, 0x12, 0x24, 0x0a, - 0x0e, 0x63, 0x61, 0x6e, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x6f, 0x72, 0x67, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x63, 0x61, 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x4f, 0x72, 0x67, 0x1a, 0x65, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x2c, 0x0a, 0x06, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, - 0x7a, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x07, 0x6d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x7a, - 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x54, 0x65, - 0x6e, 0x61, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x22, 0x4d, 0x0a, 0x18, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x21, 0x0a, - 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x61, - 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, - 0x22, 0x3e, 0x0a, 0x19, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, - 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x61, - 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, - 0x22, 0x6e, 0x0a, 0x1d, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, - 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x3d, 0x0a, 0x0f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x72, 0x65, 0x6c, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x7a, 0x70, - 0x62, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x0e, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x22, 0x14, 0x0a, 0x12, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x0a, 0x05, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x22, 0x1e, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x02, 0x69, 0x64, 0x22, 0x35, 0x0a, 0x10, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x61, 0x76, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x12, 0x0a, 0x10, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x6d, - 0x0a, 0x1c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x50, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3d, - 0x0a, 0x0f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x45, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0e, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x32, 0x0a, - 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, - 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, - 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x22, 0x38, 0x0a, 0x11, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x52, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x22, 0x81, 0x05, 0x0a, 0x18, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x24, 0x0a, 0x06, 0x74, - 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x7a, - 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x52, 0x06, 0x74, 0x65, 0x6e, 0x61, 0x6e, - 0x74, 0x12, 0x20, 0x0a, 0x05, 0x66, 0x65, 0x65, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x0a, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x52, 0x05, 0x66, 0x65, - 0x65, 0x64, 0x73, 0x12, 0x40, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3a, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, - 0x73, 0x1a, 0xdf, 0x01, 0x0a, 0x07, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x19, 0x0a, - 0x08, 0x63, 0x61, 0x6e, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x07, 0x63, 0x61, 0x6e, 0x56, 0x69, 0x65, 0x77, 0x12, 0x28, 0x0a, 0x10, 0x63, 0x61, 0x6e, 0x5f, - 0x65, 0x64, 0x69, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0e, 0x63, 0x61, 0x6e, 0x45, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x63, 0x61, 0x6e, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x5f, 0x66, 0x65, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x63, 0x61, 0x6e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x63, 0x61, - 0x6e, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x64, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0d, 0x63, 0x61, 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x65, - 0x65, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x61, 0x6e, 0x5f, 0x65, 0x64, 0x69, 0x74, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x63, 0x61, 0x6e, 0x45, 0x64, 0x69, 0x74, 0x12, 0x24, 0x0a, - 0x0e, 0x63, 0x61, 0x6e, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x63, 0x61, 0x6e, 0x53, 0x65, 0x74, 0x54, 0x65, 0x6e, - 0x61, 0x6e, 0x74, 0x1a, 0x99, 0x01, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x30, 0x0a, - 0x08, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x14, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x73, 0x12, - 0x2e, 0x0a, 0x07, 0x65, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x14, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x65, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x73, 0x12, - 0x2e, 0x0a, 0x07, 0x76, 0x69, 0x65, 0x77, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x14, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x76, 0x69, 0x65, 0x77, 0x65, 0x72, 0x73, 0x22, - 0x36, 0x0a, 0x11, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x44, 0x0a, 0x15, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x53, 0x65, 0x74, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x18, 0x0a, - 0x16, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x65, 0x74, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x49, 0x0a, 0x04, 0x46, 0x65, 0x65, 0x64, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x1d, 0x0a, 0x0a, 0x6f, 0x6e, 0x65, 0x73, 0x74, 0x6f, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x6e, 0x65, 0x73, 0x74, 0x6f, 0x70, 0x49, 0x64, 0x12, 0x12, - 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x22, 0x1d, 0x0a, 0x0b, 0x46, 0x65, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, - 0x64, 0x22, 0x11, 0x0a, 0x0f, 0x46, 0x65, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x22, 0xf1, 0x02, 0x0a, 0x17, 0x46, 0x65, 0x65, 0x64, 0x50, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x1e, 0x0a, 0x04, 0x66, 0x65, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, - 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x52, 0x04, 0x66, 0x65, 0x65, 0x64, - 0x12, 0x21, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0b, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x05, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x12, 0x3f, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, - 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0xd1, 0x01, 0x0a, 0x07, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x12, 0x19, 0x0a, 0x08, 0x63, 0x61, 0x6e, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x07, 0x63, 0x61, 0x6e, 0x56, 0x69, 0x65, 0x77, 0x12, 0x19, 0x0a, 0x08, 0x63, - 0x61, 0x6e, 0x5f, 0x65, 0x64, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x63, - 0x61, 0x6e, 0x45, 0x64, 0x69, 0x74, 0x12, 0x22, 0x0a, 0x0d, 0x63, 0x61, 0x6e, 0x5f, 0x73, 0x65, - 0x74, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x63, - 0x61, 0x6e, 0x53, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x35, 0x0a, 0x17, 0x63, 0x61, - 0x6e, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x64, 0x5f, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x63, 0x61, 0x6e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x35, 0x0a, 0x17, 0x63, 0x61, 0x6e, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, - 0x66, 0x65, 0x65, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x14, 0x63, 0x61, 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x65, 0x65, - 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x2e, 0x0a, 0x0c, 0x46, 0x65, 0x65, 0x64, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x04, 0x66, 0x65, 0x65, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x46, 0x65, - 0x65, 0x64, 0x52, 0x04, 0x66, 0x65, 0x65, 0x64, 0x22, 0x34, 0x0a, 0x10, 0x46, 0x65, 0x65, 0x64, - 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x05, - 0x66, 0x65, 0x65, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x61, 0x7a, - 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x52, 0x05, 0x66, 0x65, 0x65, 0x64, 0x73, 0x22, 0x40, - 0x0a, 0x13, 0x46, 0x65, 0x65, 0x64, 0x53, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, - 0x22, 0x12, 0x0a, 0x10, 0x46, 0x65, 0x65, 0x64, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5e, 0x0a, 0x0b, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x68, 0x61, 0x31, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x68, 0x61, 0x31, 0x12, 0x17, 0x0a, 0x07, 0x66, - 0x65, 0x65, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x66, 0x65, - 0x65, 0x64, 0x49, 0x64, 0x22, 0x18, 0x0a, 0x16, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4b, - 0x0a, 0x13, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x0c, 0x66, 0x65, 0x65, 0x64, 0x5f, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x61, 0x7a, - 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0b, - 0x66, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x24, 0x0a, 0x12, 0x46, - 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, - 0x64, 0x22, 0x51, 0x0a, 0x17, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x0d, - 0x66, 0x65, 0x65, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x66, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xf7, 0x03, 0x0a, 0x1e, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x0c, 0x66, 0x65, 0x65, 0x64, 0x5f, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, - 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x52, 0x0b, 0x66, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, - 0x04, 0x66, 0x65, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x61, 0x7a, - 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x52, 0x04, 0x66, 0x65, 0x65, 0x64, 0x12, 0x21, 0x0a, - 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x61, - 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, - 0x12, 0x46, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2c, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, - 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x40, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, - 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x46, - 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x55, 0x73, - 0x65, 0x72, 0x73, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x1a, 0x69, 0x0a, 0x07, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x61, 0x6e, 0x5f, 0x76, 0x69, 0x65, - 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x63, 0x61, 0x6e, 0x56, 0x69, 0x65, 0x77, - 0x12, 0x28, 0x0a, 0x10, 0x63, 0x61, 0x6e, 0x5f, 0x65, 0x64, 0x69, 0x74, 0x5f, 0x6d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x63, 0x61, 0x6e, 0x45, - 0x64, 0x69, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x61, - 0x6e, 0x5f, 0x65, 0x64, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x63, 0x61, - 0x6e, 0x45, 0x64, 0x69, 0x74, 0x1a, 0x67, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x2e, - 0x0a, 0x07, 0x65, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x14, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x65, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x2e, - 0x0a, 0x07, 0x76, 0x69, 0x65, 0x77, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x14, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x76, 0x69, 0x65, 0x77, 0x65, 0x72, 0x73, 0x22, 0x73, - 0x0a, 0x22, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, - 0x69, 0x66, 0x79, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x02, 0x69, 0x64, 0x12, 0x3d, 0x0a, 0x0f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x72, - 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, - 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x6c, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x0e, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x6c, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x22, 0x19, 0x0a, 0x17, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0xff, - 0x01, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x0c, 0x65, 0x6d, 0x70, - 0x74, 0x79, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x63, - 0x61, 0x6e, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x63, 0x61, 0x6e, - 0x5f, 0x65, 0x64, 0x69, 0x74, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10, 0x63, 0x61, 0x6e, 0x5f, 0x65, - 0x64, 0x69, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x10, 0x03, 0x12, 0x12, 0x0a, - 0x0e, 0x63, 0x61, 0x6e, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x6f, 0x72, 0x67, 0x10, - 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x63, 0x61, 0x6e, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, - 0x6f, 0x72, 0x67, 0x10, 0x05, 0x12, 0x1b, 0x0a, 0x17, 0x63, 0x61, 0x6e, 0x5f, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x10, 0x06, 0x12, 0x1b, 0x0a, 0x17, 0x63, 0x61, 0x6e, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x5f, 0x66, 0x65, 0x65, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x10, 0x07, 0x12, - 0x13, 0x0a, 0x0f, 0x63, 0x61, 0x6e, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x66, 0x65, - 0x65, 0x64, 0x10, 0x08, 0x12, 0x13, 0x0a, 0x0f, 0x63, 0x61, 0x6e, 0x5f, 0x64, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x64, 0x10, 0x09, 0x12, 0x11, 0x0a, 0x0d, 0x63, 0x61, 0x6e, - 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x10, 0x0a, 0x12, 0x12, 0x0a, 0x0e, - 0x63, 0x61, 0x6e, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x10, 0x0b, - 0x2a, 0x59, 0x0a, 0x0a, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, - 0x0a, 0x0c, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x10, 0x00, - 0x12, 0x0a, 0x0a, 0x06, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, - 0x6f, 0x72, 0x67, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x66, 0x65, 0x65, 0x64, 0x10, 0x03, 0x12, - 0x10, 0x0a, 0x0c, 0x66, 0x65, 0x65, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x10, - 0x04, 0x12, 0x08, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x10, 0x05, 0x2a, 0x66, 0x0a, 0x08, 0x52, - 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x0e, 0x65, 0x6d, 0x70, 0x74, 0x79, - 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x10, 0x03, 0x12, - 0x0a, 0x0a, 0x06, 0x76, 0x69, 0x65, 0x77, 0x65, 0x72, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x65, - 0x64, 0x69, 0x74, 0x6f, 0x72, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x10, 0x06, 0x32, 0xaf, 0x0f, 0x0a, 0x07, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x12, - 0x3b, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x15, 0x2e, 0x61, 0x7a, - 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x04, - 0x55, 0x73, 0x65, 0x72, 0x12, 0x11, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x55, - 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x29, 0x0a, - 0x02, 0x4d, 0x65, 0x12, 0x0f, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0a, 0x54, 0x65, 0x6e, 0x61, - 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x17, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x54, 0x65, - 0x6e, 0x61, 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x18, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x35, 0x0a, 0x06, 0x54, - 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x12, 0x13, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, - 0x61, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x61, 0x7a, 0x70, - 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x11, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x50, 0x65, 0x72, 0x6d, - 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x13, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x54, - 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, - 0x7a, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x41, 0x0a, 0x0a, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x53, 0x61, 0x76, 0x65, 0x12, 0x17, 0x2e, - 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x53, 0x61, 0x76, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x54, 0x65, - 0x6e, 0x61, 0x6e, 0x74, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x56, 0x0a, 0x13, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x50, - 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x2e, 0x61, 0x7a, 0x70, 0x62, - 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x50, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, - 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x53, 0x61, 0x76, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x16, 0x54, 0x65, - 0x6e, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x61, - 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x7a, 0x70, 0x62, - 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x0c, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x19, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, - 0x61, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x18, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x53, 0x61, - 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x11, - 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x12, 0x1e, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x17, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x61, - 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x09, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x2e, 0x61, 0x7a, 0x70, 0x62, - 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x17, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x05, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x12, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x61, 0x7a, 0x70, 0x62, - 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x48, 0x0a, 0x10, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x12, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x09, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x53, 0x61, 0x76, 0x65, 0x12, 0x16, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x17, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x61, 0x76, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x12, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x41, 0x64, 0x64, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x22, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x6f, 0x64, - 0x69, 0x66, 0x79, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x56, 0x0a, 0x15, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x65, - 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x50, 0x65, 0x72, 0x6d, 0x69, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x61, - 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0e, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x53, 0x65, 0x74, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x12, 0x1b, 0x2e, 0x61, 0x7a, 0x70, 0x62, - 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x65, 0x74, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x53, 0x65, 0x74, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x08, 0x46, 0x65, 0x65, 0x64, 0x4c, 0x69, - 0x73, 0x74, 0x12, 0x15, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x7a, 0x70, 0x62, - 0x2e, 0x46, 0x65, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x04, 0x46, 0x65, 0x65, 0x64, 0x12, 0x11, 0x2e, 0x61, 0x7a, - 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, - 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x0f, 0x46, 0x65, 0x65, 0x64, 0x50, 0x65, 0x72, 0x6d, - 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x11, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x46, - 0x65, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x7a, 0x70, - 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x0c, 0x46, - 0x65, 0x65, 0x64, 0x53, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x19, 0x2e, 0x61, 0x7a, - 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x53, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x46, 0x65, - 0x65, 0x64, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x50, 0x0a, 0x0f, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4c, - 0x69, 0x73, 0x74, 0x12, 0x1c, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0b, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x18, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x7a, - 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x16, 0x46, 0x65, 0x65, 0x64, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x12, 0x18, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x61, - 0x7a, 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x50, - 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x12, 0x65, 0x0a, 0x18, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x28, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x7a, 0x70, - 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x61, 0x76, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x68, 0x0a, 0x1b, 0x46, - 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, - 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x2e, 0x61, 0x7a, 0x70, - 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, - 0x69, 0x66, 0x79, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x7a, 0x70, 0x62, 0x2e, 0x46, 0x65, 0x65, 0x64, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_azpb_proto_rawDescOnce sync.Once - file_azpb_proto_rawDescData = file_azpb_proto_rawDesc -) - -func file_azpb_proto_rawDescGZIP() []byte { - file_azpb_proto_rawDescOnce.Do(func() { - file_azpb_proto_rawDescData = protoimpl.X.CompressGZIP(file_azpb_proto_rawDescData) - }) - return file_azpb_proto_rawDescData -} - -var file_azpb_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_azpb_proto_msgTypes = make([]protoimpl.MessageInfo, 55) -var file_azpb_proto_goTypes = []interface{}{ - (Action)(0), // 0: azpb.Action - (ObjectType)(0), // 1: azpb.ObjectType - (Relation)(0), // 2: azpb.Relation - (*EntityRelation)(nil), // 3: azpb.EntityRelation - (*User)(nil), // 4: azpb.User - (*UserListRequest)(nil), // 5: azpb.UserListRequest - (*UserRequest)(nil), // 6: azpb.UserRequest - (*UserListResponse)(nil), // 7: azpb.UserListResponse - (*UserResponse)(nil), // 8: azpb.UserResponse - (*MeRequest)(nil), // 9: azpb.MeRequest - (*MeResponse)(nil), // 10: azpb.MeResponse - (*Tenant)(nil), // 11: azpb.Tenant - (*TenantSaveRequest)(nil), // 12: azpb.TenantSaveRequest - (*TenantRequest)(nil), // 13: azpb.TenantRequest - (*TenantListRequest)(nil), // 14: azpb.TenantListRequest - (*TenantResponse)(nil), // 15: azpb.TenantResponse - (*TenantListResponse)(nil), // 16: azpb.TenantListResponse - (*TenantPermissionsResponse)(nil), // 17: azpb.TenantPermissionsResponse - (*TenantCreateRequest)(nil), // 18: azpb.TenantCreateRequest - (*TenantCreateGroupRequest)(nil), // 19: azpb.TenantCreateGroupRequest - (*TenantCreateGroupResponse)(nil), // 20: azpb.TenantCreateGroupResponse - (*TenantModifyPermissionRequest)(nil), // 21: azpb.TenantModifyPermissionRequest - (*TenantSaveResponse)(nil), // 22: azpb.TenantSaveResponse - (*Group)(nil), // 23: azpb.Group - (*GroupRequest)(nil), // 24: azpb.GroupRequest - (*GroupSaveRequest)(nil), // 25: azpb.GroupSaveRequest - (*GroupListRequest)(nil), // 26: azpb.GroupListRequest - (*GroupModifyPermissionRequest)(nil), // 27: azpb.GroupModifyPermissionRequest - (*GroupResponse)(nil), // 28: azpb.GroupResponse - (*GroupListResponse)(nil), // 29: azpb.GroupListResponse - (*GroupPermissionsResponse)(nil), // 30: azpb.GroupPermissionsResponse - (*GroupSaveResponse)(nil), // 31: azpb.GroupSaveResponse - (*GroupSetTenantRequest)(nil), // 32: azpb.GroupSetTenantRequest - (*GroupSetTenantResponse)(nil), // 33: azpb.GroupSetTenantResponse - (*Feed)(nil), // 34: azpb.Feed - (*FeedRequest)(nil), // 35: azpb.FeedRequest - (*FeedListRequest)(nil), // 36: azpb.FeedListRequest - (*FeedPermissionsResponse)(nil), // 37: azpb.FeedPermissionsResponse - (*FeedResponse)(nil), // 38: azpb.FeedResponse - (*FeedListResponse)(nil), // 39: azpb.FeedListResponse - (*FeedSetGroupRequest)(nil), // 40: azpb.FeedSetGroupRequest - (*FeedSaveResponse)(nil), // 41: azpb.FeedSaveResponse - (*FeedVersion)(nil), // 42: azpb.FeedVersion - (*FeedVersionListRequest)(nil), // 43: azpb.FeedVersionListRequest - (*FeedVersionResponse)(nil), // 44: azpb.FeedVersionResponse - (*FeedVersionRequest)(nil), // 45: azpb.FeedVersionRequest - (*FeedVersionListResponse)(nil), // 46: azpb.FeedVersionListResponse - (*FeedVersionPermissionsResponse)(nil), // 47: azpb.FeedVersionPermissionsResponse - (*FeedVersionModifyPermissionRequest)(nil), // 48: azpb.FeedVersionModifyPermissionRequest - (*FeedVersionSaveResponse)(nil), // 49: azpb.FeedVersionSaveResponse - nil, // 50: azpb.MeResponse.ExternalDataEntry - (*TenantPermissionsResponse_Actions)(nil), // 51: azpb.TenantPermissionsResponse.Actions - (*TenantPermissionsResponse_Users)(nil), // 52: azpb.TenantPermissionsResponse.Users - (*GroupPermissionsResponse_Actions)(nil), // 53: azpb.GroupPermissionsResponse.Actions - (*GroupPermissionsResponse_Users)(nil), // 54: azpb.GroupPermissionsResponse.Users - (*FeedPermissionsResponse_Actions)(nil), // 55: azpb.FeedPermissionsResponse.Actions - (*FeedVersionPermissionsResponse_Actions)(nil), // 56: azpb.FeedVersionPermissionsResponse.Actions - (*FeedVersionPermissionsResponse_Users)(nil), // 57: azpb.FeedVersionPermissionsResponse.Users -} -var file_azpb_proto_depIdxs = []int32{ - 1, // 0: azpb.EntityRelation.type:type_name -> azpb.ObjectType - 2, // 1: azpb.EntityRelation.ref_relation:type_name -> azpb.Relation - 2, // 2: azpb.EntityRelation.relation:type_name -> azpb.Relation - 4, // 3: azpb.UserListResponse.users:type_name -> azpb.User - 4, // 4: azpb.UserResponse.user:type_name -> azpb.User - 4, // 5: azpb.MeResponse.user:type_name -> azpb.User - 23, // 6: azpb.MeResponse.groups:type_name -> azpb.Group - 23, // 7: azpb.MeResponse.expanded_groups:type_name -> azpb.Group - 50, // 8: azpb.MeResponse.external_data:type_name -> azpb.MeResponse.ExternalDataEntry - 11, // 9: azpb.TenantSaveRequest.tenant:type_name -> azpb.Tenant - 11, // 10: azpb.TenantResponse.tenant:type_name -> azpb.Tenant - 11, // 11: azpb.TenantListResponse.tenants:type_name -> azpb.Tenant - 11, // 12: azpb.TenantPermissionsResponse.tenant:type_name -> azpb.Tenant - 23, // 13: azpb.TenantPermissionsResponse.groups:type_name -> azpb.Group - 51, // 14: azpb.TenantPermissionsResponse.actions:type_name -> azpb.TenantPermissionsResponse.Actions - 52, // 15: azpb.TenantPermissionsResponse.users:type_name -> azpb.TenantPermissionsResponse.Users - 23, // 16: azpb.TenantCreateGroupRequest.group:type_name -> azpb.Group - 23, // 17: azpb.TenantCreateGroupResponse.group:type_name -> azpb.Group - 3, // 18: azpb.TenantModifyPermissionRequest.entity_relation:type_name -> azpb.EntityRelation - 23, // 19: azpb.GroupSaveRequest.group:type_name -> azpb.Group - 3, // 20: azpb.GroupModifyPermissionRequest.entity_relation:type_name -> azpb.EntityRelation - 23, // 21: azpb.GroupResponse.group:type_name -> azpb.Group - 23, // 22: azpb.GroupListResponse.groups:type_name -> azpb.Group - 23, // 23: azpb.GroupPermissionsResponse.group:type_name -> azpb.Group - 11, // 24: azpb.GroupPermissionsResponse.tenant:type_name -> azpb.Tenant - 34, // 25: azpb.GroupPermissionsResponse.feeds:type_name -> azpb.Feed - 53, // 26: azpb.GroupPermissionsResponse.actions:type_name -> azpb.GroupPermissionsResponse.Actions - 54, // 27: azpb.GroupPermissionsResponse.users:type_name -> azpb.GroupPermissionsResponse.Users - 23, // 28: azpb.GroupSaveResponse.group:type_name -> azpb.Group - 34, // 29: azpb.FeedPermissionsResponse.feed:type_name -> azpb.Feed - 23, // 30: azpb.FeedPermissionsResponse.group:type_name -> azpb.Group - 55, // 31: azpb.FeedPermissionsResponse.actions:type_name -> azpb.FeedPermissionsResponse.Actions - 34, // 32: azpb.FeedResponse.feed:type_name -> azpb.Feed - 34, // 33: azpb.FeedListResponse.feeds:type_name -> azpb.Feed - 42, // 34: azpb.FeedVersionResponse.feed_version:type_name -> azpb.FeedVersion - 42, // 35: azpb.FeedVersionListResponse.feed_versions:type_name -> azpb.FeedVersion - 42, // 36: azpb.FeedVersionPermissionsResponse.feed_version:type_name -> azpb.FeedVersion - 34, // 37: azpb.FeedVersionPermissionsResponse.feed:type_name -> azpb.Feed - 23, // 38: azpb.FeedVersionPermissionsResponse.group:type_name -> azpb.Group - 56, // 39: azpb.FeedVersionPermissionsResponse.actions:type_name -> azpb.FeedVersionPermissionsResponse.Actions - 57, // 40: azpb.FeedVersionPermissionsResponse.users:type_name -> azpb.FeedVersionPermissionsResponse.Users - 3, // 41: azpb.FeedVersionModifyPermissionRequest.entity_relation:type_name -> azpb.EntityRelation - 3, // 42: azpb.TenantPermissionsResponse.Users.admins:type_name -> azpb.EntityRelation - 3, // 43: azpb.TenantPermissionsResponse.Users.members:type_name -> azpb.EntityRelation - 3, // 44: azpb.GroupPermissionsResponse.Users.managers:type_name -> azpb.EntityRelation - 3, // 45: azpb.GroupPermissionsResponse.Users.editors:type_name -> azpb.EntityRelation - 3, // 46: azpb.GroupPermissionsResponse.Users.viewers:type_name -> azpb.EntityRelation - 3, // 47: azpb.FeedVersionPermissionsResponse.Users.editors:type_name -> azpb.EntityRelation - 3, // 48: azpb.FeedVersionPermissionsResponse.Users.viewers:type_name -> azpb.EntityRelation - 5, // 49: azpb.Checker.UserList:input_type -> azpb.UserListRequest - 6, // 50: azpb.Checker.User:input_type -> azpb.UserRequest - 9, // 51: azpb.Checker.Me:input_type -> azpb.MeRequest - 14, // 52: azpb.Checker.TenantList:input_type -> azpb.TenantListRequest - 13, // 53: azpb.Checker.Tenant:input_type -> azpb.TenantRequest - 13, // 54: azpb.Checker.TenantPermissions:input_type -> azpb.TenantRequest - 12, // 55: azpb.Checker.TenantSave:input_type -> azpb.TenantSaveRequest - 21, // 56: azpb.Checker.TenantAddPermission:input_type -> azpb.TenantModifyPermissionRequest - 21, // 57: azpb.Checker.TenantRemovePermission:input_type -> azpb.TenantModifyPermissionRequest - 18, // 58: azpb.Checker.TenantCreate:input_type -> azpb.TenantCreateRequest - 19, // 59: azpb.Checker.TenantCreateGroup:input_type -> azpb.TenantCreateGroupRequest - 26, // 60: azpb.Checker.GroupList:input_type -> azpb.GroupListRequest - 24, // 61: azpb.Checker.Group:input_type -> azpb.GroupRequest - 24, // 62: azpb.Checker.GroupPermissions:input_type -> azpb.GroupRequest - 25, // 63: azpb.Checker.GroupSave:input_type -> azpb.GroupSaveRequest - 27, // 64: azpb.Checker.GroupAddPermission:input_type -> azpb.GroupModifyPermissionRequest - 27, // 65: azpb.Checker.GroupRemovePermission:input_type -> azpb.GroupModifyPermissionRequest - 32, // 66: azpb.Checker.GroupSetTenant:input_type -> azpb.GroupSetTenantRequest - 36, // 67: azpb.Checker.FeedList:input_type -> azpb.FeedListRequest - 35, // 68: azpb.Checker.Feed:input_type -> azpb.FeedRequest - 35, // 69: azpb.Checker.FeedPermissions:input_type -> azpb.FeedRequest - 40, // 70: azpb.Checker.FeedSetGroup:input_type -> azpb.FeedSetGroupRequest - 43, // 71: azpb.Checker.FeedVersionList:input_type -> azpb.FeedVersionListRequest - 45, // 72: azpb.Checker.FeedVersion:input_type -> azpb.FeedVersionRequest - 45, // 73: azpb.Checker.FeedVersionPermissions:input_type -> azpb.FeedVersionRequest - 48, // 74: azpb.Checker.FeedVersionAddPermission:input_type -> azpb.FeedVersionModifyPermissionRequest - 48, // 75: azpb.Checker.FeedVersionRemovePermission:input_type -> azpb.FeedVersionModifyPermissionRequest - 7, // 76: azpb.Checker.UserList:output_type -> azpb.UserListResponse - 8, // 77: azpb.Checker.User:output_type -> azpb.UserResponse - 10, // 78: azpb.Checker.Me:output_type -> azpb.MeResponse - 16, // 79: azpb.Checker.TenantList:output_type -> azpb.TenantListResponse - 15, // 80: azpb.Checker.Tenant:output_type -> azpb.TenantResponse - 17, // 81: azpb.Checker.TenantPermissions:output_type -> azpb.TenantPermissionsResponse - 22, // 82: azpb.Checker.TenantSave:output_type -> azpb.TenantSaveResponse - 22, // 83: azpb.Checker.TenantAddPermission:output_type -> azpb.TenantSaveResponse - 22, // 84: azpb.Checker.TenantRemovePermission:output_type -> azpb.TenantSaveResponse - 22, // 85: azpb.Checker.TenantCreate:output_type -> azpb.TenantSaveResponse - 31, // 86: azpb.Checker.TenantCreateGroup:output_type -> azpb.GroupSaveResponse - 29, // 87: azpb.Checker.GroupList:output_type -> azpb.GroupListResponse - 28, // 88: azpb.Checker.Group:output_type -> azpb.GroupResponse - 30, // 89: azpb.Checker.GroupPermissions:output_type -> azpb.GroupPermissionsResponse - 31, // 90: azpb.Checker.GroupSave:output_type -> azpb.GroupSaveResponse - 31, // 91: azpb.Checker.GroupAddPermission:output_type -> azpb.GroupSaveResponse - 31, // 92: azpb.Checker.GroupRemovePermission:output_type -> azpb.GroupSaveResponse - 33, // 93: azpb.Checker.GroupSetTenant:output_type -> azpb.GroupSetTenantResponse - 39, // 94: azpb.Checker.FeedList:output_type -> azpb.FeedListResponse - 38, // 95: azpb.Checker.Feed:output_type -> azpb.FeedResponse - 37, // 96: azpb.Checker.FeedPermissions:output_type -> azpb.FeedPermissionsResponse - 41, // 97: azpb.Checker.FeedSetGroup:output_type -> azpb.FeedSaveResponse - 46, // 98: azpb.Checker.FeedVersionList:output_type -> azpb.FeedVersionListResponse - 44, // 99: azpb.Checker.FeedVersion:output_type -> azpb.FeedVersionResponse - 47, // 100: azpb.Checker.FeedVersionPermissions:output_type -> azpb.FeedVersionPermissionsResponse - 49, // 101: azpb.Checker.FeedVersionAddPermission:output_type -> azpb.FeedVersionSaveResponse - 49, // 102: azpb.Checker.FeedVersionRemovePermission:output_type -> azpb.FeedVersionSaveResponse - 76, // [76:103] is the sub-list for method output_type - 49, // [49:76] is the sub-list for method input_type - 49, // [49:49] is the sub-list for extension type_name - 49, // [49:49] is the sub-list for extension extendee - 0, // [0:49] is the sub-list for field type_name -} - -func init() { file_azpb_proto_init() } -func file_azpb_proto_init() { - if File_azpb_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_azpb_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EntityRelation); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*User); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UserListRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UserRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UserListResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UserResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MeRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MeResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Tenant); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TenantSaveRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TenantRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TenantListRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TenantResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TenantListResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TenantPermissionsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TenantCreateRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TenantCreateGroupRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TenantCreateGroupResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TenantModifyPermissionRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TenantSaveResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Group); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupSaveRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupListRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupModifyPermissionRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupListResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupPermissionsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupSaveResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupSetTenantRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupSetTenantResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Feed); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FeedRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FeedListRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FeedPermissionsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FeedResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FeedListResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FeedSetGroupRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FeedSaveResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FeedVersion); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FeedVersionListRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FeedVersionResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FeedVersionRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FeedVersionListResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FeedVersionPermissionsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FeedVersionModifyPermissionRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FeedVersionSaveResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TenantPermissionsResponse_Actions); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TenantPermissionsResponse_Users); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupPermissionsResponse_Actions); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupPermissionsResponse_Users); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FeedPermissionsResponse_Actions); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FeedVersionPermissionsResponse_Actions); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_azpb_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FeedVersionPermissionsResponse_Users); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_azpb_proto_rawDesc, - NumEnums: 3, - NumMessages: 55, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_azpb_proto_goTypes, - DependencyIndexes: file_azpb_proto_depIdxs, - EnumInfos: file_azpb_proto_enumTypes, - MessageInfos: file_azpb_proto_msgTypes, - }.Build() - File_azpb_proto = out.File - file_azpb_proto_rawDesc = nil - file_azpb_proto_goTypes = nil - file_azpb_proto_depIdxs = nil -} diff --git a/auth/authz/azpb.proto b/auth/authz/azpb.proto deleted file mode 100644 index d2f4679a..00000000 --- a/auth/authz/azpb.proto +++ /dev/null @@ -1,332 +0,0 @@ -syntax = "proto3"; - -package azpb; - -service Checker { - rpc UserList (UserListRequest) returns (UserListResponse) {} - rpc User (UserRequest) returns (UserResponse) {} - rpc Me (MeRequest) returns (MeResponse) {} - - rpc TenantList(TenantListRequest) returns (TenantListResponse) {} - rpc Tenant(TenantRequest) returns (TenantResponse) {} - rpc TenantPermissions(TenantRequest) returns (TenantPermissionsResponse) {} - rpc TenantSave(TenantSaveRequest) returns (TenantSaveResponse) {} - rpc TenantAddPermission(TenantModifyPermissionRequest) returns (TenantSaveResponse) {} - rpc TenantRemovePermission(TenantModifyPermissionRequest) returns (TenantSaveResponse) {} - rpc TenantCreate(TenantCreateRequest) returns (TenantSaveResponse) {} - rpc TenantCreateGroup(TenantCreateGroupRequest) returns (GroupSaveResponse) {} - - rpc GroupList(GroupListRequest) returns (GroupListResponse) {} - rpc Group(GroupRequest) returns (GroupResponse) {} - rpc GroupPermissions(GroupRequest) returns (GroupPermissionsResponse) {} - rpc GroupSave(GroupSaveRequest) returns (GroupSaveResponse) {} - rpc GroupAddPermission(GroupModifyPermissionRequest) returns (GroupSaveResponse) {} - rpc GroupRemovePermission(GroupModifyPermissionRequest) returns (GroupSaveResponse) {} - rpc GroupSetTenant(GroupSetTenantRequest) returns (GroupSetTenantResponse) {} - - rpc FeedList (FeedListRequest) returns (FeedListResponse) {} - rpc Feed (FeedRequest) returns (FeedResponse) {} - rpc FeedPermissions (FeedRequest) returns (FeedPermissionsResponse) {} - rpc FeedSetGroup(FeedSetGroupRequest) returns (FeedSaveResponse) {} - - rpc FeedVersionList(FeedVersionListRequest) returns (FeedVersionListResponse) {} - rpc FeedVersion(FeedVersionRequest) returns (FeedVersionResponse) {} - rpc FeedVersionPermissions(FeedVersionRequest) returns (FeedVersionPermissionsResponse) {} - rpc FeedVersionAddPermission(FeedVersionModifyPermissionRequest) returns (FeedVersionSaveResponse) {} - rpc FeedVersionRemovePermission(FeedVersionModifyPermissionRequest) returns (FeedVersionSaveResponse) {} - -}; - -enum Action { - empty_action = 0; - can_view = 1; - can_edit = 2; - can_edit_members = 3; - can_create_org = 4; - can_delete_org = 5; - can_create_feed_version = 6; - can_delete_feed_version = 7; - can_create_feed = 8; - can_delete_feed = 9; - can_set_group = 10; - can_set_tenant = 11; -} - -enum ObjectType { - empty_object = 0; - tenant = 1; - org = 2; - feed = 3; - feed_version = 4; - user = 5; -} - -enum Relation { - empty_relation = 0; - admin = 1; - member = 2; - manager = 3; - viewer = 4; - editor = 5; - parent = 6; -} - -message EntityRelation { - ObjectType type = 1; - string id = 2; - string name = 3; - Relation ref_relation = 4; - Relation relation = 5; -} - -////// - -message User { - string id = 1; - string name = 2; - string email = 3; -} - -message UserListRequest { - string q = 1; -} - -message UserRequest { - string id = 1; -} - -message UserListResponse { - repeated User users = 1; -} - -message UserResponse { - User user = 1; -} - -message MeRequest {} - -message MeResponse { - User user = 1; - repeated Group groups = 2; - repeated Group expanded_groups = 3; - map external_data = 4; - repeated string roles = 5; -} - -////// - -message Tenant { - int64 id = 1; - string name = 2; -} - -message TenantSaveRequest { - Tenant tenant = 1; -} - -message TenantRequest { - int64 id = 1; -} - -message TenantListRequest {} - -message TenantResponse { - Tenant tenant = 1; -} - -message TenantListResponse { - repeated Tenant tenants = 1; -} - -message TenantPermissionsResponse { - Tenant tenant = 1; - repeated Group groups = 2; - message Actions { - bool can_edit_members = 1; - bool can_view = 2; - bool can_edit = 3; - bool can_create_org = 4; - bool can_delete_org = 5; - } - Actions actions = 3; - message Users { - repeated EntityRelation admins = 1; - repeated EntityRelation members = 2; - } - Users users = 4; -} - -message TenantCreateRequest {} - -message TenantCreateGroupRequest { - int64 id = 1; - Group group = 2; -} - -message TenantCreateGroupResponse { - Group group = 1; -} - -message TenantModifyPermissionRequest { - int64 id = 1; - EntityRelation entity_relation = 2; -} - - -message TenantSaveResponse { -} - -////// - -message Group { - int64 id = 1; - string name = 2; -} - -message GroupRequest { - int64 id = 1; -} - -message GroupSaveRequest { - Group group = 1; -} - -message GroupListRequest {} - -message GroupModifyPermissionRequest { - int64 id = 1; - EntityRelation entity_relation = 2; -} - -message GroupResponse { - Group group = 1; -} - -message GroupListResponse { - repeated Group groups = 1; -} - -message GroupPermissionsResponse { - Group group = 1; - Tenant tenant = 2; - repeated Feed feeds = 3; - message Actions { - bool can_view = 1; - bool can_edit_members = 2; - bool can_create_feed = 3; - bool can_delete_feed = 4; - bool can_edit = 5; - bool can_set_tenant = 6; - } - Actions actions = 4; - message Users { - repeated EntityRelation managers = 1; - repeated EntityRelation editors = 2; - repeated EntityRelation viewers = 3; - } - Users users = 5; -} - -message GroupSaveResponse { - Group group = 1; -} - -message GroupSetTenantRequest { - int64 id = 1; - int64 tenant_id = 2; -} - -message GroupSetTenantResponse {} - -////// - -message Feed { - int64 id = 1; - string onestop_id = 2; - string name = 3; -} - -message FeedRequest { - int64 id = 1; -} - -message FeedListRequest { -} - -message FeedPermissionsResponse { - Feed feed = 1; - Group group = 2; - message Actions { - bool can_view = 1; - bool can_edit = 2; - bool can_set_group = 3; - bool can_create_feed_version = 4; - bool can_delete_feed_version = 5; - } - Actions actions = 3; -} - -message FeedResponse { - Feed feed = 1; -} - -message FeedListResponse { - repeated Feed feeds = 1; -} - -message FeedSetGroupRequest { - int64 id = 1; - int64 group_id = 2; -} - - -message FeedSaveResponse { -} - -////// - -message FeedVersion { - int64 id = 1; - string name = 2; - string sha1 = 3; - int64 feed_id = 4; -} - -message FeedVersionListRequest{} - -message FeedVersionResponse { - FeedVersion feed_version = 1; -} - -message FeedVersionRequest { - int64 id = 1; -} - -message FeedVersionListResponse { - repeated FeedVersion feed_versions = 1; -} - -message FeedVersionPermissionsResponse { - FeedVersion feed_version = 1; - Feed feed = 2; - Group group = 3; - message Actions { - bool can_view = 1; - bool can_edit_members = 2; - bool can_edit = 3; - } - Actions actions = 4; - message Users { - repeated EntityRelation editors = 1; - repeated EntityRelation viewers = 2; - } - Users users = 5; -} - -message FeedVersionModifyPermissionRequest { - int64 id = 1; - EntityRelation entity_relation = 2; -} - -message FeedVersionSaveResponse { -} diff --git a/auth/authz/azpb_gen.go b/auth/authz/azpb_gen.go deleted file mode 100644 index 9543a7a4..00000000 --- a/auth/authz/azpb_gen.go +++ /dev/null @@ -1,3 +0,0 @@ -//go:generate protoc --go_out=. --go-grpc_out=. --go-grpc_opt=paths=source_relative --go-grpc_opt=Mazpb.proto=./authz --go_opt=paths=source_relative --go_opt=Mazpb.proto=./authz azpb.proto - -package authz diff --git a/auth/authz/azpb_grpc.pb.go b/auth/authz/azpb_grpc.pb.go deleted file mode 100644 index fd1f572c..00000000 --- a/auth/authz/azpb_grpc.pb.go +++ /dev/null @@ -1,1041 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.2.0 -// - protoc v4.23.3 -// source: azpb.proto - -package authz - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 - -// CheckerClient is the client API for Checker service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type CheckerClient interface { - UserList(ctx context.Context, in *UserListRequest, opts ...grpc.CallOption) (*UserListResponse, error) - User(ctx context.Context, in *UserRequest, opts ...grpc.CallOption) (*UserResponse, error) - Me(ctx context.Context, in *MeRequest, opts ...grpc.CallOption) (*MeResponse, error) - TenantList(ctx context.Context, in *TenantListRequest, opts ...grpc.CallOption) (*TenantListResponse, error) - Tenant(ctx context.Context, in *TenantRequest, opts ...grpc.CallOption) (*TenantResponse, error) - TenantPermissions(ctx context.Context, in *TenantRequest, opts ...grpc.CallOption) (*TenantPermissionsResponse, error) - TenantSave(ctx context.Context, in *TenantSaveRequest, opts ...grpc.CallOption) (*TenantSaveResponse, error) - TenantAddPermission(ctx context.Context, in *TenantModifyPermissionRequest, opts ...grpc.CallOption) (*TenantSaveResponse, error) - TenantRemovePermission(ctx context.Context, in *TenantModifyPermissionRequest, opts ...grpc.CallOption) (*TenantSaveResponse, error) - TenantCreate(ctx context.Context, in *TenantCreateRequest, opts ...grpc.CallOption) (*TenantSaveResponse, error) - TenantCreateGroup(ctx context.Context, in *TenantCreateGroupRequest, opts ...grpc.CallOption) (*GroupSaveResponse, error) - GroupList(ctx context.Context, in *GroupListRequest, opts ...grpc.CallOption) (*GroupListResponse, error) - Group(ctx context.Context, in *GroupRequest, opts ...grpc.CallOption) (*GroupResponse, error) - GroupPermissions(ctx context.Context, in *GroupRequest, opts ...grpc.CallOption) (*GroupPermissionsResponse, error) - GroupSave(ctx context.Context, in *GroupSaveRequest, opts ...grpc.CallOption) (*GroupSaveResponse, error) - GroupAddPermission(ctx context.Context, in *GroupModifyPermissionRequest, opts ...grpc.CallOption) (*GroupSaveResponse, error) - GroupRemovePermission(ctx context.Context, in *GroupModifyPermissionRequest, opts ...grpc.CallOption) (*GroupSaveResponse, error) - GroupSetTenant(ctx context.Context, in *GroupSetTenantRequest, opts ...grpc.CallOption) (*GroupSetTenantResponse, error) - FeedList(ctx context.Context, in *FeedListRequest, opts ...grpc.CallOption) (*FeedListResponse, error) - Feed(ctx context.Context, in *FeedRequest, opts ...grpc.CallOption) (*FeedResponse, error) - FeedPermissions(ctx context.Context, in *FeedRequest, opts ...grpc.CallOption) (*FeedPermissionsResponse, error) - FeedSetGroup(ctx context.Context, in *FeedSetGroupRequest, opts ...grpc.CallOption) (*FeedSaveResponse, error) - FeedVersionList(ctx context.Context, in *FeedVersionListRequest, opts ...grpc.CallOption) (*FeedVersionListResponse, error) - FeedVersion(ctx context.Context, in *FeedVersionRequest, opts ...grpc.CallOption) (*FeedVersionResponse, error) - FeedVersionPermissions(ctx context.Context, in *FeedVersionRequest, opts ...grpc.CallOption) (*FeedVersionPermissionsResponse, error) - FeedVersionAddPermission(ctx context.Context, in *FeedVersionModifyPermissionRequest, opts ...grpc.CallOption) (*FeedVersionSaveResponse, error) - FeedVersionRemovePermission(ctx context.Context, in *FeedVersionModifyPermissionRequest, opts ...grpc.CallOption) (*FeedVersionSaveResponse, error) -} - -type checkerClient struct { - cc grpc.ClientConnInterface -} - -func NewCheckerClient(cc grpc.ClientConnInterface) CheckerClient { - return &checkerClient{cc} -} - -func (c *checkerClient) UserList(ctx context.Context, in *UserListRequest, opts ...grpc.CallOption) (*UserListResponse, error) { - out := new(UserListResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/UserList", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) User(ctx context.Context, in *UserRequest, opts ...grpc.CallOption) (*UserResponse, error) { - out := new(UserResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/User", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) Me(ctx context.Context, in *MeRequest, opts ...grpc.CallOption) (*MeResponse, error) { - out := new(MeResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/Me", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) TenantList(ctx context.Context, in *TenantListRequest, opts ...grpc.CallOption) (*TenantListResponse, error) { - out := new(TenantListResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/TenantList", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) Tenant(ctx context.Context, in *TenantRequest, opts ...grpc.CallOption) (*TenantResponse, error) { - out := new(TenantResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/Tenant", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) TenantPermissions(ctx context.Context, in *TenantRequest, opts ...grpc.CallOption) (*TenantPermissionsResponse, error) { - out := new(TenantPermissionsResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/TenantPermissions", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) TenantSave(ctx context.Context, in *TenantSaveRequest, opts ...grpc.CallOption) (*TenantSaveResponse, error) { - out := new(TenantSaveResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/TenantSave", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) TenantAddPermission(ctx context.Context, in *TenantModifyPermissionRequest, opts ...grpc.CallOption) (*TenantSaveResponse, error) { - out := new(TenantSaveResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/TenantAddPermission", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) TenantRemovePermission(ctx context.Context, in *TenantModifyPermissionRequest, opts ...grpc.CallOption) (*TenantSaveResponse, error) { - out := new(TenantSaveResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/TenantRemovePermission", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) TenantCreate(ctx context.Context, in *TenantCreateRequest, opts ...grpc.CallOption) (*TenantSaveResponse, error) { - out := new(TenantSaveResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/TenantCreate", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) TenantCreateGroup(ctx context.Context, in *TenantCreateGroupRequest, opts ...grpc.CallOption) (*GroupSaveResponse, error) { - out := new(GroupSaveResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/TenantCreateGroup", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) GroupList(ctx context.Context, in *GroupListRequest, opts ...grpc.CallOption) (*GroupListResponse, error) { - out := new(GroupListResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/GroupList", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) Group(ctx context.Context, in *GroupRequest, opts ...grpc.CallOption) (*GroupResponse, error) { - out := new(GroupResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/Group", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) GroupPermissions(ctx context.Context, in *GroupRequest, opts ...grpc.CallOption) (*GroupPermissionsResponse, error) { - out := new(GroupPermissionsResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/GroupPermissions", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) GroupSave(ctx context.Context, in *GroupSaveRequest, opts ...grpc.CallOption) (*GroupSaveResponse, error) { - out := new(GroupSaveResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/GroupSave", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) GroupAddPermission(ctx context.Context, in *GroupModifyPermissionRequest, opts ...grpc.CallOption) (*GroupSaveResponse, error) { - out := new(GroupSaveResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/GroupAddPermission", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) GroupRemovePermission(ctx context.Context, in *GroupModifyPermissionRequest, opts ...grpc.CallOption) (*GroupSaveResponse, error) { - out := new(GroupSaveResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/GroupRemovePermission", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) GroupSetTenant(ctx context.Context, in *GroupSetTenantRequest, opts ...grpc.CallOption) (*GroupSetTenantResponse, error) { - out := new(GroupSetTenantResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/GroupSetTenant", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) FeedList(ctx context.Context, in *FeedListRequest, opts ...grpc.CallOption) (*FeedListResponse, error) { - out := new(FeedListResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/FeedList", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) Feed(ctx context.Context, in *FeedRequest, opts ...grpc.CallOption) (*FeedResponse, error) { - out := new(FeedResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/Feed", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) FeedPermissions(ctx context.Context, in *FeedRequest, opts ...grpc.CallOption) (*FeedPermissionsResponse, error) { - out := new(FeedPermissionsResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/FeedPermissions", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) FeedSetGroup(ctx context.Context, in *FeedSetGroupRequest, opts ...grpc.CallOption) (*FeedSaveResponse, error) { - out := new(FeedSaveResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/FeedSetGroup", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) FeedVersionList(ctx context.Context, in *FeedVersionListRequest, opts ...grpc.CallOption) (*FeedVersionListResponse, error) { - out := new(FeedVersionListResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/FeedVersionList", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) FeedVersion(ctx context.Context, in *FeedVersionRequest, opts ...grpc.CallOption) (*FeedVersionResponse, error) { - out := new(FeedVersionResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/FeedVersion", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) FeedVersionPermissions(ctx context.Context, in *FeedVersionRequest, opts ...grpc.CallOption) (*FeedVersionPermissionsResponse, error) { - out := new(FeedVersionPermissionsResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/FeedVersionPermissions", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) FeedVersionAddPermission(ctx context.Context, in *FeedVersionModifyPermissionRequest, opts ...grpc.CallOption) (*FeedVersionSaveResponse, error) { - out := new(FeedVersionSaveResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/FeedVersionAddPermission", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *checkerClient) FeedVersionRemovePermission(ctx context.Context, in *FeedVersionModifyPermissionRequest, opts ...grpc.CallOption) (*FeedVersionSaveResponse, error) { - out := new(FeedVersionSaveResponse) - err := c.cc.Invoke(ctx, "/azpb.Checker/FeedVersionRemovePermission", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// CheckerServer is the server API for Checker service. -// All implementations must embed UnimplementedCheckerServer -// for forward compatibility -type CheckerServer interface { - UserList(context.Context, *UserListRequest) (*UserListResponse, error) - User(context.Context, *UserRequest) (*UserResponse, error) - Me(context.Context, *MeRequest) (*MeResponse, error) - TenantList(context.Context, *TenantListRequest) (*TenantListResponse, error) - Tenant(context.Context, *TenantRequest) (*TenantResponse, error) - TenantPermissions(context.Context, *TenantRequest) (*TenantPermissionsResponse, error) - TenantSave(context.Context, *TenantSaveRequest) (*TenantSaveResponse, error) - TenantAddPermission(context.Context, *TenantModifyPermissionRequest) (*TenantSaveResponse, error) - TenantRemovePermission(context.Context, *TenantModifyPermissionRequest) (*TenantSaveResponse, error) - TenantCreate(context.Context, *TenantCreateRequest) (*TenantSaveResponse, error) - TenantCreateGroup(context.Context, *TenantCreateGroupRequest) (*GroupSaveResponse, error) - GroupList(context.Context, *GroupListRequest) (*GroupListResponse, error) - Group(context.Context, *GroupRequest) (*GroupResponse, error) - GroupPermissions(context.Context, *GroupRequest) (*GroupPermissionsResponse, error) - GroupSave(context.Context, *GroupSaveRequest) (*GroupSaveResponse, error) - GroupAddPermission(context.Context, *GroupModifyPermissionRequest) (*GroupSaveResponse, error) - GroupRemovePermission(context.Context, *GroupModifyPermissionRequest) (*GroupSaveResponse, error) - GroupSetTenant(context.Context, *GroupSetTenantRequest) (*GroupSetTenantResponse, error) - FeedList(context.Context, *FeedListRequest) (*FeedListResponse, error) - Feed(context.Context, *FeedRequest) (*FeedResponse, error) - FeedPermissions(context.Context, *FeedRequest) (*FeedPermissionsResponse, error) - FeedSetGroup(context.Context, *FeedSetGroupRequest) (*FeedSaveResponse, error) - FeedVersionList(context.Context, *FeedVersionListRequest) (*FeedVersionListResponse, error) - FeedVersion(context.Context, *FeedVersionRequest) (*FeedVersionResponse, error) - FeedVersionPermissions(context.Context, *FeedVersionRequest) (*FeedVersionPermissionsResponse, error) - FeedVersionAddPermission(context.Context, *FeedVersionModifyPermissionRequest) (*FeedVersionSaveResponse, error) - FeedVersionRemovePermission(context.Context, *FeedVersionModifyPermissionRequest) (*FeedVersionSaveResponse, error) - mustEmbedUnimplementedCheckerServer() -} - -// UnimplementedCheckerServer must be embedded to have forward compatible implementations. -type UnimplementedCheckerServer struct { -} - -func (UnimplementedCheckerServer) UserList(context.Context, *UserListRequest) (*UserListResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method UserList not implemented") -} -func (UnimplementedCheckerServer) User(context.Context, *UserRequest) (*UserResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method User not implemented") -} -func (UnimplementedCheckerServer) Me(context.Context, *MeRequest) (*MeResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Me not implemented") -} -func (UnimplementedCheckerServer) TenantList(context.Context, *TenantListRequest) (*TenantListResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method TenantList not implemented") -} -func (UnimplementedCheckerServer) Tenant(context.Context, *TenantRequest) (*TenantResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Tenant not implemented") -} -func (UnimplementedCheckerServer) TenantPermissions(context.Context, *TenantRequest) (*TenantPermissionsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method TenantPermissions not implemented") -} -func (UnimplementedCheckerServer) TenantSave(context.Context, *TenantSaveRequest) (*TenantSaveResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method TenantSave not implemented") -} -func (UnimplementedCheckerServer) TenantAddPermission(context.Context, *TenantModifyPermissionRequest) (*TenantSaveResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method TenantAddPermission not implemented") -} -func (UnimplementedCheckerServer) TenantRemovePermission(context.Context, *TenantModifyPermissionRequest) (*TenantSaveResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method TenantRemovePermission not implemented") -} -func (UnimplementedCheckerServer) TenantCreate(context.Context, *TenantCreateRequest) (*TenantSaveResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method TenantCreate not implemented") -} -func (UnimplementedCheckerServer) TenantCreateGroup(context.Context, *TenantCreateGroupRequest) (*GroupSaveResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method TenantCreateGroup not implemented") -} -func (UnimplementedCheckerServer) GroupList(context.Context, *GroupListRequest) (*GroupListResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GroupList not implemented") -} -func (UnimplementedCheckerServer) Group(context.Context, *GroupRequest) (*GroupResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Group not implemented") -} -func (UnimplementedCheckerServer) GroupPermissions(context.Context, *GroupRequest) (*GroupPermissionsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GroupPermissions not implemented") -} -func (UnimplementedCheckerServer) GroupSave(context.Context, *GroupSaveRequest) (*GroupSaveResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GroupSave not implemented") -} -func (UnimplementedCheckerServer) GroupAddPermission(context.Context, *GroupModifyPermissionRequest) (*GroupSaveResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GroupAddPermission not implemented") -} -func (UnimplementedCheckerServer) GroupRemovePermission(context.Context, *GroupModifyPermissionRequest) (*GroupSaveResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GroupRemovePermission not implemented") -} -func (UnimplementedCheckerServer) GroupSetTenant(context.Context, *GroupSetTenantRequest) (*GroupSetTenantResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GroupSetTenant not implemented") -} -func (UnimplementedCheckerServer) FeedList(context.Context, *FeedListRequest) (*FeedListResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method FeedList not implemented") -} -func (UnimplementedCheckerServer) Feed(context.Context, *FeedRequest) (*FeedResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Feed not implemented") -} -func (UnimplementedCheckerServer) FeedPermissions(context.Context, *FeedRequest) (*FeedPermissionsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method FeedPermissions not implemented") -} -func (UnimplementedCheckerServer) FeedSetGroup(context.Context, *FeedSetGroupRequest) (*FeedSaveResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method FeedSetGroup not implemented") -} -func (UnimplementedCheckerServer) FeedVersionList(context.Context, *FeedVersionListRequest) (*FeedVersionListResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method FeedVersionList not implemented") -} -func (UnimplementedCheckerServer) FeedVersion(context.Context, *FeedVersionRequest) (*FeedVersionResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method FeedVersion not implemented") -} -func (UnimplementedCheckerServer) FeedVersionPermissions(context.Context, *FeedVersionRequest) (*FeedVersionPermissionsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method FeedVersionPermissions not implemented") -} -func (UnimplementedCheckerServer) FeedVersionAddPermission(context.Context, *FeedVersionModifyPermissionRequest) (*FeedVersionSaveResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method FeedVersionAddPermission not implemented") -} -func (UnimplementedCheckerServer) FeedVersionRemovePermission(context.Context, *FeedVersionModifyPermissionRequest) (*FeedVersionSaveResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method FeedVersionRemovePermission not implemented") -} -func (UnimplementedCheckerServer) mustEmbedUnimplementedCheckerServer() {} - -// UnsafeCheckerServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to CheckerServer will -// result in compilation errors. -type UnsafeCheckerServer interface { - mustEmbedUnimplementedCheckerServer() -} - -func RegisterCheckerServer(s grpc.ServiceRegistrar, srv CheckerServer) { - s.RegisterService(&Checker_ServiceDesc, srv) -} - -func _Checker_UserList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UserListRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).UserList(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/UserList", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).UserList(ctx, req.(*UserListRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_User_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UserRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).User(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/User", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).User(ctx, req.(*UserRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_Me_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MeRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).Me(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/Me", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).Me(ctx, req.(*MeRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_TenantList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(TenantListRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).TenantList(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/TenantList", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).TenantList(ctx, req.(*TenantListRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_Tenant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(TenantRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).Tenant(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/Tenant", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).Tenant(ctx, req.(*TenantRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_TenantPermissions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(TenantRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).TenantPermissions(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/TenantPermissions", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).TenantPermissions(ctx, req.(*TenantRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_TenantSave_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(TenantSaveRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).TenantSave(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/TenantSave", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).TenantSave(ctx, req.(*TenantSaveRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_TenantAddPermission_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(TenantModifyPermissionRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).TenantAddPermission(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/TenantAddPermission", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).TenantAddPermission(ctx, req.(*TenantModifyPermissionRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_TenantRemovePermission_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(TenantModifyPermissionRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).TenantRemovePermission(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/TenantRemovePermission", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).TenantRemovePermission(ctx, req.(*TenantModifyPermissionRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_TenantCreate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(TenantCreateRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).TenantCreate(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/TenantCreate", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).TenantCreate(ctx, req.(*TenantCreateRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_TenantCreateGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(TenantCreateGroupRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).TenantCreateGroup(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/TenantCreateGroup", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).TenantCreateGroup(ctx, req.(*TenantCreateGroupRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_GroupList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GroupListRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).GroupList(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/GroupList", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).GroupList(ctx, req.(*GroupListRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_Group_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GroupRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).Group(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/Group", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).Group(ctx, req.(*GroupRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_GroupPermissions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GroupRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).GroupPermissions(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/GroupPermissions", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).GroupPermissions(ctx, req.(*GroupRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_GroupSave_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GroupSaveRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).GroupSave(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/GroupSave", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).GroupSave(ctx, req.(*GroupSaveRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_GroupAddPermission_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GroupModifyPermissionRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).GroupAddPermission(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/GroupAddPermission", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).GroupAddPermission(ctx, req.(*GroupModifyPermissionRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_GroupRemovePermission_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GroupModifyPermissionRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).GroupRemovePermission(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/GroupRemovePermission", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).GroupRemovePermission(ctx, req.(*GroupModifyPermissionRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_GroupSetTenant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GroupSetTenantRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).GroupSetTenant(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/GroupSetTenant", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).GroupSetTenant(ctx, req.(*GroupSetTenantRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_FeedList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(FeedListRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).FeedList(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/FeedList", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).FeedList(ctx, req.(*FeedListRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_Feed_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(FeedRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).Feed(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/Feed", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).Feed(ctx, req.(*FeedRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_FeedPermissions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(FeedRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).FeedPermissions(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/FeedPermissions", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).FeedPermissions(ctx, req.(*FeedRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_FeedSetGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(FeedSetGroupRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).FeedSetGroup(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/FeedSetGroup", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).FeedSetGroup(ctx, req.(*FeedSetGroupRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_FeedVersionList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(FeedVersionListRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).FeedVersionList(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/FeedVersionList", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).FeedVersionList(ctx, req.(*FeedVersionListRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_FeedVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(FeedVersionRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).FeedVersion(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/FeedVersion", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).FeedVersion(ctx, req.(*FeedVersionRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_FeedVersionPermissions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(FeedVersionRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).FeedVersionPermissions(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/FeedVersionPermissions", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).FeedVersionPermissions(ctx, req.(*FeedVersionRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_FeedVersionAddPermission_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(FeedVersionModifyPermissionRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).FeedVersionAddPermission(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/FeedVersionAddPermission", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).FeedVersionAddPermission(ctx, req.(*FeedVersionModifyPermissionRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Checker_FeedVersionRemovePermission_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(FeedVersionModifyPermissionRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckerServer).FeedVersionRemovePermission(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/azpb.Checker/FeedVersionRemovePermission", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckerServer).FeedVersionRemovePermission(ctx, req.(*FeedVersionModifyPermissionRequest)) - } - return interceptor(ctx, in, info, handler) -} - -// Checker_ServiceDesc is the grpc.ServiceDesc for Checker service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var Checker_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "azpb.Checker", - HandlerType: (*CheckerServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "UserList", - Handler: _Checker_UserList_Handler, - }, - { - MethodName: "User", - Handler: _Checker_User_Handler, - }, - { - MethodName: "Me", - Handler: _Checker_Me_Handler, - }, - { - MethodName: "TenantList", - Handler: _Checker_TenantList_Handler, - }, - { - MethodName: "Tenant", - Handler: _Checker_Tenant_Handler, - }, - { - MethodName: "TenantPermissions", - Handler: _Checker_TenantPermissions_Handler, - }, - { - MethodName: "TenantSave", - Handler: _Checker_TenantSave_Handler, - }, - { - MethodName: "TenantAddPermission", - Handler: _Checker_TenantAddPermission_Handler, - }, - { - MethodName: "TenantRemovePermission", - Handler: _Checker_TenantRemovePermission_Handler, - }, - { - MethodName: "TenantCreate", - Handler: _Checker_TenantCreate_Handler, - }, - { - MethodName: "TenantCreateGroup", - Handler: _Checker_TenantCreateGroup_Handler, - }, - { - MethodName: "GroupList", - Handler: _Checker_GroupList_Handler, - }, - { - MethodName: "Group", - Handler: _Checker_Group_Handler, - }, - { - MethodName: "GroupPermissions", - Handler: _Checker_GroupPermissions_Handler, - }, - { - MethodName: "GroupSave", - Handler: _Checker_GroupSave_Handler, - }, - { - MethodName: "GroupAddPermission", - Handler: _Checker_GroupAddPermission_Handler, - }, - { - MethodName: "GroupRemovePermission", - Handler: _Checker_GroupRemovePermission_Handler, - }, - { - MethodName: "GroupSetTenant", - Handler: _Checker_GroupSetTenant_Handler, - }, - { - MethodName: "FeedList", - Handler: _Checker_FeedList_Handler, - }, - { - MethodName: "Feed", - Handler: _Checker_Feed_Handler, - }, - { - MethodName: "FeedPermissions", - Handler: _Checker_FeedPermissions_Handler, - }, - { - MethodName: "FeedSetGroup", - Handler: _Checker_FeedSetGroup_Handler, - }, - { - MethodName: "FeedVersionList", - Handler: _Checker_FeedVersionList_Handler, - }, - { - MethodName: "FeedVersion", - Handler: _Checker_FeedVersion_Handler, - }, - { - MethodName: "FeedVersionPermissions", - Handler: _Checker_FeedVersionPermissions_Handler, - }, - { - MethodName: "FeedVersionAddPermission", - Handler: _Checker_FeedVersionAddPermission_Handler, - }, - { - MethodName: "FeedVersionRemovePermission", - Handler: _Checker_FeedVersionRemovePermission_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "azpb.proto", -} diff --git a/auth/authz/tk.go b/auth/authz/tk.go deleted file mode 100644 index d2a15124..00000000 --- a/auth/authz/tk.go +++ /dev/null @@ -1,248 +0,0 @@ -package authz - -import ( - "errors" - "fmt" - "strconv" -) - -var ErrUnauthorized = errors.New("unauthorized") - -// For convenience - -var FeedType = ObjectType_feed -var UserType = ObjectType_user -var TenantType = ObjectType_tenant -var GroupType = ObjectType_org -var FeedVersionType = ObjectType_feed_version - -var ViewerRelation = Relation_viewer -var MemberRelation = Relation_member -var AdminRelation = Relation_admin -var ManagerRelation = Relation_manager -var ParentRelation = Relation_parent -var EditorRelation = Relation_editor - -var CanEdit = Action_can_edit -var CanView = Action_can_view -var CanCreateFeedVersion = Action_can_create_feed_version -var CanDeleteFeedVersion = Action_can_delete_feed_version -var CanCreateFeed = Action_can_create_feed -var CanDeleteFeed = Action_can_delete_feed -var CanSetGroup = Action_can_set_group -var CanCreateOrg = Action_can_create_org -var CanEditMembers = Action_can_edit_members -var CanDeleteOrg = Action_can_delete_org -var CanSetTenant = Action_can_set_tenant - -func RelationString(v string) (Relation, error) { - if a, ok := Relation_value[v]; ok { - return Relation(a), nil - } - return Relation(0), errors.New("invalid relation") -} - -func ActionString(v string) (Action, error) { - if a, ok := Action_value[v]; ok { - return Action(a), nil - } - return Action(0), errors.New("invalid action") -} - -func ObjectTypeString(v string) (ObjectType, error) { - if a, ok := ObjectType_value[v]; ok { - return ObjectType(a), nil - } - return ObjectType(0), errors.New("invalid object type") -} - -func IsRelation(v Relation) bool { - _, ok := Relation_name[int32(v)] - return ok && v > 0 -} - -func IsAction(v Action) bool { - _, ok := Action_name[int32(v)] - return ok && v > 0 -} - -func IsObjectType(v ObjectType) bool { - _, ok := ObjectType_name[int32(v)] - return ok && v > 0 -} - -func NewEntityRelation(ek EntityKey, rel Relation) *EntityRelation { - ur := EntityRelation{ - Type: ek.Type, - Id: ek.Name, - RefRelation: ek.RefRel, - Relation: rel, - } - return &ur -} - -func (er *EntityRelation) Int64() int64 { - a, _ := strconv.Atoi(er.Id) - return int64(a) -} - -func (er *EntityRelation) WithObject(ek EntityKey) TupleKey { - tk := NewTupleKey(). - WithSubject(er.GetType(), er.GetId()). - WithObjectID(ek.Type, ek.ID()). - WithRelation(er.GetRelation()) - if er.RefRelation > 0 { - tk.Subject = tk.Subject.WithRefRel(er.RefRelation) - } - return tk - -} - -type EntityKey struct { - Type ObjectType `json:"type"` - Name string `json:"name"` - RefRel Relation `json:"ref_rel"` -} - -func NewEntityKey(t ObjectType, name string) EntityKey { - return EntityKey{Type: t, Name: name} -} - -func (ek EntityKey) Equals(other EntityKey) bool { - return ek.Type == other.Type && - ek.Name == other.Name && - ek.RefRel == other.RefRel -} - -func (ek EntityKey) WithRefRel(r Relation) EntityKey { - ek.RefRel = r - return ek -} - -func (ek EntityKey) ID() int64 { - v, _ := strconv.Atoi(ek.Name) - return int64(v) -} - -func (ek EntityKey) String() string { - if ek.Name == "" { - return ek.Type.String() - } - if ek.RefRel > 0 { - return fmt.Sprintf("%s:%s#%s", ek.Type.String(), ek.Name, ek.RefRel.String()) - } - return fmt.Sprintf("%s:%s", ek.Type.String(), ek.Name) -} - -type TupleKey struct { - Subject EntityKey - Object EntityKey - Action Action `json:"action"` - Relation Relation `json:"relation"` -} - -func NewTupleKey() TupleKey { return TupleKey{} } - -func (tk TupleKey) Equals(other TupleKey) bool { - return tk.Subject.Equals(other.Subject) && - tk.Object.Equals(other.Object) && - tk.Action == other.Action && - tk.Relation == other.Relation -} - -func (tk TupleKey) String() string { - r := "" - if IsRelation(tk.Relation) { - r = "|relation:" + tk.Relation.String() - } else if IsAction(tk.Action) { - r = "|action:" + tk.Action.String() - } - return fmt.Sprintf("%s|%s%s", tk.Subject.String(), tk.Object.String(), r) -} - -func (tk TupleKey) IsValid() bool { - return tk.Validate() == nil -} - -func (tk TupleKey) Validate() error { - if tk.Subject.Name != "" && !IsObjectType(tk.Subject.Type) { - return errors.New("invalid user type") - } - if tk.Object.Name != "" && !IsObjectType(tk.Object.Type) { - return errors.New("invalid object type") - } - if tk.Subject.Name == "" && tk.Object.Name == "" { - return errors.New("user name or object name is required") - } - if tk.Subject.Name != "" && tk.Object.Name != "" { - if tk.Action == 0 && !IsRelation(tk.Relation) { - return errors.New("invalid relation") - } - if tk.Relation == 0 && !IsAction(tk.Action) { - return errors.New("invalid action") - } - } - return nil -} - -func (tk TupleKey) ActionOrRelation() string { - if IsAction(tk.Action) { - return tk.Action.String() - } else if IsRelation(tk.Relation) { - return tk.Relation.String() - } - return "" -} - -func (tk TupleKey) WithUser(user string) TupleKey { - return TupleKey{ - Subject: NewEntityKey(UserType, user), - Object: tk.Object, - Relation: tk.Relation, - Action: tk.Action, - } -} - -func (tk TupleKey) WithSubject(userType ObjectType, userName string) TupleKey { - return TupleKey{ - Subject: NewEntityKey(userType, userName), - Object: tk.Object, - Relation: tk.Relation, - Action: tk.Action, - } -} - -func (tk TupleKey) WithSubjectID(userType ObjectType, userId int64) TupleKey { - return tk.WithSubject(userType, strconv.Itoa(int(userId))) -} - -func (tk TupleKey) WithObject(objectType ObjectType, objectName string) TupleKey { - return TupleKey{ - Subject: tk.Subject, - Object: NewEntityKey(objectType, objectName), - Relation: tk.Relation, - Action: tk.Action, - } -} - -func (tk TupleKey) WithObjectID(objectType ObjectType, objectId int64) TupleKey { - return tk.WithObject(objectType, strconv.Itoa(int(objectId))) -} - -func (tk TupleKey) WithRelation(relation Relation) TupleKey { - return TupleKey{ - Subject: tk.Subject, - Object: tk.Object, - Relation: relation, - Action: tk.Action, - } -} - -func (tk TupleKey) WithAction(action Action) TupleKey { - return TupleKey{ - Subject: tk.Subject, - Object: tk.Object, - Relation: tk.Relation, - Action: action, - } -} diff --git a/auth/azcheck/checker.go b/auth/azcheck/checker.go deleted file mode 100644 index 32ecd9b2..00000000 --- a/auth/azcheck/checker.go +++ /dev/null @@ -1,948 +0,0 @@ -package azcheck - -import ( - "context" - "database/sql" - "errors" - "strconv" - "strings" - "testing" - - sq "github.com/Masterminds/squirrel" - "github.com/jmoiron/sqlx" - - "github.com/interline-io/transitland-lib/log" - "github.com/interline-io/transitland-server/auth/auth0" - "github.com/interline-io/transitland-server/auth/authn" - "github.com/interline-io/transitland-server/auth/authz" - "github.com/interline-io/transitland-server/auth/fga" - "github.com/interline-io/transitland-server/internal/dbutil" -) - -// For less typing - -type Action = authz.Action -type ObjectType = authz.ObjectType -type Relation = authz.Relation - -var FeedType = authz.FeedType -var UserType = authz.UserType -var TenantType = authz.TenantType -var GroupType = authz.GroupType -var FeedVersionType = authz.FeedVersionType - -var ViewerRelation = authz.ViewerRelation -var MemberRelation = authz.MemberRelation -var AdminRelation = authz.AdminRelation -var ManagerRelation = authz.ManagerRelation -var ParentRelation = authz.ParentRelation -var EditorRelation = authz.EditorRelation - -var CanEdit = authz.CanEdit -var CanView = authz.CanView -var CanCreateFeedVersion = authz.CanCreateFeedVersion -var CanDeleteFeedVersion = authz.CanDeleteFeedVersion -var CanCreateFeed = authz.CanCreateFeed -var CanDeleteFeed = authz.CanDeleteFeed -var CanSetGroup = authz.CanSetGroup -var CanCreateOrg = authz.CanCreateOrg -var CanEditMembers = authz.CanEditMembers -var CanDeleteOrg = authz.CanDeleteOrg -var CanSetTenant = authz.CanSetTenant - -type EntityKey = authz.EntityKey -type TupleKey = authz.TupleKey - -var ErrUnauthorized = authz.ErrUnauthorized - -type UserProvider interface { - Users(context.Context, string) ([]authn.User, error) - UserByID(context.Context, string) (authn.User, error) -} - -type FGAProvider interface { - Check(context.Context, TupleKey, ...TupleKey) (bool, error) - ListObjects(context.Context, TupleKey) ([]TupleKey, error) - GetObjectTuples(context.Context, TupleKey) ([]TupleKey, error) - WriteTuple(context.Context, TupleKey) error - SetExclusiveSubjectRelation(context.Context, TupleKey, ...Relation) error - SetExclusiveRelation(context.Context, TupleKey) error - DeleteTuple(context.Context, TupleKey) error -} - -type CheckerConfig struct { - Auth0Domain string - Auth0ClientID string - Auth0ClientSecret string - Auth0Connection string - FGAStoreID string - FGAModelID string - FGAEndpoint string - FGALoadModelFile string - FGALoadTestData []TupleKey - GlobalAdmin string -} - -type Checker struct { - userClient UserProvider - fgaClient FGAProvider - db sqlx.Ext - globalAdmins []string - authz.UnsafeCheckerServer -} - -func NewCheckerFromConfig(cfg CheckerConfig, db sqlx.Ext) (*Checker, error) { - var userClient UserProvider - userClient = NewMockUserProvider() - var fgaClient FGAProvider - fgaClient = NewMockFGAClient() - - // Use Auth0 if configured - if cfg.Auth0Domain != "" { - auth0Client, err := auth0.NewAuth0Client(cfg.Auth0Domain, cfg.Auth0ClientID, cfg.Auth0ClientSecret) - auth0Client.Connection = cfg.Auth0Connection - if err != nil { - return nil, err - } - userClient = auth0Client - } - - // Use FGA if configured - if cfg.FGAEndpoint != "" { - fgac, err := fga.NewFGAClient(cfg.FGAEndpoint, cfg.FGAStoreID, cfg.FGAModelID) - if err != nil { - return nil, err - } - fgaClient = fgac - // Create test FGA environment - if cfg.FGALoadModelFile != "" { - if cfg.FGAStoreID == "" { - if _, err := fgac.CreateStore(context.Background(), "test"); err != nil { - return nil, err - } - } - if _, err := fgac.CreateModel(context.Background(), cfg.FGALoadModelFile); err != nil { - return nil, err - } - } - // Add test data - for _, tk := range cfg.FGALoadTestData { - ltk, found, err := ekLookup(db, tk) - if !found { - log.Info().Msgf("warning, tuple entities not found in database: %s", tk.String()) - } - if err != nil { - return nil, err - } - if err := fgaClient.WriteTuple(context.Background(), ltk); err != nil { - return nil, err - } - } - } - - checker := NewChecker(userClient, fgaClient, db) - if cfg.GlobalAdmin != "" { - checker.globalAdmins = append(checker.globalAdmins, cfg.GlobalAdmin) - } - return checker, nil -} - -func NewChecker(n UserProvider, p FGAProvider, db sqlx.Ext) *Checker { - return &Checker{ - userClient: n, - fgaClient: p, - db: db, - } -} - -// /////////////////// -// USERS -// /////////////////// - -func (c *Checker) UserList(ctx context.Context, req *authz.UserListRequest) (*authz.UserListResponse, error) { - // TODO: filter users - users, err := c.userClient.Users(ctx, req.GetQ()) - if err != nil { - return nil, err - } - var ret []*authz.User - for _, user := range users { - ret = append(ret, newAzpbUser(user)) - } - return &authz.UserListResponse{Users: ret}, nil -} - -func (c *Checker) User(ctx context.Context, req *authz.UserRequest) (*authz.UserResponse, error) { - // Special case "*" - if req.Id == "*" { - user := &authz.User{Id: "*", Name: "All users"} - return &authz.UserResponse{User: user}, nil - } - // TODO: filter users - user, err := c.userClient.UserByID(ctx, req.GetId()) - if user == nil || err != nil { - return nil, ErrUnauthorized - } - return &authz.UserResponse{User: newAzpbUser(user)}, err -} - -func (c *Checker) Me(ctx context.Context, req *authz.MeRequest) (*authz.MeResponse, error) { - user := authn.ForContext(ctx) - if user == nil || user.ID() == "" { - return nil, ErrUnauthorized - } - - // TODO: consider an explicit check to authn provider .GetUser, - // however this requires a authn provider to be configured and not just the default. - - // Direct groups - var directGroupIds []int64 - checkTk := authz.NewTupleKey(). - WithSubject(authz.UserType, user.ID()). - WithObject(authz.GroupType, "") - groupTuples, err := c.fgaClient.GetObjectTuples(ctx, checkTk) - if err != nil { - return nil, err - } - for _, groupTuple := range groupTuples { - directGroupIds = append(directGroupIds, groupTuple.Object.ID()) - } - directGroups, err := c.getGroups(ctx, directGroupIds) - if err != nil { - return nil, err - } - - // Expanded groups - expandedGroupIds, err := c.listCtxObjectRelations( - ctx, - GroupType, - ViewerRelation, - ) - if err != nil { - return nil, err - } - expandedGroups, err := c.getGroups(ctx, expandedGroupIds) - if err != nil { - return nil, err - } - - extData := map[string]string{} - if gkData, ok := user.GetExternalData("gatekeeper"); ok { - extData["gatekeeper"] = gkData - } - - // Return - ret := &authz.MeResponse{ - User: newAzpbUser(user), - Groups: directGroups, - Roles: user.Roles(), - ExpandedGroups: expandedGroups, - ExternalData: extData, - } - return ret, nil -} - -func (c *Checker) CheckGlobalAdmin(ctx context.Context) (bool, error) { - return c.checkGlobalAdmin(authn.ForContext(ctx)), nil -} - -func (c *Checker) hydrateEntityRels(ctx context.Context, ers []*authz.EntityRelation) ([]*authz.EntityRelation, error) { - // This is awful :( :( - for i, v := range ers { - if v.Type == TenantType { - if t, _ := c.getTenants(ctx, []int64{v.Int64()}); len(t) > 0 && t[0] != nil { - ers[i].Name = t[0].Name - } - } else if v.Type == GroupType { - if t, _ := c.getGroups(ctx, []int64{v.Int64()}); len(t) > 0 && t[0] != nil { - ers[i].Name = t[0].Name - } - } else if v.Type == UserType { - if t, err := c.User(ctx, &authz.UserRequest{Id: v.Id}); err == nil && t != nil && t.User != nil { - ers[i].Name = t.User.Name - } - } - } - return ers, nil -} - -// /////////////////// -// TENANTS -// /////////////////// - -func (c *Checker) getTenants(ctx context.Context, ids []int64) ([]*authz.Tenant, error) { - return getEntities[*authz.Tenant](ctx, c.db, ids, "tl_tenants", "id", "coalesce(tenant_name,'') as name") -} - -func (c *Checker) TenantList(ctx context.Context, req *authz.TenantListRequest) (*authz.TenantListResponse, error) { - ids, err := c.listCtxObjects(ctx, TenantType, CanView) - if err != nil { - return nil, err - } - t, err := c.getTenants(ctx, ids) - return &authz.TenantListResponse{Tenants: t}, err -} - -func (c *Checker) Tenant(ctx context.Context, req *authz.TenantRequest) (*authz.TenantResponse, error) { - tenantId := req.GetId() - if err := c.checkActionOrError(ctx, CanView, newEntityID(TenantType, tenantId)); err != nil { - return nil, err - } - t, err := c.getTenants(ctx, []int64{tenantId}) - return &authz.TenantResponse{Tenant: first(t)}, err -} - -func (c *Checker) TenantPermissions(ctx context.Context, req *authz.TenantRequest) (*authz.TenantPermissionsResponse, error) { - ent, err := c.Tenant(ctx, req) - if err != nil { - return nil, err - } - ret := &authz.TenantPermissionsResponse{ - Tenant: ent.Tenant, - Actions: &authz.TenantPermissionsResponse_Actions{}, - Users: &authz.TenantPermissionsResponse_Users{}, - } - - // Actions - entKey := newEntityID(TenantType, req.GetId()) - groupIds, _ := c.listSubjectRelations(ctx, entKey, GroupType, ParentRelation) - ret.Groups, _ = c.getGroups(ctx, groupIds) - ret.Actions.CanView, _ = c.checkAction(ctx, CanView, entKey) - ret.Actions.CanEditMembers, _ = c.checkAction(ctx, CanEditMembers, entKey) - ret.Actions.CanEdit, _ = c.checkAction(ctx, CanEdit, entKey) - ret.Actions.CanCreateOrg, _ = c.checkAction(ctx, CanCreateOrg, entKey) - ret.Actions.CanDeleteOrg, _ = c.checkAction(ctx, CanDeleteOrg, entKey) - - // Get tenant metadata - tps, err := c.getObjectTuples(ctx, entKey) - if err != nil { - return nil, err - } - for _, tk := range tps { - if tk.Relation == AdminRelation { - ret.Users.Admins = append(ret.Users.Admins, authz.NewEntityRelation(tk.Subject, tk.Relation)) - } - if tk.Relation == MemberRelation { - ret.Users.Members = append(ret.Users.Members, authz.NewEntityRelation(tk.Subject, tk.Relation)) - } - } - ret.Users.Admins, _ = c.hydrateEntityRels(ctx, ret.Users.Admins) - ret.Users.Members, _ = c.hydrateEntityRels(ctx, ret.Users.Members) - return ret, nil -} - -func (c *Checker) TenantSave(ctx context.Context, req *authz.TenantSaveRequest) (*authz.TenantSaveResponse, error) { - t := req.GetTenant() - tenantId := t.GetId() - if check, err := c.TenantPermissions(ctx, &authz.TenantRequest{Id: tenantId}); err != nil { - return nil, err - } else if !check.Actions.CanEdit { - return nil, ErrUnauthorized - } - newName := t.GetName() - log.Trace().Str("tenantName", newName).Int64("id", tenantId).Msg("TenantSave") - _, err := sq.StatementBuilder. - RunWith(c.db). - PlaceholderFormat(sq.Dollar). - Update("tl_tenants"). - SetMap(map[string]any{ - "tenant_name": newName, - }). - Where("id = ?", tenantId).Exec() - return &authz.TenantSaveResponse{}, err -} - -func (c *Checker) TenantAddPermission(ctx context.Context, req *authz.TenantModifyPermissionRequest) (*authz.TenantSaveResponse, error) { - tenantId := req.GetId() - if check, err := c.TenantPermissions(ctx, &authz.TenantRequest{Id: tenantId}); err != nil { - return nil, err - } else if !check.Actions.CanEditMembers { - return nil, ErrUnauthorized - } - tk := req.GetEntityRelation().WithObject(newEntityID(TenantType, tenantId)) - log.Trace().Str("tk", tk.String()).Int64("id", tenantId).Msg("TenantAddPermission") - return &authz.TenantSaveResponse{}, c.fgaClient.SetExclusiveSubjectRelation(ctx, tk, MemberRelation, AdminRelation) -} - -func (c *Checker) TenantRemovePermission(ctx context.Context, req *authz.TenantModifyPermissionRequest) (*authz.TenantSaveResponse, error) { - tenantId := req.GetId() - if check, err := c.TenantPermissions(ctx, &authz.TenantRequest{Id: tenantId}); err != nil { - return nil, err - } else if !check.Actions.CanEditMembers { - return nil, ErrUnauthorized - } - tk := req.GetEntityRelation().WithObject(newEntityID(TenantType, tenantId)) - log.Trace().Str("tk", tk.String()).Int64("id", tenantId).Msg("TenantRemovePermission") - return &authz.TenantSaveResponse{}, c.fgaClient.DeleteTuple(ctx, tk) -} - -func (c *Checker) TenantCreate(ctx context.Context, req *authz.TenantCreateRequest) (*authz.TenantSaveResponse, error) { - return &authz.TenantSaveResponse{}, nil -} - -func (c *Checker) TenantCreateGroup(ctx context.Context, req *authz.TenantCreateGroupRequest) (*authz.GroupSaveResponse, error) { - tenantId := req.GetId() - groupName := req.GetGroup().GetName() - if check, err := c.TenantPermissions(ctx, &authz.TenantRequest{Id: tenantId}); err != nil { - return nil, err - } else if !check.Actions.CanCreateOrg { - return nil, ErrUnauthorized - } - log.Trace().Str("groupName", groupName).Int64("id", tenantId).Msg("TenantCreateGroup") - groupId := int64(0) - err := sq.StatementBuilder. - RunWith(c.db). - PlaceholderFormat(sq.Dollar). - Insert("tl_groups"). - Columns("group_name"). - Values(groupName). - Suffix(`RETURNING "id"`). - QueryRow(). - Scan(&groupId) - if err != nil { - return nil, err - } - addTk := authz.NewTupleKey().WithSubjectID(TenantType, tenantId).WithObjectID(GroupType, groupId).WithRelation(ParentRelation) - if err := c.fgaClient.WriteTuple(ctx, addTk); err != nil { - return nil, err - } - return &authz.GroupSaveResponse{Group: &authz.Group{Id: groupId}}, err -} - -// /////////////////// -// GROUPS -// /////////////////// - -func (c *Checker) getGroups(ctx context.Context, ids []int64) ([]*authz.Group, error) { - return getEntities[*authz.Group](ctx, c.db, ids, "tl_groups", "id", "coalesce(group_name,'') as name") -} - -func (c *Checker) GroupList(ctx context.Context, req *authz.GroupListRequest) (*authz.GroupListResponse, error) { - ids, err := c.listCtxObjects(ctx, GroupType, CanView) - if err != nil { - return nil, err - } - t, err := c.getGroups(ctx, ids) - return &authz.GroupListResponse{Groups: t}, err -} - -func (c *Checker) Group(ctx context.Context, req *authz.GroupRequest) (*authz.GroupResponse, error) { - groupId := req.GetId() - if err := c.checkActionOrError(ctx, CanView, newEntityID(GroupType, groupId)); err != nil { - return nil, err - } - t, err := c.getGroups(ctx, []int64{groupId}) - return &authz.GroupResponse{Group: first(t)}, err -} - -func (c *Checker) GroupPermissions(ctx context.Context, req *authz.GroupRequest) (*authz.GroupPermissionsResponse, error) { - groupId := req.GetId() - ent, err := c.Group(ctx, req) - if err != nil { - return nil, err - } - ret := &authz.GroupPermissionsResponse{ - Group: ent.Group, - Users: &authz.GroupPermissionsResponse_Users{}, - Actions: &authz.GroupPermissionsResponse_Actions{}, - } - - // Actions - entKey := newEntityID(GroupType, groupId) - ret.Actions.CanView, _ = c.checkAction(ctx, CanView, entKey) - ret.Actions.CanEditMembers, _ = c.checkAction(ctx, CanEditMembers, entKey) - ret.Actions.CanEdit, _ = c.checkAction(ctx, CanEdit, entKey) - ret.Actions.CanCreateFeed, _ = c.checkAction(ctx, CanCreateFeed, entKey) - ret.Actions.CanDeleteFeed, _ = c.checkAction(ctx, CanDeleteFeed, entKey) - ret.Actions.CanSetTenant = c.ctxIsGlobalAdmin(ctx) - - // Get feeds - feedIds, _ := c.listSubjectRelations(ctx, entKey, FeedType, ParentRelation) - ret.Feeds, _ = c.getFeeds(ctx, feedIds) - - // Get group metadata - tps, err := c.getObjectTuples(ctx, entKey) - if err != nil { - return nil, err - } - for _, tk := range tps { - if tk.Relation == ParentRelation { - ct, _ := c.Tenant(ctx, &authz.TenantRequest{Id: tk.Subject.ID()}) - ret.Tenant = ct.Tenant - } - if tk.Relation == ManagerRelation { - ret.Users.Managers = append(ret.Users.Managers, authz.NewEntityRelation(tk.Subject, tk.Relation)) - } - if tk.Relation == EditorRelation { - ret.Users.Editors = append(ret.Users.Editors, authz.NewEntityRelation(tk.Subject, tk.Relation)) - } - if tk.Relation == ViewerRelation { - ret.Users.Viewers = append(ret.Users.Viewers, authz.NewEntityRelation(tk.Subject, tk.Relation)) - } - } - ret.Users.Managers, _ = c.hydrateEntityRels(ctx, ret.Users.Managers) - ret.Users.Editors, _ = c.hydrateEntityRels(ctx, ret.Users.Editors) - ret.Users.Viewers, _ = c.hydrateEntityRels(ctx, ret.Users.Viewers) - return ret, nil -} - -func (c *Checker) GroupSave(ctx context.Context, req *authz.GroupSaveRequest) (*authz.GroupSaveResponse, error) { - group := req.GetGroup() - groupId := group.GetId() - newName := group.GetName() - if check, err := c.GroupPermissions(ctx, &authz.GroupRequest{Id: groupId}); err != nil { - return nil, err - } else if !check.Actions.CanEdit { - return nil, ErrUnauthorized - } - log.Trace().Str("groupName", newName).Int64("id", groupId).Msg("GroupSave") - _, err := sq.StatementBuilder. - RunWith(c.db). - PlaceholderFormat(sq.Dollar). - Update("tl_groups"). - SetMap(map[string]any{ - "group_name": newName, - }). - Where("id = ?", groupId).Exec() - return &authz.GroupSaveResponse{}, err -} - -func (c *Checker) GroupAddPermission(ctx context.Context, req *authz.GroupModifyPermissionRequest) (*authz.GroupSaveResponse, error) { - groupId := req.GetId() - if check, err := c.GroupPermissions(ctx, &authz.GroupRequest{Id: groupId}); err != nil { - return nil, err - } else if !check.Actions.CanEditMembers { - return nil, ErrUnauthorized - } - tk := req.GetEntityRelation().WithObject(newEntityID(GroupType, groupId)) - log.Trace().Str("tk", tk.String()).Int64("id", groupId).Msg("GroupAddPermission") - return &authz.GroupSaveResponse{}, c.fgaClient.SetExclusiveSubjectRelation(ctx, tk, ViewerRelation, EditorRelation, ManagerRelation) -} - -func (c *Checker) GroupRemovePermission(ctx context.Context, req *authz.GroupModifyPermissionRequest) (*authz.GroupSaveResponse, error) { - groupId := req.GetId() - if check, err := c.GroupPermissions(ctx, &authz.GroupRequest{Id: groupId}); err != nil { - return nil, err - } else if !check.Actions.CanEditMembers { - return nil, ErrUnauthorized - } - tk := req.GetEntityRelation().WithObject(newEntityID(GroupType, groupId)) - log.Trace().Str("tk", tk.String()).Int64("id", groupId).Msg("GroupRemovePermission") - return &authz.GroupSaveResponse{}, c.fgaClient.DeleteTuple(ctx, tk) -} - -func (c *Checker) GroupSetTenant(ctx context.Context, req *authz.GroupSetTenantRequest) (*authz.GroupSetTenantResponse, error) { - groupId := req.GetId() - newTenantId := req.GetTenantId() - if check, err := c.GroupPermissions(ctx, &authz.GroupRequest{Id: groupId}); err != nil { - return nil, err - } else if !check.Actions.CanSetTenant { - return nil, ErrUnauthorized - } - tk := authz.NewTupleKey().WithSubjectID(TenantType, newTenantId).WithObjectID(GroupType, groupId).WithRelation(ParentRelation) - log.Trace().Str("tk", tk.String()).Int64("id", groupId).Msg("GroupSetTenant") - return &authz.GroupSetTenantResponse{}, c.fgaClient.SetExclusiveRelation(ctx, tk) -} - -// /////////////////// -// FEEDS -// /////////////////// - -func (c *Checker) getFeeds(ctx context.Context, ids []int64) ([]*authz.Feed, error) { - return getEntities[*authz.Feed](ctx, c.db, ids, "current_feeds", "id", "onestop_id", "coalesce(name,'') as name") -} - -func (c *Checker) FeedList(ctx context.Context, req *authz.FeedListRequest) (*authz.FeedListResponse, error) { - feedIds, err := c.listCtxObjects(ctx, FeedType, CanView) - if err != nil { - return nil, err - } - t, err := c.getFeeds(ctx, feedIds) - return &authz.FeedListResponse{Feeds: t}, err -} - -func (c *Checker) Feed(ctx context.Context, req *authz.FeedRequest) (*authz.FeedResponse, error) { - feedId := req.GetId() - if err := c.checkActionOrError(ctx, CanView, newEntityID(FeedType, feedId)); err != nil { - return nil, err - } - t, err := c.getFeeds(ctx, []int64{feedId}) - return &authz.FeedResponse{Feed: first(t)}, err -} - -func (c *Checker) FeedPermissions(ctx context.Context, req *authz.FeedRequest) (*authz.FeedPermissionsResponse, error) { - ent, err := c.Feed(ctx, req) - if err != nil { - return nil, err - } - ret := &authz.FeedPermissionsResponse{ - Feed: ent.Feed, - Actions: &authz.FeedPermissionsResponse_Actions{}, - } - - // Actions - entKey := newEntityID(FeedType, req.GetId()) - ret.Actions.CanView, _ = c.checkAction(ctx, CanView, entKey) - ret.Actions.CanEdit, _ = c.checkAction(ctx, CanEdit, entKey) - ret.Actions.CanSetGroup, _ = c.checkAction(ctx, CanSetGroup, entKey) - ret.Actions.CanCreateFeedVersion, _ = c.checkAction(ctx, CanCreateFeedVersion, entKey) - ret.Actions.CanDeleteFeedVersion, _ = c.checkAction(ctx, CanDeleteFeedVersion, entKey) - - // Get feed metadata - tps, err := c.getObjectTuples(ctx, entKey) - if err != nil { - return nil, err - } - for _, tk := range tps { - if tk.Relation == ParentRelation { - ct, _ := c.Group(ctx, &authz.GroupRequest{Id: tk.Subject.ID()}) - ret.Group = ct.Group - } - } - return ret, nil -} - -func (c *Checker) FeedSetGroup(ctx context.Context, req *authz.FeedSetGroupRequest) (*authz.FeedSaveResponse, error) { - feedId := req.GetId() - newGroup := req.GetGroupId() - if check, err := c.FeedPermissions(ctx, &authz.FeedRequest{Id: feedId}); err != nil { - return nil, err - } else if !check.Actions.CanSetGroup { - return nil, ErrUnauthorized - } - tk := authz.NewTupleKey().WithSubjectID(GroupType, newGroup).WithObjectID(FeedType, feedId).WithRelation(ParentRelation) - log.Trace().Str("tk", tk.String()).Int64("id", feedId).Msg("FeedSetGroup") - return &authz.FeedSaveResponse{}, c.fgaClient.SetExclusiveRelation(ctx, tk) -} - -///////////////////// -// FEED VERSIONS -///////////////////// - -func (c *Checker) getFeedVersions(ctx context.Context, ids []int64) ([]*authz.FeedVersion, error) { - return getEntities[*authz.FeedVersion](ctx, c.db, ids, "feed_versions", "id", "feed_id", "sha1", "coalesce(name,'') as name") -} - -func (c *Checker) FeedVersionList(ctx context.Context, req *authz.FeedVersionListRequest) (*authz.FeedVersionListResponse, error) { - fvids, err := c.listCtxObjects(ctx, FeedVersionType, CanView) - if err != nil { - return nil, err - } - t, err := c.getFeedVersions(ctx, fvids) - return &authz.FeedVersionListResponse{FeedVersions: t}, err -} - -func (c *Checker) FeedVersion(ctx context.Context, req *authz.FeedVersionRequest) (*authz.FeedVersionResponse, error) { - fvid := req.GetId() - feedId := int64(0) - // We need to get feed id before any other checks - // If there is a "not found" error here, save it for after the global admin check - // This is for consistency with other permission checks - t, fvErr := c.getFeedVersions(ctx, []int64{fvid}) - fv := first(t) - if fv != nil { - feedId = fv.FeedId - } - ctxTk := authz.NewTupleKey().WithObjectID(FeedVersionType, fvid).WithSubjectID(FeedType, feedId).WithRelation(ParentRelation) - if err := c.checkActionOrError(ctx, CanView, newEntityID(FeedVersionType, fvid), ctxTk); err != nil { - return nil, err - } - // Now return deferred fvErr - if fvErr != nil { - return nil, fvErr - } - return &authz.FeedVersionResponse{FeedVersion: fv}, nil -} - -func (c *Checker) FeedVersionPermissions(ctx context.Context, req *authz.FeedVersionRequest) (*authz.FeedVersionPermissionsResponse, error) { - ent, err := c.FeedVersion(ctx, req) - if err != nil { - return nil, err - } - ret := &authz.FeedVersionPermissionsResponse{ - FeedVersion: ent.FeedVersion, - Users: &authz.FeedVersionPermissionsResponse_Users{}, - Actions: &authz.FeedVersionPermissionsResponse_Actions{}, - } - - // Actions - ctxTk := authz.NewTupleKey().WithObjectID(FeedVersionType, ent.FeedVersion.Id).WithSubjectID(FeedType, ent.FeedVersion.FeedId).WithRelation(ParentRelation) - entKey := newEntityID(FeedVersionType, req.GetId()) - ret.Actions.CanView, _ = c.checkAction(ctx, CanView, entKey, ctxTk) - ret.Actions.CanEditMembers, _ = c.checkAction(ctx, CanEditMembers, entKey, ctxTk) - ret.Actions.CanEdit, _ = c.checkAction(ctx, CanEdit, entKey, ctxTk) - - // Get fv metadata - tps, err := c.getObjectTuples(ctx, entKey, ctxTk) - if err != nil { - return nil, err - } - for _, tk := range tps { - if tk.Relation == EditorRelation { - ret.Users.Editors = append(ret.Users.Editors, authz.NewEntityRelation(tk.Subject, tk.Relation)) - } - if tk.Relation == ViewerRelation { - ret.Users.Viewers = append(ret.Users.Viewers, authz.NewEntityRelation(tk.Subject, tk.Relation)) - } - } - ret.Users.Editors, _ = c.hydrateEntityRels(ctx, ret.Users.Editors) - ret.Users.Viewers, _ = c.hydrateEntityRels(ctx, ret.Users.Viewers) - return ret, nil -} - -func (c *Checker) FeedVersionAddPermission(ctx context.Context, req *authz.FeedVersionModifyPermissionRequest) (*authz.FeedVersionSaveResponse, error) { - fvid := req.GetId() - if check, err := c.FeedVersionPermissions(ctx, &authz.FeedVersionRequest{Id: fvid}); err != nil { - return nil, err - } else if !check.Actions.CanEditMembers { - return nil, ErrUnauthorized - } - tk := req.GetEntityRelation().WithObject(newEntityID(FeedVersionType, fvid)) - log.Trace().Str("tk", tk.String()).Int64("id", fvid).Msg("FeedVersionAddPermission") - return &authz.FeedVersionSaveResponse{}, c.fgaClient.SetExclusiveSubjectRelation(ctx, tk, ViewerRelation, EditorRelation, ManagerRelation) -} - -func (c *Checker) FeedVersionRemovePermission(ctx context.Context, req *authz.FeedVersionModifyPermissionRequest) (*authz.FeedVersionSaveResponse, error) { - fvid := req.GetId() - if check, err := c.FeedVersionPermissions(ctx, &authz.FeedVersionRequest{Id: fvid}); err != nil { - return nil, err - } else if !check.Actions.CanEditMembers { - return nil, ErrUnauthorized - } - tk := req.GetEntityRelation().WithObject(newEntityID(FeedVersionType, fvid)) - log.Trace().Str("tk", tk.String()).Int64("id", fvid).Msg("FeedVersionRemovePermission") - return &authz.FeedVersionSaveResponse{}, c.fgaClient.DeleteTuple(ctx, tk) -} - -// /////////////////// -// internal -// /////////////////// - -func (c *Checker) listCtxObjects(ctx context.Context, objectType ObjectType, action Action) ([]int64, error) { - checkUser := authn.ForContext(ctx) - if checkUser == nil { - return nil, nil - } - tk := authz.NewTupleKey().WithUser(checkUser.ID()).WithObject(objectType, "").WithAction(action) - objTks, err := c.fgaClient.ListObjects(ctx, tk) - if err != nil { - return nil, err - } - var ret []int64 - for _, tk := range objTks { - ret = append(ret, tk.Object.ID()) - } - return ret, nil -} - -func (c *Checker) listCtxObjectRelations(ctx context.Context, objectType ObjectType, rel Relation) ([]int64, error) { - checkUser := authn.ForContext(ctx) - if checkUser == nil { - return nil, nil - } - tk := authz.NewTupleKey().WithUser(checkUser.ID()).WithObject(objectType, "").WithRelation(rel) - objTks, err := c.fgaClient.ListObjects(ctx, tk) - if err != nil { - return nil, err - } - var ret []int64 - for _, tk := range objTks { - ret = append(ret, tk.Object.ID()) - } - return ret, nil -} - -func (c *Checker) listSubjectRelations(ctx context.Context, sub EntityKey, objectType ObjectType, relation Relation) ([]int64, error) { - tk := authz.NewTupleKey().WithSubject(sub.Type, sub.Name).WithObject(objectType, "").WithRelation(relation) - rels, err := c.fgaClient.ListObjects(ctx, tk) - if err != nil { - return nil, err - } - var ret []int64 - for _, v := range rels { - ret = append(ret, v.Object.ID()) - } - return ret, nil -} - -func (c *Checker) getSubjectTuples(ctx context.Context, obj EntityKey, ctxtk ...TupleKey) ([]TupleKey, error) { - return c.fgaClient.GetObjectTuples(ctx, authz.NewTupleKey().WithSubject(obj.Type, obj.Name)) -} - -func (c *Checker) getObjectTuples(ctx context.Context, obj EntityKey, ctxtk ...TupleKey) ([]TupleKey, error) { - return c.fgaClient.GetObjectTuples(ctx, authz.NewTupleKey().WithObject(obj.Type, obj.Name)) -} - -func (c *Checker) checkActionOrError(ctx context.Context, checkAction Action, obj EntityKey, ctxtk ...TupleKey) error { - ok, err := c.checkAction(ctx, checkAction, obj, ctxtk...) - if err != nil { - return err - } - if !ok { - return ErrUnauthorized - } - return nil -} - -func (c *Checker) checkAction(ctx context.Context, checkAction Action, obj EntityKey, ctxtk ...TupleKey) (bool, error) { - checkUser := authn.ForContext(ctx) - if checkUser == nil { - return false, nil - } - userName := checkUser.ID() - if c.checkGlobalAdmin(checkUser) { - log.Debug().Str("check_user", userName).Str("obj", obj.String()).Str("check_action", checkAction.String()).Msg("global admin action") - return true, nil - } - checkTk := authz.NewTupleKey().WithUser(userName).WithObject(obj.Type, obj.Name).WithAction(checkAction) - ret, err := c.fgaClient.Check(ctx, checkTk, ctxtk...) - log.Trace().Str("tk", checkTk.String()).Bool("result", ret).Err(err).Msg("checkAction") - return ret, err -} - -func (c *Checker) ctxIsGlobalAdmin(ctx context.Context) bool { - checkUser := authn.ForContext(ctx) - if checkUser == nil { - return false - } - return c.checkGlobalAdmin(checkUser) -} - -func (c *Checker) checkGlobalAdmin(checkUser authn.User) bool { - if c == nil { - return false - } - if checkUser == nil { - return false - } - if checkUser.HasRole("admin") { - return true - } - userName := checkUser.ID() - for _, v := range c.globalAdmins { - if v == userName { - return true - } - } - return false -} - -// Helpers - -type hasId interface { - GetId() int64 -} - -func checkIds[T hasId](ents []T, ids []int64) error { - if len(ents) != len(ids) { - return errors.New("not found") - } - check := map[int64]bool{} - for _, ent := range ents { - check[ent.GetId()] = true - } - for _, id := range ids { - if _, ok := check[id]; !ok { - return errors.New("not found") - } - } - return nil -} - -func getEntities[T hasId](ctx context.Context, db sqlx.Ext, ids []int64, table string, cols ...string) ([]T, error) { - var t []T - q := sq.StatementBuilder.Select(cols...).From(table).Where(sq.Eq{"id": ids}) - if err := dbutil.Select(ctx, db, q, &t); err != nil { - log.Trace().Err(err) - return nil, err - } - if err := checkIds(t, ids); err != nil { - return nil, err - } - return t, nil -} - -func first[T any](v []T) T { - var xt T - if len(v) > 0 { - return v[0] - } - return xt -} - -// todo: rename to dbTestTupleLookup and make arg TestTuple -func dbTupleLookup(t testing.TB, dbx sqlx.Ext, tk TupleKey) TupleKey { - var err error - var found bool - tk.Subject, found, err = dbNameToEntityKey(dbx, tk.Subject) - if !found && t != nil { - t.Logf("lookup warning: %s not found", tk.Subject.String()) - } - if err != nil { - t.Log(err) - } - tk.Object, found, err = dbNameToEntityKey(dbx, tk.Object) - if !found && t != nil { - t.Logf("lookup warning: %s not found", tk.Object.String()) - } - if err != nil { - t.Log(err) - } - return tk -} - -func ekLookup(dbx sqlx.Ext, tk TupleKey) (TupleKey, bool, error) { - var err error - var found1 bool - var found2 bool - tk.Subject, found1, err = dbNameToEntityKey(dbx, tk.Subject) - if err != nil { - return tk, false, err - } - tk.Object, found2, err = dbNameToEntityKey(dbx, tk.Object) - if err != nil { - return tk, false, err - } - return tk, found1 && found2, nil -} - -func dbNameToEntityKey(dbx sqlx.Ext, ek EntityKey) (EntityKey, bool, error) { - if ek.Name == "" { - return ek, false, nil - } - nsplit := strings.Split(ek.Name, "#") - oname := nsplit[0] - nname := ek.Name - var err error - switch ek.Type { - case TenantType: - err = sqlx.Get(dbx, &nname, "select id from tl_tenants where tenant_name = $1", oname) - case GroupType: - err = sqlx.Get(dbx, &nname, "select id from tl_groups where group_name = $1", oname) - case FeedType: - err = sqlx.Get(dbx, &nname, "select id from current_feeds where onestop_id = $1", oname) - case FeedVersionType: - err = sqlx.Get(dbx, &nname, "select id from feed_versions where sha1 = $1", oname) - case UserType: - } - found := false - if err == sql.ErrNoRows { - err = nil - } else { - found = true - } - if err != nil { - return ek, found, err - } - nsplit[0] = nname - ek.Name = strings.Join(nsplit, "#") - return ek, found, nil -} - -func newEntityID(t ObjectType, id int64) EntityKey { - return authz.NewEntityKey(t, strconv.Itoa(int(id))) -} - -func newAzpbUser(u authn.User) *authz.User { - return &authz.User{Id: u.ID(), Name: u.Name(), Email: u.Email()} -} diff --git a/auth/azcheck/checker_test.go b/auth/azcheck/checker_test.go deleted file mode 100644 index 2488acea..00000000 --- a/auth/azcheck/checker_test.go +++ /dev/null @@ -1,1890 +0,0 @@ -package azcheck - -import ( - "context" - "encoding/json" - "fmt" - "log" - "os" - "testing" - "time" - - "github.com/interline-io/transitland-server/auth/authn" - "github.com/interline-io/transitland-server/auth/authz" - "github.com/interline-io/transitland-server/internal/testutil" - "github.com/stretchr/testify/assert" -) - -func init() { - // Ensure Checker implements CheckerServer - var _ authz.CheckerServer = &Checker{} -} - -type testCase struct { - Subject authz.EntityKey - Object authz.EntityKey - Action authz.Action - Relation authz.Relation - Expect string - Notes string - ExpectError bool - ExpectUnauthorized bool - CheckAsUser string - ExpectActions []authz.Action - ExpectKeys []authz.EntityKey -} - -func (tk *testCase) TupleKey() TupleKey { - return TupleKey{Subject: tk.Subject, Object: tk.Object, Relation: tk.Relation, Action: tk.Action} -} - -func (tk *testCase) String() string { - if tk.Notes != "" { - return tk.Notes - } - a := tk.TupleKey().String() - if tk.CheckAsUser != "" { - a = a + "|checkuser:" + tk.CheckAsUser - } - return a -} - -func TestMain(m *testing.M) { - if a, ok := testutil.CheckTestDB(); !ok { - log.Print(a) - return - } - os.Exit(m.Run()) -} - -var checkerGetTests = []testCase{ - { - Subject: EntityKey{ - Type: 0, - Name: "", - }, - Object: newEntityKey(TenantType, "tl-tenant"), - - Expect: "user:tl-tenant-admin:admin user:ian:member user:drew:member user:tl-tenant-member:member", - }, - { - Subject: EntityKey{ - Type: 0, - Name: "", - }, - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Expect: "feed:BA:parent user:tl-tenant-member:viewer", - }, - { - Subject: EntityKey{ - Type: 0, - Name: "", - }, - Object: newEntityKey(FeedType, "CT"), - Expect: "org:tl-tenant:parent", - }, -} - -func TestChecker(t *testing.T) { - fgaUrl, a, ok := testutil.CheckEnv("TL_TEST_FGA_ENDPOINT") - if !ok { - t.Skip(a) - return - } - if a, ok := testutil.CheckTestDB(); !ok { - t.Skip(a) - return - } - dbx := testutil.MustOpenTestDB() - checkerTestData := []testCase{ - // Assign users to tenants - { - Notes: "all users can access all-users-tenant", - Subject: newEntityKey(UserType, "*"), - Object: newEntityKey(TenantType, "all-users-tenant"), - Relation: MemberRelation, - }, - { - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(TenantType, "tl-tenant"), - Relation: AdminRelation, - }, - { - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(TenantType, "tl-tenant"), - Relation: MemberRelation, - }, - { - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(TenantType, "tl-tenant"), - Relation: MemberRelation, - }, - { - Subject: newEntityKey(UserType, "test2"), - Object: newEntityKey(TenantType, "restricted-tenant"), - Relation: MemberRelation, - }, - { - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(TenantType, "tl-tenant"), - Relation: MemberRelation, - }, - // Assign groups to tenants - { - Subject: newEntityKey(TenantType, "tl-tenant"), - Object: newEntityKey(GroupType, "CT-group"), - Relation: ParentRelation, - }, - { - Subject: newEntityKey(TenantType, "tl-tenant"), - Object: newEntityKey(GroupType, "BA-group"), - Relation: ParentRelation, - }, - { - Subject: newEntityKey(TenantType, "tl-tenant"), - Object: newEntityKey(GroupType, "HA-group"), - Relation: ParentRelation, - }, - { - Subject: newEntityKey(TenantType, "tl-tenant"), - Object: newEntityKey(GroupType, "EX-group"), - Relation: ParentRelation, - }, - { - Subject: newEntityKey(TenantType, "tl-tenant").WithRefRel(MemberRelation), - Object: newEntityKey(GroupType, "HA-group"), - Relation: ViewerRelation, - }, - { - Subject: newEntityKey(TenantType, "restricted-tenant"), - Object: newEntityKey(GroupType, "test-group"), - Relation: ParentRelation, - }, - // Assign users to groups - { - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(GroupType, "CT-group"), - Relation: ViewerRelation, - }, - { - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(GroupType, "BA-group"), - Relation: EditorRelation, - }, - { - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(GroupType, "CT-group"), - Relation: ManagerRelation, - }, - { - Subject: newEntityKey(UserType, "test-group-viewer"), - Object: newEntityKey(GroupType, "test-group"), - Relation: ViewerRelation, - }, - { - Subject: newEntityKey(UserType, "test-group-editor"), - Object: newEntityKey(GroupType, "test-group"), - Relation: EditorRelation, - }, - // Assign feeds to groups - { - Subject: newEntityKey(GroupType, "CT-group"), - Object: newEntityKey(FeedType, "CT"), - Relation: ParentRelation, - }, - { - Subject: newEntityKey(GroupType, "BA-group"), - Object: newEntityKey(FeedType, "BA"), - Relation: ParentRelation, - }, - { - Subject: newEntityKey(GroupType, "HA-group"), - Object: newEntityKey(FeedType, "HA"), - Relation: ParentRelation, - }, - { - Subject: newEntityKey(GroupType, "EX-group"), - Object: newEntityKey(FeedType, "EX"), - Relation: ParentRelation, - }, - // Assign feed versions - { - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - }, - { - Subject: newEntityKey(GroupType, "test-group").WithRefRel(ViewerRelation), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - }, - { - Subject: newEntityKey(TenantType, "tl-tenant").WithRefRel(MemberRelation), - Object: newEntityKey(FeedVersionType, "d2813c293bcfd7a97dde599527ae6c62c98e66c6"), - Relation: ViewerRelation, - }, - } - - // Users - - t.Run("UserList", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, checkerTestData) - tcs := []struct { - Notes string - CheckAsUser string - ExpectUsers []string - ExpectError bool - Query string - }{ - { - Notes: "user ian can see all users", - CheckAsUser: "ian", - ExpectUsers: []string{"ian", "drew", "tl-tenant-member", "new-user"}, - }, - { - Notes: "user ian can filter with query=drew", - CheckAsUser: "ian", - Query: "drew", - ExpectUsers: []string{"drew"}, - }, - // TODO: user filtering - // { - // CheckAsUser: "no-one", - // ExpectUsers: []string{}, - // ExpectError: true, - // }, - } - for _, tc := range tcs { - t.Run(tc.Notes, func(t *testing.T) { - ents, err := checker.UserList(newUserCtx(tc.CheckAsUser), &authz.UserListRequest{Q: tc.Query}) - if !checkExpectError(t, err, tc.ExpectError) { - return - } - var entNames []string - for _, ent := range ents.Users { - entNames = append(entNames, ent.Id) - } - assert.ElementsMatch(t, tc.ExpectUsers, entNames) - }) - } - }) - - t.Run("User", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, checkerTestData) - tcs := []struct { - Notes string - CheckAsUser string - ExpectUserId string - ExpectError bool - }{ - { - Notes: "ok", - CheckAsUser: "ian", - ExpectUserId: "drew", - }, - { - Notes: "not found", - CheckAsUser: "ian", - ExpectUserId: "not found", - ExpectError: true, - }, - } - for _, tc := range tcs { - t.Run(tc.Notes, func(t *testing.T) { - ent, err := checker.User( - newUserCtx(tc.CheckAsUser), - &authz.UserRequest{Id: tc.ExpectUserId}, - ) - if !checkExpectError(t, err, tc.ExpectError) { - return - } - if ent == nil { - t.Fatal("got no result") - } - assert.Equal(t, tc.ExpectUserId, ent.User.Id) - }) - } - }) - - t.Run("Me", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, checkerTestData) - tcs := []struct { - Name string - CheckAsUser string - ExpectUserId string - ExpectDirectGroupNames []string - ExpectExpandedGroupNames []string - ExpectError bool - }{ - { - Name: "ian", - CheckAsUser: "ian", - ExpectUserId: "ian", - ExpectDirectGroupNames: []string{"CT-group", "BA-group"}, - ExpectExpandedGroupNames: []string{"CT-group", "HA-group", "BA-group"}, - }, - { - Name: "drew", - CheckAsUser: "drew", - ExpectUserId: "drew", - ExpectDirectGroupNames: []string{"CT-group"}, - ExpectExpandedGroupNames: []string{"CT-group", "HA-group"}, - }, - { - Name: "no one", - CheckAsUser: "no one", - ExpectUserId: "", - ExpectError: true, - }, - } - for _, tc := range tcs { - t.Run(tc.Name, func(t *testing.T) { - ent, err := checker.Me(newUserCtx(tc.CheckAsUser), &authz.MeRequest{}) - if !checkExpectError(t, err, tc.ExpectError) { - return - } - if ent == nil { - t.Fatal("got no result") - } - assert.Equal(t, tc.ExpectUserId, ent.User.Id) - var directGroupNames []string - for _, g := range ent.Groups { - directGroupNames = append(directGroupNames, g.Name) - } - assert.ElementsMatch(t, tc.ExpectDirectGroupNames, directGroupNames, "group names") - - var expandedGroupNames []string - for _, g := range ent.ExpandedGroups { - expandedGroupNames = append(expandedGroupNames, g.Name) - } - assert.ElementsMatch(t, tc.ExpectExpandedGroupNames, expandedGroupNames, "group names") - }) - } - }) - - // TENANTS - t.Run("TenantList", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, checkerTestData) - checks := []testCase{ - { - Notes: "user tl-tenant-admin is admin of tl-tenant and user:* on all-users-tenant", - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(TenantType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(TenantType, "tl-tenant", "all-users-tenant"), - }, - { - Notes: "user ian is member of tl-tenant and user:* on all-users-tenant", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(TenantType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(TenantType, "tl-tenant", "all-users-tenant"), - }, - { - Notes: "user tl-tenant-member is member of tl-tenant and user:* on all-users-tenant", - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(TenantType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(TenantType, "tl-tenant", "all-users-tenant"), - }, - { - Notes: "user new-user is user:* on all-users-tenant", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(TenantType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(TenantType, "all-users-tenant"), - }, - } - - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - ret, err := checker.TenantList( - newUserCtx(tc.CheckAsUser, tc.Subject.Name), - &authz.TenantListRequest{}, - ) - if err != nil { - t.Fatal(err) - } - var gotNames []string - for _, v := range ret.Tenants { - gotNames = append(gotNames, v.Name) - } - var expectNames []string - for _, v := range tc.ExpectKeys { - expectNames = append(expectNames, v.Name) - } - assert.ElementsMatch(t, expectNames, gotNames, "tenant names") - }) - } - }) - - t.Run("TenantPermissions", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, checkerTestData) - checks := []testCase{ - // User checks - { - Notes: "user tl-tenant-admin is an admin of tl-tenant", - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(TenantType, "tl-tenant"), - ExpectActions: []Action{CanView, CanEdit, CanEditMembers, CanCreateOrg, CanDeleteOrg}, - }, - { - Notes: "user tl-tenant-admin is unauthorized for restricted-tenant", - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(TenantType, "restricted-tenant"), - ExpectUnauthorized: true, - }, - { - Notes: "user ian is viewer of tl-tenant", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(TenantType, "tl-tenant"), - ExpectActions: []Action{CanView, -CanEditMembers, -CanCreateOrg, -CanDeleteOrg}, - }, - { - Notes: "user ian is unauthorized for restricted-tenant", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(TenantType, "restricted-tenant"), - ExpectUnauthorized: true, - }, - { - Notes: "user drew is a viewer of tl-tenant", - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(TenantType, "tl-tenant"), - ExpectActions: []Action{CanView, -CanEditMembers, -CanCreateOrg, -CanDeleteOrg}, - }, - { - Notes: "user drew is unauthorized for restricted-tenant", - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(TenantType, "restricted-tenant"), - ExpectUnauthorized: true, - }, - { - Notes: "user tl-tenant-member is a viewer of tl-tenant", - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(TenantType, "tl-tenant"), - ExpectActions: []Action{CanView, -CanEdit}, - }, - { - Notes: "user tl-tenant-member is unauthorized for restricted-tenant", - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(TenantType, "restricted-tenant"), - ExpectUnauthorized: true, - }, - { - Notes: "user tl-tenant-member is a viewer of tl-tenant", - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(TenantType, "tl-tenant"), - ExpectActions: []Action{CanView, -CanEdit, -CanEditMembers, -CanCreateOrg, -CanDeleteOrg}, - }, - { - Notes: "user tl-tenant-member is unauthorized for restricted-tenant", - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(TenantType, "restricted-tenant"), - ExpectUnauthorized: true, - }, - { - Notes: "user tl-tenant-member expects unauthorized error for non-existing tenant", - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(TenantType, "not found"), - ExpectUnauthorized: true, - }, - { - Notes: "user ian is viewer of all-users-tenant through user:*", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(TenantType, "all-users-tenant"), - ExpectActions: []Action{CanView, -CanEdit, -CanEditMembers, -CanCreateOrg, -CanDeleteOrg}, - }, - { - Notes: "user new-user is viewer of all-users-tenant through user:*", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(TenantType, "all-users-tenant"), - ExpectActions: []Action{CanView, -CanEdit, -CanEditMembers, -CanCreateOrg, -CanDeleteOrg}, - }, - // General checks - { - Notes: "global admins are admins of all tenants", - Subject: newEntityKey(UserType, "global_admin"), - Object: newEntityKey(TenantType, "all-users-tenant"), - ExpectActions: []Action{CanView, CanEdit, CanEditMembers, CanCreateOrg, CanDeleteOrg}, - }, - { - Notes: "global admins get not found on not found tenant", - Subject: newEntityKey(UserType, "global_admin"), - Object: newEntityKey(TenantType, "not found"), - ExpectError: true, - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - ltk := dbTupleLookup(t, dbx, tc.TupleKey()) - ret, err := checker.TenantPermissions( - newUserCtx(tc.CheckAsUser, ltk.Subject.Name), - &authz.TenantRequest{Id: ltk.Object.ID()}, - ) - checkErrUnauthorized(t, err, tc.ExpectError, tc.ExpectUnauthorized) - if err != nil { - return - } - checkActionSubset(t, ret.Actions, tc.ExpectActions) - }) - } - }) - - t.Run("TenantAddPermission", func(t *testing.T) { - checks := []testCase{ - // User checks - { - Notes: "user tl-tenant-admin is an admin of tl-tenant and can add a user", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(TenantType, "tl-tenant"), - Relation: MemberRelation, - CheckAsUser: "tl-tenant-admin", - }, - { - Notes: "user tl-tenant-admin is an admin of tl-tenant and can add user:*", - Subject: newEntityKey(UserType, "*"), - Object: newEntityKey(TenantType, "tl-tenant"), - Relation: MemberRelation, - CheckAsUser: "tl-tenant-admin", - }, - { - Notes: "user ian is a vewier of tl-tenant is not authorized to add a user", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(TenantType, "tl-tenant"), - Relation: MemberRelation, - CheckAsUser: "ian", - ExpectUnauthorized: true, - }, - // General checks - { - Notes: "error for invalid relation", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(TenantType, "tl-tenant"), - Relation: ParentRelation, - ExpectError: true, - CheckAsUser: "tl-tenant-admin", - }, - { - Notes: "error for disallowed relation", - Subject: newEntityKey(UserType, "*"), - Object: newEntityKey(TenantType, "tl-tenant"), - Relation: AdminRelation, - ExpectError: true, - CheckAsUser: "tl-tenant-admin", - }, - { - Notes: "replaces relation if it already exists", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(TenantType, "tl-tenant"), - Relation: MemberRelation, - CheckAsUser: "tl-tenant-admin", - }, - { - Notes: "users get unauthorized when attempting to add user to not found tenant", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(TenantType, "not found"), - Relation: MemberRelation, - CheckAsUser: "tl-tenant-admin", - ExpectUnauthorized: true, - }, - { - Notes: "global admins can add users to all tenants", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(TenantType, "restricted-tenant"), - Relation: MemberRelation, - CheckAsUser: "global_admin", - }, - { - Notes: "global admins get not found when adding user to a not found tenant", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(TenantType, "not found"), - Relation: MemberRelation, - CheckAsUser: "global_admin", - ExpectError: true, - }, - // TODO - // { - // Notes: "user tl-tenant-admin gets an error when attempting to add a user that does not exist", - // Subject: newEntityKey(UserType, "not found"), - // Object: newEntityKey(TenantType, "tl-tenant"), - // Relation: MemberRelation, - // CheckAsUser: "tl-tenant-admin", - // ExpectError: true, - // }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - // Mutating test - initialize for each test - checker := newTestChecker(t, fgaUrl, checkerTestData) - ltk := dbTupleLookup(t, dbx, tc.TupleKey()) - _, err := checker.TenantAddPermission( - newUserCtx(tc.CheckAsUser, ltk.Subject.Name), - &authz.TenantModifyPermissionRequest{ - Id: ltk.Object.ID(), - EntityRelation: authz.NewEntityRelation(ltk.Subject, ltk.Relation), - }, - ) - checkErrUnauthorized(t, err, tc.ExpectError, tc.ExpectUnauthorized) - }) - } - }) - - t.Run("TenantRemovePermission", func(t *testing.T) { - checks := []testCase{ - // User checks - { - Notes: "tl-tenant-admin is a admin of tl-tenant and can remove a user", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(TenantType, "tl-tenant"), - Relation: MemberRelation, - CheckAsUser: "tl-tenant-admin", - }, - { - Notes: "user ian is a viewer of tl-tenant and is not authorized to remove a user", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(TenantType, "tl-tenant"), - Relation: MemberRelation, - CheckAsUser: "ian", - ExpectUnauthorized: true, - }, - { - Notes: "user tl-tenant-admin is not a member of restricted-tenant and is not authorized to remove a user", - Subject: newEntityKey(UserType, "test2"), - Object: newEntityKey(TenantType, "restricted-tenant"), - Relation: MemberRelation, - CheckAsUser: "tl-tenant-admin", - ExpectUnauthorized: true, - }, - // General checks - { - Notes: "error if relation does not exist", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(TenantType, "tl-tenant"), - Relation: MemberRelation, - CheckAsUser: "tl-tenant-admin", - ExpectError: true, - }, { - Notes: "users get unauthorized when attemping to add user to not found tenant", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(TenantType, "not found"), - Relation: MemberRelation, - CheckAsUser: "tl-tenant-admin", - ExpectUnauthorized: true, - }, - { - Notes: "global admins can remove users from all tenants", - Subject: newEntityKey(UserType, "test2"), - Object: newEntityKey(TenantType, "restricted-tenant"), - Relation: MemberRelation, - CheckAsUser: "global_admin", - }, - { - Notes: "global admins get error when removing user from not found tenant", - Subject: newEntityKey(UserType, "test2"), - Object: newEntityKey(TenantType, "not found"), - Relation: MemberRelation, - CheckAsUser: "global_admin", - ExpectError: true, - }, - // TODO - // { - // Notes: "removing a non-existing user causes an error", - // Subject: newEntityKey(UserType, "asd123"), - // Object: newEntityKey(TenantType, "tl-tenant"), - // Relation: MemberRelation, - // CheckAsUser: "tl-tenant-admin", - // ExpectError: true, - // }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - // Mutating test - initialize for each test - checker := newTestChecker(t, fgaUrl, checkerTestData) - ltk := dbTupleLookup(t, dbx, tc.TupleKey()) - _, err := checker.TenantRemovePermission( - newUserCtx(tc.CheckAsUser, ltk.Subject.Name), - &authz.TenantModifyPermissionRequest{ - Id: ltk.Object.ID(), - EntityRelation: authz.NewEntityRelation(ltk.Subject, ltk.Relation), - }, - ) - checkErrUnauthorized(t, err, tc.ExpectError, tc.ExpectUnauthorized) - }) - } - }) - - t.Run("TenantSave", func(t *testing.T) { - checks := []testCase{ - // User checks - { - Notes: "user ian is a viewer of tl-tenant and is not authorized to edit", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(TenantType, "tl-tenant"), - ExpectUnauthorized: true, - }, - { - Notes: "user new-user is not a viewer of tl-tenant", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(TenantType, "tl-tenant"), - ExpectUnauthorized: true, - }, - { - Notes: "user new-user is a viewer of all-users-tenant through user:* but not admin", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(TenantType, "all-users-tenant"), - ExpectUnauthorized: true, - }, - { - Notes: "user tl-tenant-admin is admin of tl-tenant and can edit", - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(TenantType, "tl-tenant"), - }, - // General checks - { - Notes: "users get unauthorized for tenant that does not exist", - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(TenantType, "not found"), - ExpectUnauthorized: true, - }, - { - Notes: "global admins get error for not found tenant", - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(TenantType, "new tenant"), - CheckAsUser: "global_admin", - ExpectError: true, - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - // Mutating test - initialize for each test - checker := newTestChecker(t, fgaUrl, checkerTestData) - ltk := dbTupleLookup(t, dbx, tc.TupleKey()) - _, err := checker.TenantSave( - newUserCtx(tc.CheckAsUser, ltk.Subject.Name), - &authz.TenantSaveRequest{ - Tenant: &authz.Tenant{ - Id: ltk.Object.ID(), - Name: tc.Object.Name, - }, - }, - ) - if checkErrUnauthorized(t, err, tc.ExpectError, tc.ExpectUnauthorized) { - return - } - if err != nil { - t.Fatal(err) - } - }) - } - }) - - t.Run("TenantCreateGroup", func(t *testing.T) { - checks := []testCase{ - // User checks - { - Notes: "user ian is viewer of tl-tenant and not authorized to create groups", - Subject: newEntityKey(TenantType, "tl-tenant"), - Object: newEntityKey(GroupType, "new-group"), - ExpectUnauthorized: true, - CheckAsUser: "ian", - }, - { - Notes: "user new-user is viewer of all-users-tenant and not authorized to create groups", - Subject: newEntityKey(TenantType, "all-users-tenant"), - Object: newEntityKey(GroupType, "new-group"), - ExpectUnauthorized: true, - CheckAsUser: "new-user", - }, - { - Notes: "user tl-tenant-admin is admin of tl-tenant and can create groups", - Subject: newEntityKey(TenantType, "tl-tenant"), - Object: newEntityKey(GroupType, fmt.Sprintf("new-group2-%d", time.Now().UnixNano())), - CheckAsUser: "tl-tenant-admin", - }, - // General checks - { - Notes: "global admins can create groups in all tenants", - Subject: newEntityKey(TenantType, "tl-tenant"), - Object: newEntityKey(GroupType, fmt.Sprintf("new-group3-%d", time.Now().UnixNano())), - CheckAsUser: "global_admin", - }, - { - Notes: "global admins can create groups in all tenants", - Subject: newEntityKey(TenantType, "restricted-tenant"), - Object: newEntityKey(GroupType, fmt.Sprintf("new-group4-%d", time.Now().UnixNano())), - CheckAsUser: "global_admin", - }, - { - Notes: "global admins get not found for tenant that does not exist", - Subject: newEntityKey(TenantType, "not found"), - Object: newEntityKey(GroupType, fmt.Sprintf("new-group5-%d", time.Now().UnixNano())), - CheckAsUser: "global_admin", - ExpectError: true, - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - // Mutating test - initialize for each test - checker := newTestChecker(t, fgaUrl, checkerTestData) - ltk := dbTupleLookup(t, dbx, tc.TupleKey()) - _, err := checker.TenantCreateGroup( - newUserCtx(tc.CheckAsUser, ltk.Subject.Name), - &authz.TenantCreateGroupRequest{ - Id: ltk.Subject.ID(), - Group: &authz.Group{Name: tc.Object.Name}, - }, - ) - if checkErrUnauthorized(t, err, tc.ExpectError, tc.ExpectUnauthorized) { - return - } - if err != nil { - t.Fatal(err) - } - // TODO: DELETE GROUP - }) - } - }) - - // GROUPS - t.Run("GroupList", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, checkerTestData) - checks := []testCase{ - { - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(GroupType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(GroupType, "CT-group", "BA-group", "HA-group", "EX-group"), - }, - { - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(GroupType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(GroupType, "CT-group", "BA-group", "HA-group"), - }, - { - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(GroupType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(GroupType, "CT-group", "HA-group"), - }, - { - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(GroupType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(GroupType, "HA-group"), - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - ret, err := checker.GroupList( - newUserCtx(tc.CheckAsUser, tc.Subject.Name), - &authz.GroupListRequest{}, - ) - if err != nil { - t.Fatal(err) - } - var gotNames []string - for _, v := range ret.Groups { - gotNames = append(gotNames, v.Name) - } - var expectNames []string - for _, v := range tc.ExpectKeys { - expectNames = append(expectNames, v.Name) - } - assert.ElementsMatch(t, expectNames, gotNames, "group names") - }) - } - }) - - t.Run("GroupPermissions", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, checkerTestData) - checks := []testCase{ - // User checks - { - Notes: "user tl-tenant-admin is admin of parent tenant to CT-group", - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(GroupType, "CT-group"), - ExpectActions: []Action{CanView, CanEdit, CanEditMembers, CanCreateFeed, CanDeleteFeed}, - }, - { - Notes: "user tl-tenant-admin is admin of parent tenant to BA-group", - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(GroupType, "BA-group"), - ExpectActions: []Action{CanView, CanEdit, CanEditMembers, CanCreateFeed, CanDeleteFeed}, - }, - { - Notes: "user tl-tenant-admin is admin of parent tenant to BA-group", - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(GroupType, "HA-group"), - ExpectActions: []Action{CanView, CanEdit, CanEditMembers, CanCreateFeed, CanDeleteFeed}, - }, - { - Notes: "user tl-tenant-admin is admin of parent tenant to BA-group", - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(GroupType, "EX-group"), - ExpectActions: []Action{CanView, CanEdit, CanEditMembers, CanCreateFeed, CanDeleteFeed}, - }, - { - Notes: "user ian is a viewer of CT-group", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(GroupType, "CT-group"), - ExpectActions: []Action{CanView, -CanEdit, -CanEditMembers, -CanCreateFeed, -CanDeleteFeed}, - }, - { - Notes: "user ian is a editor of CT-group", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(GroupType, "BA-group"), - ExpectActions: []Action{CanView, CanEdit, -CanEditMembers, -CanCreateFeed, -CanDeleteFeed}, - }, - { - Notes: "user ian is a viewer of HA-group through tl-tenant#member", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(GroupType, "HA-group"), - ExpectActions: []Action{CanView, -CanEdit, -CanEditMembers, -CanCreateFeed, -CanDeleteFeed}, - }, - { - Notes: "user ian is not authorized for EX-group", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(GroupType, "EX-group"), - ExpectUnauthorized: true, - }, - { - Notes: "user ian is not authorized for test-group", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(GroupType, "test-group"), - ExpectUnauthorized: true, - }, - { - Notes: "user drew is a manager of CT-group", - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(GroupType, "CT-group"), - ExpectActions: []Action{CanView, CanEdit, CanEditMembers, CanCreateFeed, CanDeleteFeed}, - }, - { - Notes: "user drew is not authrozied for BA-group", - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(GroupType, "BA-group"), - ExpectUnauthorized: true, - }, - { - Notes: "user drew is a viewer of HA-group through tl-tenant#member", - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(GroupType, "HA-group"), - ExpectActions: []Action{CanView, -CanEdit, -CanEditMembers, -CanCreateFeed, -CanDeleteFeed}, - }, - { - Notes: "user drew is not authorized for EX-group", - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(GroupType, "EX-group"), - ExpectUnauthorized: true, - }, - { - Notes: "user drew is not authorized for group test-group", - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(GroupType, "test-group"), - ExpectUnauthorized: true, - }, - { - Notes: "user tl-tenant-member is a viewer of HA-group through tl-tenant#member", - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(GroupType, "HA-group"), - ExpectActions: []Action{CanView, -CanEdit}, - }, - { - Notes: "tl-tenant-member is not authorized to access EX-group", - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(GroupType, "EX-group"), - ExpectUnauthorized: true, - }, - // General checks - { - Notes: "users get unauthorized for groups that are not found", - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(GroupType, "test-group"), - ExpectUnauthorized: true, - }, - { - Notes: "global admins are managers of all groups", - Subject: newEntityKey(UserType, "global_admin"), - Object: newEntityKey(GroupType, "EX-group"), - ExpectActions: []Action{CanView, CanEdit, CanEditMembers, CanCreateFeed, CanDeleteFeed, CanSetTenant}, - }, - { - Notes: "global admins get not found for not found groups", - Subject: newEntityKey(UserType, "global_admin"), - Object: newEntityKey(GroupType, "not found"), - ExpectError: true, - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - ltk := dbTupleLookup(t, dbx, tc.TupleKey()) - ret, err := checker.GroupPermissions( - newUserCtx(tc.CheckAsUser, ltk.Subject.Name), - &authz.GroupRequest{Id: ltk.Object.ID()}, - ) - checkErrUnauthorized(t, err, tc.ExpectError, tc.ExpectUnauthorized) - if err != nil { - return - } - checkActionSubset(t, ret.Actions, tc.ExpectActions) - }) - } - }) - - t.Run("GroupAddPermission", func(t *testing.T) { - checks := []testCase{ - // User checks - // TODO - // { - // Notes: "user tl-tenant-admin gets error when adding user that does not exist", - // Subject: newEntityKey(UserType, "test100"), - // Object: newEntityKey(GroupType, "HA-group"), - // Relation: ViewerRelation, - // ExpectError: true, - // CheckAsUser: "tl-tenant-admin", - // }, - { - Notes: "tl-tenant-admin is manager of CT-group through tl-tenant and can add user", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(GroupType, "CT-group"), - Relation: ViewerRelation, - CheckAsUser: "tl-tenant-admin", - }, - { - Notes: "tl-tenant-admin is manager of CT-group through tl-tenant and can add tenant#member as viewer", - Subject: newEntityKey(TenantType, "tl-tenant").WithRefRel(MemberRelation), - Object: newEntityKey(GroupType, "CT-group"), - Relation: ViewerRelation, - CheckAsUser: "tl-tenant-admin", - }, - { - Notes: "tl-tenant-admin is manager of CT-group through tl-tenant and can add tenant#member as editor", - Subject: newEntityKey(TenantType, "tl-tenant").WithRefRel(MemberRelation), - Object: newEntityKey(GroupType, "CT-group"), - Relation: EditorRelation, - CheckAsUser: "tl-tenant-admin", - }, - { - Notes: "user ian is viewer of CT-group and not authorized to add users", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(GroupType, "CT-group"), - Relation: ViewerRelation, - ExpectUnauthorized: true, - CheckAsUser: "ian", - }, - { - Notes: "user drew is a manager of CT-group and can add users", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(GroupType, "CT-group"), - Relation: ViewerRelation, - CheckAsUser: "drew", - }, - // General checks - { - Notes: "users get unauthorized for groups that do not exist", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(GroupType, "not found"), - Relation: ViewerRelation, - CheckAsUser: "ian", - ExpectUnauthorized: true, - }, - { - Notes: "error for invalid relation", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(GroupType, "CT-group"), - Relation: ParentRelation, - CheckAsUser: "tl-tenant-admin", - ExpectError: true, - }, - { - Notes: "error for invalid relation", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(GroupType, "HA-group"), - Relation: ParentRelation, - ExpectError: true, - CheckAsUser: "tl-tenant-admin", - }, - { - Notes: "error for disallowed relation", - Subject: newEntityKey(GroupType, "BA-group").WithRefRel(MemberRelation), - Object: newEntityKey(GroupType, "CT-group"), - Relation: ViewerRelation, - CheckAsUser: "tl-tenant-admin", - ExpectError: true, - }, - { - Notes: "error for disallowed relation", - Subject: newEntityKey(TenantType, "tl-tenant#admin"), - Object: newEntityKey(GroupType, "CT-group"), - Relation: EditorRelation, - CheckAsUser: "tl-tenant-admin", - ExpectError: true, - }, - { - Notes: "global admin can add users to any group", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(GroupType, "CT-group"), - Relation: ViewerRelation, - CheckAsUser: "global_admin", - }, - { - Notes: "global admin gets not found for groups that do not exist", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(GroupType, "not found"), - Relation: ViewerRelation, - CheckAsUser: "global_admin", - ExpectError: true, - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - // Mutating test - initialize for each test - checker := newTestChecker(t, fgaUrl, checkerTestData) - ltk := dbTupleLookup(t, dbx, tc.TupleKey()) - _, err := checker.GroupAddPermission( - newUserCtx(tc.CheckAsUser, ltk.Subject.Name), - &authz.GroupModifyPermissionRequest{ - Id: ltk.Object.ID(), - EntityRelation: authz.NewEntityRelation(ltk.Subject, ltk.Relation), - }, - ) - checkErrUnauthorized(t, err, tc.ExpectError, tc.ExpectUnauthorized) - }) - } - }) - - t.Run("GroupRemovePermission", func(t *testing.T) { - checks := []testCase{ - // User checks - { - Notes: "user tl-tenant-admin is manager of CT-group through tl-tenant", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(GroupType, "CT-group"), - Relation: ViewerRelation, - CheckAsUser: "tl-tenant-admin", - }, - { - Notes: "user ian is viewer of BA-group and is not authorized to add users", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(GroupType, "BA-group"), - Relation: ViewerRelation, - ExpectUnauthorized: true, - CheckAsUser: "ian", - }, - // General checks - { - Notes: "users get authorized for groups that do not exist", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(GroupType, "not found"), - Relation: ViewerRelation, - ExpectUnauthorized: true, - CheckAsUser: "ian", - }, - { - Notes: "users get error for removing tuple that does not exist", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(GroupType, "BA-group"), - Relation: ViewerRelation, - ExpectError: true, - CheckAsUser: "tl-tenant-admin", - }, - { - Notes: "global admins can remove users from any group", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(GroupType, "CT-group"), - Relation: ViewerRelation, - CheckAsUser: "global_admin", - }, - { - Notes: "global admins get error for removing tuples that do not exist", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(GroupType, "CT-group"), - Relation: EditorRelation, - CheckAsUser: "global_admin", - ExpectError: true, - }, - { - Notes: "global admins get not found for groups that do not exist", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(GroupType, "not found"), - Relation: ViewerRelation, - CheckAsUser: "global_admin", - ExpectError: true, - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - // Mutating test - initialize for each test - checker := newTestChecker(t, fgaUrl, checkerTestData) - ltk := dbTupleLookup(t, dbx, tc.TupleKey()) - _, err := checker.GroupRemovePermission( - newUserCtx(tc.CheckAsUser, ltk.Subject.Name), - &authz.GroupModifyPermissionRequest{ - Id: ltk.Object.ID(), - EntityRelation: authz.NewEntityRelation(ltk.Subject, ltk.Relation), - }, - ) - checkErrUnauthorized(t, err, tc.ExpectError, tc.ExpectUnauthorized) - }) - } - }) - - t.Run("GroupSave", func(t *testing.T) { - checks := []testCase{ - // User checks - { - Notes: "user ian is a viewer of CT-group and cannot edit", - CheckAsUser: "ian", - Object: newEntityKey(GroupType, "CT-group"), - ExpectUnauthorized: true, - }, - { - Notes: "user tl-tenant-admin is a manager of BA-group through tl-tenant and can edit", - Object: newEntityKey(GroupType, "BA-group"), - CheckAsUser: "tl-tenant-admin", - }, - // General checks - { - Notes: "users get unauthorized for groups that are not found", - Object: newEntityKey(GroupType, "not found"), - CheckAsUser: "tl-tenant-admin", - ExpectUnauthorized: true, - }, - { - Notes: "global admins can edit any group", - Object: newEntityKey(GroupType, "BA-group"), - CheckAsUser: "global_admin", - }, - { - Notes: "global admins get not found for groups that are not found", - Object: newEntityKey(GroupType, "not found"), - CheckAsUser: "global_admin", - ExpectError: true, - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - // Mutating test - initialize for each test - checker := newTestChecker(t, fgaUrl, checkerTestData) - ltk := dbTupleLookup(t, dbx, tc.TupleKey()) - _, err := checker.GroupSave( - newUserCtx(tc.CheckAsUser, ltk.Subject.Name), - &authz.GroupSaveRequest{ - Group: &authz.Group{ - Id: ltk.Object.ID(), - Name: tc.Object.Name, - }, - }, - ) - if checkErrUnauthorized(t, err, tc.ExpectError, tc.ExpectUnauthorized) { - return - } - if err != nil { - t.Fatal(err) - } - }) - } - }) - - // FEEDS - t.Run("FeedList", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, checkerTestData) - checks := []testCase{ - { - Notes: "user tl-tenant-admin can see all feeds with groups that are in tl-tenant", - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(FeedType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(FeedType, "CT", "BA", "HA", "EX"), - }, - { - Notes: "user ian is viewer in CT-group, BA-group, and also HA-group through tl-tenant#member", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(FeedType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(FeedType, "CT", "BA", "HA"), - }, - { - Notes: "user drew is editor of CT-group and can see feed CT and also feed HA through tl-tenant#member on HA-group", - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(FeedType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(FeedType, "CT", "HA"), - }, - { - Notes: "user tl-tenant-member can see feed HA through tl-tenant#member on HA-group", - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(FeedType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(FeedType, "HA"), - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - ret, err := checker.FeedList( - newUserCtx(tc.CheckAsUser, tc.Subject.Name), - &authz.FeedListRequest{}, - ) - if err != nil { - t.Fatal(err) - } - var gotNames []string - for _, v := range ret.Feeds { - gotNames = append(gotNames, v.OnestopId) - } - var expectNames []string - for _, v := range tc.ExpectKeys { - expectNames = append(expectNames, v.Name) - } - assert.ElementsMatch(t, expectNames, gotNames, "feed names") - }) - } - }) - - t.Run("FeedPermissions", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, checkerTestData) - checks := []testCase{ - // User checks - { - Notes: "user ian is a viewer of CT through CT-group", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(FeedType, "CT"), - ExpectActions: []Action{CanView, -CanEdit, -CanCreateFeedVersion, -CanDeleteFeedVersion}, - }, - { - Notes: "user ian is a editor of BA through BA-group", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(FeedType, "BA"), - ExpectActions: []Action{CanView, CanEdit, CanCreateFeedVersion, CanDeleteFeedVersion}, - }, - { - Notes: "user ian is a viewer of HA through HA-group through tl-tenant#member", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(FeedType, "HA"), - ExpectActions: []Action{CanView, -CanEdit, -CanCreateFeedVersion, -CanDeleteFeedVersion}, - }, - { - Notes: "user ian is unauthorized for feed EX", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(FeedType, "EX"), - ExpectUnauthorized: true, - }, - { - Notes: "user ian is unauthorized for feed test", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(FeedType, "test"), - ExpectUnauthorized: true, - }, - { - Notes: "user drew is manager of feed CT through CT-group", - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(FeedType, "CT"), - ExpectActions: []Action{CanView, CanEdit, CanCreateFeedVersion, CanDeleteFeedVersion, CanSetGroup}, - }, - { - Notes: "user drew is unauthorized for feed BA", - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(FeedType, "BA"), - ExpectUnauthorized: true, - }, - { - Notes: "user drew is viewer of feed HA through HA-group through tl-tenant#member", - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(FeedType, "HA"), - ExpectActions: []Action{CanView, -CanEdit}, - }, - { - Notes: "user tl-tenant-member is unauthorized for feed BA", - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(FeedType, "BA"), - ExpectUnauthorized: true, - }, - { - Notes: "user tl-tenant-member is viewer for feed HA through HA-group through tl-tenant#member", - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(FeedType, "HA"), - ExpectActions: []Action{CanView, -CanEdit}, - }, - // General checks - { - Notes: "users get unauthorized for a feed that is not found", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(FeedType, "not found"), - ExpectUnauthorized: true, - }, - { - Notes: "global admins are manager for all feeds", - Subject: newEntityKey(UserType, "global_admin"), - Object: newEntityKey(FeedType, "BA"), - ExpectActions: []Action{CanView, CanEdit, CanCreateFeedVersion, CanDeleteFeedVersion, CanSetGroup}, - }, - { - Notes: "global admins get not found for feed that does not exist", - Subject: newEntityKey(UserType, "global_admin"), - Object: newEntityKey(FeedType, "not found"), - ExpectError: true, - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - ltk := dbTupleLookup(t, dbx, tc.TupleKey()) - ret, err := checker.FeedPermissions( - newUserCtx(tc.CheckAsUser, ltk.Subject.Name), - &authz.FeedRequest{Id: ltk.Object.ID()}, - ) - checkErrUnauthorized(t, err, tc.ExpectError, tc.ExpectUnauthorized) - if err != nil { - return - } - checkActionSubset(t, ret.Actions, tc.ExpectActions) - }) - } - }) - - t.Run("FeedSetGroup", func(t *testing.T) { - tcs := []testCase{ - // User checks - // TODO!! - // { - // Notes: "user drew is a manager of feed CT and can assign it to a different group", - // Subject: newEntityKey(FeedType, "CT"), - // Object: newEntityKey(GroupType, "test-group"), - // CheckAsUser: "drew", - // }, - { - Notes: "user ian is an editor of group BA and is not authorized to assign to a different group", - Subject: newEntityKey(FeedType, "BA"), - Object: newEntityKey(GroupType, "test-group"), - CheckAsUser: "ian", - ExpectUnauthorized: true, - }, - { - Notes: "user drew is not authorized to assign feed EX to a group", - Subject: newEntityKey(FeedType, "EX"), - Object: newEntityKey(GroupType, "EX-group"), - CheckAsUser: "drew", - ExpectUnauthorized: true, - }, - // General checks - { - Notes: "user global_admin is a global admin and can assign a feed to a group", - Subject: newEntityKey(FeedType, "BA"), - Object: newEntityKey(GroupType, "CT-group"), - CheckAsUser: "global_admin", - }, - } - for _, tc := range tcs { - t.Run(tc.String(), func(t *testing.T) { - // Mutating test - initialize for each test - checker := newTestChecker(t, fgaUrl, checkerTestData) - ltk := dbTupleLookup(t, dbx, tc.TupleKey()) - _, err := checker.FeedSetGroup( - newUserCtx(tc.CheckAsUser, ltk.Subject.Name), - &authz.FeedSetGroupRequest{Id: ltk.Subject.ID(), GroupId: ltk.Object.ID()}, - ) - if checkErrUnauthorized(t, err, tc.ExpectError, tc.ExpectUnauthorized) { - return - } - // Verify write - fr, err := checker.FeedPermissions( - newUserCtx(tc.CheckAsUser, ltk.Subject.Name), - &authz.FeedRequest{Id: ltk.Subject.ID()}, - ) - if err != nil { - t.Fatal(err) - } - assert.Equal(t, tc.Object.Name, fr.Group.Name) - }) - } - }) - - // FEED VERSIONS - t.Run("FeedVersionList", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, checkerTestData) - // Only user:tl-tenant-member has permissions explicitly defined - checks := []testCase{ - // User checks - { - Notes: "tl-tenant-admin has no explicit feed versions but can access d281 through tenant#member", - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(FeedVersionType, ""), - ExpectKeys: newEntityKeys(FeedVersionType, "d2813c293bcfd7a97dde599527ae6c62c98e66c6"), - }, - { - Notes: "ian has no explicit feed versions but can access d281 through tenant#member", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(FeedVersionType, ""), - ExpectKeys: newEntityKeys(FeedVersionType, "d2813c293bcfd7a97dde599527ae6c62c98e66c6"), - }, - { - Notes: "drew has no explicit feed versions but can access d281 through tenant#member", - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(FeedVersionType, ""), - ExpectKeys: newEntityKeys(FeedVersionType, "d2813c293bcfd7a97dde599527ae6c62c98e66c6"), - }, - { - Notes: "tl-tenant-admin has explicit access to e535 and can access d281 through tenant#member", - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(FeedVersionType, ""), - ExpectKeys: newEntityKeys(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0", "d2813c293bcfd7a97dde599527ae6c62c98e66c6"), - }, - // General checks - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - ret, err := checker.FeedVersionList( - newUserCtx(tc.CheckAsUser, tc.Subject.Name), - &authz.FeedVersionListRequest{}, - ) - if err != nil { - t.Fatal(err) - } - var gotNames []string - for _, v := range ret.FeedVersions { - gotNames = append(gotNames, v.Sha1) - } - var expectNames []string - for _, v := range tc.ExpectKeys { - expectNames = append(expectNames, v.Name) - } - assert.ElementsMatch(t, expectNames, gotNames, "feed version names") - }) - } - }) - - t.Run("FeedVersionPermissions", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, checkerTestData) - checks := []testCase{ - // User checks - { - Notes: "tl-tenant-admin is a editor of e535 through tenant", - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - ExpectActions: []Action{CanView, CanEdit, CanEditMembers}, - }, - { - Notes: "user ian is an editor of e535 through feed BA through group BA-group", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - ExpectActions: []Action{CanView, CanEdit}, - }, - { - Notes: "drew is not authorized to read e535", - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - ExpectActions: []Action{-CanView}, - ExpectUnauthorized: true, - }, - { - Notes: "tl-tenant-member is directly granted viewer on e535", - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - ExpectActions: []Action{CanView}, - }, - { - Notes: "user test-group-viewer is viewer on e535 through grant to test-group#viewer", - Subject: newEntityKey(UserType, "test-group-viewer"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - ExpectActions: []Action{CanView, -CanEdit, -CanEditMembers}, - }, - // General checks - { - Notes: "users get unauthorized for feed versions that do not exist", - Subject: newEntityKey(UserType, "test-group-viewer"), - Object: newEntityKey(FeedVersionType, "not found"), - ExpectUnauthorized: true, - }, - { - Notes: "global admins get error for feed versions that do not exist", - Subject: newEntityKey(UserType, "global_admin"), - Object: newEntityKey(FeedVersionType, "not found"), - ExpectError: true, - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - ltk := dbTupleLookup(t, dbx, tc.TupleKey()) - ret, err := checker.FeedVersionPermissions( - newUserCtx(tc.CheckAsUser, ltk.Subject.Name), - &authz.FeedVersionRequest{Id: ltk.Object.ID()}, - ) - checkErrUnauthorized(t, err, tc.ExpectError, tc.ExpectUnauthorized) - if err != nil { - return - } - checkActionSubset(t, ret.Actions, tc.ExpectActions) - }) - } - }) - - t.Run("FeedVersionAddPermission", func(t *testing.T) { - checks := []testCase{ - // User checks - { - Notes: "user tl-tenant-admin is a manager of e535 through tenant#admin and can edit users", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - CheckAsUser: "tl-tenant-admin", - }, - { - Notes: "user ian is editor of e535 through BA and BA-group and can not edit users", - Subject: newEntityKey(UserType, "test3"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - CheckAsUser: "ian", - ExpectUnauthorized: true, - }, - // General checks - { - Notes: "existing tuple will still remove other subject matched tuples", - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - CheckAsUser: "tl-tenant-admin", - }, - { - Notes: "invalid relation returns error", - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ParentRelation, - ExpectError: true, - CheckAsUser: "tl-tenant-admin", - }, - { - Notes: "disallowed relation returns error", - Subject: newEntityKey(GroupType, "BA-group#editor"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - ExpectError: true, - CheckAsUser: "tl-tenant-admin", - }, - { - Notes: "global admins get error when editing feed version that does not exist", - Subject: newEntityKey(UserType, "test3"), - Object: newEntityKey(FeedVersionType, "not found"), - Relation: ViewerRelation, - CheckAsUser: "global_admin", - ExpectError: true, - }, - { - Notes: "global admins can edit users of any feed version", - Subject: newEntityKey(UserType, "new-user"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - CheckAsUser: "global_admin", - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - // Mutating test - initialize for each test - checker := newTestChecker(t, fgaUrl, checkerTestData) - ltk := dbTupleLookup(t, dbx, tc.TupleKey()) - _, err := checker.FeedVersionAddPermission( - newUserCtx(tc.CheckAsUser, ltk.Subject.Name), - &authz.FeedVersionModifyPermissionRequest{ - Id: ltk.Object.ID(), - EntityRelation: authz.NewEntityRelation(ltk.Subject, ltk.Relation), - }, - ) - checkErrUnauthorized(t, err, tc.ExpectError, tc.ExpectUnauthorized) - }) - } - }) - - t.Run("FeedVersionRemovePermission", func(t *testing.T) { - checks := []testCase{ - // User checks - { - Notes: "user tl-tenant-admin is a manager of feed version e535 through tenant#admin and can edit permissions", - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - CheckAsUser: "tl-tenant-admin", - }, - { - Notes: "user ian is not a manager of feed version e535", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - ExpectUnauthorized: true, - CheckAsUser: "ian", - }, - // General checks - { - Notes: "global admins get not found when editing permissions of a feed version that does not exist", - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(FeedVersionType, "not found"), - Relation: ViewerRelation, - ExpectError: true, - CheckAsUser: "global_admin", - }, - { - Notes: "global admins can edit permissions of any feed version", - Subject: newEntityKey(UserType, "tl-tenant-member"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - CheckAsUser: "global_admin", - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - // Mutating test - initialize for each test - checker := newTestChecker(t, fgaUrl, checkerTestData) - ltk := dbTupleLookup(t, dbx, tc.TupleKey()) - _, err := checker.FeedVersionRemovePermission( - newUserCtx(tc.CheckAsUser, ltk.Subject.Name), - &authz.FeedVersionModifyPermissionRequest{ - Id: ltk.Object.ID(), - EntityRelation: authz.NewEntityRelation(ltk.Subject, ltk.Relation), - }, - ) - checkErrUnauthorized(t, err, tc.ExpectError, tc.ExpectUnauthorized) - }) - } - }) - -} - -func stringOr(a, b string) string { - if a != "" { - return a - } - return b -} - -func checkActionSubset(t testing.TB, actions any, checks []Action) { - checkA, err := actionsToMap(actions) - if err != nil { - t.Error(err) - } - checkActions := checkActionsToMap(checks) - checkMapSubset(t, checkA, checkActions) -} - -func checkMapSubset(t testing.TB, got map[string]bool, expect map[string]bool) { - var keys = map[string]bool{} - for k := range got { - keys[k] = true - } - for k := range expect { - keys[k] = true - } - for k := range keys { - if got[k] != expect[k] { - t.Errorf("key %s mismatch, got %t expect %t", k, got[k], expect[k]) - } - } -} - -func actionsToMap(actions any) (map[string]bool, error) { - jj, err := json.Marshal(actions) - if err != nil { - return nil, err - } - ret := map[string]bool{} - if err := json.Unmarshal(jj, &ret); err != nil { - return nil, err - } - return ret, nil -} - -func checkActionsToMap(v []Action) map[string]bool { - ret := map[string]bool{} - for _, checkAction := range v { - expect := true - if checkAction < 0 { - expect = false - checkAction *= -1 - } - ret[checkAction.String()] = expect - } - return ret -} - -func newTestChecker(t testing.TB, url string, testData []testCase) *Checker { - dbx := testutil.MustOpenTestDB() - cfg := CheckerConfig{ - FGAEndpoint: url, - FGALoadModelFile: testutil.RelPath("test/authz/tls.json"), - GlobalAdmin: "global_admin", - } - - checker, err := NewCheckerFromConfig(cfg, dbx) - if err != nil { - t.Fatal(err) - } - - // Add test data - for _, tc := range testData { - if err := checker.fgaClient.WriteTuple(context.Background(), dbTupleLookup(t, dbx, tc.TupleKey())); err != nil { - t.Fatal(err) - } - } - - // Override UserProvider - userClient := NewMockUserProvider() - userClient.AddUser("ian", authn.NewCtxUser("ian", "Ian", "ian@example.com")) - userClient.AddUser("drew", authn.NewCtxUser("drew", "Drew", "drew@example.com")) - userClient.AddUser("tl-tenant-member", authn.NewCtxUser("tl-tenant-member", "Tenant Member", "tl-tenant-member@example.com")) - userClient.AddUser("new-user", authn.NewCtxUser("new-user", "Unassigned Member", "new-user@example.com")) - checker.userClient = userClient - return checker -} - -func checkErrUnauthorized(t testing.TB, err error, expectError bool, expectUnauthorized bool) bool { - // return true if there was an error - // log unexpected errors - if err == nil { - if expectUnauthorized { - t.Errorf("expected unauthorized, got no error") - } else if expectError { - t.Errorf("expected error, got no error") - } - } else { - if expectUnauthorized && err != ErrUnauthorized { - t.Errorf("expected unauthorized, got error '%s'", err.Error()) - } - if !(expectUnauthorized || expectError) { - t.Errorf("got error '%s', expected no error", err.Error()) - } - } - return err != nil -} - -func checkExpectError(t testing.TB, err error, expect bool) bool { - if err != nil && !expect { - t.Errorf("got error '%s', did not expect error", err.Error()) - return false - } - if err == nil && expect { - t.Errorf("got no error, expected error") - return false - } - if err != nil { - return false - } - return true -} - -func newEntityKey(t ObjectType, name string) EntityKey { - return authz.NewEntityKey(t, name) -} - -func newEntityKeys(t ObjectType, keys ...string) []EntityKey { - var ret []EntityKey - for _, k := range keys { - ret = append(ret, newEntityKey(t, k)) - } - return ret -} - -func newUserCtx(first ...string) context.Context { - for _, f := range first { - if f != "" { - return authn.WithUser(context.Background(), authn.NewCtxUser(f, f, f)) - } - } - return context.Background() -} diff --git a/auth/azcheck/mock.go b/auth/azcheck/mock.go deleted file mode 100644 index fa21ed3b..00000000 --- a/auth/azcheck/mock.go +++ /dev/null @@ -1,79 +0,0 @@ -package azcheck - -import ( - "context" - "errors" - "strings" - - "github.com/interline-io/transitland-server/auth/authn" -) - -type MockUserProvider struct { - users map[string]authn.User -} - -func NewMockUserProvider() *MockUserProvider { - return &MockUserProvider{ - users: map[string]authn.User{}, - } -} - -func (c *MockUserProvider) AddUser(key string, u authn.User) { - c.users[key] = authn.NewCtxUser(u.ID(), u.Name(), u.Email()) -} - -func (c *MockUserProvider) UserByID(ctx context.Context, id string) (authn.User, error) { - if user, ok := c.users[id]; ok { - return user, nil - } - return nil, errors.New("unauthorized") -} - -func (c *MockUserProvider) Users(ctx context.Context, userQuery string) ([]authn.User, error) { - var ret []authn.User - uq := strings.ToLower(userQuery) - for _, user := range c.users { - user := user - un := strings.ToLower(user.Name()) - if userQuery == "" || strings.Contains(un, uq) { - ret = append(ret, user) - } - } - return ret, nil -} - -////// - -type MockFGAClient struct{} - -func NewMockFGAClient() *MockFGAClient { - return &MockFGAClient{} -} - -func (c *MockFGAClient) Check(context.Context, TupleKey, ...TupleKey) (bool, error) { - return false, nil -} - -func (c *MockFGAClient) ListObjects(context.Context, TupleKey) ([]TupleKey, error) { - return nil, nil -} - -func (c *MockFGAClient) GetObjectTuples(context.Context, TupleKey) ([]TupleKey, error) { - return nil, nil -} - -func (c *MockFGAClient) WriteTuple(context.Context, TupleKey) error { - return nil -} - -func (c *MockFGAClient) SetExclusiveRelation(context.Context, TupleKey) error { - return nil -} - -func (c *MockFGAClient) SetExclusiveSubjectRelation(context.Context, TupleKey, ...Relation) error { - return nil -} - -func (c *MockFGAClient) DeleteTuple(context.Context, TupleKey) error { - return nil -} diff --git a/auth/azcheck/server.go b/auth/azcheck/server.go deleted file mode 100644 index d9698482..00000000 --- a/auth/azcheck/server.go +++ /dev/null @@ -1,224 +0,0 @@ -package azcheck - -import ( - "encoding/json" - "io" - "io/ioutil" - "net/http" - "strconv" - - "github.com/go-chi/chi/v5" - "github.com/interline-io/transitland-lib/log" - "github.com/interline-io/transitland-server/auth/authz" - "github.com/interline-io/transitland-server/internal/util" - "github.com/interline-io/transitland-server/model" -) - -func NewServer(checker model.Checker) (http.Handler, error) { - router := chi.NewRouter() - - ///////////////// - // USERS - ///////////////// - - router.Get("/users", func(w http.ResponseWriter, r *http.Request) { - ret, err := checker.UserList(r.Context(), &authz.UserListRequest{Q: r.URL.Query().Get("q")}) - handleJson(w, ret, err) - }) - router.Get("/users/{user_id}", func(w http.ResponseWriter, r *http.Request) { - ret, err := checker.User(r.Context(), &authz.UserRequest{Id: chi.URLParam(r, "user_id")}) - handleJson(w, ret, err) - }) - router.Get("/me", func(w http.ResponseWriter, r *http.Request) { - ret, err := checker.Me(r.Context(), &authz.MeRequest{}) - handleJson(w, ret, err) - }) - - ///////////////// - // TENANTS - ///////////////// - - router.Get("/tenants", func(w http.ResponseWriter, r *http.Request) { - ret, err := checker.TenantList(r.Context(), &authz.TenantListRequest{}) - handleJson(w, ret, err) - }) - router.Get("/tenants/{tenant_id}", func(w http.ResponseWriter, r *http.Request) { - ret, err := checker.TenantPermissions(r.Context(), &authz.TenantRequest{Id: checkId(r, "tenant_id")}) - handleJson(w, ret, err) - }) - router.Post("/tenants/{tenant_id}", func(w http.ResponseWriter, r *http.Request) { - check := authz.Tenant{} - if err := parseJson(r.Body, &check); err != nil { - handleJson(w, nil, err) - return - } - check.Id = checkId(r, "tenant_id") - _, err := checker.TenantSave(r.Context(), &authz.TenantSaveRequest{Tenant: &check}) - handleJson(w, nil, err) - }) - router.Post("/tenants/{tenant_id}/groups", func(w http.ResponseWriter, r *http.Request) { - check := authz.Group{} - if err := parseJson(r.Body, &check); err != nil { - handleJson(w, nil, err) - return - } - _, err := checker.TenantCreateGroup(r.Context(), &authz.TenantCreateGroupRequest{Id: checkId(r, "tenant_id"), Group: &check}) - handleJson(w, nil, err) - }) - router.Post("/tenants/{tenant_id}/permissions", func(w http.ResponseWriter, r *http.Request) { - check := &authz.EntityRelation{} - if err := parseJson(r.Body, check); err != nil { - handleJson(w, nil, err) - } - entId := checkId(r, "tenant_id") - _, err := checker.TenantAddPermission(r.Context(), &authz.TenantModifyPermissionRequest{Id: entId, EntityRelation: check}) - handleJson(w, nil, err) - }) - router.Delete("/tenants/{tenant_id}/permissions", func(w http.ResponseWriter, r *http.Request) { - check := &authz.EntityRelation{} - if err := parseJson(r.Body, check); err != nil { - handleJson(w, nil, err) - } - entId := checkId(r, "tenant_id") - _, err := checker.TenantRemovePermission(r.Context(), &authz.TenantModifyPermissionRequest{Id: entId, EntityRelation: check}) - handleJson(w, nil, err) - }) - - ///////////////// - // GROUPS - ///////////////// - - router.Get("/groups", func(w http.ResponseWriter, r *http.Request) { - ret, err := checker.GroupList(r.Context(), &authz.GroupListRequest{}) - handleJson(w, ret, err) - }) - router.Post("/groups/{group_id}", func(w http.ResponseWriter, r *http.Request) { - check := authz.Group{} - if err := parseJson(r.Body, &check); err != nil { - handleJson(w, nil, err) - return - } - check.Id = checkId(r, "group_id") - _, err := checker.GroupSave(r.Context(), &authz.GroupSaveRequest{Group: &check}) - handleJson(w, nil, err) - }) - router.Get("/groups/{group_id}", func(w http.ResponseWriter, r *http.Request) { - ret, err := checker.GroupPermissions(r.Context(), &authz.GroupRequest{Id: checkId(r, "group_id")}) - handleJson(w, ret, err) - }) - router.Post("/groups/{group_id}/permissions", func(w http.ResponseWriter, r *http.Request) { - check := &authz.EntityRelation{} - if err := parseJson(r.Body, check); err != nil { - handleJson(w, nil, err) - } - entId := checkId(r, "group_id") - _, err := checker.GroupAddPermission(r.Context(), &authz.GroupModifyPermissionRequest{Id: entId, EntityRelation: check}) - handleJson(w, nil, err) - }) - router.Delete("/groups/{group_id}/permissions", func(w http.ResponseWriter, r *http.Request) { - check := &authz.EntityRelation{} - if err := parseJson(r.Body, check); err != nil { - handleJson(w, nil, err) - } - entId := checkId(r, "group_id") - _, err := checker.GroupRemovePermission(r.Context(), &authz.GroupModifyPermissionRequest{Id: entId, EntityRelation: check}) - handleJson(w, nil, err) - }) - router.Post("/groups/{group_id}/tenant", func(w http.ResponseWriter, r *http.Request) { - check := authz.GroupSetTenantRequest{} - if err := parseJson(r.Body, &check); err != nil { - handleJson(w, nil, err) - return - } - check.Id = checkId(r, "group_id") - _, err := checker.GroupSetTenant(r.Context(), &check) - handleJson(w, nil, err) - }) - - ///////////////// - // FEEDS - ///////////////// - - router.Get("/feeds", func(w http.ResponseWriter, r *http.Request) { - ret, err := checker.FeedList(r.Context(), &authz.FeedListRequest{}) - handleJson(w, ret, err) - }) - router.Get("/feeds/{feed_id}", func(w http.ResponseWriter, r *http.Request) { - ret, err := checker.FeedPermissions(r.Context(), &authz.FeedRequest{Id: checkId(r, "feed_id")}) - handleJson(w, ret, err) - }) - router.Post("/feeds/{feed_id}/group", func(w http.ResponseWriter, r *http.Request) { - check := authz.FeedSetGroupRequest{} - if err := parseJson(r.Body, &check); err != nil { - handleJson(w, nil, err) - return - } - check.Id = checkId(r, "feed_id") - _, err := checker.FeedSetGroup(r.Context(), &check) - handleJson(w, nil, err) - }) - - ///////////////// - // FEED VERSIONS - ///////////////// - - router.Get("/feed_versions", func(w http.ResponseWriter, r *http.Request) { - ret, err := checker.FeedVersionList(r.Context(), &authz.FeedVersionListRequest{}) - handleJson(w, ret, err) - }) - router.Get("/feed_versions/{feed_version_id}", func(w http.ResponseWriter, r *http.Request) { - ret, err := checker.FeedVersionPermissions(r.Context(), &authz.FeedVersionRequest{Id: checkId(r, "feed_version_id")}) - handleJson(w, ret, err) - }) - router.Post("/feed_versions/{feed_version_id}/permissions", func(w http.ResponseWriter, r *http.Request) { - check := &authz.EntityRelation{} - if err := parseJson(r.Body, check); err != nil { - handleJson(w, nil, err) - } - entId := checkId(r, "feed_version_id") - _, err := checker.FeedVersionAddPermission(r.Context(), &authz.FeedVersionModifyPermissionRequest{Id: entId, EntityRelation: check}) - handleJson(w, nil, err) - }) - router.Delete("/feed_versions/{feed_version_id}/permissions", func(w http.ResponseWriter, r *http.Request) { - check := &authz.EntityRelation{} - if err := parseJson(r.Body, check); err != nil { - handleJson(w, nil, err) - } - entId := checkId(r, "feed_version_id") - _, err := checker.FeedVersionRemovePermission(r.Context(), &authz.FeedVersionModifyPermissionRequest{Id: entId, EntityRelation: check}) - handleJson(w, nil, err) - }) - - return router, nil -} - -func handleJson(w http.ResponseWriter, ret any, err error) { - if err == ErrUnauthorized { - log.Error().Err(err).Msg("unauthorized") - http.Error(w, util.MakeJsonError(http.StatusText(http.StatusUnauthorized)), http.StatusUnauthorized) - return - } else if err != nil { - log.Error().Err(err).Msg("admin api error") - http.Error(w, util.MakeJsonError(http.StatusText(http.StatusInternalServerError)), http.StatusInternalServerError) - return - } - if ret == nil { - ret = map[string]bool{"success": true} - } - jj, _ := json.Marshal(ret) - w.Header().Add("Content-Type", "application/json") - w.Write(jj) -} - -func checkId(r *http.Request, key string) int64 { - v, _ := strconv.Atoi(chi.URLParam(r, key)) - return int64(v) -} - -func parseJson(r io.Reader, v any) error { - data, err := ioutil.ReadAll(io.LimitReader(r, 1_000_000)) - if err != nil { - return err - } - return json.Unmarshal(data, v) -} diff --git a/auth/azcheck/server_test.go b/auth/azcheck/server_test.go deleted file mode 100644 index d8f14cf6..00000000 --- a/auth/azcheck/server_test.go +++ /dev/null @@ -1,466 +0,0 @@ -package azcheck - -import ( - "fmt" - "net/http" - "net/http/httptest" - "testing" - - "github.com/interline-io/transitland-server/auth/ancheck" - "github.com/interline-io/transitland-server/auth/authz" - "github.com/interline-io/transitland-server/internal/testutil" - "github.com/stretchr/testify/assert" - "github.com/tidwall/gjson" -) - -func TestServer(t *testing.T) { - fgaUrl, a, ok := testutil.CheckEnv("TL_TEST_FGA_ENDPOINT") - if !ok { - t.Skip(a) - return - } - dbx := testutil.MustOpenTestDB() - serverTestData := []testCase{ - { - Subject: newEntityKey(TenantType, "tl-tenant"), - Object: newEntityKey(GroupType, "BA-group"), - Relation: ParentRelation, - Notes: "org:BA-group belongs to tenant:tl-tenant", - }, - { - Subject: newEntityKey(TenantType, "tl-tenant"), - Object: newEntityKey(GroupType, "CT-group"), - Relation: ParentRelation, - Notes: "org:CT-group belongs to tenant:tl-tenant", - }, - { - Subject: newEntityKey(TenantType, "restricted-tenant"), - Object: newEntityKey(GroupType, "test-group"), - Relation: ParentRelation, - }, - { - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(TenantType, "tl-tenant"), - Relation: AdminRelation, - }, - - { - Subject: newEntityKey(GroupType, "BA-group"), - Object: newEntityKey(FeedType, "BA"), - Relation: ParentRelation, - }, - { - Subject: newEntityKey(GroupType, "CT-group"), - Object: newEntityKey(FeedType, "CT"), - Relation: ParentRelation, - }, - - { - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(TenantType, "tl-tenant"), - Relation: MemberRelation, - }, - { - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(TenantType, "tl-tenant"), - Relation: MemberRelation, - }, - { - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(GroupType, "BA-group"), - Relation: ViewerRelation, - }, - { - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(GroupType, "CT-group"), - Relation: EditorRelation, - }, - { - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - Notes: "assign drew permission to view this BA feed", - }, - } - - // USERS - t.Run("Me", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, serverTestData) - checks := []testCase{ - { - CheckAsUser: "ian", - ExpectKeys: newEntityKeys(GroupType, "BA-group"), - }, - { - CheckAsUser: "drew", - ExpectKeys: newEntityKeys(GroupType, "CT-group"), - }, - { - CheckAsUser: "asdf", - ExpectKeys: newEntityKeys(GroupType), - ExpectError: true, - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - srv := testServerWithUser(checker, tc) - req, _ := http.NewRequest("GET", "/me", nil) - rr := httptest.NewRecorder() - srv.ServeHTTP(rr, req) - checkHttpExpectError(t, tc, rr) - assert.ElementsMatch( - t, - ekGetNames(tc.ExpectKeys), - responseGetNames(t, rr.Body.Bytes(), "groups", "name"), - ) - }) - } - }) - - // TENANTS - t.Run("TenantList", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, serverTestData) - checks := []testCase{ - { - Subject: newEntityKey(UserType, "tl-tenant-admin"), - ExpectKeys: newEntityKeys(TenantType, "tl-tenant"), - }, - { - Subject: newEntityKey(UserType, "ian"), - ExpectKeys: newEntityKeys(TenantType, "tl-tenant"), - }, - { - Subject: newEntityKey(UserType, "drew"), - ExpectKeys: newEntityKeys(TenantType, "tl-tenant"), - }, - { - Subject: newEntityKey(UserType, "unknown"), - ExpectKeys: newEntityKeys(TenantType), - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - srv := testServerWithUser(checker, tc) - req, _ := http.NewRequest("GET", "/tenants", nil) - rr := httptest.NewRecorder() - srv.ServeHTTP(rr, req) - checkHttpExpectError(t, tc, rr) - assert.ElementsMatch( - t, - ekGetNames(tc.ExpectKeys), - responseGetNames(t, rr.Body.Bytes(), "tenants", "name"), - ) - }) - } - }) - - t.Run("TenantPermissions", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, serverTestData) - checks := []testCase{ - { - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(TenantType, "tl-tenant"), - ExpectActions: []Action{CanView, CanEdit, CanEditMembers, CanCreateOrg, CanDeleteOrg}, - }, - { - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(TenantType, "restricted-tenant"), - ExpectUnauthorized: true, - }, - { - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(TenantType, "tl-tenant"), - ExpectActions: []Action{CanView}, - }, - { - Subject: newEntityKey(UserType, "unknown"), - Object: newEntityKey(TenantType, "tl-tenant"), - ExpectUnauthorized: true, - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - ltk := dbTupleLookup(t, dbx, tc.TupleKey()) - srv := testServerWithUser(checker, tc) - req, _ := http.NewRequest("GET", fmt.Sprintf("/tenants/%s", ltk.Object.Name), nil) - rr := httptest.NewRecorder() - srv.ServeHTTP(rr, req) - checkHttpExpectError(t, tc, rr) - gotActions := responseGetActions(t, rr.Body.Bytes()) - assert.ElementsMatch(t, tc.ExpectActions, gotActions) - }) - } - }) - - // GROUPS - t.Run("GroupList", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, serverTestData) - checks := []testCase{ - { - Subject: newEntityKey(UserType, "tl-tenant-admin"), - ExpectKeys: newEntityKeys(GroupType, "BA-group", "CT-group"), - }, - { - Subject: newEntityKey(UserType, "ian"), - ExpectKeys: newEntityKeys(GroupType, "BA-group"), - }, - { - Subject: newEntityKey(UserType, "drew"), - ExpectKeys: newEntityKeys(GroupType, "CT-group"), - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - srv := testServerWithUser(checker, tc) - req, _ := http.NewRequest("GET", "/groups", nil) - rr := httptest.NewRecorder() - srv.ServeHTTP(rr, req) - checkHttpExpectError(t, tc, rr) - assert.ElementsMatch( - t, - ekGetNames(tc.ExpectKeys), - responseGetNames(t, rr.Body.Bytes(), "groups", "name"), - ) - }) - } - }) - - t.Run("GroupPermissions", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, serverTestData) - checks := []testCase{ - { - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(GroupType, "BA-group"), - ExpectActions: []Action{CanView, CanEdit, CanEditMembers, CanCreateFeed, CanDeleteFeed}, - }, - { - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(GroupType, "BA-group"), - ExpectActions: []Action{CanView}, - }, - { - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(GroupType, "CT-group"), - ExpectActions: []Action{CanView, CanEdit}, - }, - { - Subject: newEntityKey(UserType, "unknown"), - Object: newEntityKey(GroupType, "CT-group"), - ExpectUnauthorized: true, - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - ltk := dbTupleLookup(t, dbx, tc.TupleKey()) - srv := testServerWithUser(checker, tc) - req, _ := http.NewRequest("GET", fmt.Sprintf("/groups/%s", ltk.Object.Name), nil) - rr := httptest.NewRecorder() - srv.ServeHTTP(rr, req) - checkHttpExpectError(t, tc, rr) - gotActions := responseGetActions(t, rr.Body.Bytes()) - assert.ElementsMatch(t, tc.ExpectActions, gotActions) - }) - } - }) - - // FEEDS - t.Run("FeedList", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, serverTestData) - checks := []testCase{ - { - Subject: newEntityKey(UserType, "tl-tenant-admin"), - ExpectKeys: newEntityKeys(TenantType, "BA", "CT"), - }, - { - Subject: newEntityKey(UserType, "ian"), - ExpectKeys: newEntityKeys(TenantType, "BA"), - }, - { - Subject: newEntityKey(UserType, "drew"), - ExpectKeys: newEntityKeys(TenantType, "CT"), - }, - { - Subject: newEntityKey(UserType, "unknown"), - ExpectKeys: newEntityKeys(TenantType), - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - srv := testServerWithUser(checker, tc) - req, _ := http.NewRequest("GET", "/feeds", nil) - rr := httptest.NewRecorder() - srv.ServeHTTP(rr, req) - checkHttpExpectError(t, tc, rr) - assert.ElementsMatch( - t, - ekGetNames(tc.ExpectKeys), - responseGetNames(t, rr.Body.Bytes(), "feeds", "onestop_id"), - ) - }) - } - }) - - t.Run("FeedPermissions", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, serverTestData) - checks := []testCase{ - { - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(FeedType, "BA"), - ExpectActions: []Action{CanView, CanEdit, CanCreateFeedVersion, CanDeleteFeedVersion, CanSetGroup}, - }, - { - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(FeedType, "BA"), - ExpectActions: []Action{CanView}, - }, - { - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(FeedType, "CT"), - ExpectActions: []Action{CanView, CanEdit, CanCreateFeedVersion, CanDeleteFeedVersion}, - }, - { - Subject: newEntityKey(UserType, "unknown"), - Object: newEntityKey(FeedType, "CT"), - ExpectUnauthorized: true, - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - ltk := dbTupleLookup(t, dbx, tc.TupleKey()) - srv := testServerWithUser(checker, tc) - req, _ := http.NewRequest("GET", fmt.Sprintf("/feeds/%s", ltk.Object.Name), nil) - rr := httptest.NewRecorder() - srv.ServeHTTP(rr, req) - checkHttpExpectError(t, tc, rr) - gotActions := responseGetActions(t, rr.Body.Bytes()) - assert.ElementsMatch(t, tc.ExpectActions, gotActions) - }) - } - }) - - // FEED VERSIONS - t.Run("FeedVersionList", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, serverTestData) - checks := []testCase{ - { - Subject: newEntityKey(UserType, "tl-tenant-admin"), - ExpectKeys: newEntityKeys(FeedVersionType), - }, - { - Subject: newEntityKey(UserType, "ian"), - ExpectKeys: newEntityKeys(FeedVersionType), - }, - { - Subject: newEntityKey(UserType, "drew"), - ExpectKeys: newEntityKeys(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - srv := testServerWithUser(checker, tc) - req, _ := http.NewRequest("GET", "/feed_versions", nil) - rr := httptest.NewRecorder() - srv.ServeHTTP(rr, req) - checkHttpExpectError(t, tc, rr) - assert.ElementsMatch( - t, - ekGetNames(tc.ExpectKeys), - responseGetNames(t, rr.Body.Bytes(), "feed_versions", "sha1"), - ) - }) - } - }) - - t.Run("FeedVersionPermissions", func(t *testing.T) { - checker := newTestChecker(t, fgaUrl, serverTestData) - checks := []testCase{ - { - Subject: newEntityKey(UserType, "tl-tenant-admin"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - ExpectActions: []Action{CanView, CanEdit, CanEditMembers}, - }, - { - Subject: newEntityKey(UserType, "ian"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - ExpectActions: []Action{CanView}, - }, - { - Subject: newEntityKey(UserType, "drew"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - ExpectActions: []Action{CanView}, - }, - { - Subject: newEntityKey(UserType, "unknown"), - Object: newEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - ExpectUnauthorized: true, - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - ltk := dbTupleLookup(t, dbx, tc.TupleKey()) - srv := testServerWithUser(checker, tc) - req, _ := http.NewRequest("GET", fmt.Sprintf("/feed_versions/%s", ltk.Object.Name), nil) - rr := httptest.NewRecorder() - srv.ServeHTTP(rr, req) - checkHttpExpectError(t, tc, rr) - gotActions := responseGetActions(t, rr.Body.Bytes()) - assert.ElementsMatch(t, tc.ExpectActions, gotActions) - }) - } - }) - -} - -func testServerWithUser(c *Checker, tk testCase) http.Handler { - srv, _ := NewServer(c) - srv = ancheck.UserDefaultMiddleware(stringOr(tk.CheckAsUser, tk.Subject.Name))(srv) - return srv -} - -func checkHttpExpectError(t testing.TB, tk testCase, rr *httptest.ResponseRecorder) { - status := rr.Code - if tk.ExpectUnauthorized { - if status != http.StatusUnauthorized { - t.Errorf("got error code %d, expected %d", status, http.StatusUnauthorized) - } - } else if tk.ExpectError { - if status == http.StatusOK { - t.Errorf("got status %d, expected non-200", status) - } - } else if status != http.StatusOK { - t.Errorf("got error code %d, expected 200", status) - } - -} - -func responseGetNames(t testing.TB, data []byte, path string, key string) []string { - a := gjson.ParseBytes(data).Get(path) - var ret []string - for _, b := range a.Array() { - ret = append(ret, b.Get(key).Str) - } - return ret -} - -func ekGetNames(eks []EntityKey) []string { - var ret []string - for _, ek := range eks { - ret = append(ret, ek.Name) - } - return ret -} - -func responseGetActions(t testing.TB, data []byte) []Action { - a := gjson.ParseBytes(data).Get("actions") - var ret []Action - for k, v := range a.Map() { - if v.Bool() { - a, err := authz.ActionString(k) - if err != nil { - t.Errorf("invalid action %s", k) - } - ret = append(ret, a) - } - } - return ret -} diff --git a/auth/fga/fga.go b/auth/fga/fga.go deleted file mode 100644 index d07b9ad2..00000000 --- a/auth/fga/fga.go +++ /dev/null @@ -1,288 +0,0 @@ -package fga - -import ( - "context" - "encoding/json" - "fmt" - "io/ioutil" - "net/url" - "strings" - - "github.com/interline-io/transitland-lib/log" - "github.com/interline-io/transitland-server/auth/authz" - openfga "github.com/openfga/go-sdk" -) - -func FromFGATupleKey(fgatk openfga.TupleKey) authz.TupleKey { - rel, _ := authz.RelationString(*fgatk.Relation) - act, _ := authz.ActionString(*fgatk.Relation) - return authz.TupleKey{ - Subject: NewEntityKeySplit(*fgatk.User), - Object: NewEntityKeySplit(*fgatk.Object), - Relation: rel, - Action: act, - } -} - -func ToFGATupleKey(tk authz.TupleKey) openfga.TupleKey { - fgatk := openfga.TupleKey{} - if tk.Subject.Name != "" { - fgatk.User = openfga.PtrString(tk.Subject.String()) - } else if authz.IsObjectType(tk.Subject.Type) { - fgatk.Object = openfga.PtrString(tk.Subject.Type.String() + ":") - } - if tk.Object.Name != "" { - fgatk.Object = openfga.PtrString(tk.Object.String()) - } else if authz.IsObjectType(tk.Object.Type) { - fgatk.Object = openfga.PtrString(tk.Object.Type.String() + ":") - } - if authz.IsAction(tk.Action) { - fgatk.Relation = openfga.PtrString(tk.Action.String()) - } else if authz.IsRelation(tk.Relation) { - fgatk.Relation = openfga.PtrString(tk.Relation.String()) - } - return fgatk -} - -func NewEntityKeySplit(v string) authz.EntityKey { - ret := authz.EntityKey{} - a := strings.Split(v, ":") - if len(a) > 1 { - ret.Type, _ = authz.ObjectTypeString(a[0]) - ret.Name = a[1] - } else if len(a) > 0 { - ret.Type, _ = authz.ObjectTypeString(a[0]) - } - ns := strings.Split(ret.Name, "#") - if len(ns) > 1 { - ret.Name = ns[0] - ret.RefRel, _ = authz.RelationString(ns[1]) - } - return ret -} - -// ////////// - -type FGAClient struct { - ModelID string - client *openfga.APIClient -} - -func NewFGAClient(endpoint string, storeId string, modelId string) (*FGAClient, error) { - ep, err := url.Parse(endpoint) - if err != nil { - return nil, err - } - cfg, err := openfga.NewConfiguration(openfga.Configuration{ - ApiScheme: ep.Scheme, - ApiHost: ep.Host, - StoreId: storeId, - }) - if err != nil { - return nil, err - } - apiClient := openfga.NewAPIClient(cfg) - return &FGAClient{ - ModelID: modelId, - client: apiClient, - }, nil -} - -func (c *FGAClient) Check(ctx context.Context, tk authz.TupleKey, ctxTuples ...authz.TupleKey) (bool, error) { - if err := tk.Validate(); err != nil { - return false, err - } - var fgaCtxTuples openfga.ContextualTupleKeys - for _, ctxTuple := range ctxTuples { - fgaCtxTuples.TupleKeys = append(fgaCtxTuples.TupleKeys, ToFGATupleKey(ctxTuple)) - } - body := openfga.CheckRequest{ - AuthorizationModelId: openfga.PtrString(c.ModelID), - TupleKey: ToFGATupleKey(tk), - ContextualTuples: &fgaCtxTuples, - } - data, _, err := c.client.OpenFgaApi.Check(context.Background()).Body(body).Execute() - if err != nil { - return false, err - } - return data.GetAllowed(), nil -} - -func (c *FGAClient) ListObjects(ctx context.Context, tk authz.TupleKey) ([]authz.TupleKey, error) { - body := openfga.ListObjectsRequest{ - AuthorizationModelId: openfga.PtrString(c.ModelID), - User: tk.Subject.String(), - Relation: tk.ActionOrRelation(), - Type: tk.Object.Type.String(), - } - data, _, err := c.client.OpenFgaApi.ListObjects(context.Background()).Body(body).Execute() - if err != nil { - return nil, err - } - var ret []authz.TupleKey - for _, v := range data.GetObjects() { - ret = append(ret, authz.TupleKey{ - Subject: authz.NewEntityKey(tk.Subject.Type, tk.Subject.Name), - Object: NewEntityKeySplit(v), - Action: tk.Action, - }) - } - return ret, nil -} - -func (c *FGAClient) GetObjectTuples(ctx context.Context, tk authz.TupleKey) ([]authz.TupleKey, error) { - if err := tk.Validate(); err != nil { - return nil, err - } - fgatk := ToFGATupleKey(tk) - body := openfga.ReadRequest{ - TupleKey: &fgatk, - } - data, _, err := c.client.OpenFgaApi.Read(ctx).Body(body).Execute() - if err != nil { - return nil, err - } - var ret []authz.TupleKey - for _, t := range *data.Tuples { - ret = append(ret, FromFGATupleKey(t.GetKey())) - } - return ret, nil -} - -func (c *FGAClient) SetExclusiveRelation(ctx context.Context, tk authz.TupleKey) error { - return c.replaceTuple(ctx, tk, false, tk.Relation) - -} - -func (c *FGAClient) SetExclusiveSubjectRelation(ctx context.Context, tk authz.TupleKey, checkRelations ...authz.Relation) error { - return c.replaceTuple(ctx, tk, true, checkRelations...) -} - -func (c *FGAClient) replaceTuple(ctx context.Context, tk authz.TupleKey, checkSubjectEqual bool, checkRelations ...authz.Relation) error { - if err := tk.Validate(); err != nil { - log.Error().Err(err).Str("tk", tk.String()).Msg("replaceTuple") - return err - } - relTypeOk := false - for _, checkRel := range checkRelations { - if tk.Relation == checkRel { - relTypeOk = true - } - } - if !relTypeOk { - return fmt.Errorf("unknown relation %s for types %s and %s", tk.Relation.String(), tk.Subject.Type.String(), tk.Object.Type.String()) - } - log.Trace().Str("tk", tk.String()).Msg("replaceTuple") - - currentTks, err := c.GetObjectTuples(ctx, authz.NewTupleKey().WithObject(tk.Object.Type, tk.Object.Name)) - if err != nil { - return err - } - - var matchTks []authz.TupleKey - var delTks []authz.TupleKey - for _, checkTk := range currentTks { - relMatch := false - for _, r := range checkRelations { - if checkTk.Relation == r { - relMatch = true - } - } - if !relMatch { - continue - } - if checkSubjectEqual && !checkTk.Subject.Equals(tk.Subject) { - continue - } - if checkTk.Equals(tk) { - matchTks = append(matchTks, checkTk) - } else { - delTks = append(delTks, checkTk) - } - } - - // Write new tuple before deleting others - if len(matchTks) == 0 { - if err := c.WriteTuple(ctx, tk); err != nil { - return err - } - } - - // Delete exsiting tuples - var errs []error - for _, delTk := range delTks { - if err := c.DeleteTuple(ctx, delTk); err != nil { - errs = append(errs, err) - } - } - for _, err := range errs { - log.Trace().Err(err).Str("tk", tk.String()).Msg("replaceTuple") - } - if len(errs) > 0 { - return errs[0] - } - return nil -} - -func (c *FGAClient) WriteTuple(ctx context.Context, tk authz.TupleKey) error { - if err := tk.Validate(); err != nil { - log.Error().Str("tk", tk.String()).Msg("WriteTuple") - return err - } - log.Trace().Str("tk", tk.String()).Msg("WriteTuple") - body := openfga.WriteRequest{ - Writes: &openfga.TupleKeys{TupleKeys: []openfga.TupleKey{ToFGATupleKey(tk)}}, - AuthorizationModelId: openfga.PtrString(c.ModelID), - } - _, _, err := c.client.OpenFgaApi.Write(context.Background()).Body(body).Execute() - return err -} - -func (c *FGAClient) DeleteTuple(ctx context.Context, tk authz.TupleKey) error { - if err := tk.Validate(); err != nil { - log.Error().Err(err).Str("tk", tk.String()).Msg("DeleteTuple") - return err - } - log.Trace().Str("tk", tk.String()).Msg("DeleteTuple") - body := openfga.WriteRequest{ - Deletes: &openfga.TupleKeys{TupleKeys: []openfga.TupleKey{ToFGATupleKey(tk)}}, - AuthorizationModelId: openfga.PtrString(c.ModelID), - } - _, _, err := c.client.OpenFgaApi.Write(context.Background()).Body(body).Execute() - return err -} - -func (c *FGAClient) CreateStore(ctx context.Context, storeName string) (string, error) { - // Create new store - resp, _, err := c.client.OpenFgaApi.CreateStore(context.Background()).Body(openfga.CreateStoreRequest{ - Name: storeName, - }).Execute() - if err != nil { - return "", err - } - storeId := resp.GetId() - log.Info().Msgf("created store: %s", storeId) - c.client.SetStoreId(storeId) - return storeId, nil -} - -func (c *FGAClient) CreateModel(ctx context.Context, fn string) (string, error) { - // Create new model - var dslJson []byte - var err error - if dslJson, err = ioutil.ReadFile(fn); err != nil { - return "", err - } - var body openfga.WriteAuthorizationModelRequest - if err := json.Unmarshal(dslJson, &body); err != nil { - return "", err - } - modelId := "" - if resp, _, err := c.client.OpenFgaApi.WriteAuthorizationModel(context.Background()).Body(body).Execute(); err != nil { - return "", err - } else { - modelId = resp.GetAuthorizationModelId() - } - log.Info().Msgf("created model: %s", modelId) - return modelId, nil -} diff --git a/auth/fga/fga_test.go b/auth/fga/fga_test.go deleted file mode 100644 index 5d97e7ff..00000000 --- a/auth/fga/fga_test.go +++ /dev/null @@ -1,1086 +0,0 @@ -package fga - -import ( - "context" - "fmt" - "strings" - "testing" - - "github.com/interline-io/transitland-server/auth/authz" - "github.com/interline-io/transitland-server/internal/testutil" - "github.com/stretchr/testify/assert" -) - -// For less typing - -type Action = authz.Action -type ObjectType = authz.ObjectType -type Relation = authz.Relation - -var FeedType = authz.FeedType -var UserType = authz.UserType -var TenantType = authz.TenantType -var GroupType = authz.GroupType -var FeedVersionType = authz.FeedVersionType - -var ViewerRelation = authz.ViewerRelation -var MemberRelation = authz.MemberRelation -var AdminRelation = authz.AdminRelation -var ManagerRelation = authz.ManagerRelation -var ParentRelation = authz.ParentRelation -var EditorRelation = authz.EditorRelation - -var CanEdit = authz.CanEdit -var CanView = authz.CanView -var CanCreateFeedVersion = authz.CanCreateFeedVersion -var CanDeleteFeedVersion = authz.CanDeleteFeedVersion -var CanCreateFeed = authz.CanCreateFeed -var CanDeleteFeed = authz.CanDeleteFeed -var CanSetGroup = authz.CanSetGroup -var CanCreateOrg = authz.CanCreateOrg -var CanEditMembers = authz.CanEditMembers -var CanDeleteOrg = authz.CanDeleteOrg -var CanSetTenant = authz.CanSetTenant - -// Tests - -type testCase struct { - Subject authz.EntityKey - Object authz.EntityKey - Action authz.Action - Relation authz.Relation - Expect string - Notes string - ExpectError bool - ExpectUnauthorized bool - CheckAsUser string - ExpectActions []authz.Action - ExpectKeys []authz.EntityKey -} - -func (tk *testCase) TupleKey() authz.TupleKey { - return authz.TupleKey{Subject: tk.Subject, Object: tk.Object, Relation: tk.Relation, Action: tk.Action} -} - -func (tk *testCase) String() string { - if tk.Notes != "" { - return tk.Notes - } - a := tk.TupleKey().String() - if tk.CheckAsUser != "" { - a = a + "|checkuser:" + tk.CheckAsUser - } - return a -} - -func TestFGAClient(t *testing.T) { - fgaUrl, a, ok := testutil.CheckEnv("TL_TEST_FGA_ENDPOINT") - if !ok { - t.Skip(a) - return - } - - testData := []testCase{ - // Assign users to tenants - { - Notes: "All users can access all-users-tenant", - Subject: authz.NewEntityKey(UserType, "*"), - Object: authz.NewEntityKey(TenantType, "all-users-tenant"), - Relation: MemberRelation, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-admin"), - Object: authz.NewEntityKey(TenantType, "tl-tenant"), - Relation: AdminRelation, - }, - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(TenantType, "tl-tenant"), - Relation: MemberRelation, - }, - { - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(TenantType, "tl-tenant"), - Relation: MemberRelation, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(TenantType, "tl-tenant"), - Relation: MemberRelation, - }, - { - Subject: authz.NewEntityKey(UserType, "test2"), - Object: authz.NewEntityKey(TenantType, "restricted-tenant"), - Relation: MemberRelation, - }, - // Assign groups to tenants - { - Notes: "org:CT-group belongs to tenant:tl-tenant", - Subject: authz.NewEntityKey(TenantType, "tl-tenant"), - Object: authz.NewEntityKey(GroupType, "CT-group"), - Relation: ParentRelation, - }, - { - Notes: "org:BA-group belongs to tenant:tl-tenant", - Subject: authz.NewEntityKey(TenantType, "tl-tenant"), - Object: authz.NewEntityKey(GroupType, "BA-group"), - Relation: ParentRelation, - }, - { - Notes: "org:HA-group belongs to tenant:tl-tenant", - Subject: authz.NewEntityKey(TenantType, "tl-tenant"), - Object: authz.NewEntityKey(GroupType, "HA-group"), - Relation: ParentRelation, - }, - { - Notes: "org:EX-group will be for admins only", - Subject: authz.NewEntityKey(TenantType, "tl-tenant"), - Object: authz.NewEntityKey(GroupType, "EX-group"), - Relation: ParentRelation, - }, - { - Notes: "all tl-tenant members can view HA-group", - Subject: authz.NewEntityKey(TenantType, "tl-tenant#member"), - Object: authz.NewEntityKey(GroupType, "HA-group"), - Relation: ViewerRelation, - }, - { - Subject: authz.NewEntityKey(TenantType, "restricted-tenant"), - Object: authz.NewEntityKey(GroupType, "test-group"), - Relation: ParentRelation, - }, - // Assign users to groups - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(GroupType, "CT-group"), - Relation: ViewerRelation, - }, - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(GroupType, "BA-group"), - Relation: EditorRelation, - }, - { - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(GroupType, "CT-group"), - Relation: EditorRelation, - }, - { - Subject: authz.NewEntityKey(UserType, "test-group-viewer"), - Object: authz.NewEntityKey(GroupType, "test-group"), - Relation: ViewerRelation, - }, - { - Subject: authz.NewEntityKey(UserType, "test-group-editor"), - Object: authz.NewEntityKey(GroupType, "test-group"), - Relation: EditorRelation, - }, - // Assign feeds to groups - { - Subject: authz.NewEntityKey(GroupType, "CT-group"), - Object: authz.NewEntityKey(FeedType, "CT"), - Relation: ParentRelation, - Notes: "feed:CT should be viewable to members of org:CT-group (ian drew) and editable by org:CT-group editors (drew)", - }, - { - Subject: authz.NewEntityKey(GroupType, "BA-group"), - Object: authz.NewEntityKey(FeedType, "BA"), - Relation: ParentRelation, - Notes: "feed:BA should be viewable to members of org:BA-group () and editable by org:BA-group editors (ian)", - }, - { - Subject: authz.NewEntityKey(GroupType, "HA-group"), - Object: authz.NewEntityKey(FeedType, "HA"), - Relation: ParentRelation, - Notes: "feed:HA should be viewable to all members of tenant:tl-tenant", - }, - { - Subject: authz.NewEntityKey(GroupType, "EX-group"), - Object: authz.NewEntityKey(FeedType, "EX"), - Relation: ParentRelation, - Notes: "feed:EX should only be viewable to admins of tenant:tl-tenant", - }, - // Assign feed version specific permissions - // NOTE: This assignment is necessary for FGA tests - // This relation is implicit in full Checker tests - { - Subject: authz.NewEntityKey(FeedType, "BA"), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ParentRelation, - }, - // Assign users to feed versions - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - }, - { - Subject: authz.NewEntityKey(GroupType, "test-group").WithRefRel(ViewerRelation), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - }, - { - Subject: authz.NewEntityKey(TenantType, "tl-tenant").WithRefRel(MemberRelation), - Object: authz.NewEntityKey(FeedVersionType, "d2813c293bcfd7a97dde599527ae6c62c98e66c6"), - Relation: ViewerRelation, - }, - } - - t.Run("GetObjectTuples", func(t *testing.T) { - fgac := newTestFGAClient(t, fgaUrl, testData) - checks := []testCase{ - { - Object: authz.NewEntityKey(TenantType, "tl-tenant"), - Expect: "user:tl-tenant-admin:admin user:ian:member user:drew:member user:tl-tenant-member:member", - }, - { - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Expect: "feed:BA:parent user:tl-tenant-member:viewer org:test-group#viewer:viewer", - }, - { - Object: authz.NewEntityKey(FeedType, "CT"), - Expect: "org:CT-group:parent", - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - tks, err := fgac.GetObjectTuples(context.Background(), tc.TupleKey()) - if err != nil { - t.Error(err) - } - expect := strings.Split(tc.Expect, " ") - var got []string - for _, vtk := range tks { - got = append(got, fmt.Sprintf("%s:%s", vtk.Subject.String(), vtk.Relation)) - } - assert.ElementsMatch(t, expect, got, "usertype:username:relation does not match") - }) - } - }) - - t.Run("Check", func(t *testing.T) { - fgac := newTestFGAClient(t, fgaUrl, testData) - checks := []testCase{ - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-admin"), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - ExpectActions: []Action{CanView}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-admin"), - Object: authz.NewEntityKey(GroupType, "CT-group"), - ExpectActions: []Action{CanView, CanEdit, CanEditMembers, CanCreateFeed, CanDeleteFeed}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-admin"), - Object: authz.NewEntityKey(GroupType, "BA-group"), - ExpectActions: []Action{CanView, CanEdit, CanEditMembers, CanCreateFeed, CanDeleteFeed}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-admin"), - Object: authz.NewEntityKey(GroupType, "HA-group"), - ExpectActions: []Action{CanView, CanEdit, CanEditMembers, CanCreateFeed, CanDeleteFeed}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-admin"), - Object: authz.NewEntityKey(GroupType, "EX-group"), - ExpectActions: []Action{CanView, CanEdit, CanEditMembers, CanCreateFeed, CanDeleteFeed}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-admin"), - Object: authz.NewEntityKey(GroupType, "test-group"), - ExpectActions: []Action{-CanView, -CanEdit, -CanEditMembers, -CanCreateFeed, -CanDeleteFeed}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-admin"), - Object: authz.NewEntityKey(TenantType, "tl-tenant"), - ExpectActions: []Action{CanView, CanEdit, CanEditMembers, CanCreateOrg, CanDeleteOrg}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-admin"), - Object: authz.NewEntityKey(TenantType, "restricted-tenant"), - ExpectActions: []Action{-CanView, -CanEdit, -CanEditMembers, -CanCreateOrg, -CanDeleteOrg}, - }, - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - ExpectActions: []Action{CanView}, - }, - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(FeedType, "CT"), - ExpectActions: []Action{CanView, -CanEdit, -CanCreateFeedVersion, -CanDeleteFeedVersion}, - }, - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(FeedType, "BA"), - ExpectActions: []Action{CanView, CanEdit, CanCreateFeedVersion, CanDeleteFeedVersion}, - }, - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(FeedType, "HA"), - ExpectActions: []Action{CanView, -CanEdit, -CanCreateFeedVersion, -CanDeleteFeedVersion}, - }, - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(FeedType, "EX"), - ExpectActions: []Action{-CanView, -CanEdit, -CanCreateFeedVersion, -CanDeleteFeedVersion}, - }, - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(FeedType, "test"), - ExpectActions: []Action{-CanView, -CanEdit, -CanCreateFeedVersion, -CanDeleteFeedVersion}, - }, - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(GroupType, "CT-group"), - ExpectActions: []Action{CanView, -CanEdit, -CanEditMembers, -CanCreateFeed, -CanDeleteFeed}, - }, - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(GroupType, "BA-group"), - ExpectActions: []Action{CanView, CanEdit, -CanEditMembers, -CanCreateFeed, -CanDeleteFeed}, - }, - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(GroupType, "HA-group"), - ExpectActions: []Action{CanView, -CanEdit, -CanEditMembers, -CanCreateFeed, -CanDeleteFeed}, - }, - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(GroupType, "EX-group"), - ExpectActions: []Action{-CanView, -CanEdit, -CanEditMembers, -CanCreateFeed, -CanDeleteFeed}, - }, - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(GroupType, "test-group"), - ExpectActions: []Action{-CanView, -CanEdit, -CanEditMembers, -CanCreateFeed, -CanDeleteFeed}, - }, - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(TenantType, "tl-tenant"), - ExpectActions: []Action{CanView, -CanEditMembers, -CanCreateOrg, -CanDeleteOrg}, - }, - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(TenantType, "restricted-tenant"), - ExpectActions: []Action{-CanView, -CanEditMembers, -CanCreateOrg, -CanDeleteOrg}, - }, - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(TenantType, "all-users-tenant"), - ExpectActions: []Action{CanView, -CanEditMembers, -CanCreateOrg, -CanDeleteOrg}, - }, - { - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(TenantType, "all-users-tenant"), - ExpectActions: []Action{CanView, -CanEditMembers, -CanCreateOrg, -CanDeleteOrg}, - }, - { - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - ExpectActions: []Action{-CanView}, - }, - { - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(FeedType, "CT"), - ExpectActions: []Action{CanView, CanEdit}, - }, - { - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(FeedType, "BA"), - ExpectActions: []Action{-CanView, -CanEdit}, - }, - { - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(FeedType, "HA"), - ExpectActions: []Action{CanView, -CanEdit}, - }, - { - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(FeedType, "EX"), - ExpectActions: []Action{-CanView, -CanEdit}, - }, - { - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(FeedType, "test"), - ExpectActions: []Action{-CanView, -CanEdit}, - }, - { - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(GroupType, "CT-group"), - ExpectActions: []Action{CanView, CanEdit, -CanEditMembers, -CanCreateFeed, -CanDeleteFeed}, - }, - { - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(GroupType, "BA-group"), - ExpectActions: []Action{-CanView, -CanEdit, -CanEditMembers, -CanCreateFeed, -CanDeleteFeed}, - }, - { - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(GroupType, "HA-group"), - ExpectActions: []Action{CanView, -CanEdit, -CanEditMembers, -CanCreateFeed, -CanDeleteFeed}, - }, - { - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(GroupType, "EX-group"), - ExpectActions: []Action{-CanView, -CanEdit, -CanEditMembers, -CanCreateFeed, -CanDeleteFeed}, - }, - { - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(GroupType, "test-group"), - ExpectActions: []Action{-CanView, -CanEdit, -CanEditMembers, -CanCreateFeed, -CanDeleteFeed}, - }, - { - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(TenantType, "tl-tenant"), - ExpectActions: []Action{CanView, -CanEditMembers, -CanCreateOrg, -CanDeleteOrg}, - }, - { - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(TenantType, "restricted-tenant"), - ExpectActions: []Action{-CanView, -CanEditMembers, -CanCreateOrg, -CanDeleteOrg}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(TenantType, "tl-tenant"), - ExpectActions: []Action{CanView, -CanEdit}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(TenantType, "restricted-tenant"), - ExpectActions: []Action{-CanView, -CanEdit}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - ExpectActions: []Action{CanView}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(FeedType, "CT"), - ExpectActions: []Action{-CanView, -CanEdit}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(FeedType, "BA"), - ExpectActions: []Action{-CanView, -CanEdit}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(FeedType, "HA"), - ExpectActions: []Action{CanView, -CanEdit}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(FeedType, "EX"), - ExpectActions: []Action{-CanView, -CanEdit}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(FeedType, "test"), - ExpectActions: []Action{-CanView, -CanEdit}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(GroupType, "HA-group"), - ExpectActions: []Action{CanView, -CanEdit}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(GroupType, "EX-group"), - ExpectActions: []Action{-CanView, -CanEdit}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(TenantType, "tl-tenant"), - ExpectActions: []Action{CanView, -CanEdit, -CanEditMembers, -CanCreateOrg, -CanDeleteOrg}, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(TenantType, "restricted-tenant"), - ExpectActions: []Action{-CanView, -CanEdit, -CanEditMembers, -CanCreateOrg, -CanDeleteOrg}, - }, - { - Subject: authz.NewEntityKey(UserType, "test-group-viewer"), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - ExpectActions: []Action{CanView, -CanEdit, -CanEditMembers}, - }, - { - Subject: authz.NewEntityKey(UserType, "test-group-editor"), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - ExpectActions: []Action{CanView, -CanEdit, -CanEditMembers}, - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - for _, checkAction := range tc.ExpectActions { - expect := true - if checkAction < 0 { - expect = false - checkAction = checkAction * -1 - } - var err error - ltk := tc.TupleKey() - ltk.Action = checkAction - ok, err := fgac.Check(context.Background(), ltk) - if err != nil { - t.Fatal(err) - } - if ok && !expect { - t.Errorf("for %s got %t, expected %t", checkAction.String(), ok, expect) - } - if !ok && expect { - t.Errorf("got %s %t, expected %t", checkAction.String(), ok, expect) - } - } - }) - } - }) - - t.Run("ListObjects", func(t *testing.T) { - fgac := newTestFGAClient(t, fgaUrl, testData) - checks := []testCase{ - { - Notes: "tl-tenant-admin can access all feeds in tl-tenant", - Subject: authz.NewEntityKey(UserType, "tl-tenant-admin"), - Object: authz.NewEntityKey(FeedType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(FeedType, "CT", "BA", "HA", "EX"), - }, - { - Notes: "tl-tenant-admin can edit all feeds in tl-tenant", - Subject: authz.NewEntityKey(UserType, "tl-tenant-admin"), - Object: authz.NewEntityKey(FeedType, ""), - Action: CanEdit, - ExpectKeys: newEntityKeys(FeedType, "CT", "BA", "HA", "EX"), - }, - { - Notes: "tl-tenant-admin can view all groups in tl-tenant", - Subject: authz.NewEntityKey(UserType, "tl-tenant-admin"), - Object: authz.NewEntityKey(GroupType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(GroupType, "CT-group", "BA-group", "HA-group", "EX-group"), - }, - { - Notes: "tl-tenant-admin can edit all groups in tl-tenant", - Subject: authz.NewEntityKey(UserType, "tl-tenant-admin"), - Object: authz.NewEntityKey(GroupType, ""), - Action: CanEdit, - ExpectKeys: newEntityKeys(GroupType, "CT-group", "BA-group", "HA-group", "EX-group"), - }, - { - Notes: "tl-tenant-admin can view tenants tl-tenant and all-users-tenant", - Subject: authz.NewEntityKey(UserType, "tl-tenant-admin"), - Object: authz.NewEntityKey(TenantType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(TenantType, "tl-tenant", "all-users-tenant"), - }, - { - Notes: "tl-tenant-admin can view a feed version that belongs to a feed or group in tl-tenant or d281 which viewable to all tenant members", - Subject: authz.NewEntityKey(UserType, "tl-tenant-admin"), - Object: authz.NewEntityKey(FeedVersionType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0", "d2813c293bcfd7a97dde599527ae6c62c98e66c6"), - }, - { - Notes: "ian can edit feed BA in tl-tenant", - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(FeedType, ""), - Action: CanEdit, - ExpectKeys: newEntityKeys(FeedType, "BA"), - }, - { - Notes: "ian can view feeds CT, BA, HA", - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(FeedType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(FeedType, "CT", "BA", "HA"), - }, - { - Notes: "ian can view groups CT-group BA-group HA-group", - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(GroupType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(GroupType, "CT-group", "BA-group", "HA-group"), - }, - { - Notes: "ian can view tenants tl-tenant (member explicitly) and all-users-tenant (user:*)", - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(TenantType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(TenantType, "tl-tenant", "all-users-tenant"), - }, - { - Notes: "ian can view feed version e535 because of access to feed BA, group BA-group or d281 which is viewable to all tenant members", - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(FeedVersionType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0", "d2813c293bcfd7a97dde599527ae6c62c98e66c6"), - }, - { - Notes: "drew can edit feed CT because editor of CT-group", - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(FeedType, ""), - Action: CanEdit, - ExpectKeys: newEntityKeys(FeedType, "CT"), - }, - { - Notes: "drew can view feed CT because editor of CT-group and HA because HA has all tenant members", - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(FeedType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(FeedType, "CT", "HA"), - }, - { - Notes: "drew can access tl-tenant because member and all-users-tenant because user:*", - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(TenantType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(TenantType, "tl-tenant", "all-users-tenant"), - }, - { - Notes: "drew can access group CT-group because member and HA-group through tenant#member", - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(GroupType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(GroupType, "CT-group", "HA-group"), - }, - { - Notes: "drew is not explicitly assigned any feed versions but can access d281 because it is viewable to all tenant members", - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(FeedVersionType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(FeedVersionType, "d2813c293bcfd7a97dde599527ae6c62c98e66c6"), - }, - { - Notes: "tl-tenant-member can access HA-group through HA-group#viewer:tl-tenant#member", - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(GroupType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(GroupType, "HA-group"), - }, - { - Notes: "tl-tenant-member can access feed HA through group:HA-group", - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(FeedType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(FeedType, "HA"), - }, - { - Notes: "tl-tenant-member can view tl-tenant through member and all-users-tenant through user:*", - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(TenantType, ""), - Action: CanView, - ExpectKeys: newEntityKeys(TenantType, "tl-tenant", "all-users-tenant"), - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - ltk := tc.TupleKey() - ltk.Action = tc.Action - objs, err := fgac.ListObjects(context.Background(), ltk) - if err != nil { - t.Fatal(err) - } - var gotNames []string - for _, v := range objs { - gotNames = append(gotNames, v.Object.Name) - } - var expectNames []string - for _, ek := range tc.ExpectKeys { - expectNames = append(expectNames, ek.Name) - } - assert.ElementsMatch(t, expectNames, gotNames, "object ids") - }) - } - }) - - t.Run("WriteTuple", func(t *testing.T) { - checks := []testCase{ - { - Notes: "user:* can be a member of a tenant", - Subject: authz.NewEntityKey(UserType, "*"), - Object: authz.NewEntityKey(TenantType, "tl-tenants"), - Relation: MemberRelation, - }, - { - Notes: "user:* cannot be an admin of a tenant", - Subject: authz.NewEntityKey(UserType, "*"), - Object: authz.NewEntityKey(TenantType, "tl-tenants"), - Relation: AdminRelation, - ExpectError: true, - }, - { - Notes: "a tenant#member can be a viewer of a group", - Subject: authz.NewEntityKey(TenantType, "tl-tenant#member"), - Object: authz.NewEntityKey(GroupType, "BA-group"), - Relation: ViewerRelation, - }, - { - Notes: "a tenant#admin cannot be a viewer of a group", - Subject: authz.NewEntityKey(TenantType, "tl-tenant#admin"), - Object: authz.NewEntityKey(GroupType, "BA-group"), - Relation: ViewerRelation, - ExpectError: true, - }, - { - Notes: "a tenant#member can be an editor of a group", - Subject: authz.NewEntityKey(TenantType, "tl-tenant#member"), - Object: authz.NewEntityKey(GroupType, "BA-group"), - Relation: EditorRelation, - // Formerly disallowed, now OK - // ExpectError: true, - }, - { - Notes: "user can be a member of a tenant", - Subject: authz.NewEntityKey(UserType, "test100"), - Object: authz.NewEntityKey(TenantType, "tl-tenant"), - Relation: MemberRelation, - }, - { - Notes: "user can be an admin of a tenant", - Subject: authz.NewEntityKey(UserType, "test100"), - Object: authz.NewEntityKey(TenantType, "tl-tenant"), - Relation: AdminRelation, - }, - { - Notes: "already exists", - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(TenantType, "tl-tenant"), - Relation: MemberRelation, - ExpectError: true, - }, - { - Notes: "a user can be a viewer of a group", - Subject: authz.NewEntityKey(UserType, "test100"), - Object: authz.NewEntityKey(GroupType, "HA-group"), - Relation: ViewerRelation, - }, - { - Notes: "a user can be an editor of a group", - Subject: authz.NewEntityKey(UserType, "test100"), - Object: authz.NewEntityKey(GroupType, "HA-group"), - Relation: EditorRelation, - }, - { - Notes: "a user can be a manager of a group", - Subject: authz.NewEntityKey(UserType, "test100"), - Object: authz.NewEntityKey(GroupType, "HA-group"), - Relation: ManagerRelation, - }, - { - Notes: "invalid relation", - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(GroupType, "HA-group"), - Relation: ParentRelation, - ExpectError: true, - }, - { - Notes: "a user can be a viewer of a group", - Subject: authz.NewEntityKey(UserType, "test102"), - Object: authz.NewEntityKey(GroupType, "100"), - Relation: ViewerRelation, - }, - { - Notes: "a user can be a viewer of a feed version", - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - }, - { - Notes: "a user can be a editor of a feed version", - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: EditorRelation, - }, - { - Notes: "already exists", - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - ExpectError: true, - }, - { - Notes: "a tenant#member can be a viewer of a feed version", - Subject: authz.NewEntityKey(TenantType, "tl-tenant#member"), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - }, - { - Notes: "a tenant#member can be an editor of a feed version", - Subject: authz.NewEntityKey(TenantType, "tl-tenant#member"), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: EditorRelation, - // Formerly disallowed, now OK - // ExpectError: true, - }, - { - Notes: "a tenant#admin can be a viewer of a feed version", - Subject: authz.NewEntityKey(TenantType, "tl-tenant#admin"), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - ExpectError: true, - }, - { - Notes: "a group#member can be a viewer of a feed version", - Subject: authz.NewEntityKey(TenantType, "HA-group#member"), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - }, - { - Notes: "a group#editor cannot be a viewer of a feed version", - Subject: authz.NewEntityKey(GroupType, "HA-group#editor"), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: ViewerRelation, - ExpectError: true, - }, - { - Notes: "a group#viewer can be an editor of a feed version", - Subject: authz.NewEntityKey(GroupType, "HA-group").WithRefRel(ViewerRelation), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: EditorRelation, - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - // Mutating, so create fresh each test - fgac := newTestFGAClient(t, fgaUrl, testData) - // Write tuple and check if error was expected - ltk := tc.TupleKey() - err := fgac.WriteTuple(context.Background(), ltk) - if !checkExpectError(t, err, tc.ExpectError) { - return - } - // Check was written - tks, err := fgac.GetObjectTuples(context.Background(), ltk) - if err != nil { - t.Error(err) - } - var gotTks []string - for _, v := range tks { - gotTks = append(gotTks, fmt.Sprintf("%s:%s", v.Subject.String(), v.Relation)) - } - checkTk := fmt.Sprintf("%s:%s", ltk.Subject.String(), ltk.Relation) - assert.Contains(t, gotTks, checkTk, "written tuple not found in updated object tuples") - }) - } - }) - - t.Run("DeleteTuple", func(t *testing.T) { - checks := []testCase{ - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(GroupType, "CT-group"), - Relation: 4, - }, - { - Subject: authz.NewEntityKey(UserType, "test102"), - Object: authz.NewEntityKey(GroupType, "100"), - Relation: 4, - Notes: "unauthorized", - ExpectError: true, - }, - { - Subject: authz.NewEntityKey(UserType, "tl-tenant-member"), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: 4, - }, - { - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(FeedVersionType, "e535eb2b3b9ac3ef15d82c56575e914575e732e0"), - Relation: 4, - Notes: "unauthorized", - ExpectError: true, - }, - { - Subject: authz.NewEntityKey(UserType, "test2"), - Object: authz.NewEntityKey(TenantType, "restricted-tenant"), - Relation: 2, - }, - { - Subject: authz.NewEntityKey(UserType, "test101"), - Object: authz.NewEntityKey(GroupType, "BA-group"), - Relation: 4, - Notes: "does not exist", - ExpectError: true, - }, - { - Subject: authz.NewEntityKey(UserType, "test101"), - Object: authz.NewEntityKey(GroupType, "BA-group"), - Relation: 4, - Notes: "unauthorized", - ExpectError: true, - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - // Mutating test - fgac := newTestFGAClient(t, fgaUrl, testData) - ltk := tc.TupleKey() - err := fgac.DeleteTuple(context.Background(), ltk) - if !checkExpectError(t, err, tc.ExpectError) { - return - } - }) - } - }) - - t.Run("SetExclusiveSubjectRelation", func(t *testing.T) { - checks := []testCase{ - { - Notes: "changes ian permissions from Viewer to Manager", - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(GroupType, "CT-group"), - Relation: ManagerRelation, - Expect: "user:ian:manager user:drew:editor", - }, - { - Notes: "changes drew permissions from Editor to Viewer", - Subject: authz.NewEntityKey(UserType, "drew"), - Object: authz.NewEntityKey(GroupType, "CT-group"), - Relation: ViewerRelation, - Expect: "user:drew:viewer user:ian:viewer", - }, - { - Notes: "assigns ian permissions as Manager, nothing to delete", - Subject: authz.NewEntityKey(UserType, "ian"), - Object: authz.NewEntityKey(GroupType, "HA-group"), - Relation: ManagerRelation, - Expect: "user:ian:manager tenant:tl-tenant#member:viewer", - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - // Mutating test - fgac := newTestFGAClient(t, fgaUrl, testData) - ltk := tc.TupleKey() - checkRelTypes := []Relation{ViewerRelation, EditorRelation, ManagerRelation} - err := fgac.SetExclusiveSubjectRelation(context.Background(), ltk, checkRelTypes...) - if !checkExpectError(t, err, tc.ExpectError) { - return - } - newTks, err := fgac.GetObjectTuples(context.Background(), authz.NewTupleKey().WithObject(ltk.Object.Type, ltk.Object.Name)) - if err != nil { - t.Error(err) - } - expect := strings.Split(tc.Expect, " ") - var got []string - for _, vtk := range newTks { - ok := false - for _, checkRel := range checkRelTypes { - if vtk.Relation == checkRel { - ok = true - } - } - if !ok { - continue - } - got = append(got, fmt.Sprintf("%s:%s", vtk.Subject.String(), vtk.Relation)) - } - assert.ElementsMatch(t, expect, got, "usertype:username:relation does not match") - }) - } - }) - - t.Run("SetExclusiveRelation", func(t *testing.T) { - checks := []testCase{ - { - Notes: "changes feed parent", - Object: authz.NewEntityKey(FeedType, "CT"), - Subject: authz.NewEntityKey(GroupType, "BA-group"), - Relation: ParentRelation, - Expect: "org:BA-group:parent", - }, - { - Notes: "changes group tenant", - Object: authz.NewEntityKey(GroupType, "CT-group"), - Subject: authz.NewEntityKey(TenantType, "all-users-tenant"), - Relation: ParentRelation, - Expect: "tenant:all-users-tenant:parent", - }, - { - Notes: "assigns group to tenant", - Object: authz.NewEntityKey(GroupType, "new-group"), - Subject: authz.NewEntityKey(TenantType, "all-users-tenant"), - Relation: ParentRelation, - Expect: "tenant:all-users-tenant:parent", - }, - } - for _, tc := range checks { - t.Run(tc.String(), func(t *testing.T) { - // Mutating test - fgac := newTestFGAClient(t, fgaUrl, testData) - ltk := tc.TupleKey() - checkRelTypes := []Relation{ParentRelation} - err := fgac.SetExclusiveRelation(context.Background(), ltk) - if !checkExpectError(t, err, tc.ExpectError) { - return - } - newTks, err := fgac.GetObjectTuples(context.Background(), authz.NewTupleKey().WithObject(ltk.Object.Type, ltk.Object.Name)) - if err != nil { - t.Error(err) - } - expect := strings.Split(tc.Expect, " ") - var got []string - for _, vtk := range newTks { - ok := false - for _, checkRel := range checkRelTypes { - if vtk.Relation == checkRel { - ok = true - } - } - if !ok { - continue - } - got = append(got, fmt.Sprintf("%s:%s", vtk.Subject.String(), vtk.Relation)) - } - assert.ElementsMatch(t, expect, got, "usertype:username:relation does not match") - }) - } - }) - -} - -func checkExpectError(t testing.TB, err error, expect bool) bool { - if err != nil && !expect { - t.Errorf("got error '%s', did not expect error", err.Error()) - return false - } - if err == nil && expect { - t.Errorf("got no error, expected error") - return false - } - if err != nil { - return false - } - return true -} - -func newEntityKeys(t authz.ObjectType, keys ...string) []authz.EntityKey { - var ret []authz.EntityKey - for _, k := range keys { - ret = append(ret, authz.NewEntityKey(t, k)) - } - return ret -} - -func newTestFGAClient(t testing.TB, url string, testTuples []testCase) *FGAClient { - fgac, err := NewFGAClient(url, "", "") - if err != nil { - t.Fatal(err) - return nil - } - if _, err := fgac.CreateStore(context.Background(), "test"); err != nil { - t.Fatal(err) - } - if _, err := fgac.CreateModel(context.Background(), testutil.RelPath("test/authz/tls.json")); err != nil { - t.Fatal(err) - } - for _, tk := range testTuples { - if err := fgac.WriteTuple(context.Background(), tk.TupleKey()); err != nil { - t.Fatal(err) - } - } - return fgac -} diff --git a/cmd/tlserver/main.go b/cmd/tlserver/main.go index f2e273a9..f138816d 100644 --- a/cmd/tlserver/main.go +++ b/cmd/tlserver/main.go @@ -4,11 +4,11 @@ import ( "flag" "os" + "github.com/interline-io/log" "github.com/interline-io/transitland-lib/dmfr/fetch" "github.com/interline-io/transitland-lib/dmfr/importer" "github.com/interline-io/transitland-lib/dmfr/sync" "github.com/interline-io/transitland-lib/dmfr/unimporter" - "github.com/interline-io/transitland-lib/log" "github.com/interline-io/transitland-lib/tl" "github.com/interline-io/transitland-server/server" ) diff --git a/finders/dbfinder/feed_select.go b/finders/dbfinder/feed_select.go index dc4fd407..ba424c60 100644 --- a/finders/dbfinder/feed_select.go +++ b/finders/dbfinder/feed_select.go @@ -2,7 +2,7 @@ package dbfinder import ( sq "github.com/Masterminds/squirrel" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" "github.com/interline-io/transitland-server/model" ) diff --git a/finders/dbfinder/feed_version_select.go b/finders/dbfinder/feed_version_select.go index d6035aeb..5ef0a73e 100644 --- a/finders/dbfinder/feed_version_select.go +++ b/finders/dbfinder/feed_version_select.go @@ -2,7 +2,7 @@ package dbfinder import ( sq "github.com/Masterminds/squirrel" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" "github.com/interline-io/transitland-lib/tl/tt" "github.com/interline-io/transitland-server/model" ) diff --git a/finders/dbfinder/finder.go b/finders/dbfinder/finder.go index 94a8a485..ca0f05e3 100644 --- a/finders/dbfinder/finder.go +++ b/finders/dbfinder/finder.go @@ -7,10 +7,10 @@ import ( "time" sq "github.com/Masterminds/squirrel" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" "github.com/interline-io/transitland-lib/tl" "github.com/interline-io/transitland-lib/tl/tt" - "github.com/interline-io/transitland-server/auth/authz" + "github.com/interline-io/transitland-mw/auth/authz" "github.com/interline-io/transitland-server/internal/clock" "github.com/interline-io/transitland-server/internal/dbutil" "github.com/interline-io/transitland-server/internal/xy" diff --git a/finders/rtfinder/finder.go b/finders/rtfinder/finder.go index f0e44e37..7f9df743 100644 --- a/finders/rtfinder/finder.go +++ b/finders/rtfinder/finder.go @@ -6,7 +6,7 @@ import ( "strconv" "time" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" "github.com/interline-io/transitland-lib/rt/pb" "github.com/interline-io/transitland-server/internal/clock" "github.com/interline-io/transitland-server/model" diff --git a/finders/rtfinder/lookup.go b/finders/rtfinder/lookup.go index ed3007bb..edb1e7b3 100644 --- a/finders/rtfinder/lookup.go +++ b/finders/rtfinder/lookup.go @@ -4,7 +4,7 @@ import ( "sync" "time" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" "github.com/jmoiron/sqlx" ) diff --git a/finders/rtfinder/redis.go b/finders/rtfinder/redis.go index 7d05b2a2..709c9cc4 100644 --- a/finders/rtfinder/redis.go +++ b/finders/rtfinder/redis.go @@ -7,7 +7,7 @@ import ( "time" "github.com/go-redis/redis/v8" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" "github.com/interline-io/transitland-lib/rt/pb" ) diff --git a/finders/rtfinder/source.go b/finders/rtfinder/source.go index 93027595..0b670b2c 100644 --- a/finders/rtfinder/source.go +++ b/finders/rtfinder/source.go @@ -1,7 +1,7 @@ package rtfinder import ( - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" "github.com/interline-io/transitland-lib/rt/pb" "google.golang.org/protobuf/proto" ) diff --git a/go.mod b/go.mod index 37fafd9e..052c679d 100644 --- a/go.mod +++ b/go.mod @@ -1,66 +1,62 @@ module github.com/interline-io/transitland-server -go 1.18 +go 1.20 require ( github.com/99designs/gqlgen v0.17.26 - github.com/Masterminds/squirrel v1.5.3 - github.com/amberflo/metering-go/v2 v2.0.1 - github.com/auth0/go-auth0 v0.17.2 + github.com/Masterminds/squirrel v1.5.4 github.com/aws/aws-sdk-go v1.44.218 github.com/aws/aws-sdk-go-v2 v1.17.5 github.com/aws/aws-sdk-go-v2/config v1.18.15 github.com/aws/aws-sdk-go-v2/service/location v1.22.1 github.com/digitalocean/go-workers2 v0.10.3 github.com/flopp/go-staticmaps v0.0.0-20220221183018-c226716bec53 - github.com/form3tech-oss/jwt-go v3.2.5+incompatible github.com/go-chi/chi v1.5.4 - github.com/go-chi/chi/v5 v5.0.8 + github.com/go-chi/chi/v5 v5.0.10 github.com/go-chi/cors v1.2.1 github.com/go-redis/redis/v8 v8.11.5 - github.com/go-redis/redismock/v8 v8.11.5 github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 github.com/graph-gophers/dataloader/v7 v7.1.0 github.com/hypirion/go-filecache v0.0.0-20160810125507-e3e6ef6981f0 + github.com/interline-io/log v0.0.0-20231211003339-8bdc406adcd2 github.com/interline-io/transitland-lib v0.14.0-rc1.0.20231202005632-a9ea742322f7 + github.com/interline-io/transitland-mw v0.0.0-20231209020231-3660286a28cd github.com/jellydator/ttlcache/v2 v2.11.1 github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.7 - github.com/openfga/go-sdk v0.2.2 - github.com/prometheus/client_golang v1.14.0 - github.com/rs/zerolog v1.29.0 + github.com/rs/zerolog v1.31.0 github.com/stretchr/testify v1.8.4 - github.com/tidwall/gjson v1.14.4 + github.com/tidwall/gjson v1.17.0 github.com/tidwall/rtree v1.10.0 github.com/tidwall/tinylru v1.1.0 github.com/twpayne/go-geom v1.5.1 github.com/vektah/gqlparser/v2 v2.5.1 - github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c - google.golang.org/grpc v1.56.0 - google.golang.org/protobuf v1.30.0 + google.golang.org/protobuf v1.31.0 gopkg.in/dnaeon/go-vcr.v2 v2.3.0 ) require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.2 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v0.9.0 // indirect - github.com/PuerkitoBio/rehttp v1.1.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1 // indirect + github.com/PuerkitoBio/rehttp v1.3.0 // indirect github.com/agnivade/levenshtein v1.1.1 // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect + github.com/amberflo/metering-go/v2 v2.5.0 // indirect + github.com/auth0/go-auth0 v0.17.2 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.1 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.13.15 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.23 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.30 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.21 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.24 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.6 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.23 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.23 // indirect - github.com/aws/aws-sdk-go-v2/service/s3 v1.30.5 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.5 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.26.10 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.12.4 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.4 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.18.5 // indirect @@ -74,51 +70,55 @@ require ( github.com/dimchansky/utfbom v1.1.1 // indirect github.com/flopp/go-coordsparser v0.0.0-20201115094714-8baaeb7062d5 // indirect github.com/fogleman/gg v1.3.0 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect + github.com/golang-jwt/jwt v3.2.1+incompatible // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.3.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru/v2 v2.0.1 // indirect github.com/iancoleman/orderedmap v0.2.0 // indirect github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect - github.com/jlaffaye/ftp v0.1.0 // indirect + github.com/jlaffaye/ftp v0.0.0-20220524001917-dfa1e758f3af // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-sqlite3 v1.14.16 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mmcloughlin/geohash v0.10.0 // indirect - github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect + github.com/openfga/go-sdk v0.2.3 // indirect + github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.42.0 // indirect - github.com/prometheus/procfs v0.9.0 // indirect + github.com/prometheus/client_golang v1.17.0 // indirect + github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect + github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/procfs v0.11.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3 // indirect - github.com/snabb/isoweek v1.0.3 // indirect + github.com/snabb/isoweek v1.0.1 // indirect github.com/tidwall/geoindex v1.7.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect - github.com/tkrajina/gpxgo v1.2.1 // indirect + github.com/tkrajina/gpxgo v1.1.2 // indirect github.com/urfave/cli/v2 v2.24.4 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/image v0.6.0 // indirect - golang.org/x/mod v0.9.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - golang.org/x/tools v0.7.0 // indirect + github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect + golang.org/x/crypto v0.16.0 // indirect + golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d // indirect + golang.org/x/mod v0.8.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/oauth2 v0.15.0 // indirect + golang.org/x/sync v0.4.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.6.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect + google.golang.org/grpc v1.59.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 85f221d8..66ac7d7c 100644 --- a/go.sum +++ b/go.sum @@ -13,31 +13,31 @@ cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiy dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/99designs/gqlgen v0.17.26 h1:fxgSTbPf1G30uWAWSoHd+9gSNMagmP04k58ThJ1/ikQ= github.com/99designs/gqlgen v0.17.26/go.mod h1:i4rEatMrzzu6RXaHydq1nmEPZkb3bKQsnxNRHS4DQB4= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0 h1:rTnT/Jrcm+figWlYz4Ixzt0SJVR2cMC8lvZcimipiEY= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.2 h1:uqM+VoHjVH6zdlkLF2b6O0ZANcHoj3rO0PoQ3jglUJA= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.2/go.mod h1:twTKAa1E6hLmSDjLhaCkbTMQKc7p/rNLU40rLxGEOCI= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0 h1:leh5DwKv6Ihwi+h60uHtn6UWAxBbZ0q8DwQVMzf61zw= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 h1:u/LLAOFgsMv7HmNL4Qufg58y+qElGOt5qv0z1mURkRY= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0/go.mod h1:2e8rMJtl2+2j+HXbTBwnyGpm5Nou7KhvSfxOq8JpTag= -github.com/AzureAD/microsoft-authentication-library-for-go v0.9.0 h1:UE9n9rkJF62ArLb1F3DEjRt8O3jLwMWdSoypKV4f3MU= -github.com/AzureAD/microsoft-authentication-library-for-go v0.9.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8Jgil9UUZtMvxhEFqWo= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1 h1:BMTdr+ib5ljLa9MxTJK8x/Ds0MbBb4MfuW5BL0zMJnI= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1/go.mod h1:c6WvOhtmjNUWbLfOG1qxM/q0SPvQNSVJvolm+C52dIU= +github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1 h1:BWe8a+f/t+7KY7zH2mqygeUD0t8hNFXe08p1Pb3/jKE= +github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= -github.com/Masterminds/squirrel v1.5.3 h1:YPpoceAcxuzIljlr5iWpNKaql7hLeG1KLSrhvdHpkZc= -github.com/Masterminds/squirrel v1.5.3/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= +github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= +github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/rehttp v1.1.0 h1:JFZ7OeK+hbJpTxhNB0NDZT47AuXqCU0Smxfjtph7/Rs= -github.com/PuerkitoBio/rehttp v1.1.0/go.mod h1:LUwKPoDbDIA2RL5wYZCNsQ90cx4OJ4AWBmq6KzWZL1s= +github.com/PuerkitoBio/rehttp v1.3.0 h1:w54Pb72MQn2eJrSdPsvGqXlAfiK1+NMTGDrOJJ4YvSU= +github.com/PuerkitoBio/rehttp v1.3.0/go.mod h1:LUwKPoDbDIA2RL5wYZCNsQ90cx4OJ4AWBmq6KzWZL1s= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/amberflo/metering-go/v2 v2.0.1 h1:4FXP837vZVOj1zHJIqmPC6rPAHKY8D6D7X/cia92VhI= -github.com/amberflo/metering-go/v2 v2.0.1/go.mod h1:6IGhO3TgPMXhg5h/u0SC1NuQEhX7mU3MfEPBAfq1aXI= +github.com/amberflo/metering-go/v2 v2.5.0 h1:2Xu9TfQVtGeh0oXEZigknMbcQQHJ+GfIRreZjaSSuc4= +github.com/amberflo/metering-go/v2 v2.5.0/go.mod h1:jiKk5ddwmHDR49qjexDm1l+Yl0y9sbkDbRc2cgvAjZY= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= @@ -49,42 +49,47 @@ github.com/auth0/go-auth0 v0.17.2 h1:qEttAY4yYeEJl6wu0iOwlet26wUKA2G5YOUomfuxcy4 github.com/auth0/go-auth0 v0.17.2/go.mod h1:Hlp4kYcvn2JSD1tAmPQ8DD7MMoiO0bwVJwTHXqJbDDE= github.com/aws/aws-sdk-go v1.44.218 h1:p707+xOCazWhkSpZOeyhtTcg7Z+asxxvueGgYPSitn4= github.com/aws/aws-sdk-go v1.44.218/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go-v2 v1.16.4/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU= github.com/aws/aws-sdk-go-v2 v1.17.5 h1:TzCUW1Nq4H8Xscph5M/skINUitxM5UBAyvm2s7XBzL4= github.com/aws/aws-sdk-go-v2 v1.17.5/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.1 h1:SdK4Ppk5IzLs64ZMvr6MrSficMtjY2oS0WOORXTlxwU= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.1/go.mod h1:n8Bs1ElDD2wJ9kCRTczA83gYbBmjSwZp3umc6zF4EeM= github.com/aws/aws-sdk-go-v2/config v1.18.15 h1:509yMO0pJUGUugBP2H9FOFyV+7Mz7sRR+snfDN5W4NY= github.com/aws/aws-sdk-go-v2/config v1.18.15/go.mod h1:vS0tddZqpE8cD9CyW0/kITHF5Bq2QasW9Y1DFHD//O0= github.com/aws/aws-sdk-go-v2/credentials v1.13.15 h1:0rZQIi6deJFjOEgHI9HI2eZcLPPEGQPictX66oRFLL8= github.com/aws/aws-sdk-go-v2/credentials v1.13.15/go.mod h1:vRMLMD3/rXU+o6j2MW5YefrGMBmdTvkLLGqFwMLBHQc= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.23 h1:Kbiv9PGnQfG/imNI4L/heyUXvzKmcWSBeDvkrQz5pFc= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.23/go.mod h1:mOtmAg65GT1HIL/HT/PynwPbS+UG0BgCZ6vhkPqnxWo= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.11/go.mod h1:tmUB6jakq5DFNcXsXOA/ZQ7/C8VnSKYkx58OI7Fh79g= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29 h1:9/aKwwus0TQxppPXFmf010DFrE+ssSbzroLVYINA+xE= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29/go.mod h1:Dip3sIGv485+xerzVv24emnjX5Sg88utCL8fwGmCeWg= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.5/go.mod h1:fV1AaS2gFc1tM0RCb015FJ0pvWVUfJZANzjwoO4YakM= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23 h1:b/Vn141DBuLVgXbhRWIrl9g+ww7G+ScV5SzniWR13jQ= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23/go.mod h1:mr6c4cHC+S/MMkrjtSlG4QA36kOznDep+0fga5L/fGQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.30 h1:IVx9L7YFhpPq0tTnGo8u8TpluFu7nAn9X3sUDMb11c0= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.30/go.mod h1:vsbq62AOBwQ1LJ/GWKFxX8beUEYeRp/Agitrxee2/qM= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.21 h1:QdxdY43AiwsqG/VAqHA7bIVSm3rKr8/p9i05ydA0/RM= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.21/go.mod h1:QtIEat7ksHH8nFItljyvMI0dGj8lipK2XZ4PhNihTEU= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.24 h1:Qmm8klpAdkuN3/rPrIMa/hZQ1z93WMBPjOzdAsbSnlo= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.24/go.mod h1:QelGeWBVRh9PbbXsfXKTFlU9FjT6W2yP+dW5jMQzOkg= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.2 h1:1fs9WkbFcMawQjxEI0B5L0SqvBhJZebxWM6Z3x/qHWY= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.2/go.mod h1:0jDVeWUFPbI3sOfsXXAsIdiawXcn7VBLx/IlFVTRP64= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.1 h1:T4pFel53bkHjL2mMo+4DKE6r6AuoZnM0fg7k1/ratr4= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.1/go.mod h1:GeUru+8VzrTXV/83XyMJ80KpH8xO89VPoUileyNQ+tc= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.6 h1:9mvDAsMiN+07wcfGM+hJ1J3dOKZ2YOpDiPZ6ufRJcgw= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.6/go.mod h1:Eus+Z2iBIEfhOvhSdMTcscNOMy6n3X9/BJV0Zgax98w= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.5/go.mod h1:ZbkttHXaVn3bBo/wpJbQGiiIWR90eTBUVBrEHUEQlho= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.23 h1:QoOybhwRfciWUBbZ0gp9S7XaDnCuSTeK/fySB99V1ls= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.23/go.mod h1:9uPh+Hrz2Vn6oMnQYiUi/zbh3ovbnQk19YKINkQny44= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.23 h1:qc+RW0WWZ2KApMnsu/EVCPqLTyIH55uc7YQq7mq4XqE= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.23/go.mod h1:FJhZWVWBCcgAF8jbep7pxQ1QUsjzTwa9tvEXGw2TDRo= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.5 h1:DyPYkrH4R2zn+Pdu6hM3VTuPsQYAE6x2WB24X85Sgw0= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.5/go.mod h1:XtL92YWo0Yq80iN3AgYRERJqohg4TozrqRlxYhHGJ7g= github.com/aws/aws-sdk-go-v2/service/location v1.22.1 h1:JX2LelZl/oOcIzI9bADNBcJdWkTIzQPl2S14RE1qnBs= github.com/aws/aws-sdk-go-v2/service/location v1.22.1/go.mod h1:cZaIbqpY/e5pbOB+huP3459vQ65wjagkuG1Xn5CALHA= -github.com/aws/aws-sdk-go-v2/service/s3 v1.30.5 h1:kFfb+NMap4R7nDvBYyABa/nw7KFMtAfygD1Hyoxh4uE= -github.com/aws/aws-sdk-go-v2/service/s3 v1.30.5/go.mod h1:Dze3kNt4T+Dgb8YCfuIFSBLmE6hadKNxqfdF0Xmqz1I= +github.com/aws/aws-sdk-go-v2/service/s3 v1.26.10 h1:GWdLZK0r1AK5sKb8rhB9bEXqXCK8WNuyv4TBAD6ZviQ= +github.com/aws/aws-sdk-go-v2/service/s3 v1.26.10/go.mod h1:+O7qJxF8nLorAhuIVhYTHse6okjHJJm4EwhhzvpnkT0= github.com/aws/aws-sdk-go-v2/service/sso v1.12.4 h1:qJdM48OOLl1FBSzI7ZrA1ZfLwOyCYqkXV5lko1hYDBw= github.com/aws/aws-sdk-go-v2/service/sso v1.12.4/go.mod h1:jtLIhd+V+lft6ktxpItycqHqiVXrPIRjWIsFIlzMriw= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.4 h1:YRkWXQveFb0tFC0TLktmmhGsOcCgLwvq88MC2al47AA= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.4/go.mod h1:zVwRrfdSmbRZWkUkWjOItY7SOalnFnq/Yg2LVPqDjwc= github.com/aws/aws-sdk-go-v2/service/sts v1.18.5 h1:L1600eLr0YvTT7gNh3Ni24yGI7NSHkq9Gp62vijPRCs= github.com/aws/aws-sdk-go-v2/service/sts v1.18.5/go.mod h1:1mKZHLLpDMHTNSYPJ7qrcnCQdHCWsNQaT0xRvq2u80s= +github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM= github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0 h1:0NmehRCgyk5rljDQLKUO+cRJCnduDyn11+zGZIc9Z48= @@ -104,18 +109,14 @@ github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dR github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= @@ -154,8 +155,8 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs= github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIuEg= -github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= -github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= +github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -166,16 +167,15 @@ github.com/go-redis/redis/v8 v8.4.4/go.mod h1:nA0bQuF0i5JFx4Ta9RZxGKXFrQ8cRWntra github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-redis/redismock/v8 v8.11.5 h1:RJFIiua58hrBrSpXhnGX3on79AU3S271H4ZhRI1wyVo= -github.com/go-redis/redismock/v8 v8.11.5/go.mod h1:UaAU9dEe1C+eGr+FHV5prCWIt0hafyPWbGMEWE0UWdA= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= +github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo= @@ -188,7 +188,6 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -198,7 +197,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -210,16 +208,17 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.4/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -262,18 +261,21 @@ github.com/hypirion/go-filecache v0.0.0-20160810125507-e3e6ef6981f0 h1:j2u0/ByW6 github.com/hypirion/go-filecache v0.0.0-20160810125507-e3e6ef6981f0/go.mod h1:OAbJoUHgvd45ehc9u+zUsJue3P0elNL/Knbnr3ZDrkY= github.com/iancoleman/orderedmap v0.2.0 h1:sq1N/TFpYH++aViPcaKjys3bDClUEU7s5B+z6jq8pNA= github.com/iancoleman/orderedmap v0.2.0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/interline-io/log v0.0.0-20231211003339-8bdc406adcd2 h1:ScRM8Kr6UwAvblyGMdupRwEy7eWCROPLWmGJf1J1aOk= +github.com/interline-io/log v0.0.0-20231211003339-8bdc406adcd2/go.mod h1:chJaM8SKcHI6ivoeFuZ8M8axTjSV4TPmuQ+sAyAHa34= github.com/interline-io/transitland-lib v0.14.0-rc1.0.20231202005632-a9ea742322f7 h1:rwkKzYzl05Q4TM++L9RIJbXPjIvURoMN5vEr8dvUV/Q= github.com/interline-io/transitland-lib v0.14.0-rc1.0.20231202005632-a9ea742322f7/go.mod h1:UcfuCX6DyKt/yn5GECFn3jQ6NcZEjt5XyPjf8a3tXZ4= -github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc= +github.com/interline-io/transitland-mw v0.0.0-20231209020231-3660286a28cd h1:Id8Pd4MJOto/z3Tquy3ox996iwJY9gfSG/W24jaGqGQ= +github.com/interline-io/transitland-mw v0.0.0-20231209020231-3660286a28cd/go.mod h1:N+53bL3yiFx3SoDMBJtC2dkmAZNBeRHP9safiAfvykw= +github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= github.com/jellydator/ttlcache/v2 v2.11.1 h1:AZGME43Eh2Vv3giG6GeqeLeFXxwxn1/qHItqWZl6U64= github.com/jellydator/ttlcache/v2 v2.11.1/go.mod h1:RtE5Snf0/57e+2cLWFYWCCsLas2Hy3c5Z4n14XmSvTI= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/jlaffaye/ftp v0.1.0 h1:DLGExl5nBoSFoNshAUHwXAezXwXBvFdx7/qwhucWNSE= -github.com/jlaffaye/ftp v0.1.0/go.mod h1:hhq4G4crv+nW2qXtNYcuzLeOudG92Ps37HEKeg2e3lE= +github.com/jlaffaye/ftp v0.0.0-20220524001917-dfa1e758f3af h1:sh8vAWJ+vr9izhkDAMS3JRGDIjj0tNVwxfwd+2U2xMo= +github.com/jlaffaye/ftp v0.0.0-20220524001917-dfa1e758f3af/go.mod h1:oZaomI+9/et52UBjvNU9LCIqmgt816+7ljXCx0EIPzo= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= @@ -291,8 +293,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -308,14 +310,12 @@ github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= @@ -337,31 +337,26 @@ github.com/mmcloughlin/geohash v0.10.0 h1:9w1HchfDfdeLc+jFEf/04D27KP7E2QmpDu52wP github.com/mmcloughlin/geohash v0.10.0/go.mod h1:oNZxQo5yWJh0eMQEP/8hwQuVx9Z9tjwFUqcTB1SmG0c= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.6/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.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/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= 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.4/go.mod h1:g/HbgYopi++010VEqkFgJHKC09uJiW9UkXvMUuKHUCQ= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= -github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= -github.com/openfga/go-sdk v0.2.2 h1:zzQPdcX/CNLXwycqYNx5LvP78kzVs6R8p5GXw/0II3s= -github.com/openfga/go-sdk v0.2.2/go.mod h1:ZB13O8GilPc0ITWssOszgxmz6CnIe8PQLZqbqAnx2IY= +github.com/openfga/go-sdk v0.2.3 h1:VPCouXbUP+vtGREbLu8BIuzFiA1kBDQ6tnunFTxtLzc= +github.com/openfga/go-sdk v0.2.3/go.mod h1:2k8hL4VJ46GXUGbnQ1QOrcZWcP1kKATLPeqVnuLzgIE= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= +github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -370,42 +365,41 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= +github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= +github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= -github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= -github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= +github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w= -github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= +github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3 h1:ZuhckGJ10ulaKkdvJtiAqsLTiPrLaXSdnVgXJKJkTxE= -github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3/go.mod h1:9/Rh6yILuLysoQnZ2oNooD2g7aBnvM7r/fNVxRNWfBc= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/snabb/isoweek v1.0.3 h1:BwEULUhj7UToLLa7FivDTLzA4y1epTYkLhnn31huBRs= -github.com/snabb/isoweek v1.0.3/go.mod h1:J5hJfY1CG56xmKCC/4XfoaWZcOiB+qntmyKEDATSnlw= +github.com/snabb/isoweek v1.0.1 h1:B4IsN2GU8lCNVkaUUgOzaVpPkKC2DdY9zcnxz5yc0qg= +github.com/snabb/isoweek v1.0.1/go.mod h1:CAijAxH7NMgjqGc9baHMDE4sTHMt4B/f6X/XLiEE1iA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -420,7 +414,6 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= @@ -430,8 +423,8 @@ github.com/tidwall/cities v0.1.0 h1:CVNkmMf7NEC9Bvokf5GoSsArHCKRMTgLuubRTHnH0mE= github.com/tidwall/cities v0.1.0/go.mod h1:lV/HDp2gCcRcHJWqgt6Di54GiDrTZwh1aG2ZUPNbqa4= github.com/tidwall/geoindex v1.7.0 h1:jtk41sfgwIt8MEDyC3xyKSj75iXXf6rjReJGDNPtR5o= github.com/tidwall/geoindex v1.7.0/go.mod h1:rvVVNEFfkJVWGUdEfU8QaoOg/9zFX0h9ofWzA60mz1I= -github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= -github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= +github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/lotsa v1.0.2 h1:dNVBH5MErdaQ/xd9s769R31/n2dXavsQ0Yf4TMEHHw8= github.com/tidwall/lotsa v1.0.2/go.mod h1:X6NiU+4yHA3fE3Puvpnn1XMDrFZrE9JO2/w+UMuqgR8= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -443,9 +436,8 @@ github.com/tidwall/rtree v1.10.0 h1:+EcI8fboEaW1L3/9oW/6AMoQ8HiEIHyR7bQOGnmz4Mg= github.com/tidwall/rtree v1.10.0/go.mod h1:iDJQ9NBRtbfKkzZu02za+mIlaP+bjYPnunbSNidpbCQ= github.com/tidwall/tinylru v1.1.0 h1:XY6IUfzVTU9rpwdhKUF6nQdChgCdGjkMfLzbWyiau6I= github.com/tidwall/tinylru v1.1.0/go.mod h1:3+bX+TJ2baOLMWTnlyNWHh4QMnFyARg2TLTQ6OFbzw8= +github.com/tkrajina/gpxgo v1.1.2 h1:il6rjS6IGm3yqa/yr7+fKBlF3ufWDEPZrYi/kxI1Jv0= github.com/tkrajina/gpxgo v1.1.2/go.mod h1:795sjVRFo5wWyN6oOZp0RYienGGBJjpAlgOz2nCngA0= -github.com/tkrajina/gpxgo v1.2.1 h1:MJJtT4Re5btDGg89brFDrUP3EWz+cBmyo8pQwV0ZOak= -github.com/tkrajina/gpxgo v1.2.1/go.mod h1:795sjVRFo5wWyN6oOZp0RYienGGBJjpAlgOz2nCngA0= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/twpayne/go-geom v1.5.1 h1:8MmGNqjDaepxHqA2/J2AftwxKzzCXmQx1gX+syYctyA= github.com/twpayne/go-geom v1.5.1/go.mod h1:Ixuwq8wG6UqI/udYOkKFHJIktCHN0yCozVDng4rYQUQ= @@ -477,8 +469,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= 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= @@ -486,9 +478,8 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs= golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.6.0 h1:bR8b5okrPI3g/gyZakLZHeWxAR8Dn5CyxXv1hLH5g/4= -golang.org/x/image v0.6.0/go.mod h1:MXLdDR43H7cDJq5GEGXEVeeNhPgi+YYEQ2pC1byI1x0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -505,9 +496,8 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -528,19 +518,17 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= 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= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= +golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -549,8 +537,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -568,31 +556,26 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/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-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210105210732-16f7687f5001/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.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.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 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= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -601,10 +584,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -629,12 +610,10 @@ golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210112230658-8b4aab62c064/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -660,15 +639,15 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.56.0 h1:+y7Bs8rtMd07LeXmL3NxcTLn7mUkbKZqEpPhMNkwJEE= -google.golang.org/grpc v1.56.0/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= 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= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -680,8 +659,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/dbutil/dbutil.go b/internal/dbutil/dbutil.go index c3e270da..d488f893 100644 --- a/internal/dbutil/dbutil.go +++ b/internal/dbutil/dbutil.go @@ -8,7 +8,7 @@ import ( sq "github.com/Masterminds/squirrel" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" "github.com/interline-io/transitland-lib/tldb" "github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx/reflectx" diff --git a/internal/directions/aws_router.go b/internal/directions/aws_router.go index d961e136..b4c09559 100644 --- a/internal/directions/aws_router.go +++ b/internal/directions/aws_router.go @@ -10,7 +10,7 @@ import ( awsconfig "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/location" "github.com/aws/aws-sdk-go-v2/service/location/types" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" "github.com/interline-io/transitland-lib/tl" "github.com/interline-io/transitland-lib/tl/tt" "github.com/interline-io/transitland-server/internal/clock" diff --git a/internal/directions/directions.go b/internal/directions/directions.go index b2a9f720..1316a848 100644 --- a/internal/directions/directions.go +++ b/internal/directions/directions.go @@ -6,7 +6,7 @@ import ( "os" "sync" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" "github.com/interline-io/transitland-server/model" ) diff --git a/internal/directions/valhalla_router.go b/internal/directions/valhalla_router.go index 3a8b418d..26230e23 100644 --- a/internal/directions/valhalla_router.go +++ b/internal/directions/valhalla_router.go @@ -11,7 +11,7 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" "github.com/interline-io/transitland-lib/tl/tt" "github.com/interline-io/transitland-server/internal/clock" "github.com/interline-io/transitland-server/internal/httpcache" diff --git a/internal/ecache/ecache.go b/internal/ecache/ecache.go index cfc3a000..90e7f001 100644 --- a/internal/ecache/ecache.go +++ b/internal/ecache/ecache.go @@ -8,7 +8,7 @@ import ( "time" "github.com/go-redis/redis/v8" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" ) type Item[T any] struct { diff --git a/internal/gbfs/fetch.go b/internal/gbfs/fetch.go index 9a217613..15491d73 100644 --- a/internal/gbfs/fetch.go +++ b/internal/gbfs/fetch.go @@ -3,9 +3,9 @@ package gbfs import ( "encoding/json" + "github.com/interline-io/log" "github.com/interline-io/transitland-lib/dmfr" "github.com/interline-io/transitland-lib/dmfr/fetch" - "github.com/interline-io/transitland-lib/log" "github.com/interline-io/transitland-lib/tl/request" "github.com/interline-io/transitland-lib/tl/tt" "github.com/interline-io/transitland-lib/tldb" diff --git a/internal/jobs/local_jobs.go b/internal/jobs/local_jobs.go index 78180f24..3291ddc5 100644 --- a/internal/jobs/local_jobs.go +++ b/internal/jobs/local_jobs.go @@ -8,7 +8,7 @@ import ( "sync/atomic" "time" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" ) var jobCounter = uint64(0) diff --git a/internal/jobs/log.go b/internal/jobs/log.go index b451a3b1..c5391652 100644 --- a/internal/jobs/log.go +++ b/internal/jobs/log.go @@ -4,7 +4,7 @@ import ( "context" "time" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" ) type jlog struct { diff --git a/internal/jobs/redis_jobs.go b/internal/jobs/redis_jobs.go index 424b6737..59743041 100644 --- a/internal/jobs/redis_jobs.go +++ b/internal/jobs/redis_jobs.go @@ -11,7 +11,7 @@ import ( workers "github.com/digitalocean/go-workers2" "github.com/go-redis/redis/v8" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" ) // RedisJobs is a simple wrapper around go-workers diff --git a/internal/testfinder/testfinder.go b/internal/testfinder/testfinder.go index ac06effd..5107052b 100644 --- a/internal/testfinder/testfinder.go +++ b/internal/testfinder/testfinder.go @@ -8,8 +8,8 @@ import ( "testing" "github.com/interline-io/transitland-lib/rt" - "github.com/interline-io/transitland-server/auth/authz" - "github.com/interline-io/transitland-server/auth/azcheck" + "github.com/interline-io/transitland-mw/auth/authz" + "github.com/interline-io/transitland-mw/auth/azcheck" "github.com/interline-io/transitland-server/config" "github.com/interline-io/transitland-server/finders/dbfinder" "github.com/interline-io/transitland-server/finders/gbfsfinder" diff --git a/internal/testutil/db.go b/internal/testutil/db.go index 3097844a..de7d9035 100644 --- a/internal/testutil/db.go +++ b/internal/testutil/db.go @@ -5,7 +5,7 @@ import ( "os" "github.com/go-redis/redis/v8" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" "github.com/interline-io/transitland-server/internal/dbutil" "github.com/jmoiron/sqlx" ) diff --git a/internal/testutil/recorder.go b/internal/testutil/recorder.go index 2927a424..31ace8e2 100644 --- a/internal/testutil/recorder.go +++ b/internal/testutil/recorder.go @@ -6,7 +6,7 @@ import ( "net/http" "net/url" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" "gopkg.in/dnaeon/go-vcr.v2/cassette" "gopkg.in/dnaeon/go-vcr.v2/recorder" ) diff --git a/meters/amberflo.go b/meters/amberflo.go deleted file mode 100644 index cdbf14ea..00000000 --- a/meters/amberflo.go +++ /dev/null @@ -1,246 +0,0 @@ -package meters - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "time" - - "github.com/amberflo/metering-go/v2" - "github.com/interline-io/transitland-lib/log" - "github.com/rs/zerolog" - "github.com/xtgo/uuid" -) - -type AmberfloMeterProvider struct { - apikey string - interval time.Duration - client *metering.Metering - usageClient *metering.UsageClient - cfgs map[string]amberFloConfig -} - -func NewAmberfloMeterProvider(apikey string, interval time.Duration, batchSize int) *AmberfloMeterProvider { - afLog := &amberfloLogger{logger: log.Logger} - meteringClient := metering.NewMeteringClient( - apikey, - metering.WithBatchSize(batchSize), - metering.WithIntervalSeconds(interval), - metering.WithLogger(afLog), - ) - usageClient := metering.NewUsageClient( - apikey, - metering.WithCustomLogger(afLog), - ) - return &AmberfloMeterProvider{ - apikey: apikey, - interval: interval, - client: meteringClient, - usageClient: usageClient, - cfgs: map[string]amberFloConfig{}, - } -} - -type amberFloConfig struct { - Name string `json:"name,omitempty"` - DefaultUser string `json:"default_user,omitempty"` - ExternalIDKey string `json:"external_id_key,omitempty"` - Dimensions Dimensions `json:"dimensions,omitempty"` -} - -func (m *AmberfloMeterProvider) LoadConfig(path string) error { - cfgs := map[string]amberFloConfig{} - data, err := ioutil.ReadFile(path) - if err != nil { - return err - } - if err := json.Unmarshal(data, &cfgs); err != nil { - return err - } - m.cfgs = cfgs - return nil -} - -func (m *AmberfloMeterProvider) NewMeter(user MeterUser) ApiMeter { - return &amberFloMeter{ - user: user, - mp: m, - } -} - -func (m *AmberfloMeterProvider) Close() error { - return m.client.Shutdown() -} - -func (m *AmberfloMeterProvider) Flush() error { - // metering.Flush() // in API docs but not in library - time.Sleep(m.interval) - return nil -} - -func (m *AmberfloMeterProvider) getValue(user MeterUser, meterName string, startTime time.Time, endTime time.Time, checkDims Dimensions) (float64, bool) { - cfg, ok := m.getcfg(meterName) - if !ok { - return 0, false - } - customerId, ok := m.getCustomerID(cfg, user) - if !ok { - return 0, false - } - if cfg.Name == "" { - return 0, false - } - timeRange := &metering.TimeRange{ - StartTimeInSeconds: startTime.In(time.UTC).Unix(), - EndTimeInSeconds: endTime.In(time.UTC).Unix(), - } - if timeRange.EndTimeInSeconds > time.Now().In(time.UTC).Unix() { - timeRange.EndTimeInSeconds = 0 - } - - filter := make(map[string][]string) - filter["customerId"] = []string{customerId} - for _, dim := range checkDims { - filter[dim.Key] = []string{dim.Value} - } - - timeGroupingInterval := metering.Hour - switch timeSpan := endTime.Unix() - startTime.Unix(); { - case timeSpan > 24*60*60: - timeGroupingInterval = metering.Month - case timeSpan > 60*60: - timeGroupingInterval = metering.Day - default: - timeGroupingInterval = metering.Hour - } - - usageResult, err := m.usageClient.GetUsage(&metering.UsagePayload{ - MeterApiName: cfg.Name, - Aggregation: metering.Sum, - TimeGroupingInterval: timeGroupingInterval, - GroupBy: []string{"customerId"}, - TimeRange: timeRange, - Filter: filter, - }) - if err != nil { - log.Error().Err(err).Str("user", user.ID()).Msg("could not get value") - return 0, false - } - // jj, _ := json.Marshal(&usageResult) - // fmt.Println("usageResult:", string(jj)) - - if usageResult == nil || len(usageResult.ClientMeters) == 0 || len(usageResult.ClientMeters[0].Values) == 0 { - log.Error().Err(err).Str("user", user.ID()).Msg("could not get value; no client value meter") - return 0, false - } - - total := usageResult.ClientMeters[0].GroupValue - return total, true -} - -func (m *AmberfloMeterProvider) sendMeter(user MeterUser, meterName string, value float64, extraDimensions Dimensions) error { - cfg, ok := m.getcfg(meterName) - if !ok { - return nil - } - customerId, ok := m.getCustomerID(cfg, user) - if !ok { - log.Error().Str("user", user.ID()).Msg("could not meter; no amberflo user id") - return nil - } - uniqueId := uuid.NewRandom().String() - utcMillis := time.Now().In(time.UTC).UnixNano() / int64(time.Millisecond) - amberFloDims := map[string]string{} - for _, v := range cfg.Dimensions { - amberFloDims[v.Key] = v.Value - } - for _, v := range extraDimensions { - amberFloDims[v.Key] = v.Value - } - return m.client.Meter(&metering.MeterMessage{ - MeterApiName: cfg.Name, - UniqueId: uniqueId, - MeterTimeInMillis: utcMillis, - CustomerId: customerId, - MeterValue: value, - Dimensions: amberFloDims, - }) -} - -func (m *AmberfloMeterProvider) getCustomerID(cfg amberFloConfig, user MeterUser) (string, bool) { - customerId := cfg.DefaultUser - if user != nil { - eidKey := cfg.ExternalIDKey - if eidKey == "" { - eidKey = "amberflo" - } - if a, ok := user.GetExternalData(eidKey); ok { - customerId = a - } - } - if customerId == "" { - log.Error().Str("user", user.ID()).Str("external_id_key", cfg.ExternalIDKey).Msg("could not get value; no amberflo customer id") - } - return customerId, customerId != "" -} - -func (m *AmberfloMeterProvider) getcfg(meterName string) (amberFloConfig, bool) { - cfg, ok := m.cfgs[meterName] - if !ok { - cfg = amberFloConfig{ - Name: meterName, - } - } - if cfg.Name == "" { - log.Error().Str("meter", meterName).Msg("could not meter; no amberflo config for meter") - return cfg, false - } - return cfg, true -} - -////////// - -type amberFloMeter struct { - user MeterUser - addDims []eventAddDim - mp *AmberfloMeterProvider -} - -func (m *amberFloMeter) Meter(meterName string, value float64, extraDimensions Dimensions) error { - var eventDims []Dimension - // Copy in matching dimensions set through AddDimension - for _, addDim := range m.addDims { - if addDim.MeterName == meterName { - eventDims = append(eventDims, Dimension{Key: addDim.Key, Value: addDim.Value}) - } - } - eventDims = append(eventDims, extraDimensions...) - log.Trace(). - Str("user", m.user.ID()). - Str("meter", meterName). - Float64("meter_value", value). - Msg("meter") - return m.mp.sendMeter(m.user, meterName, value, eventDims) -} - -func (m *amberFloMeter) AddDimension(meterName string, key string, value string) { - m.addDims = append(m.addDims, eventAddDim{MeterName: meterName, Key: key, Value: value}) -} - -func (m *amberFloMeter) GetValue(meterName string, startTime time.Time, endTime time.Time, dims Dimensions) (float64, bool) { - return m.mp.getValue(m.user, meterName, startTime, endTime, dims) -} - -///////// - -type amberfloLogger struct { - logger zerolog.Logger -} - -func (l *amberfloLogger) Log(args ...interface{}) { - l.logger.Trace().Msgf("amberflo: " + fmt.Sprint(args...)) -} - -func (l *amberfloLogger) Logf(format string, args ...interface{}) { - l.logger.Trace().Msgf("amberflo: "+format, args...) -} diff --git a/meters/amberflo_test.go b/meters/amberflo_test.go deleted file mode 100644 index 1e7b4cda..00000000 --- a/meters/amberflo_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package meters - -import ( - "errors" - "os" - "testing" - "time" - - "github.com/interline-io/transitland-server/internal/testutil" -) - -func TestAmberfloMeter(t *testing.T) { - mp, testConfig, err := getTestAmberfloMeter() - if err != nil { - t.Skip(err.Error()) - return - } - testMeter(t, mp, testConfig) -} - -func getTestAmberfloMeter() (*AmberfloMeterProvider, testMeterConfig, error) { - checkKeys := []string{ - "TL_TEST_AMBERFLO_APIKEY", - "TL_TEST_AMBERFLO_METER1", - "TL_TEST_AMBERFLO_METER2", - "TL_TEST_AMBERFLO_USER1", - "TL_TEST_AMBERFLO_USER2", - "TL_TEST_AMBERFLO_USER3", - } - for _, k := range checkKeys { - _, a, ok := testutil.CheckEnv(k) - if !ok { - return nil, testMeterConfig{}, errors.New(a) - } - } - eidKey := "amberflo" - testConfig := testMeterConfig{ - testMeter1: os.Getenv("TL_TEST_AMBERFLO_METER1"), - testMeter2: os.Getenv("TL_TEST_AMBERFLO_METER2"), - user1: &testUser{ - name: os.Getenv("TL_TEST_AMBERFLO_USER1"), - data: map[string]string{eidKey: os.Getenv("TL_TEST_AMBERFLO_USER1")}, - }, - user2: &testUser{ - name: os.Getenv("TL_TEST_AMBERFLO_USER2"), - data: map[string]string{eidKey: os.Getenv("TL_TEST_AMBERFLO_USER2")}, - }, - user3: &testUser{ - name: os.Getenv("TL_TEST_AMBERFLO_USER3"), - data: map[string]string{eidKey: os.Getenv("TL_TEST_AMBERFLO_USER3")}, - }, - } - mp := NewAmberfloMeterProvider(os.Getenv("TL_TEST_AMBERFLO_APIKEY"), 1*time.Second, 1) - mp.cfgs[testConfig.testMeter1] = amberFloConfig{Name: testConfig.testMeter1, ExternalIDKey: eidKey} - mp.cfgs[testConfig.testMeter2] = amberFloConfig{Name: testConfig.testMeter2, ExternalIDKey: eidKey} - return mp, testConfig, nil -} diff --git a/meters/default.go b/meters/default.go deleted file mode 100644 index addd94db..00000000 --- a/meters/default.go +++ /dev/null @@ -1,126 +0,0 @@ -package meters - -import ( - "sync" - "time" - - "github.com/interline-io/transitland-lib/log" -) - -type DefaultMeterProvider struct { - values map[string]defaultMeterUserEvents - lock sync.Mutex -} - -func NewDefaultMeterProvider() *DefaultMeterProvider { - return &DefaultMeterProvider{ - values: map[string]defaultMeterUserEvents{}, - } -} - -func (m *DefaultMeterProvider) Flush() error { - return nil -} - -func (m *DefaultMeterProvider) Close() error { - return nil -} - -func (m *DefaultMeterProvider) NewMeter(user MeterUser) ApiMeter { - return &defaultUserMeter{ - user: user, - mp: m, - } -} - -func (m *DefaultMeterProvider) sendMeter(u MeterUser, meterName string, value float64, dims []Dimension) error { - m.lock.Lock() - defer m.lock.Unlock() - a, ok := m.values[meterName] - if !ok { - a = defaultMeterUserEvents{} - m.values[meterName] = a - } - userName := "" - if u != nil { - userName = u.ID() - } - event := defaultMeterEvent{ - value: value, - time: time.Now().In(time.UTC), - dims: dims, - } - a[userName] = append(a[userName], event) - log.Trace(). - Str("user", userName). - Str("meter", meterName). - Float64("meter_value", value). - Msg("meter") - return nil -} - -func (m *DefaultMeterProvider) getValue(u MeterUser, meterName string, startTime time.Time, endTime time.Time, checkDims Dimensions) (float64, bool) { - m.lock.Lock() - defer m.lock.Unlock() - a, ok := m.values[meterName] - if !ok { - return 0, false - } - total := 0.0 - for _, userEvent := range a[u.ID()] { - match := true - if userEvent.time.Equal(endTime) || userEvent.time.After(endTime) { - // fmt.Println("not matched on end time", userEvent.time, endTime) - match = false - } - if userEvent.time.Before(startTime) { - // fmt.Println("not matched on start time", userEvent.time, startTime) - match = false - } - if !dimsContainedIn(checkDims, userEvent.dims) { - // fmt.Println("not matched on dims") - match = false - } - if match { - // fmt.Println("matched:", userEvent.value) - total += userEvent.value - } - } - return total, ok -} - -type defaultUserMeter struct { - user MeterUser - addDims []eventAddDim - mp *DefaultMeterProvider -} - -func (m *defaultUserMeter) Meter(meterName string, value float64, extraDimensions Dimensions) error { - // Copy in matching dimensions set through AddDimension - var eventDims []Dimension - for _, addDim := range m.addDims { - if addDim.MeterName == meterName { - eventDims = append(eventDims, Dimension{Key: addDim.Key, Value: addDim.Value}) - } - } - eventDims = append(eventDims, extraDimensions...) - return m.mp.sendMeter(m.user, meterName, value, eventDims) -} - -func (m *defaultUserMeter) AddDimension(meterName string, key string, value string) { - m.addDims = append(m.addDims, eventAddDim{MeterName: meterName, Key: key, Value: value}) -} - -func (m *defaultUserMeter) GetValue(meterName string, startTime time.Time, endTime time.Time, dims Dimensions) (float64, bool) { - return m.mp.getValue(m.user, meterName, startTime, endTime, dims) -} - -/////////// - -type defaultMeterEvent struct { - time time.Time - dims []Dimension - value float64 -} - -type defaultMeterUserEvents map[string][]defaultMeterEvent diff --git a/meters/default_test.go b/meters/default_test.go deleted file mode 100644 index 7c0ea275..00000000 --- a/meters/default_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package meters - -import ( - "testing" -) - -func TestDefaultMeter(t *testing.T) { - mp := NewDefaultMeterProvider() - testConfig := testMeterConfig{ - testMeter1: "test1", - testMeter2: "test2", - user1: &testUser{name: "test1"}, - user2: &testUser{name: "test2"}, - user3: &testUser{name: "test3"}, - } - testMeter(t, mp, testConfig) -} diff --git a/meters/limit.go b/meters/limit.go deleted file mode 100644 index c3dd91c1..00000000 --- a/meters/limit.go +++ /dev/null @@ -1,129 +0,0 @@ -package meters - -import ( - "errors" - "fmt" - "time" - - "github.com/interline-io/transitland-lib/log" - "github.com/tidwall/gjson" -) - -func init() { - var _ MeterProvider = &LimitMeterProvider{} -} - -type LimitMeterProvider struct { - Enabled bool - DefaultLimits []UserMeterLimit - MeterProvider -} - -func NewLimitMeterProvider(provider MeterProvider) *LimitMeterProvider { - return &LimitMeterProvider{ - MeterProvider: provider, - } -} - -func (c *LimitMeterProvider) NewMeter(u MeterUser) ApiMeter { - userData, _ := u.GetExternalData("gatekeeper") - return &LimitMeter{ - userId: u.ID(), - userData: userData, - provider: c, - ApiMeter: c.MeterProvider.NewMeter(u), - } -} - -type LimitMeter struct { - userId string - userData string - provider *LimitMeterProvider - ApiMeter -} - -func (c *LimitMeter) GetLimits(meterName string, checkDims Dimensions) []UserMeterLimit { - // The limit matches the event dimensions if all of the LIMIT dimensions are contained in event - var lims []UserMeterLimit - for _, userLimit := range parseGkUserLimits(c.userData) { - if userLimit.MeterName == meterName && dimsContainedIn(userLimit.Dims, checkDims) { - lims = append(lims, userLimit) - } - } - for _, defaultLimit := range c.provider.DefaultLimits { - if defaultLimit.MeterName == meterName && dimsContainedIn(defaultLimit.Dims, checkDims) { - lims = append(lims, defaultLimit) - } - } - return lims -} - -func (c *LimitMeter) Meter(meterName string, value float64, extraDimensions Dimensions) error { - if c.provider.Enabled { - for _, lim := range c.GetLimits(meterName, extraDimensions) { - d1, d2 := lim.Span() - currentValue, _ := c.GetValue(meterName, d1, d2, lim.Dims) - if currentValue+value > lim.Limit { - log.Info().Str("meter", meterName).Str("user", c.userId).Float64("limit", lim.Limit).Float64("current", currentValue).Float64("add", value).Str("dims", fmt.Sprintf("%v", lim.Dims)).Msg("rate limited") - return errors.New("rate check: limited") - } else { - log.Info().Str("meter", meterName).Str("user", c.userId).Float64("limit", lim.Limit).Float64("current", currentValue).Float64("add", value).Str("dims", fmt.Sprintf("%v", lim.Dims)).Msg("rate check: ok") - } - } - } - return c.ApiMeter.Meter(meterName, value, extraDimensions) -} - -type UserMeterLimit struct { - User string - MeterName string - Dims Dimensions - Period string - Limit float64 -} - -func (lim *UserMeterLimit) Span() (time.Time, time.Time) { - now := time.Now().In(time.UTC) - d1 := now - d2 := now - if lim.Period == "hourly" { - d1 = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, time.UTC) - d2 = d1.Add(3600 * time.Second) - } else if lim.Period == "daily" { - d1 = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC) - d2 = d1.AddDate(0, 0, 1) - } else if lim.Period == "monthly" { - d1 = time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, time.UTC) - d2 = d1.AddDate(0, 1, 0) - } else if lim.Period == "yearly" { - d1 = time.Date(now.Year(), 1, 1, 0, 0, 0, 0, time.UTC) - d2 = d1.AddDate(1, 0, 0) - } else if lim.Period == "total" { - d1 = time.Unix(0, 0) - d2 = time.Unix(1<<63-1, 0) - } else { - return now, now - } - return d1, d2 -} - -func parseGkUserLimits(v string) []UserMeterLimit { - var lims []UserMeterLimit - for _, productLimit := range gjson.Get(v, "product_limits").Map() { - for _, plim := range productLimit.Array() { - lim := UserMeterLimit{ - MeterName: plim.Get("amberflo_meter").String(), - Limit: plim.Get("limit_value").Float(), - Period: plim.Get("time_period").String(), - } - if dim := plim.Get("amberflo_dimension").String(); dim != "" { - lim.Dims = append(lim.Dims, Dimension{ - Key: dim, - Value: plim.Get("amberflo_dimension_value").String(), - }) - } - lims = append(lims, lim) - } - } - return lims -} diff --git a/meters/limit_test.go b/meters/limit_test.go deleted file mode 100644 index efa33a34..00000000 --- a/meters/limit_test.go +++ /dev/null @@ -1,162 +0,0 @@ -package meters - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestLimitMeter(t *testing.T) { - meterName := "testmeter" - user := testUser{name: "testuser"} - // cmp.DefaultLimits = testLims(meterName) - // for _, lim := range cmp.DefaultLimits { - for _, lim := range testLims(meterName) { - t.Run("", func(t *testing.T) { - mp := NewDefaultMeterProvider() - cmp := NewLimitMeterProvider(mp) - cmp.Enabled = true - cmp.DefaultLimits = []UserMeterLimit{lim} - testLimitMeter(t, - cmp, - lim.MeterName, - user, - lim, - ) - }) - } -} - -func TestLimitMeter_Amberflo(t *testing.T) { - mp, testConfig, err := getTestAmberfloMeter() - if err != nil { - t.Skip(err.Error()) - return - } - user := testUser{ - name: testConfig.user1.ID(), - data: map[string]string{"amberflo": "amberflo"}, - } - for _, lim := range testLims(testConfig.testMeter1) { - t.Run("", func(t *testing.T) { - cmp := NewLimitMeterProvider(mp) - cmp.Enabled = true - cmp.DefaultLimits = []UserMeterLimit{lim} - testLimitMeter(t, - cmp, - lim.MeterName, - user, - lim, - ) - }) - } -} - -func TestLimitMeter_Gatekeeper(t *testing.T) { - // JSON blob - gkData := ` - { - "product_limits": { - "tlv2_api": [ - { - "amberflo_dimension": "fv", - "amberflo_dimension_value": true, - "amberflo_meter": "testmeter", - "limit_value": 100, - "time_period": "monthly" - }, - { - "amberflo_dimension": "fv", - "amberflo_dimension_value": false, - "amberflo_meter": "testmeter", - "limit_value": 500, - "time_period": "monthly" - } - ] - }, - }` - user := testUser{name: "testuser"} - user.data = map[string]string{"gatekeeper": gkData} - lims := parseGkUserLimits(gkData) - for _, lim := range lims { - t.Run("", func(t *testing.T) { - mp := NewDefaultMeterProvider() - cmp := NewLimitMeterProvider(mp) - cmp.Enabled = true - testLimitMeter(t, - cmp, - lim.MeterName, - user, - lim, - ) - }) - } -} - -func testLims(meterName string) []UserMeterLimit { - testKey := 1 // time.Now().In(time.UTC).Unix() - lims := []UserMeterLimit{ - // foo tests - { - MeterName: meterName, - Period: "hourly", - Limit: 50.0, - Dims: Dimensions{{Key: "ok", Value: fmt.Sprintf("foo:%d", testKey)}}, - }, - { - MeterName: meterName, - Period: "daily", - Limit: 80.0, - Dims: Dimensions{{Key: "ok", Value: fmt.Sprintf("foo:%d", testKey)}}, - }, - { - MeterName: meterName, - Period: "monthly", - Limit: 110.0, - Dims: Dimensions{{Key: "ok", Value: fmt.Sprintf("foo:%d", testKey)}}, - }, - // bar tests - { - MeterName: meterName, - Period: "hourly", - Limit: 140.0, - Dims: Dimensions{{Key: "ok", Value: fmt.Sprintf("bar:%d", testKey)}}, - }, - { - MeterName: meterName, - Period: "daily", - Limit: 170.0, - Dims: Dimensions{{Key: "ok", Value: fmt.Sprintf("bar:%d", testKey)}}, - }, - { - MeterName: meterName, - Period: "monthly", - Limit: 200.0, - Dims: Dimensions{{Key: "ok", Value: fmt.Sprintf("bar:%d", testKey)}}, - }, - } - return lims -} - -func testLimitMeter(t *testing.T, cmp *LimitMeterProvider, meterName string, user testUser, lim UserMeterLimit) { - incr := 1.0 - m := cmp.NewMeter(user) - startTime, endTime := lim.Span() - base, _ := m.GetValue(meterName, startTime, endTime, lim.Dims) - - // Probably ok - if err := m.Meter(meterName, incr, lim.Dims); err != nil { - t.Error(err) - } - cmp.MeterProvider.Flush() - - // push past limit - if err := m.Meter(meterName, incr+lim.Limit, lim.Dims); err == nil { - t.Error("expected error, got none") - } - - // Check updated value - total, _ := m.GetValue(meterName, startTime, endTime, lim.Dims) - assert.Equal(t, base+incr, total, "expected total") -} diff --git a/meters/meters.go b/meters/meters.go deleted file mode 100644 index ec6d58b7..00000000 --- a/meters/meters.go +++ /dev/null @@ -1,108 +0,0 @@ -package meters - -import ( - "context" - "net/http" - "os" - "time" - - "github.com/interline-io/transitland-server/auth/authn" -) - -var meterCtxKey = struct{ name string }{"apiMeter"} - -type ApiMeter interface { - Meter(string, float64, Dimensions) error - AddDimension(string, string, string) - GetValue(string, time.Time, time.Time, Dimensions) (float64, bool) -} - -type MeterProvider interface { - NewMeter(MeterUser) ApiMeter - Close() error - Flush() error -} - -type MeterUser interface { - ID() string - GetExternalData(string) (string, bool) -} - -func WithMeter(apiMeter MeterProvider, meterName string, meterValue float64, dims Dimensions) func(http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Make ctxMeter available in context - ctx := r.Context() - ctxMeter := apiMeter.NewMeter(authn.ForContext(ctx)) - r = r.WithContext(context.WithValue(ctx, meterCtxKey, ctxMeter)) - if err := ctxMeter.Meter(meterName, meterValue, dims); err != nil { - http.Error(w, "429", http.StatusTooManyRequests) - return - } - next.ServeHTTP(w, r) - }) - } -} - -func ForContext(ctx context.Context) ApiMeter { - raw, _ := ctx.Value(meterCtxKey).(ApiMeter) - return raw -} - -type Dimension struct { - Key string - Value string -} - -type Dimensions []Dimension - -type eventAddDim struct { - MeterName string - Key string - Value string -} - -func dimsContainedIn(checkDims Dimensions, eventDims Dimensions) bool { - for _, matchDim := range checkDims { - match := false - for _, ed := range eventDims { - if ed.Key == matchDim.Key && ed.Value == matchDim.Value { - match = true - } - } - if !match { - return false - } - } - return true -} - -////// - -type Config struct { - EnableMetering bool - EnableRateLimits bool - MeteringProvider string - MeteringAmberfloConfig string -} - -func GetProvider(cfg Config) (MeterProvider, error) { - var meterProvider MeterProvider - meterProvider = NewDefaultMeterProvider() - if cfg.MeteringProvider == "amberflo" { - a := NewAmberfloMeterProvider(os.Getenv("AMBERFLO_APIKEY"), 30*time.Second, 100) - if cfg.MeteringAmberfloConfig != "" { - if err := a.LoadConfig(cfg.MeteringAmberfloConfig); err != nil { - return nil, err - } - } - meterProvider = a - } - if cfg.EnableRateLimits { - mp := NewLimitMeterProvider(meterProvider) - mp.Enabled = true - // mp.DefaultLimits = append(mp.DefaultLimits, meters.UserMeterLimit{Limit: 10, Period: "monthly", MeterName: "rest"}) - meterProvider = mp - } - return meterProvider, nil -} diff --git a/meters/meters_test.go b/meters/meters_test.go deleted file mode 100644 index 96ae6799..00000000 --- a/meters/meters_test.go +++ /dev/null @@ -1,127 +0,0 @@ -package meters - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -type testUser struct { - name string - data map[string]string -} - -func (u testUser) ID() string { - return u.name -} - -func (u testUser) GetExternalData(key string) (string, bool) { - if u.data == nil { - return "", false - } - a, ok := u.data[key] - return a, ok -} - -type testMeterConfig struct { - testMeter1 string - testMeter2 string - user1 MeterUser - user2 MeterUser - user3 MeterUser -} - -func testMeter(t *testing.T, mp MeterProvider, cfg testMeterConfig) { - d1, d2 := (&UserMeterLimit{Period: "hourly"}).Span() - t.Run("Meter", func(t *testing.T) { - m := mp.NewMeter(cfg.user1) - v, _ := m.GetValue(cfg.testMeter1, d1, d2, nil) - - m.Meter(cfg.testMeter1, 1, nil) - mp.Flush() - - a, _ := m.GetValue(cfg.testMeter1, d1, d2, nil) - assert.Equal(t, 1.0, a-v) - - m.Meter(cfg.testMeter1, 1, nil) - mp.Flush() - - b, _ := m.GetValue(cfg.testMeter1, d1, d2, nil) - assert.Equal(t, 2.0, b-v) - }) - t.Run("NewMeter", func(t *testing.T) { - m1 := mp.NewMeter(cfg.user1) - - v1, _ := m1.GetValue(cfg.testMeter1, d1, d2, nil) - v2, _ := m1.GetValue(cfg.testMeter2, d1, d2, nil) - - m1.Meter(cfg.testMeter1, 1, nil) - m1.Meter(cfg.testMeter2, 2, nil) - mp.Flush() - - va1, _ := m1.GetValue(cfg.testMeter1, d1, d2, nil) - assert.Equal(t, 1.0, va1-v1) - va2, _ := m1.GetValue(cfg.testMeter2, d1, d2, nil) - assert.Equal(t, 2.0, va2-v2) - }) - t.Run("GetValue", func(t *testing.T) { - m1 := mp.NewMeter(cfg.user1) - m2 := mp.NewMeter(cfg.user2) - m3 := mp.NewMeter(cfg.user3) - v1, _ := m1.GetValue(cfg.testMeter1, d1, d2, nil) - v2, _ := m2.GetValue(cfg.testMeter1, d1, d2, nil) - v3, _ := m3.GetValue(cfg.testMeter1, d1, d2, nil) - - m1.Meter(cfg.testMeter1, 1, nil) - m2.Meter(cfg.testMeter1, 2.0, nil) - mp.Flush() - - a, ok := m1.GetValue(cfg.testMeter1, d1, d2, nil) - assert.Equal(t, 1.0, a-v1) - assert.Equal(t, true, ok) - - a, ok = m2.GetValue(cfg.testMeter1, d1, d2, nil) - assert.Equal(t, 2.0, a-v2) - assert.Equal(t, true, ok) - - a, _ = m3.GetValue(cfg.testMeter1, d1, d2, nil) - assert.Equal(t, 0.0, a-v3) - }) - - t.Run("GetValue match dims", func(t *testing.T) { - addDims1 := []Dimension{{Key: "test", Value: "a"}, {Key: "other", Value: "boo"}} - addDims2 := []Dimension{{Key: "test", Value: "b"}} - checkDims1 := []Dimension{{Key: "test", Value: "a"}} - checkDims2 := []Dimension{{Key: "test", Value: "b"}} - - m1 := mp.NewMeter(cfg.user1) - m2 := mp.NewMeter(cfg.user2) - m3 := mp.NewMeter(cfg.user3) - - // Initial values - v1, _ := m1.GetValue(cfg.testMeter1, d1, d2, checkDims1) - v2, _ := m2.GetValue(cfg.testMeter1, d1, d2, checkDims2) - v3, _ := m3.GetValue(cfg.testMeter1, d1, d2, checkDims1) - - // m1 meter - m1.Meter(cfg.testMeter1, 1, addDims1) - // m2 uses different dimension - m2.Meter(cfg.testMeter1, 2.0, addDims2) - mp.Flush() - - a, ok := m1.GetValue(cfg.testMeter1, d1, d2, checkDims1) - assert.Equal(t, 1.0, a-v1) - assert.Equal(t, true, ok) - - a, ok = m2.GetValue(cfg.testMeter1, d1, d2, checkDims1) - assert.Equal(t, 0.0, a) - assert.Equal(t, true, ok) - - a, ok = m2.GetValue(cfg.testMeter1, d1, d2, checkDims2) - assert.Equal(t, 2.0, a-v2) - assert.Equal(t, true, ok) - - a, _ = m3.GetValue(cfg.testMeter1, d1, d2, checkDims1) - assert.Equal(t, 0.0, a-v3) - }) -} diff --git a/metrics/default.go b/metrics/default.go deleted file mode 100644 index 39f62b28..00000000 --- a/metrics/default.go +++ /dev/null @@ -1,33 +0,0 @@ -package metrics - -import "net/http" - -type DefaultMetric struct{} - -func NewDefaultMetric() *DefaultMetric { - return &DefaultMetric{} -} - -func (m *DefaultMetric) NewJobMetric(queue string) JobMetric { - return &DefaultMetric{} -} - -func (m *DefaultMetric) NewApiMetric(handlerName string) ApiMetric { - return &DefaultMetric{} -} - -func (m *DefaultMetric) MetricsHandler() http.Handler { - return nil -} - -func (m *DefaultMetric) AddStartedJob(queueName string, jobType string) { - return -} - -func (m *DefaultMetric) AddCompletedJob(queueName string, jobType string, success bool) { - return -} - -func (m *DefaultMetric) AddResponse(method string, responseCode int, requestSize int64, responseSize int64, responseTime float64) { - return -} diff --git a/metrics/http.go b/metrics/http.go deleted file mode 100644 index 34110314..00000000 --- a/metrics/http.go +++ /dev/null @@ -1,61 +0,0 @@ -package metrics - -import ( - "net/http" - "time" - - "github.com/interline-io/transitland-lib/log" -) - -func WithMetric(m ApiMetric) func(http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - t := time.Now() - sw := newstatusResponseWriter(w) - next.ServeHTTP(sw, r) - td := float64(time.Since(t).Milliseconds()) / 1000.0 - log.Trace(). - Str("method", r.Method). - Int("code", sw.statusCode). - Int64("http_request_size_bytes", r.ContentLength). - Int64("http_response_size_bytes", sw.bytesWritten). - Float64("http_request_duration_seconds", td). - Msgf("metrics") - m.AddResponse(r.Method, sw.statusCode, r.ContentLength, sw.bytesWritten, td) - }) - } -} - -// statusResponseWriter adapted from -// https://www.alexedwards.net/blog/how-to-use-the-http-responsecontroller-type -type statusResponseWriter struct { - http.ResponseWriter // Embed a http.ResponseWriter - statusCode int - headerWritten bool - bytesWritten int64 -} - -func newstatusResponseWriter(w http.ResponseWriter) *statusResponseWriter { - return &statusResponseWriter{ - ResponseWriter: w, - statusCode: http.StatusOK, - } -} - -func (mw *statusResponseWriter) WriteHeader(statusCode int) { - mw.ResponseWriter.WriteHeader(statusCode) - if !mw.headerWritten { - mw.statusCode = statusCode - mw.headerWritten = true - } -} - -func (mw *statusResponseWriter) Write(b []byte) (int, error) { - mw.headerWritten = true - mw.bytesWritten += int64(len(b)) - return mw.ResponseWriter.Write(b) -} - -func (mw *statusResponseWriter) Unwrap() http.ResponseWriter { - return mw.ResponseWriter -} diff --git a/metrics/jobs.go b/metrics/jobs.go deleted file mode 100644 index 894276ef..00000000 --- a/metrics/jobs.go +++ /dev/null @@ -1,32 +0,0 @@ -package metrics - -import ( - "context" - - "github.com/interline-io/transitland-server/internal/jobs" -) - -func NewJobMiddleware(queue string, m JobMetric) jobs.JobMiddleware { - return func(w jobs.JobWorker) jobs.JobWorker { - return &jobWorker{ - jobWorker: w, - jobMetric: m, - } - } -} - -type jobWorker struct { - jobMetric JobMetric - jobWorker jobs.JobWorker -} - -func (w *jobWorker) Run(ctx context.Context, job jobs.Job) error { - w.jobMetric.AddStartedJob(job.Queue, job.JobType) - err := w.jobWorker.Run(ctx, job) - if err != nil { - w.jobMetric.AddCompletedJob(job.Queue, job.JobType, false) - } else { - w.jobMetric.AddCompletedJob(job.Queue, job.JobType, true) - } - return err -} diff --git a/metrics/metrics.go b/metrics/metrics.go deleted file mode 100644 index a8da8433..00000000 --- a/metrics/metrics.go +++ /dev/null @@ -1,32 +0,0 @@ -package metrics - -import "net/http" - -type ApiMetric interface { - AddResponse(method string, responseCode int, requestSize int64, responseSize int64, responseTime float64) -} - -type JobMetric interface { - AddStartedJob(string, string) - AddCompletedJob(string, string, bool) -} - -type MetricProvider interface { - NewApiMetric(handlerName string) ApiMetric - NewJobMetric(queue string) JobMetric - MetricsHandler() http.Handler -} - -type Config struct { - EnableMetrics bool - MetricsProvider string -} - -func GetProvider(cfg Config) (MetricProvider, error) { - var metricProvider MetricProvider - metricProvider = NewDefaultMetric() - if cfg.MetricsProvider == "prometheus" { - metricProvider = NewPromMetrics() - } - return metricProvider, nil -} diff --git a/metrics/prom.go b/metrics/prom.go deleted file mode 100644 index bf57c46a..00000000 --- a/metrics/prom.go +++ /dev/null @@ -1,130 +0,0 @@ -package metrics - -import ( - "net/http" - "strconv" - - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/collectors" - "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/prometheus/client_golang/prometheus/promhttp" -) - -type PromMetrics struct { - buckets []float64 - registry *prometheus.Registry -} - -func NewPromMetrics() *PromMetrics { - registry := prometheus.NewRegistry() - registry.MustRegister( - collectors.NewGoCollector(), - collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}), - ) - return &PromMetrics{ - registry: registry, - buckets: nil, - } -} - -func (m *PromMetrics) MetricsHandler() http.Handler { - return promhttp.HandlerFor(m.registry, promhttp.HandlerOpts{}) -} - -func (m *PromMetrics) NewJobMetric(queue string) JobMetric { - reg := m.registry - jobsTotal := promauto.With(reg).NewCounterVec( - prometheus.CounterOpts{ - Name: "jobs_processed", - Help: "Total number of jobs processed", - }, []string{"queue", "class"}, - ) - jobsOk := promauto.With(reg).NewCounterVec( - prometheus.CounterOpts{ - Name: "jobs_ok", - Help: "Number of jobs completed successfully", - }, []string{"queue", "class"}, - ) - jobsFailed := promauto.With(reg).NewCounterVec( - prometheus.CounterOpts{ - Name: "jobs_failed", - Help: "Failed number of jobs", - }, []string{"queue", "class"}, - ) - return &promJobMetrics{ - jobsTotal: jobsTotal, - jobsOk: jobsOk, - jobsFailed: jobsFailed, - } -} - -func (m *PromMetrics) NewApiMetric(handlerName string) ApiMetric { - reg := prometheus.WrapRegistererWith(prometheus.Labels{"handler": handlerName}, m.registry) - requestsTotal := promauto.With(reg).NewCounterVec( - prometheus.CounterOpts{ - Name: "http_requests_total", - Help: "Tracks the number of HTTP requests.", - }, []string{"method", "code"}, - ) - requestDuration := promauto.With(reg).NewHistogramVec( - prometheus.HistogramOpts{ - Name: "http_request_duration_seconds", - Help: "Tracks the latencies for HTTP requests.", - Buckets: m.buckets, - }, - []string{"method", "code"}, - ) - requestSize := promauto.With(reg).NewSummaryVec( - prometheus.SummaryOpts{ - Name: "http_request_size_bytes", - Help: "Tracks the size of HTTP requests.", - }, - []string{"method", "code"}, - ) - responseSize := promauto.With(reg).NewSummaryVec( - prometheus.SummaryOpts{ - Name: "http_response_size_bytes", - Help: "Tracks the size of HTTP responses.", - }, - []string{"method", "code"}, - ) - return &promApiMetrics{ - requestsTotal: requestsTotal, - requestDuration: requestDuration, - requestSize: requestSize, - responseSize: responseSize, - } -} - -type promJobMetrics struct { - jobsTotal *prometheus.CounterVec - jobsOk *prometheus.CounterVec - jobsFailed *prometheus.CounterVec -} - -func (m *promJobMetrics) AddStartedJob(queueName string, jobType string) { - m.jobsTotal.With(prometheus.Labels{"queue": queueName, "class": jobType}).Add(1) -} - -func (m *promJobMetrics) AddCompletedJob(queueName string, jobType string, success bool) { - if success { - m.jobsOk.With(prometheus.Labels{"queue": queueName, "class": jobType}).Add(1) - return - } - m.jobsFailed.With(prometheus.Labels{"queue": queueName, "class": jobType}).Add(1) -} - -type promApiMetrics struct { - requestsTotal *prometheus.CounterVec - requestDuration *prometheus.HistogramVec - requestSize *prometheus.SummaryVec - responseSize *prometheus.SummaryVec -} - -func (m *promApiMetrics) AddResponse(method string, responseCode int, requestSize int64, responseSize int64, responseTime float64) { - label := prometheus.Labels{"method": method, "code": strconv.Itoa(responseCode)} - m.requestsTotal.With(label).Add(1) - m.requestSize.With(label).Observe(float64(requestSize)) - m.requestDuration.With(label).Observe(float64(responseTime)) - m.responseSize.With(label).Observe(float64(responseSize)) -} diff --git a/model/finders.go b/model/finders.go index e000d29a..280e71ab 100644 --- a/model/finders.go +++ b/model/finders.go @@ -6,7 +6,7 @@ import ( "github.com/interline-io/transitland-lib/rt/pb" "github.com/interline-io/transitland-lib/tl/tt" - "github.com/interline-io/transitland-server/auth/authz" + "github.com/interline-io/transitland-mw/auth/authz" "github.com/interline-io/transitland-server/config" "github.com/interline-io/transitland-server/internal/gbfs" diff --git a/server/gql/agency_resolver_test.go b/server/gql/agency_resolver_test.go index 2db1bb6e..c911da33 100644 --- a/server/gql/agency_resolver_test.go +++ b/server/gql/agency_resolver_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/99designs/gqlgen/client" - "github.com/interline-io/transitland-server/auth/ancheck" - "github.com/interline-io/transitland-server/auth/authz" + "github.com/interline-io/transitland-mw/auth/ancheck" + "github.com/interline-io/transitland-mw/auth/authz" "github.com/interline-io/transitland-server/internal/testfinder" "github.com/interline-io/transitland-server/internal/testutil" ) diff --git a/server/gql/fvsl_cache.go b/server/gql/fvsl_cache.go index 09c3ca29..9c21b3b4 100644 --- a/server/gql/fvsl_cache.go +++ b/server/gql/fvsl_cache.go @@ -5,7 +5,7 @@ import ( "sync" "time" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" "github.com/interline-io/transitland-server/model" ) diff --git a/server/gql/loaders.go b/server/gql/loaders.go index 22893d65..2a6013ec 100644 --- a/server/gql/loaders.go +++ b/server/gql/loaders.go @@ -7,7 +7,7 @@ import ( "time" dataloader "github.com/graph-gophers/dataloader/v7" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" "github.com/interline-io/transitland-lib/tl/tt" "github.com/interline-io/transitland-server/config" "github.com/interline-io/transitland-server/model" diff --git a/server/gql/mutation_resolver.go b/server/gql/mutation_resolver.go index e82a8ca0..35f50f1a 100644 --- a/server/gql/mutation_resolver.go +++ b/server/gql/mutation_resolver.go @@ -8,7 +8,6 @@ import ( "github.com/99designs/gqlgen/graphql" "github.com/interline-io/transitland-server/actions" - "github.com/interline-io/transitland-server/auth/authn" "github.com/interline-io/transitland-server/model" ) @@ -21,7 +20,7 @@ func (r *mutationResolver) ValidateGtfs(ctx context.Context, file *graphql.Uploa if file != nil { src = file.File } - return actions.ValidateUpload(ctx, r.cfg, src, url, rturls, authn.ForContext(ctx)) + return actions.ValidateUpload(ctx, r.cfg, src, url, rturls) } func (r *mutationResolver) FeedVersionFetch(ctx context.Context, file *graphql.Upload, url *string, feedId string) (*model.FeedVersionFetchResult, error) { @@ -33,19 +32,19 @@ func (r *mutationResolver) FeedVersionFetch(ctx context.Context, file *graphql.U if url != nil { feedUrl = *url } - return actions.StaticFetch(ctx, r.cfg, r.finder, feedId, feedSrc, feedUrl, authn.ForContext(ctx), r.authzChecker) + return actions.StaticFetch(ctx, r.cfg, r.finder, feedId, feedSrc, feedUrl, r.authzChecker) } func (r *mutationResolver) FeedVersionImport(ctx context.Context, fvid int) (*model.FeedVersionImportResult, error) { - return actions.FeedVersionImport(ctx, r.cfg, r.finder, r.authzChecker, authn.ForContext(ctx), fvid) + return actions.FeedVersionImport(ctx, r.cfg, r.finder, r.authzChecker, fvid) } func (r *mutationResolver) FeedVersionUnimport(ctx context.Context, fvid int) (*model.FeedVersionUnimportResult, error) { - return actions.FeedVersionUnimport(ctx, r.cfg, r.finder, r.authzChecker, authn.ForContext(ctx), fvid) + return actions.FeedVersionUnimport(ctx, r.cfg, r.finder, r.authzChecker, fvid) } func (r *mutationResolver) FeedVersionUpdate(ctx context.Context, fvid int, values model.FeedVersionSetInput) (*model.FeedVersion, error) { - err := actions.FeedVersionUpdate(ctx, r.cfg, r.finder, r.authzChecker, authn.ForContext(ctx), fvid, values) + err := actions.FeedVersionUpdate(ctx, r.cfg, r.finder, r.authzChecker, fvid, values) return nil, err } diff --git a/server/gql/mutation_resolver_test.go b/server/gql/mutation_resolver_test.go index 22946497..eb0bce0d 100644 --- a/server/gql/mutation_resolver_test.go +++ b/server/gql/mutation_resolver_test.go @@ -9,7 +9,7 @@ import ( "testing" "github.com/99designs/gqlgen/client" - "github.com/interline-io/transitland-server/auth/ancheck" + "github.com/interline-io/transitland-mw/auth/ancheck" "github.com/interline-io/transitland-server/internal/testfinder" "github.com/interline-io/transitland-server/internal/testutil" "github.com/interline-io/transitland-server/model" diff --git a/server/gql/query_resolver.go b/server/gql/query_resolver.go index 1247cd26..41175fc0 100644 --- a/server/gql/query_resolver.go +++ b/server/gql/query_resolver.go @@ -4,8 +4,8 @@ import ( "context" "errors" - "github.com/interline-io/transitland-server/auth/authz" - "github.com/interline-io/transitland-server/meters" + "github.com/interline-io/transitland-mw/auth/authz" + "github.com/interline-io/transitland-mw/meters" "github.com/interline-io/transitland-server/model" ) diff --git a/server/gql/resolver_test.go b/server/gql/resolver_test.go index 13c0f161..a5e7be86 100644 --- a/server/gql/resolver_test.go +++ b/server/gql/resolver_test.go @@ -8,8 +8,8 @@ import ( "time" "github.com/99designs/gqlgen/client" - "github.com/interline-io/transitland-server/auth/ancheck" - "github.com/interline-io/transitland-server/auth/authn" + "github.com/interline-io/transitland-mw/auth/ancheck" + "github.com/interline-io/transitland-mw/auth/authn" "github.com/interline-io/transitland-server/internal/clock" "github.com/interline-io/transitland-server/internal/testfinder" "github.com/interline-io/transitland-server/internal/testutil" diff --git a/server/gql/server.go b/server/gql/server.go index 3e146daf..1a05dec3 100644 --- a/server/gql/server.go +++ b/server/gql/server.go @@ -7,7 +7,7 @@ import ( "github.com/99designs/gqlgen/graphql" "github.com/99designs/gqlgen/graphql/handler" - "github.com/interline-io/transitland-server/auth/authn" + "github.com/interline-io/transitland-mw/auth/authn" "github.com/interline-io/transitland-server/config" "github.com/interline-io/transitland-server/internal/generated/gqlout" "github.com/interline-io/transitland-server/model" diff --git a/server/rest/feed_version_download.go b/server/rest/feed_version_download.go index fedf8725..4bf60751 100644 --- a/server/rest/feed_version_download.go +++ b/server/rest/feed_version_download.go @@ -11,8 +11,8 @@ import ( "github.com/interline-io/transitland-lib/dmfr/store" "github.com/interline-io/transitland-lib/tl" "github.com/interline-io/transitland-lib/tl/request" + "github.com/interline-io/transitland-mw/meters" "github.com/interline-io/transitland-server/internal/util" - "github.com/interline-io/transitland-server/meters" "github.com/tidwall/gjson" ) diff --git a/server/rest/feed_version_download_test.go b/server/rest/feed_version_download_test.go index 3949ba83..dacf6881 100644 --- a/server/rest/feed_version_download_test.go +++ b/server/rest/feed_version_download_test.go @@ -5,8 +5,8 @@ import ( "net/http/httptest" "testing" - "github.com/interline-io/transitland-server/auth/ancheck" - "github.com/interline-io/transitland-server/auth/authn" + "github.com/interline-io/transitland-mw/auth/ancheck" + "github.com/interline-io/transitland-mw/auth/authn" "github.com/interline-io/transitland-server/internal/testutil" ) diff --git a/server/rest/filecache.go b/server/rest/filecache.go index ae4a0c49..3a61b861 100644 --- a/server/rest/filecache.go +++ b/server/rest/filecache.go @@ -5,7 +5,7 @@ import ( "os" "github.com/hypirion/go-filecache" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" ) // local file cache diff --git a/server/rest/map.go b/server/rest/map.go index bd6d855e..dd62cedc 100644 --- a/server/rest/map.go +++ b/server/rest/map.go @@ -8,7 +8,7 @@ import ( sm "github.com/flopp/go-staticmaps" "github.com/golang/geo/s2" - "github.com/interline-io/transitland-lib/log" + "github.com/interline-io/log" "github.com/twpayne/go-geom" "github.com/twpayne/go-geom/encoding/geojson" ) diff --git a/server/rest/rest.go b/server/rest/rest.go index d13f3e10..8838ae2e 100644 --- a/server/rest/rest.go +++ b/server/rest/rest.go @@ -14,11 +14,11 @@ import ( "strings" "github.com/go-chi/chi/v5" - "github.com/interline-io/transitland-lib/log" - "github.com/interline-io/transitland-server/auth/ancheck" + "github.com/interline-io/log" + "github.com/interline-io/transitland-mw/auth/ancheck" + "github.com/interline-io/transitland-mw/meters" "github.com/interline-io/transitland-server/config" "github.com/interline-io/transitland-server/internal/util" - "github.com/interline-io/transitland-server/meters" "github.com/interline-io/transitland-server/model" ) diff --git a/server/server.go b/server/server.go deleted file mode 100644 index 58c8813a..00000000 --- a/server/server.go +++ /dev/null @@ -1,123 +0,0 @@ -package server - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "net/http" - "net/url" - "strconv" - "time" - - "github.com/go-redis/redis/v8" - "github.com/interline-io/transitland-lib/log" - "github.com/interline-io/transitland-server/auth/authn" -) - -// log request and duration -func LoggingMiddleware(longQueryDuration int) func(http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - t1 := time.Now() - userName := "" - if user := authn.ForContext(ctx); user != nil { - userName = user.ID() - } - // Get request body for logging if request is json and length under 20kb - var body []byte - if r.Header.Get("content-type") == "application/json" && r.ContentLength < 1024*20 { - body, _ = ioutil.ReadAll(r.Body) - r.Body = ioutil.NopCloser(bytes.NewBuffer(body)) - } - // Wrap context to get error code and errors - wr := wrapResponseWriter(w) - next.ServeHTTP(wr, r) - // Extra logging of request body if duration > 1s - durationMs := (time.Now().UnixNano() - t1.UnixNano()) / 1e6 - msg := log.Info(). - Int64("duration_ms", durationMs). - Str("method", r.Method). - Str("path", r.URL.EscapedPath()). - Str("query", r.URL.Query().Encode()). - Str("user", userName). - Int("status", wr.status) - // Add duration info - if durationMs > int64(longQueryDuration) { - // Verify it's valid json - msg = msg.Bool("long_query", true) - var x interface{} - if err := json.Unmarshal(body, &x); err == nil { - msg = msg.RawJSON("body", body) - } - } - // Get any GraphQL errors. We need to log these because the response - // code will always be 200. - // var gqlErrs []string - // if len(gqlErrs) > 0 { - // msg = msg.Strs("gql_errors", gqlErrs) - // } - msg.Msg("request") - }) - } -} - -func getRedisOpts(v string) (*redis.Options, error) { - a, err := url.Parse(v) - if err != nil { - return nil, err - } - if a.Scheme != "redis" { - return nil, errors.New("redis URL must begin with redis://") - } - port := a.Port() - if port == "" { - port = "6379" - } - addr := fmt.Sprintf("%s:%s", a.Hostname(), port) - dbNo := 0 - if len(a.Path) > 0 { - var err error - f := a.Path[1:len(a.Path)] - dbNo, err = strconv.Atoi(f) - if err != nil { - return nil, err - } - } - return &redis.Options{Addr: addr, DB: dbNo}, nil -} - -// https://blog.questionable.services/article/guide-logging-middleware-go/ -// responseWriter is a minimal wrapper for http.ResponseWriter that allows the -// written HTTP status code to be captured for logging. -type responseWriter struct { - status int - wroteHeader bool - http.ResponseWriter -} - -func wrapResponseWriter(w http.ResponseWriter) *responseWriter { - return &responseWriter{ResponseWriter: w} -} - -func (rw *responseWriter) Status() int { - return rw.status -} - -func (rw *responseWriter) WriteHeader(code int) { - if !rw.wroteHeader { - rw.status = code - rw.wroteHeader = true - } - rw.ResponseWriter.WriteHeader(code) -} - -func (rw *responseWriter) Write(response []byte) (int, error) { - if !rw.wroteHeader { - rw.status = http.StatusOK - rw.wroteHeader = true - } - return rw.ResponseWriter.Write(response) -} diff --git a/server/server_cmd.go b/server/server_cmd.go index 8d46768c..af31472a 100644 --- a/server/server_cmd.go +++ b/server/server_cmd.go @@ -6,23 +6,28 @@ import ( "flag" "fmt" "os/signal" + "strconv" "strings" "syscall" "time" "net/http" "net/http/pprof" + "net/url" "os" "github.com/go-chi/chi/middleware" "github.com/go-chi/chi/v5" "github.com/go-chi/cors" "github.com/go-redis/redis/v8" + "github.com/interline-io/log" "github.com/interline-io/transitland-lib/dmfr" - "github.com/interline-io/transitland-lib/log" "github.com/interline-io/transitland-lib/tl" - "github.com/interline-io/transitland-server/auth/ancheck" - "github.com/interline-io/transitland-server/auth/azcheck" + "github.com/interline-io/transitland-mw/auth/ancheck" + "github.com/interline-io/transitland-mw/auth/azcheck" + "github.com/interline-io/transitland-mw/lmw" + "github.com/interline-io/transitland-mw/meters" + "github.com/interline-io/transitland-mw/metrics" "github.com/interline-io/transitland-server/config" "github.com/interline-io/transitland-server/finders/dbfinder" "github.com/interline-io/transitland-server/finders/gbfsfinder" @@ -30,8 +35,6 @@ import ( "github.com/interline-io/transitland-server/internal/dbutil" "github.com/interline-io/transitland-server/internal/jobs" "github.com/interline-io/transitland-server/internal/playground" - "github.com/interline-io/transitland-server/meters" - "github.com/interline-io/transitland-server/metrics" "github.com/interline-io/transitland-server/model" "github.com/interline-io/transitland-server/server/gql" "github.com/interline-io/transitland-server/server/rest" @@ -252,7 +255,7 @@ func (cmd *Command) Run() error { } // Add logging middleware - must be after auth - root.Use(LoggingMiddleware(cmd.LongQueryDuration)) + root.Use(lmw.LoggingMiddleware(cmd.LongQueryDuration)) // Profiling if cmd.EnableProfiler { @@ -326,7 +329,7 @@ func (cmd *Command) Run() error { Config: cfg, } // Add metrics - jobQueue.Use(metrics.NewJobMiddleware("", metricProvider.NewJobMetric("default"))) + // jobQueue.Use(metrics.NewJobMiddleware("", metricProvider.NewJobMetric("default"))) if cmd.EnableWorkers { log.Infof("Enabling job workers") jobQueue.AddWorker("default", workers.GetWorker, jobOptions, jobWorkers) @@ -391,3 +394,28 @@ func (i *arrayFlags) Set(value string) error { *i = append(*i, value) return nil } + +func getRedisOpts(v string) (*redis.Options, error) { + a, err := url.Parse(v) + if err != nil { + return nil, err + } + if a.Scheme != "redis" { + return nil, errors.New("redis URL must begin with redis://") + } + port := a.Port() + if port == "" { + port = "6379" + } + addr := fmt.Sprintf("%s:%s", a.Hostname(), port) + dbNo := 0 + if len(a.Path) > 0 { + var err error + f := a.Path[1:len(a.Path)] + dbNo, err = strconv.Atoi(f) + if err != nil { + return nil, err + } + } + return &redis.Options{Addr: addr, DB: dbNo}, nil +} diff --git a/test_setup.sh b/test_setup.sh index 77c5650d..43c46e26 100755 --- a/test_setup.sh +++ b/test_setup.sh @@ -15,3 +15,4 @@ tlserver import -dburl="$TL_TEST_SERVER_DATABASE_URL" -storage="$TL_TEST_STORAGE tlserver sync -dburl="$TL_TEST_SERVER_DATABASE_URL" test/data/server/server-test.dmfr.json # supplemental data psql -f test_supplement.pgsql + diff --git a/workers/static_fetch_worker.go b/workers/static_fetch_worker.go index 42f0b9a2..0ba9596e 100644 --- a/workers/static_fetch_worker.go +++ b/workers/static_fetch_worker.go @@ -16,7 +16,7 @@ type StaticFetchWorker struct { func (w *StaticFetchWorker) Run(ctx context.Context, job jobs.Job) error { log := job.Opts.Logger.With().Str("feed_id", w.FeedID).Str("feed_url", w.FeedUrl).Logger() - if result, err := actions.StaticFetch(ctx, job.Opts.Config, job.Opts.Finder, w.FeedID, nil, w.FeedUrl, nil, nil); err != nil { + if result, err := actions.StaticFetch(ctx, job.Opts.Config, job.Opts.Finder, w.FeedID, nil, w.FeedUrl, nil); err != nil { log.Error().Err(err).Msg("staticfetch worker: request failed") return err } else if result.FetchError != nil {