diff --git a/users/client/cache.go b/users/client/cache.go index 1bb822f7a..52d2e6885 100644 --- a/users/client/cache.go +++ b/users/client/cache.go @@ -38,18 +38,18 @@ type CachingClientConfig struct { } type cachingClient struct { - users.UsersClient + users.AuthServiceClient probeCredCache gcache.Cache orgCredCache gcache.Cache userCache gcache.Cache } -func newCachingClient(cfg CachingClientConfig, client users.UsersClient) *cachingClient { +func newCachingClient(cfg CachingClientConfig, client users.AuthServiceClient) *cachingClient { return &cachingClient{ - UsersClient: client, - probeCredCache: gcache.New(cfg.ProbeCredCacheSize).LRU().Expiration(cfg.ProbeCredCacheExpiration).Build(), - orgCredCache: gcache.New(cfg.OrgCredCacheSize).LRU().Expiration(cfg.OrgCredCacheExpiration).Build(), - userCache: gcache.New(cfg.UserCacheSize).LRU().Expiration(cfg.UserCacheExpiration).Build(), + AuthServiceClient: client, + probeCredCache: gcache.New(cfg.ProbeCredCacheSize).LRU().Expiration(cfg.ProbeCredCacheExpiration).Build(), + orgCredCache: gcache.New(cfg.OrgCredCacheSize).LRU().Expiration(cfg.OrgCredCacheExpiration).Build(), + userCache: gcache.New(cfg.UserCacheSize).LRU().Expiration(cfg.UserCacheExpiration).Build(), } } @@ -59,9 +59,9 @@ type cacheValue struct { } // LookupOrg authenticates a cookie for access to an org by extenal ID. -func (c *cachingClient) LookupOrg(ctx context.Context, in *users.LookupOrgRequest, opts ...grpc.CallOption) (*users.LookupOrgResponse, error) { +func (c *cachingClient) AuthUserForOrg(ctx context.Context, in *users.LookupOrgRequest, opts ...grpc.CallOption) (*users.LookupOrgResponse, error) { if c.orgCredCache == nil { - return c.UsersClient.LookupOrg(ctx, in, opts...) + return c.AuthServiceClient.AuthUserForOrg(ctx, in, opts...) } org, err := c.orgCredCache.Get(*in) @@ -70,7 +70,7 @@ func (c *cachingClient) LookupOrg(ctx context.Context, in *users.LookupOrgReques return org.(cacheValue).out.(*users.LookupOrgResponse), org.(cacheValue).err } - out, err := c.UsersClient.LookupOrg(ctx, in, opts...) + out, err := c.AuthServiceClient.AuthUserForOrg(ctx, in, opts...) if err == nil || isErrorCachable(err) { c.orgCredCache.Set(*in, cacheValue{out, err}) } @@ -78,9 +78,9 @@ func (c *cachingClient) LookupOrg(ctx context.Context, in *users.LookupOrgReques } // LookupUsingToken authenticates a token for access to an org. -func (c *cachingClient) LookupUsingToken(ctx context.Context, in *users.LookupUsingTokenRequest, opts ...grpc.CallOption) (*users.LookupUsingTokenResponse, error) { +func (c *cachingClient) AuthTokenForOrg(ctx context.Context, in *users.LookupUsingTokenRequest, opts ...grpc.CallOption) (*users.LookupUsingTokenResponse, error) { if c.probeCredCache == nil { - return c.UsersClient.LookupUsingToken(ctx, in, opts...) + return c.AuthServiceClient.AuthTokenForOrg(ctx, in, opts...) } org, err := c.probeCredCache.Get(*in) @@ -89,7 +89,7 @@ func (c *cachingClient) LookupUsingToken(ctx context.Context, in *users.LookupUs return org.(cacheValue).out.(*users.LookupUsingTokenResponse), org.(cacheValue).err } - out, err := c.UsersClient.LookupUsingToken(ctx, in, opts...) + out, err := c.AuthServiceClient.AuthTokenForOrg(ctx, in, opts...) if err == nil || isErrorCachable(err) { c.probeCredCache.Set(*in, cacheValue{out, err}) } @@ -98,7 +98,7 @@ func (c *cachingClient) LookupUsingToken(ctx context.Context, in *users.LookupUs func (c *cachingClient) GetUser(ctx context.Context, in *users.GetUserRequest, opts ...grpc.CallOption) (*users.GetUserResponse, error) { if c.userCache == nil { - return c.UsersClient.GetUser(ctx, in, opts...) + return c.AuthServiceClient.GetUser(ctx, in, opts...) } out, err := c.userCache.Get(*in) @@ -107,7 +107,7 @@ func (c *cachingClient) GetUser(ctx context.Context, in *users.GetUserRequest, o return out.(*users.GetUserResponse), nil } - out, err = c.UsersClient.GetUser(ctx, in, opts...) + out, err = c.AuthServiceClient.GetUser(ctx, in, opts...) if err == nil { c.userCache.Set(*in, out) } diff --git a/users/client/client.go b/users/client/client.go index 5ceb4f67e..effbf9a1d 100644 --- a/users/client/client.go +++ b/users/client/client.go @@ -12,31 +12,33 @@ import ( ) // New is a factory for Authenticators -func New(kind, address string, opts CachingClientConfig) (users.UsersClient, error) { - var client users.UsersClient +func New(kind, address string, opts CachingClientConfig) (users.UsersClient, users.AuthServiceClient, error) { + var usersClient users.UsersClient + var authClient users.AuthServiceClient var err error switch kind { case "mock": - client = MockClient{} + usersClient = MockClient{} + authClient = MockAuthClient{} case "grpc": - client, err = newGRPCClient(address) + usersClient, authClient, err = newGRPCClient(address) if err != nil { - return nil, err + return nil, nil, err } default: log.Fatal("Incorrect authenticator type: ", kind) - return nil, nil + return nil, nil, nil } if opts.CacheEnabled { - client = newCachingClient(opts, client) + authClient = newCachingClient(opts, authClient) } - return client, nil + return usersClient, authClient, nil } -func newGRPCClient(address string) (users.UsersClient, error) { +func newGRPCClient(address string) (users.UsersClient, users.AuthServiceClient, error) { address, dialOptions, err := httpgrpc_server.ParseURL(address) if err != nil { - return nil, err + return nil, nil, err } dialOptions = append(dialOptions, @@ -51,7 +53,7 @@ func newGRPCClient(address string) (users.UsersClient, error) { dialOptions..., ) if err != nil { - return nil, err + return nil, nil, err } - return users.NewUsersClient(conn), nil + return users.NewUsersClient(conn), users.NewAuthServiceClient(conn), nil } diff --git a/users/client/middleware.go b/users/client/middleware.go index 44ed7f955..80209c4e7 100644 --- a/users/client/middleware.go +++ b/users/client/middleware.go @@ -44,8 +44,8 @@ const ( // AuthOrgMiddleware is a middleware.Interface for authentication organisations based on the // cookie and an org name in the path type AuthOrgMiddleware struct { - UsersClient users.UsersClient - OrgExternalID func(*http.Request) (string, bool) + AuthServiceClient users.AuthServiceClient + OrgExternalID func(*http.Request) (string, bool) UserIDHeader string FeatureFlagsHeader string @@ -72,7 +72,7 @@ func (a AuthOrgMiddleware) Wrap(next http.Handler) http.Handler { return } - response, err := a.UsersClient.LookupOrg(ctx, &users.LookupOrgRequest{ + response, err := a.AuthServiceClient.AuthUserForOrg(ctx, &users.LookupOrgRequest{ Cookie: authCookie.Value, OrgExternalID: orgExternalID, AuthorizeFor: a.AuthorizeFor, @@ -103,7 +103,7 @@ func (a AuthOrgMiddleware) Wrap(next http.Handler) http.Handler { // AuthProbeMiddleware is a middleware.Interface for authentication probes based on the headers type AuthProbeMiddleware struct { - UsersClient users.UsersClient + AuthServiceClient users.AuthServiceClient FeatureFlagsHeader string RequireFeatureFlags []string AuthorizeFor users.AuthorizedAction @@ -121,7 +121,7 @@ func (a AuthProbeMiddleware) Wrap(next http.Handler) http.Handler { return } - response, err := a.UsersClient.LookupUsingToken(ctx, &users.LookupUsingTokenRequest{ + response, err := a.AuthServiceClient.AuthTokenForOrg(ctx, &users.LookupUsingTokenRequest{ Token: token, AuthorizeFor: a.AuthorizeFor, }) @@ -149,7 +149,7 @@ func (a AuthProbeMiddleware) Wrap(next http.Handler) http.Handler { // AuthAdminMiddleware is a middleware.Interface for authentication probes based on the headers type AuthAdminMiddleware struct { - UsersClient users.UsersClient + AuthServiceClient users.AuthServiceClient } // Wrap implements middleware.Interface @@ -164,7 +164,7 @@ func (a AuthAdminMiddleware) Wrap(next http.Handler) http.Handler { return } - response, err := a.UsersClient.LookupAdmin(ctx, &users.LookupAdminRequest{ + response, err := a.AuthServiceClient.AuthUserForAdmin(ctx, &users.LookupAdminRequest{ Cookie: authCookie.Value, }) if err != nil { @@ -182,7 +182,7 @@ func (a AuthAdminMiddleware) Wrap(next http.Handler) http.Handler { // AuthUserMiddleware is a middleware.Interface for authentication users based on the // cookie (and not to any specific org) type AuthUserMiddleware struct { - UsersClient users.UsersClient + AuthServiceClient users.AuthServiceClient UserIDHeader string RequireFeatureFlags []string } @@ -198,7 +198,7 @@ func (a AuthUserMiddleware) Wrap(next http.Handler) http.Handler { return } - response, err := a.UsersClient.LookupUser(ctx, &users.LookupUserRequest{ + response, err := a.AuthServiceClient.AuthUser(ctx, &users.LookupUserRequest{ Cookie: authCookie.Value, }) @@ -352,6 +352,7 @@ func validateGCPExternalAccountID(externalAccountID string) (string, error) { // WebhooksMiddleware is a middleware.Interface for authentication request based // on the webhook secret (and signing key if one exists). type WebhooksMiddleware struct { + AuthServiceClient users.AuthServiceClient UsersClient users.UsersClient WebhooksIntegrationTypeHeader string } @@ -362,7 +363,7 @@ func (a WebhooksMiddleware) Wrap(next http.Handler) http.Handler { secretID := mux.Vars(r)["secretID"] // Verify the secretID - response, err := a.UsersClient.LookupOrganizationWebhookUsingSecretID(r.Context(), &users.LookupOrganizationWebhookUsingSecretIDRequest{ + response, err := a.AuthServiceClient.AuthWebhookSecretForOrg(r.Context(), &users.LookupOrganizationWebhookUsingSecretIDRequest{ SecretID: secretID, }) if err != nil { diff --git a/users/client/mock_client.go b/users/client/mock_client.go index 50881271f..1c9444567 100644 --- a/users/client/mock_client.go +++ b/users/client/mock_client.go @@ -1,44 +1,58 @@ package client import ( + "errors" + "golang.org/x/net/context" "google.golang.org/grpc" "github.com/weaveworks/service/users" ) -// MockClient is a mock usersClient that can be used in testing -type MockClient struct{} +// MockAuthClient is a mock users.AuthServiceClient that can be used in testing +type MockAuthClient struct{} -// LookupOrg authenticates a cookie for access to an org by external ID. -func (MockClient) LookupOrg(ctx context.Context, in *users.LookupOrgRequest, opts ...grpc.CallOption) (*users.LookupOrgResponse, error) { +var _ users.AuthServiceClient = &MockAuthClient{} + +// AuthUserForOrg authenticates a cookie for access to an org by external ID. +func (MockAuthClient) AuthUserForOrg(ctx context.Context, in *users.LookupOrgRequest, opts ...grpc.CallOption) (*users.LookupOrgResponse, error) { return &users.LookupOrgResponse{ OrganizationID: "mockID", UserID: "mockUserID", }, nil } -// LookupUsingToken authenticates a token for access to an org. -func (MockClient) LookupUsingToken(ctx context.Context, in *users.LookupUsingTokenRequest, opts ...grpc.CallOption) (*users.LookupUsingTokenResponse, error) { +// AuthTokenForOrg authenticates a token for access to an org. +func (MockAuthClient) AuthTokenForOrg(ctx context.Context, in *users.LookupUsingTokenRequest, opts ...grpc.CallOption) (*users.LookupUsingTokenResponse, error) { return &users.LookupUsingTokenResponse{ OrganizationID: "mockID", }, nil } -// LookupAdmin authenticates a cookie for admin access. -func (MockClient) LookupAdmin(ctx context.Context, in *users.LookupAdminRequest, opts ...grpc.CallOption) (*users.LookupAdminResponse, error) { +// AuthUserForAdmin authenticates a cookie for admin access. +func (MockAuthClient) AuthUserForAdmin(ctx context.Context, in *users.LookupAdminRequest, opts ...grpc.CallOption) (*users.LookupAdminResponse, error) { return &users.LookupAdminResponse{ AdminID: "mockUserID", }, nil } -// LookupUser authenticates a cookie. -func (MockClient) LookupUser(ctx context.Context, in *users.LookupUserRequest, opts ...grpc.CallOption) (*users.LookupUserResponse, error) { +// AuthUser authenticates a cookie. +func (MockAuthClient) AuthUser(ctx context.Context, in *users.LookupUserRequest, opts ...grpc.CallOption) (*users.LookupUserResponse, error) { return &users.LookupUserResponse{ UserID: "mockUserID", }, nil } +// AuthWebhookSecretForOrg gets the webhook given the external org ID and the secret ID of the webhook. +func (MockAuthClient) AuthWebhookSecretForOrg(ctx context.Context, in *users.LookupOrganizationWebhookUsingSecretIDRequest, opts ...grpc.CallOption) (*users.LookupOrganizationWebhookUsingSecretIDResponse, error) { + return &users.LookupOrganizationWebhookUsingSecretIDResponse{}, nil +} + +// MockClient is a mock usersClient that can be used in testing +type MockClient struct{} + +var _ users.UsersClient = &MockClient{} + // GetOrganizations gets the organizations for a user func (MockClient) GetOrganizations(ctx context.Context, in *users.GetOrganizationsRequest, opts ...grpc.CallOption) (*users.GetOrganizationsResponse, error) { return &users.GetOrganizationsResponse{}, nil @@ -125,12 +139,34 @@ func (MockClient) GetSummary(ctx context.Context, in *users.Empty, opts ...grpc. return &users.Summary{}, nil } -// LookupOrganizationWebhookUsingSecretID gets the webhook given the external org ID and the secret ID of the webhook. -func (MockClient) LookupOrganizationWebhookUsingSecretID(ctx context.Context, in *users.LookupOrganizationWebhookUsingSecretIDRequest, opts ...grpc.CallOption) (*users.LookupOrganizationWebhookUsingSecretIDResponse, error) { - return &users.LookupOrganizationWebhookUsingSecretIDResponse{}, nil -} - // SetOrganizationWebhookFirstSeenAt sets the FirstSeenAt field on the webhook to the current time func (MockClient) SetOrganizationWebhookFirstSeenAt(ctx context.Context, in *users.SetOrganizationWebhookFirstSeenAtRequest, opts ...grpc.CallOption) (*users.SetOrganizationWebhookFirstSeenAtResponse, error) { return &users.SetOrganizationWebhookFirstSeenAtResponse{}, nil } + +var errLegacy = errors.New("Legacy mocks methods, to be removed once we remove these from the proto file") + +// LookupOrg authenticates a cookie for access to an org by external ID. +func (MockClient) LookupOrg(ctx context.Context, in *users.LookupOrgRequest, opts ...grpc.CallOption) (*users.LookupOrgResponse, error) { + return nil, errLegacy +} + +// LookupUsingToken authenticates a token for access to an org. +func (MockClient) LookupUsingToken(ctx context.Context, in *users.LookupUsingTokenRequest, opts ...grpc.CallOption) (*users.LookupUsingTokenResponse, error) { + return nil, errLegacy +} + +// LookupAdmin authenticates a cookie for admin access. +func (MockClient) LookupAdmin(ctx context.Context, in *users.LookupAdminRequest, opts ...grpc.CallOption) (*users.LookupAdminResponse, error) { + return nil, errLegacy +} + +// LookupUser authenticates a cookie. +func (MockClient) LookupUser(ctx context.Context, in *users.LookupUserRequest, opts ...grpc.CallOption) (*users.LookupUserResponse, error) { + return nil, errLegacy +} + +// LookupOrganizationWebhookUsingSecretID gets the webhook given the external org ID and the secret ID of the webhook. +func (MockClient) LookupOrganizationWebhookUsingSecretID(ctx context.Context, in *users.LookupOrganizationWebhookUsingSecretIDRequest, opts ...grpc.CallOption) (*users.LookupOrganizationWebhookUsingSecretIDResponse, error) { + return nil, errLegacy +} diff --git a/users/grpc/auth.go b/users/grpc/auth.go new file mode 100644 index 000000000..7d786dc7c --- /dev/null +++ b/users/grpc/auth.go @@ -0,0 +1,114 @@ +package grpc + +import ( + "errors" + "fmt" + "strings" + "time" + + "github.com/weaveworks/service/common/featureflag" + "github.com/weaveworks/service/common/orgs" + + "github.com/weaveworks/service/users" + "github.com/weaveworks/service/users/db" + "github.com/weaveworks/service/users/db/filter" + "github.com/weaveworks/service/users/emailer" + "github.com/weaveworks/service/users/sessions" + "golang.org/x/net/context" +) + +// AuthUserForOrg authenticates a cookie for access to an org by external ID. +func (a *usersServer) AuthUserForOrg(ctx context.Context, req *users.LookupOrgRequest) (*users.LookupOrgResponse, error) { + session, err := a.sessions.Decode(req.Cookie) + if err != nil { + return nil, err + } + + organizations, err := a.db.ListOrganizationsForUserIDs(ctx, session.UserID) + if err == users.ErrNotFound { + err = users.ErrInvalidAuthenticationData + } + if err != nil { + return nil, err + } + for _, org := range organizations { + if strings.ToLower(org.ExternalID) == strings.ToLower(req.OrgExternalID) { + err := authorizeAction(req.AuthorizeFor, org) + if err != nil { + return nil, err + } + + return &users.LookupOrgResponse{ + OrganizationID: org.ID, + UserID: session.UserID, + FeatureFlags: org.FeatureFlags, + }, nil + } + } + return nil, users.ErrInvalidAuthenticationData +} + +// AuthUserForAdmin authenticates a cookie for admin access. +func (a *usersServer) AuthUserForAdmin(ctx context.Context, req *users.LookupAdminRequest) (*users.LookupAdminResponse, error) { + session, err := a.sessions.Decode(req.Cookie) + if err != nil { + return nil, err + } + u, err := a.db.FindUserByID(ctx, session.UserID) + if err == users.ErrNotFound { + err = users.ErrInvalidAuthenticationData + } + if err != nil { + return nil, err + } + if !u.Admin { + return nil, users.ErrInvalidAuthenticationData + } + return &users.LookupAdminResponse{ + AdminID: u.ID, + }, nil +} + +// AuthUserForOrg authenticates a token for access to an org. +func (a *usersServer) AuthUserForOrg(ctx context.Context, req *users.LookupUsingTokenRequest) (*users.LookupUsingTokenResponse, error) { + o, err := a.db.FindOrganizationByProbeToken(ctx, req.Token) + if err == users.ErrNotFound { + err = users.ErrInvalidAuthenticationData + } + if err != nil { + return nil, err + } + err = authorizeAction(req.AuthorizeFor, o) + if err != nil { + return nil, err + } + return &users.LookupUsingTokenResponse{ + OrganizationID: o.ID, + FeatureFlags: o.FeatureFlags, + }, nil +} + +// AuthUser authenticates a cookie. +func (a *usersServer) AuthUser(ctx context.Context, req *users.LookupUserRequest) (*users.LookupUserResponse, error) { + session, err := a.sessions.Decode(req.Cookie) + if err != nil { + return nil, err + } + return &users.LookupUserResponse{ + UserID: session.UserID, + }, nil +} + +// AuthWebhookSecretForOrg gets the webhook given the external org ID and the secret ID of the webhook. +func (a *usersServer) AuthWebhookSecretForOrg(ctx context.Context, req *users.LookupOrganizationWebhookUsingSecretIDRequest) (*users.LookupOrganizationWebhookUsingSecretIDResponse, error) { + webhook, err := a.db.FindOrganizationWebhookBySecretID(ctx, req.SecretID) + if err == users.ErrNotFound { + err = httpgrpc.Errorf(http.StatusNotFound, "Webhook does not exist.") + } + if err != nil { + return nil, err + } + return &users.LookupOrganizationWebhookUsingSecretIDResponse{ + Webhook: webhook, + }, nil +} diff --git a/users/grpc/lookup.go b/users/grpc/users.go similarity index 86% rename from users/grpc/lookup.go rename to users/grpc/users.go index 6bec8e2be..4e6e36d04 100644 --- a/users/grpc/lookup.go +++ b/users/grpc/users.go @@ -48,88 +48,30 @@ func authorizeAction(action users.AuthorizedAction, org *users.Organization) err return nil } +/** LEGACY remove these after all clients in production are upgraded **/ + // LookupOrg authenticates a cookie for access to an org by external ID. func (a *usersServer) LookupOrg(ctx context.Context, req *users.LookupOrgRequest) (*users.LookupOrgResponse, error) { - session, err := a.sessions.Decode(req.Cookie) - if err != nil { - return nil, err - } - - organizations, err := a.db.ListOrganizationsForUserIDs(ctx, session.UserID) - if err == users.ErrNotFound { - err = users.ErrInvalidAuthenticationData - } - if err != nil { - return nil, err - } - for _, org := range organizations { - if strings.ToLower(org.ExternalID) == strings.ToLower(req.OrgExternalID) { - err := authorizeAction(req.AuthorizeFor, org) - if err != nil { - return nil, err - } - - return &users.LookupOrgResponse{ - OrganizationID: org.ID, - UserID: session.UserID, - FeatureFlags: org.FeatureFlags, - }, nil - } - } - return nil, users.ErrInvalidAuthenticationData + return a.AuthUserForOrg(ctx, req) } // LookupAdmin authenticates a cookie for admin access. func (a *usersServer) LookupAdmin(ctx context.Context, req *users.LookupAdminRequest) (*users.LookupAdminResponse, error) { - session, err := a.sessions.Decode(req.Cookie) - if err != nil { - return nil, err - } - u, err := a.db.FindUserByID(ctx, session.UserID) - if err == users.ErrNotFound { - err = users.ErrInvalidAuthenticationData - } - if err != nil { - return nil, err - } - if !u.Admin { - return nil, users.ErrInvalidAuthenticationData - } - return &users.LookupAdminResponse{ - AdminID: u.ID, - }, nil + return a.AuthUserForAdmin(ctx, req) } // LookupUsingToken authenticates a token for access to an org. func (a *usersServer) LookupUsingToken(ctx context.Context, req *users.LookupUsingTokenRequest) (*users.LookupUsingTokenResponse, error) { - o, err := a.db.FindOrganizationByProbeToken(ctx, req.Token) - if err == users.ErrNotFound { - err = users.ErrInvalidAuthenticationData - } - if err != nil { - return nil, err - } - err = authorizeAction(req.AuthorizeFor, o) - if err != nil { - return nil, err - } - return &users.LookupUsingTokenResponse{ - OrganizationID: o.ID, - FeatureFlags: o.FeatureFlags, - }, nil + return a.AuthTokenForOrg(ctx, req) } // LookupUser authenticates a cookie. func (a *usersServer) LookupUser(ctx context.Context, req *users.LookupUserRequest) (*users.LookupUserResponse, error) { - session, err := a.sessions.Decode(req.Cookie) - if err != nil { - return nil, err - } - return &users.LookupUserResponse{ - UserID: session.UserID, - }, nil + return a.AuthUser(ctx, req) } +/** END LEGACY **/ + func (a *usersServer) GetOrganizations(ctx context.Context, req *users.GetOrganizationsRequest) (*users.GetOrganizationsResponse, error) { fs := []filter.Filter{} if req.Query != "" { diff --git a/users/grpc/lookup_test.go b/users/grpc/users_test.go similarity index 100% rename from users/grpc/lookup_test.go rename to users/grpc/users_test.go diff --git a/users/grpc/webhooks.go b/users/grpc/webhooks.go index c51d2078a..e16dbddd5 100644 --- a/users/grpc/webhooks.go +++ b/users/grpc/webhooks.go @@ -8,20 +8,14 @@ import ( "golang.org/x/net/context" ) +/** LEGACY remove these after deployment **/ // LookupOrganizationWebhookUsingSecretID gets the webhook given the external org ID and the secret ID of the webhook. func (a *usersServer) LookupOrganizationWebhookUsingSecretID(ctx context.Context, req *users.LookupOrganizationWebhookUsingSecretIDRequest) (*users.LookupOrganizationWebhookUsingSecretIDResponse, error) { - webhook, err := a.db.FindOrganizationWebhookBySecretID(ctx, req.SecretID) - if err == users.ErrNotFound { - err = httpgrpc.Errorf(http.StatusNotFound, "Webhook does not exist.") - } - if err != nil { - return nil, err - } - return &users.LookupOrganizationWebhookUsingSecretIDResponse{ - Webhook: webhook, - }, nil + return a.AuthWebhookSecretForOrg(ctx, req) } +/** END LEGACY **/ + // LookupOrganizationWebhookUsingSecretID gets the webhook given the external org ID and the secret ID of the webhook. func (a *usersServer) SetOrganizationWebhookFirstSeenAt(ctx context.Context, req *users.SetOrganizationWebhookFirstSeenAtRequest) (*users.SetOrganizationWebhookFirstSeenAtResponse, error) { firstSeenAt, err := a.db.SetOrganizationWebhookFirstSeenAt(ctx, req.SecretID) diff --git a/users/users.pb.go b/users/users.pb.go index c5bd3a877..8659a3d4c 100644 --- a/users/users.pb.go +++ b/users/users.pb.go @@ -4152,6 +4152,8 @@ type UsersClient interface { LookupAdmin(ctx context.Context, in *LookupAdminRequest, opts ...grpc.CallOption) (*LookupAdminResponse, error) // LookupUser authenticates a cookie. LookupUser(ctx context.Context, in *LookupUserRequest, opts ...grpc.CallOption) (*LookupUserResponse, error) + // LookupOrganizationWebhookUsingSecretID returns a Webhook given the external org ID and the webhook secret ID + LookupOrganizationWebhookUsingSecretID(ctx context.Context, in *LookupOrganizationWebhookUsingSecretIDRequest, opts ...grpc.CallOption) (*LookupOrganizationWebhookUsingSecretIDResponse, error) // GetOrganizations returns a list of all organizations by default. See // GetOrganizationsRequest for more details. GetOrganizations(ctx context.Context, in *GetOrganizationsRequest, opts ...grpc.CallOption) (*GetOrganizationsResponse, error) @@ -4191,8 +4193,6 @@ type UsersClient interface { // GetSummary exports a summary of the DB. // WARNING: this is a relatively expensive query, and basically exports the entire DB. GetSummary(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Summary, error) - // LookupOrganizationWebhookUsingSecretID returns a Webhook given the external org ID and the webhook secret ID - LookupOrganizationWebhookUsingSecretID(ctx context.Context, in *LookupOrganizationWebhookUsingSecretIDRequest, opts ...grpc.CallOption) (*LookupOrganizationWebhookUsingSecretIDResponse, error) // SetOrganizationWebhookFirstSeenAt sets the FirstSeenAt field on the webhook to the current time SetOrganizationWebhookFirstSeenAt(ctx context.Context, in *SetOrganizationWebhookFirstSeenAtRequest, opts ...grpc.CallOption) (*SetOrganizationWebhookFirstSeenAtResponse, error) } @@ -4241,6 +4241,15 @@ func (c *usersClient) LookupUser(ctx context.Context, in *LookupUserRequest, opt return out, nil } +func (c *usersClient) LookupOrganizationWebhookUsingSecretID(ctx context.Context, in *LookupOrganizationWebhookUsingSecretIDRequest, opts ...grpc.CallOption) (*LookupOrganizationWebhookUsingSecretIDResponse, error) { + out := new(LookupOrganizationWebhookUsingSecretIDResponse) + err := grpc.Invoke(ctx, "/users.Users/LookupOrganizationWebhookUsingSecretID", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *usersClient) GetOrganizations(ctx context.Context, in *GetOrganizationsRequest, opts ...grpc.CallOption) (*GetOrganizationsResponse, error) { out := new(GetOrganizationsResponse) err := grpc.Invoke(ctx, "/users.Users/GetOrganizations", in, out, c.cc, opts...) @@ -4367,15 +4376,6 @@ func (c *usersClient) GetSummary(ctx context.Context, in *Empty, opts ...grpc.Ca return out, nil } -func (c *usersClient) LookupOrganizationWebhookUsingSecretID(ctx context.Context, in *LookupOrganizationWebhookUsingSecretIDRequest, opts ...grpc.CallOption) (*LookupOrganizationWebhookUsingSecretIDResponse, error) { - out := new(LookupOrganizationWebhookUsingSecretIDResponse) - err := grpc.Invoke(ctx, "/users.Users/LookupOrganizationWebhookUsingSecretID", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *usersClient) SetOrganizationWebhookFirstSeenAt(ctx context.Context, in *SetOrganizationWebhookFirstSeenAtRequest, opts ...grpc.CallOption) (*SetOrganizationWebhookFirstSeenAtResponse, error) { out := new(SetOrganizationWebhookFirstSeenAtResponse) err := grpc.Invoke(ctx, "/users.Users/SetOrganizationWebhookFirstSeenAt", in, out, c.cc, opts...) @@ -4396,6 +4396,8 @@ type UsersServer interface { LookupAdmin(context.Context, *LookupAdminRequest) (*LookupAdminResponse, error) // LookupUser authenticates a cookie. LookupUser(context.Context, *LookupUserRequest) (*LookupUserResponse, error) + // LookupOrganizationWebhookUsingSecretID returns a Webhook given the external org ID and the webhook secret ID + LookupOrganizationWebhookUsingSecretID(context.Context, *LookupOrganizationWebhookUsingSecretIDRequest) (*LookupOrganizationWebhookUsingSecretIDResponse, error) // GetOrganizations returns a list of all organizations by default. See // GetOrganizationsRequest for more details. GetOrganizations(context.Context, *GetOrganizationsRequest) (*GetOrganizationsResponse, error) @@ -4435,8 +4437,6 @@ type UsersServer interface { // GetSummary exports a summary of the DB. // WARNING: this is a relatively expensive query, and basically exports the entire DB. GetSummary(context.Context, *Empty) (*Summary, error) - // LookupOrganizationWebhookUsingSecretID returns a Webhook given the external org ID and the webhook secret ID - LookupOrganizationWebhookUsingSecretID(context.Context, *LookupOrganizationWebhookUsingSecretIDRequest) (*LookupOrganizationWebhookUsingSecretIDResponse, error) // SetOrganizationWebhookFirstSeenAt sets the FirstSeenAt field on the webhook to the current time SetOrganizationWebhookFirstSeenAt(context.Context, *SetOrganizationWebhookFirstSeenAtRequest) (*SetOrganizationWebhookFirstSeenAtResponse, error) } @@ -4517,6 +4517,24 @@ func _Users_LookupUser_Handler(srv interface{}, ctx context.Context, dec func(in return interceptor(ctx, in, info, handler) } +func _Users_LookupOrganizationWebhookUsingSecretID_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LookupOrganizationWebhookUsingSecretIDRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UsersServer).LookupOrganizationWebhookUsingSecretID(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/users.Users/LookupOrganizationWebhookUsingSecretID", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UsersServer).LookupOrganizationWebhookUsingSecretID(ctx, req.(*LookupOrganizationWebhookUsingSecretIDRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Users_GetOrganizations_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetOrganizationsRequest) if err := dec(in); err != nil { @@ -4769,24 +4787,6 @@ func _Users_GetSummary_Handler(srv interface{}, ctx context.Context, dec func(in return interceptor(ctx, in, info, handler) } -func _Users_LookupOrganizationWebhookUsingSecretID_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(LookupOrganizationWebhookUsingSecretIDRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UsersServer).LookupOrganizationWebhookUsingSecretID(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/users.Users/LookupOrganizationWebhookUsingSecretID", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UsersServer).LookupOrganizationWebhookUsingSecretID(ctx, req.(*LookupOrganizationWebhookUsingSecretIDRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _Users_SetOrganizationWebhookFirstSeenAt_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(SetOrganizationWebhookFirstSeenAtRequest) if err := dec(in); err != nil { @@ -4825,6 +4825,10 @@ var _Users_serviceDesc = grpc.ServiceDesc{ MethodName: "LookupUser", Handler: _Users_LookupUser_Handler, }, + { + MethodName: "LookupOrganizationWebhookUsingSecretID", + Handler: _Users_LookupOrganizationWebhookUsingSecretID_Handler, + }, { MethodName: "GetOrganizations", Handler: _Users_GetOrganizations_Handler, @@ -4881,10 +4885,6 @@ var _Users_serviceDesc = grpc.ServiceDesc{ MethodName: "GetSummary", Handler: _Users_GetSummary_Handler, }, - { - MethodName: "LookupOrganizationWebhookUsingSecretID", - Handler: _Users_LookupOrganizationWebhookUsingSecretID_Handler, - }, { MethodName: "SetOrganizationWebhookFirstSeenAt", Handler: _Users_SetOrganizationWebhookFirstSeenAt_Handler, @@ -4894,6 +4894,212 @@ var _Users_serviceDesc = grpc.ServiceDesc{ Metadata: "users.proto", } +// Client API for AuthService service + +type AuthServiceClient interface { + // AuthUser authenticates a cookie for validity. + AuthUser(ctx context.Context, in *LookupUserRequest, opts ...grpc.CallOption) (*LookupUserResponse, error) + // AuthUserOrgRequest authenticates & authorizes a cookie for access to an org by extenal ID. + AuthUserForOrg(ctx context.Context, in *LookupOrgRequest, opts ...grpc.CallOption) (*LookupOrgResponse, error) + // AuthTokenForOrg authenticates & authorizes a token for access to an org. + AuthTokenForOrg(ctx context.Context, in *LookupUsingTokenRequest, opts ...grpc.CallOption) (*LookupUsingTokenResponse, error) + // AuthWebhookSecretForOrg returns a Webhook given the external org ID and the webhook secret ID + AuthWebhookSecretForOrg(ctx context.Context, in *LookupOrganizationWebhookUsingSecretIDRequest, opts ...grpc.CallOption) (*LookupOrganizationWebhookUsingSecretIDResponse, error) + // AuthUserForAdmin authenticates & authorizes a cookie for weave cloud admin access. + AuthUserForAdmin(ctx context.Context, in *LookupAdminRequest, opts ...grpc.CallOption) (*LookupAdminResponse, error) +} + +type authServiceClient struct { + cc *grpc.ClientConn +} + +func NewAuthServiceClient(cc *grpc.ClientConn) AuthServiceClient { + return &authServiceClient{cc} +} + +func (c *authServiceClient) AuthUser(ctx context.Context, in *LookupUserRequest, opts ...grpc.CallOption) (*LookupUserResponse, error) { + out := new(LookupUserResponse) + err := grpc.Invoke(ctx, "/users.AuthService/AuthUser", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) AuthUserForOrg(ctx context.Context, in *LookupOrgRequest, opts ...grpc.CallOption) (*LookupOrgResponse, error) { + out := new(LookupOrgResponse) + err := grpc.Invoke(ctx, "/users.AuthService/AuthUserForOrg", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) AuthTokenForOrg(ctx context.Context, in *LookupUsingTokenRequest, opts ...grpc.CallOption) (*LookupUsingTokenResponse, error) { + out := new(LookupUsingTokenResponse) + err := grpc.Invoke(ctx, "/users.AuthService/AuthTokenForOrg", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) AuthWebhookSecretForOrg(ctx context.Context, in *LookupOrganizationWebhookUsingSecretIDRequest, opts ...grpc.CallOption) (*LookupOrganizationWebhookUsingSecretIDResponse, error) { + out := new(LookupOrganizationWebhookUsingSecretIDResponse) + err := grpc.Invoke(ctx, "/users.AuthService/AuthWebhookSecretForOrg", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) AuthUserForAdmin(ctx context.Context, in *LookupAdminRequest, opts ...grpc.CallOption) (*LookupAdminResponse, error) { + out := new(LookupAdminResponse) + err := grpc.Invoke(ctx, "/users.AuthService/AuthUserForAdmin", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for AuthService service + +type AuthServiceServer interface { + // AuthUser authenticates a cookie for validity. + AuthUser(context.Context, *LookupUserRequest) (*LookupUserResponse, error) + // AuthUserOrgRequest authenticates & authorizes a cookie for access to an org by extenal ID. + AuthUserForOrg(context.Context, *LookupOrgRequest) (*LookupOrgResponse, error) + // AuthTokenForOrg authenticates & authorizes a token for access to an org. + AuthTokenForOrg(context.Context, *LookupUsingTokenRequest) (*LookupUsingTokenResponse, error) + // AuthWebhookSecretForOrg returns a Webhook given the external org ID and the webhook secret ID + AuthWebhookSecretForOrg(context.Context, *LookupOrganizationWebhookUsingSecretIDRequest) (*LookupOrganizationWebhookUsingSecretIDResponse, error) + // AuthUserForAdmin authenticates & authorizes a cookie for weave cloud admin access. + AuthUserForAdmin(context.Context, *LookupAdminRequest) (*LookupAdminResponse, error) +} + +func RegisterAuthServiceServer(s *grpc.Server, srv AuthServiceServer) { + s.RegisterService(&_AuthService_serviceDesc, srv) +} + +func _AuthService_AuthUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LookupUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).AuthUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/users.AuthService/AuthUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).AuthUser(ctx, req.(*LookupUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_AuthUserForOrg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LookupOrgRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).AuthUserForOrg(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/users.AuthService/AuthUserForOrg", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).AuthUserForOrg(ctx, req.(*LookupOrgRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_AuthTokenForOrg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LookupUsingTokenRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).AuthTokenForOrg(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/users.AuthService/AuthTokenForOrg", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).AuthTokenForOrg(ctx, req.(*LookupUsingTokenRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_AuthWebhookSecretForOrg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LookupOrganizationWebhookUsingSecretIDRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).AuthWebhookSecretForOrg(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/users.AuthService/AuthWebhookSecretForOrg", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).AuthWebhookSecretForOrg(ctx, req.(*LookupOrganizationWebhookUsingSecretIDRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_AuthUserForAdmin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LookupAdminRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).AuthUserForAdmin(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/users.AuthService/AuthUserForAdmin", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).AuthUserForAdmin(ctx, req.(*LookupAdminRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _AuthService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "users.AuthService", + HandlerType: (*AuthServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AuthUser", + Handler: _AuthService_AuthUser_Handler, + }, + { + MethodName: "AuthUserForOrg", + Handler: _AuthService_AuthUserForOrg_Handler, + }, + { + MethodName: "AuthTokenForOrg", + Handler: _AuthService_AuthTokenForOrg_Handler, + }, + { + MethodName: "AuthWebhookSecretForOrg", + Handler: _AuthService_AuthWebhookSecretForOrg_Handler, + }, + { + MethodName: "AuthUserForAdmin", + Handler: _AuthService_AuthUserForAdmin_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "users.proto", +} + func (m *LookupOrgRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -14878,162 +15084,167 @@ var ( func init() { proto.RegisterFile("users.proto", fileDescriptorUsers) } var fileDescriptorUsers = []byte{ - // 2510 bytes of a gzipped FileDescriptorProto + // 2578 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x19, 0x4b, 0x73, 0xdb, 0xc6, - 0x99, 0x90, 0x48, 0x91, 0xfc, 0x28, 0xd3, 0xd4, 0xea, 0x05, 0xc1, 0x32, 0x29, 0x23, 0xb6, 0x2b, - 0x3b, 0x92, 0x9c, 0x51, 0xd3, 0x36, 0x6d, 0xc6, 0x8d, 0xf9, 0x90, 0x64, 0xd5, 0xaa, 0x24, 0x43, - 0x92, 0x9b, 0xda, 0x9d, 0x38, 0x10, 0xb5, 0xa2, 0x31, 0x26, 0x01, 0x06, 0x0f, 0xd7, 0xca, 0x29, - 0xc7, 0x1e, 0x33, 0xd3, 0x43, 0x7b, 0xec, 0xb1, 0xc7, 0x5e, 0xfb, 0x0b, 0x9a, 0x63, 0x8e, 0x3d, - 0x29, 0xb5, 0x7a, 0x69, 0x35, 0x3d, 0x64, 0xa6, 0x97, 0x1e, 0x3b, 0x58, 0x2c, 0x80, 0xc5, 0x8b, - 0x22, 0x1c, 0x4d, 0x6e, 0xd8, 0xef, 0xbd, 0x8b, 0x6f, 0xbf, 0xd7, 0x42, 0xc9, 0x32, 0xb0, 0x6e, - 0xac, 0xf4, 0x75, 0xcd, 0xd4, 0x50, 0x8e, 0x2c, 0x84, 0xe5, 0x8e, 0x62, 0xbe, 0xb0, 0x0e, 0x57, - 0xda, 0x5a, 0xef, 0x5e, 0x47, 0xeb, 0x68, 0xf7, 0x08, 0xf6, 0xd0, 0x3a, 0x26, 0x2b, 0xb2, 0x20, - 0x5f, 0x0e, 0x97, 0x50, 0xeb, 0x68, 0x5a, 0xa7, 0x8b, 0x7d, 0x2a, 0x53, 0xe9, 0x61, 0xc3, 0x94, - 0x7b, 0x7d, 0x87, 0x40, 0xfc, 0x3d, 0x07, 0x95, 0x2d, 0x4d, 0x7b, 0x69, 0xf5, 0x77, 0xf4, 0x8e, - 0x84, 0x3f, 0xb3, 0xb0, 0x61, 0xa2, 0x19, 0x18, 0x6b, 0x6a, 0xda, 0x4b, 0x05, 0xf3, 0xdc, 0x02, - 0xb7, 0x58, 0x94, 0xe8, 0x0a, 0xdd, 0x84, 0x2b, 0x3b, 0x7a, 0x67, 0xed, 0xb5, 0x89, 0x75, 0x55, - 0xee, 0x6e, 0xb6, 0xf8, 0x11, 0x82, 0x0e, 0x02, 0xd1, 0x87, 0x30, 0x5e, 0xb7, 0xcc, 0x17, 0x9a, - 0xae, 0x7c, 0x8e, 0xd7, 0x35, 0x9d, 0xcf, 0x2e, 0x70, 0x8b, 0xe5, 0xd5, 0xd9, 0x15, 0x67, 0x37, - 0x1e, 0xea, 0xa8, 0xde, 0x36, 0x15, 0x4d, 0x95, 0x02, 0xc4, 0xbf, 0xc8, 0x16, 0x46, 0x2b, 0x59, - 0xf1, 0x6f, 0x1c, 0x4c, 0x30, 0x56, 0x19, 0x7d, 0x4d, 0x35, 0x30, 0x6a, 0x41, 0x79, 0x47, 0xef, - 0xc8, 0xaa, 0xf2, 0xb9, 0x6c, 0x73, 0x6e, 0xb6, 0x1c, 0xf3, 0x1a, 0xf3, 0xe7, 0xa7, 0x35, 0x5e, - 0x0b, 0x60, 0x96, 0xb4, 0x9e, 0x62, 0xe2, 0x5e, 0xdf, 0x3c, 0x91, 0x42, 0x3c, 0x68, 0x09, 0xc6, - 0x0e, 0x0c, 0xac, 0xbb, 0xd6, 0x37, 0xa6, 0xce, 0x4f, 0x6b, 0x15, 0x8b, 0x40, 0x18, 0x2e, 0x4a, - 0x83, 0x7e, 0x0e, 0xe3, 0xeb, 0x58, 0x36, 0x2d, 0x1d, 0xaf, 0x77, 0xe5, 0x8e, 0xc1, 0x8f, 0x2e, - 0x8c, 0x2e, 0x16, 0x1b, 0xc2, 0xf9, 0x69, 0x6d, 0xe6, 0x98, 0x81, 0x33, 0x9c, 0x01, 0x7a, 0xb1, - 0x0b, 0xb3, 0xce, 0x46, 0x0e, 0x0c, 0x45, 0xed, 0xec, 0x6b, 0x2f, 0xb1, 0xea, 0x9e, 0xf2, 0x14, - 0xe4, 0xc8, 0x9a, 0x1e, 0xb2, 0xb3, 0x88, 0x9c, 0xde, 0x48, 0x8a, 0xd3, 0x13, 0xff, 0xc4, 0x01, - 0x1f, 0x55, 0x77, 0xa9, 0xc7, 0x17, 0x3e, 0x90, 0x91, 0x94, 0x07, 0xb2, 0x04, 0xc8, 0xb1, 0xb0, - 0x7e, 0xd4, 0x53, 0xd4, 0x0b, 0x3c, 0x4e, 0x5c, 0x87, 0xc9, 0x00, 0x35, 0xdd, 0xca, 0x3d, 0xc8, - 0x13, 0x80, 0xb7, 0x87, 0xe9, 0xf3, 0xd3, 0xda, 0x84, 0xec, 0x80, 0x18, 0xd5, 0x2e, 0x95, 0xf8, - 0xae, 0xeb, 0x4f, 0xf6, 0x6f, 0xbd, 0x48, 0x69, 0xc3, 0x35, 0xd1, 0x21, 0xa6, 0x3a, 0x7d, 0xbf, - 0xe1, 0x2e, 0xf6, 0x1b, 0x71, 0x07, 0x66, 0x37, 0xb0, 0xc9, 0x9e, 0x9d, 0xc1, 0xfc, 0xf7, 0xc7, - 0x16, 0xd6, 0x4f, 0xdc, 0xff, 0x4e, 0x16, 0xa8, 0x0a, 0xb0, 0x2b, 0x77, 0xf0, 0xb6, 0xd5, 0x3b, - 0xc4, 0xce, 0x5f, 0xcf, 0x49, 0x0c, 0x44, 0x7c, 0x06, 0x7c, 0x54, 0x20, 0x35, 0xed, 0x23, 0x72, - 0x2f, 0x7d, 0x04, 0xcf, 0x2d, 0x8c, 0x2e, 0x96, 0x56, 0x27, 0xa9, 0xd3, 0xb0, 0xb8, 0x46, 0xf6, - 0xab, 0xd3, 0x5a, 0x46, 0x0a, 0xd2, 0x8b, 0xbf, 0x86, 0xda, 0x06, 0x36, 0x1b, 0x4a, 0xb7, 0x2b, - 0x1f, 0x76, 0x71, 0xac, 0xd5, 0x3f, 0x86, 0xd1, 0x6d, 0xed, 0xb7, 0xc4, 0xe6, 0xd2, 0xaa, 0xb0, - 0xe2, 0xc4, 0x95, 0x15, 0x37, 0xae, 0xac, 0xec, 0xbb, 0x71, 0xa5, 0x51, 0xb0, 0x15, 0x7c, 0xf9, - 0x4d, 0x8d, 0x93, 0x6c, 0x06, 0xb1, 0x0d, 0x0b, 0xc9, 0xa2, 0x2f, 0xcb, 0xfe, 0x27, 0x30, 0xbf, - 0x81, 0xcd, 0x7d, 0x5d, 0x91, 0xbb, 0x97, 0x6a, 0xfc, 0xa7, 0x70, 0x3d, 0x41, 0xee, 0x65, 0x59, - 0xfe, 0x0c, 0x6e, 0x6c, 0x60, 0xb3, 0x85, 0xbb, 0x8a, 0xfa, 0x99, 0x85, 0x55, 0xf3, 0x52, 0xcd, - 0xc7, 0x20, 0x0e, 0x12, 0x7e, 0x59, 0x7b, 0xf8, 0x23, 0x07, 0x33, 0x21, 0xdf, 0x74, 0x2d, 0x5f, - 0x00, 0x60, 0xd2, 0x05, 0x71, 0xf8, 0x87, 0x19, 0x89, 0x81, 0xa1, 0xf7, 0x61, 0x6a, 0xa3, 0xb9, - 0xeb, 0x02, 0xea, 0xed, 0xb6, 0x66, 0xa9, 0xa6, 0x1b, 0x9c, 0x1f, 0x66, 0xa4, 0x58, 0xac, 0x2d, - 0x77, 0x53, 0xf5, 0xe4, 0x8e, 0xba, 0x72, 0x7d, 0x58, 0x23, 0x0b, 0x23, 0x9b, 0x2d, 0xf1, 0xe3, - 0xc8, 0x35, 0xf4, 0xb6, 0x7d, 0x1f, 0xc6, 0x59, 0x38, 0x3d, 0xdd, 0x01, 0xbb, 0x0e, 0x90, 0x8b, - 0xff, 0x29, 0x05, 0xf9, 0x51, 0xd9, 0x56, 0x48, 0xef, 0xf4, 0xc8, 0x66, 0xcb, 0xbe, 0xd0, 0x91, - 0x4c, 0xc9, 0x6e, 0x1c, 0x41, 0x76, 0x5b, 0xee, 0x61, 0xc7, 0x78, 0x89, 0x7c, 0x93, 0x20, 0xa0, - 0x6b, 0x87, 0xd8, 0xc9, 0x0b, 0x59, 0x87, 0xc7, 0x87, 0xa0, 0x06, 0x14, 0x9b, 0x3a, 0x96, 0x4d, - 0x7c, 0x54, 0x37, 0xf9, 0x5c, 0x0a, 0x77, 0xf0, 0xd9, 0x90, 0x18, 0x0a, 0xe0, 0x63, 0x76, 0x00, - 0x0f, 0x06, 0x69, 0x74, 0x17, 0x2a, 0x12, 0x3e, 0xb6, 0x0c, 0xdc, 0x92, 0x4d, 0xb9, 0xde, 0x6e, - 0x63, 0xc3, 0xe0, 0xf3, 0x0b, 0xdc, 0x62, 0x41, 0x8a, 0xc0, 0x83, 0xb4, 0x07, 0xfd, 0xae, 0x26, - 0x1f, 0xf1, 0x85, 0x30, 0xad, 0x03, 0x47, 0x1f, 0xc3, 0xd4, 0xba, 0xa2, 0x1b, 0xe6, 0x1e, 0xc6, - 0x6a, 0x53, 0x53, 0x55, 0xdc, 0x76, 0xb6, 0x52, 0x1c, 0x6a, 0x2b, 0x1c, 0xd9, 0x4a, 0xac, 0x04, - 0x24, 0x40, 0x61, 0xb7, 0x2b, 0x9b, 0xc7, 0x9a, 0xde, 0xe3, 0x81, 0x9c, 0x9b, 0xb7, 0x46, 0x0b, - 0x50, 0x5a, 0x53, 0x5f, 0x29, 0xba, 0xa6, 0xf6, 0xb0, 0x6a, 0xf2, 0x25, 0x82, 0x66, 0x41, 0x68, - 0x0b, 0xca, 0xe4, 0x92, 0xaf, 0xbd, 0xee, 0x2b, 0x3a, 0x36, 0xea, 0x26, 0x3f, 0x9e, 0xe2, 0x70, - 0x43, 0xbc, 0x68, 0x05, 0xd0, 0x53, 0x4b, 0xd3, 0x65, 0xea, 0xae, 0x34, 0xa4, 0x5f, 0x21, 0x6a, - 0x63, 0x30, 0xe8, 0x29, 0x4c, 0xb3, 0x50, 0xff, 0x0f, 0x97, 0x53, 0x1c, 0x4b, 0xbc, 0x08, 0xf4, - 0x02, 0xe6, 0x89, 0x75, 0xbb, 0x58, 0x3d, 0x52, 0xd4, 0x0e, 0x31, 0xf2, 0x64, 0x5b, 0x33, 0x95, - 0x63, 0x85, 0xa8, 0xb8, 0x9a, 0x42, 0xc5, 0x40, 0x49, 0xe8, 0x37, 0x30, 0xc3, 0x9c, 0xc3, 0x11, - 0xa3, 0xa3, 0x92, 0x42, 0x47, 0x82, 0x0c, 0xb4, 0x04, 0xa3, 0x1b, 0xcd, 0x5d, 0x7e, 0x82, 0x8a, - 0x72, 0x2e, 0xe9, 0x06, 0x11, 0xd8, 0xec, 0x6a, 0xd6, 0x91, 0xfb, 0xb3, 0x25, 0x9b, 0xcc, 0xce, - 0xec, 0xfb, 0x58, 0xee, 0x6d, 0xb6, 0x78, 0xe4, 0x64, 0x76, 0x67, 0x85, 0x6e, 0x43, 0xd9, 0xfe, - 0x62, 0xee, 0xe5, 0x24, 0xc1, 0x87, 0xa0, 0xf6, 0x3d, 0x6b, 0xe1, 0x2e, 0x76, 0xfe, 0xc2, 0x54, - 0x9a, 0x7b, 0xe6, 0xb1, 0x21, 0x1e, 0xf2, 0xcd, 0x2e, 0x96, 0x55, 0xab, 0xcf, 0x4f, 0x93, 0xeb, - 0xe0, 0x2e, 0xd1, 0xa7, 0xc0, 0x7b, 0x3e, 0xbc, 0xde, 0xb5, 0x5e, 0xb3, 0x37, 0x61, 0x26, 0xc5, - 0x59, 0x25, 0x4a, 0x41, 0x9f, 0xc0, 0xac, 0x87, 0xdb, 0xc6, 0x26, 0xab, 0x60, 0x36, 0x85, 0x82, - 0x24, 0x21, 0x81, 0x1d, 0xec, 0xea, 0x5a, 0x8f, 0x55, 0xc0, 0xbf, 0xd5, 0x0e, 0x42, 0x52, 0xd0, - 0x21, 0xcc, 0x79, 0xb8, 0xbd, 0xb6, 0xd6, 0xc7, 0xac, 0x8a, 0xb9, 0x14, 0x2a, 0x92, 0xc5, 0x04, - 0x23, 0x97, 0x84, 0x65, 0x43, 0x53, 0x79, 0x81, 0xf8, 0x43, 0x04, 0x2e, 0x7e, 0x33, 0x02, 0x93, - 0x31, 0xee, 0x16, 0x89, 0xfa, 0x4b, 0x30, 0x91, 0x90, 0xcb, 0xa4, 0x28, 0x02, 0xcd, 0x43, 0xd1, - 0xae, 0xe3, 0x5f, 0xd9, 0x97, 0x95, 0x24, 0x82, 0x82, 0xe4, 0x03, 0x82, 0xd1, 0x3e, 0xfb, 0x76, - 0xd1, 0xbe, 0x0a, 0xd0, 0xd4, 0x54, 0xc3, 0xea, 0x91, 0xca, 0x35, 0xe7, 0x64, 0x14, 0x1f, 0x62, - 0x9f, 0xc1, 0x9e, 0x75, 0x68, 0xb4, 0x75, 0xa5, 0x6f, 0x67, 0x31, 0x92, 0x91, 0xc6, 0x9c, 0x33, - 0x08, 0xc3, 0xed, 0xbd, 0xb1, 0xb0, 0x2d, 0xfc, 0x0a, 0x77, 0x49, 0x5a, 0x28, 0x4a, 0x51, 0x84, - 0x1d, 0x05, 0x59, 0xe0, 0x9e, 0x29, 0x9b, 0x96, 0x41, 0x32, 0x43, 0x51, 0x8a, 0xc1, 0x88, 0xf7, - 0xe1, 0xca, 0x06, 0x36, 0x37, 0x9a, 0xbb, 0x6e, 0xed, 0x10, 0x7b, 0x94, 0x5c, 0xc2, 0x51, 0x8a, - 0x2d, 0x28, 0xbb, 0xec, 0x34, 0xc1, 0xaf, 0x3a, 0x21, 0x83, 0xbb, 0x28, 0x64, 0xd0, 0xf4, 0x6e, - 0x13, 0x8b, 0x0f, 0xa0, 0x72, 0xd0, 0x3f, 0x92, 0x4d, 0x1c, 0xb0, 0x63, 0x38, 0x39, 0x8e, 0x84, - 0x49, 0x98, 0x60, 0x24, 0x38, 0xa6, 0xd8, 0x7d, 0x99, 0xb8, 0x17, 0xac, 0x43, 0xd8, 0x70, 0xed, - 0x6a, 0xaa, 0x46, 0xab, 0xa5, 0x40, 0xc9, 0x30, 0x03, 0x63, 0x4c, 0x7f, 0x50, 0x94, 0xe8, 0x2a, - 0xe8, 0x28, 0xa3, 0x29, 0x2e, 0x87, 0xcf, 0x26, 0xde, 0x82, 0x77, 0x06, 0x5a, 0x48, 0x77, 0x72, - 0x0c, 0x42, 0x88, 0xcc, 0xae, 0x18, 0x86, 0xdd, 0x00, 0x82, 0xac, 0x4d, 0x4e, 0xcd, 0x27, 0xdf, - 0x76, 0x3b, 0xf4, 0x44, 0xee, 0x5a, 0x98, 0xfa, 0xbf, 0xb3, 0x10, 0xaf, 0xc3, 0xb5, 0x58, 0x3d, - 0xd4, 0x8c, 0x45, 0xf2, 0xb7, 0x43, 0xcd, 0x1c, 0xdb, 0x9e, 0x79, 0x8d, 0xd8, 0x07, 0x70, 0xd5, - 0xa3, 0xa4, 0x8e, 0x71, 0x0b, 0xb2, 0xf6, 0x9a, 0xfe, 0xd1, 0x12, 0xfd, 0xa3, 0x36, 0x88, 0xba, - 0x02, 0x41, 0x8b, 0x7f, 0x19, 0x75, 0xe8, 0xd0, 0xb4, 0x7f, 0xc7, 0x1b, 0xb9, 0xf3, 0xd3, 0x1a, - 0xb7, 0x4c, 0xae, 0x7a, 0x0d, 0x72, 0x6b, 0x3d, 0x59, 0xe9, 0xd2, 0x39, 0x42, 0xf1, 0xfc, 0xb4, - 0x96, 0xc3, 0x36, 0x40, 0x72, 0xe0, 0xe8, 0x9a, 0xdb, 0xe0, 0x8f, 0xb2, 0xac, 0xb4, 0xcf, 0x7f, - 0x0c, 0x65, 0xf2, 0x91, 0xe6, 0x86, 0x5f, 0xb1, 0xad, 0x23, 0x52, 0x68, 0xdd, 0x11, 0x10, 0x80, - 0x7e, 0x09, 0xe3, 0x24, 0xd8, 0x6d, 0x69, 0x1d, 0x45, 0x1d, 0xaa, 0x40, 0x0c, 0x09, 0x0c, 0xb0, - 0xa3, 0x0d, 0xd6, 0xab, 0xc6, 0xd2, 0xca, 0x62, 0x62, 0xd0, 0x35, 0xc8, 0x91, 0x3e, 0xdc, 0x29, - 0x21, 0xbd, 0x73, 0x20, 0x30, 0xf4, 0x08, 0x4a, 0x5b, 0xb2, 0x6f, 0x73, 0x21, 0xad, 0x1e, 0x96, - 0x5b, 0xac, 0x43, 0x8d, 0xd4, 0x0c, 0x27, 0xd1, 0x4a, 0x65, 0x48, 0x17, 0x15, 0x45, 0x58, 0x48, - 0x16, 0x41, 0xbd, 0xef, 0x43, 0x98, 0x63, 0x68, 0x68, 0xb1, 0x32, 0xac, 0x82, 0x79, 0x10, 0xe2, - 0x98, 0xa9, 0xe8, 0x8f, 0xe0, 0xba, 0x83, 0x0d, 0xd7, 0xce, 0xc3, 0x8a, 0x5f, 0x80, 0x6a, 0x92, - 0x00, 0xaa, 0xe2, 0xdf, 0x59, 0xc8, 0xda, 0xf5, 0x4e, 0x92, 0x5f, 0xcf, 0xd1, 0xc6, 0x64, 0x84, - 0x45, 0x38, 0xfd, 0xc9, 0xad, 0x80, 0xf2, 0x80, 0x5b, 0xb3, 0xd7, 0xfc, 0xa7, 0xb1, 0x05, 0x70, - 0xd6, 0xb9, 0x26, 0x76, 0xf0, 0x71, 0x58, 0xe2, 0x6a, 0xe1, 0xe7, 0x49, 0xb5, 0xf0, 0x70, 0xce, - 0xcc, 0xf9, 0x8e, 0x91, 0x50, 0x10, 0x3f, 0x8e, 0x94, 0xfa, 0x63, 0xe9, 0xef, 0x5d, 0xb0, 0xde, - 0xef, 0x5d, 0x50, 0x63, 0xe7, 0xd3, 0x9a, 0x3e, 0xb8, 0xd0, 0x96, 0x13, 0x0b, 0xed, 0x42, 0x5a, - 0x45, 0x49, 0xd5, 0x76, 0xe0, 0xea, 0x17, 0xdf, 0xfe, 0xea, 0x8b, 0x79, 0x3b, 0x46, 0xf6, 0xcd, - 0x13, 0xf1, 0x03, 0xc8, 0xef, 0x59, 0xbd, 0x9e, 0xac, 0x9f, 0xa0, 0x65, 0xc8, 0xaf, 0xa9, 0xa6, - 0xae, 0xe0, 0xf0, 0xa4, 0x81, 0x12, 0xd8, 0xc8, 0x13, 0xc9, 0xa5, 0x11, 0xbf, 0x00, 0x18, 0x67, - 0x31, 0x68, 0x39, 0x52, 0xc4, 0x07, 0x5c, 0x38, 0x5c, 0xcb, 0xdf, 0x80, 0x82, 0x0d, 0x89, 0xba, - 0xb4, 0x07, 0xb6, 0x03, 0xd4, 0x8e, 0xde, 0x09, 0x7b, 0xb4, 0x03, 0x43, 0xef, 0x86, 0x87, 0xde, - 0x59, 0x96, 0x28, 0x34, 0xfb, 0xae, 0x41, 0x7e, 0x47, 0xef, 0x10, 0x5d, 0x39, 0x96, 0xcc, 0x85, - 0xda, 0x69, 0x8a, 0x24, 0x07, 0xb7, 0xef, 0xa6, 0x2b, 0xf4, 0x90, 0x4c, 0x13, 0xfc, 0x43, 0xcf, - 0xa7, 0x28, 0xf7, 0x02, 0x9c, 0x89, 0x3d, 0x76, 0xe1, 0x52, 0x7b, 0xec, 0xe2, 0xe0, 0x1e, 0x1b, - 0x86, 0xe9, 0xb1, 0x4b, 0xdf, 0xa1, 0xc7, 0xbe, 0xa8, 0xaf, 0x1d, 0xff, 0x1e, 0xfa, 0xda, 0x2b, - 0x97, 0xd0, 0xd7, 0x2e, 0x43, 0xb9, 0xa1, 0x74, 0xbb, 0xb6, 0x62, 0x55, 0x3e, 0xec, 0xe2, 0x23, - 0xd2, 0xf4, 0x7b, 0x49, 0x32, 0x84, 0x8c, 0x1d, 0xcc, 0x5c, 0x4d, 0x31, 0x98, 0xa9, 0x24, 0x0c, - 0x66, 0xe2, 0x47, 0x16, 0x13, 0xe9, 0x47, 0x16, 0xe8, 0xbb, 0x8f, 0x2c, 0x56, 0xc9, 0x44, 0x90, - 0x82, 0x23, 0xad, 0x7a, 0x2c, 0x0e, 0x3d, 0x81, 0x49, 0x1f, 0xee, 0x5b, 0x93, 0xa6, 0x75, 0x8f, - 0x13, 0x80, 0x1e, 0xc0, 0x35, 0x1f, 0x1c, 0x6d, 0x7e, 0xa6, 0x89, 0x49, 0x83, 0x48, 0x50, 0x03, - 0xe6, 0xe3, 0xd1, 0xb4, 0x21, 0x9a, 0x21, 0x22, 0x06, 0xd2, 0x88, 0xff, 0x1d, 0x85, 0xfc, 0xaf, - 0xf0, 0xe1, 0x0b, 0x4d, 0x7b, 0x99, 0x94, 0xb4, 0x97, 0x23, 0x8f, 0x3b, 0x81, 0x58, 0x17, 0x7e, - 0xc5, 0xb9, 0x0f, 0x57, 0x37, 0x55, 0x13, 0x77, 0x74, 0x02, 0xd8, 0x3f, 0xe9, 0xd3, 0x39, 0x64, - 0x63, 0xf2, 0xfc, 0xb4, 0x76, 0x55, 0x09, 0xa2, 0xa4, 0x30, 0x2d, 0x5a, 0x84, 0xc2, 0x1e, 0x6e, - 0xeb, 0xd8, 0xf4, 0xc2, 0xe1, 0xf8, 0xf9, 0x69, 0xad, 0x60, 0x50, 0x98, 0xe4, 0x61, 0xd1, 0x03, - 0xa8, 0x38, 0xdf, 0x7b, 0x4a, 0x47, 0x55, 0xd4, 0xce, 0x23, 0x7c, 0x42, 0x23, 0x23, 0x79, 0x3f, - 0x31, 0x42, 0x38, 0x29, 0x42, 0x8d, 0x76, 0xd2, 0x95, 0xa1, 0xd3, 0x34, 0x17, 0x15, 0xdb, 0x2e, - 0x53, 0xb8, 0x1c, 0xdd, 0x61, 0x87, 0x3b, 0xf9, 0xa1, 0x04, 0xda, 0x29, 0xb3, 0x78, 0xe4, 0x32, - 0x85, 0x27, 0x3d, 0x07, 0x50, 0xf2, 0xe2, 0xe5, 0x50, 0x81, 0x76, 0x96, 0x8a, 0x2c, 0x1d, 0xfb, - 0x6c, 0x4e, 0x31, 0xcb, 0xc8, 0x11, 0x1f, 0xc1, 0xb2, 0xf7, 0x06, 0xea, 0xfd, 0x3b, 0xea, 0x06, - 0xe4, 0x79, 0xcf, 0x3d, 0x64, 0xb7, 0x34, 0x14, 0x98, 0xbf, 0xe2, 0x14, 0x86, 0xde, 0x5a, 0x7c, - 0x0a, 0x2b, 0xc3, 0x0a, 0xa3, 0x5d, 0xd2, 0xa2, 0xe7, 0x73, 0xb4, 0x51, 0x2a, 0xd3, 0x34, 0x4d, - 0xa1, 0x92, 0x8b, 0x16, 0xd7, 0x61, 0x31, 0xd4, 0xab, 0x51, 0x0c, 0xb3, 0x9b, 0x61, 0x6c, 0x34, - 0xe0, 0xce, 0x10, 0x72, 0xa8, 0x79, 0xeb, 0xc1, 0x43, 0xe7, 0x52, 0xc4, 0x1d, 0x96, 0xf1, 0xee, - 0x63, 0xa8, 0x84, 0x1f, 0x55, 0x51, 0x11, 0x72, 0x3b, 0xfb, 0x0f, 0xd7, 0xa4, 0x4a, 0x06, 0xf1, - 0x30, 0xb5, 0xb9, 0xbd, 0xb7, 0x5f, 0xdf, 0x6e, 0xae, 0x3d, 0x6f, 0xd5, 0xf7, 0xeb, 0xcf, 0xeb, - 0xcd, 0xe6, 0xda, 0xde, 0x5e, 0x85, 0x8b, 0x62, 0x0e, 0x76, 0xb7, 0x76, 0xea, 0xad, 0xca, 0xc8, - 0xea, 0x5f, 0xcb, 0x90, 0xb3, 0x1b, 0x47, 0x03, 0x3d, 0x80, 0xa2, 0x77, 0xea, 0xc8, 0x7d, 0xc3, - 0x0d, 0x3f, 0xb7, 0x0b, 0x7c, 0x14, 0x41, 0x4b, 0xf5, 0x0c, 0x3a, 0x70, 0x9f, 0xe7, 0xfd, 0x07, - 0x5d, 0x54, 0x0d, 0xd0, 0x47, 0x1e, 0x96, 0x85, 0x5a, 0x22, 0xde, 0x13, 0xbb, 0x0e, 0x25, 0xe6, - 0x5d, 0x15, 0xcd, 0x05, 0x38, 0xd8, 0x97, 0x59, 0x41, 0x88, 0x43, 0x79, 0x72, 0x9a, 0x00, 0xfe, - 0x53, 0x29, 0xe2, 0x43, 0x8a, 0xbd, 0xee, 0x5c, 0x98, 0x8b, 0xc1, 0xb0, 0x7b, 0x0c, 0x3f, 0x6d, - 0x7a, 0x7b, 0x4c, 0x78, 0x44, 0xf5, 0xf6, 0x98, 0xf4, 0x26, 0x2a, 0x66, 0x50, 0x8f, 0xbc, 0x98, - 0xc6, 0xbe, 0x3c, 0xa2, 0xdb, 0x3e, 0xfb, 0xa0, 0x57, 0x4f, 0xe1, 0x07, 0x17, 0xd2, 0x79, 0xea, - 0x8e, 0x60, 0x3a, 0xf6, 0xad, 0x10, 0xbd, 0xe3, 0xcb, 0x48, 0x7c, 0xa1, 0x14, 0x6e, 0x0e, 0x26, - 0xf2, 0xb4, 0x18, 0x20, 0x24, 0x3f, 0xe9, 0xa1, 0x45, 0x5f, 0xca, 0xe0, 0x27, 0x45, 0xe1, 0xce, - 0x10, 0x94, 0x9e, 0x52, 0x89, 0xcc, 0x50, 0x02, 0xaf, 0x5d, 0xd7, 0xe3, 0xcf, 0xdf, 0x15, 0x5f, - 0x4d, 0x42, 0x7b, 0x32, 0x3f, 0x81, 0xc9, 0x98, 0x01, 0x0f, 0xba, 0xe1, 0xf6, 0x02, 0x89, 0x43, - 0x26, 0x41, 0x1c, 0x44, 0xe2, 0xc9, 0x7f, 0x15, 0x19, 0x20, 0xb1, 0xd5, 0x06, 0xba, 0x13, 0x2f, - 0x24, 0x66, 0x2a, 0x27, 0xdc, 0x1d, 0x86, 0xd4, 0xd3, 0xfb, 0x13, 0x18, 0x73, 0xe6, 0x90, 0x68, - 0xca, 0x3f, 0x03, 0x7f, 0x9a, 0x28, 0x4c, 0x87, 0xa0, 0x1e, 0xe3, 0x03, 0x28, 0x7a, 0x83, 0x43, - 0x2f, 0x56, 0x84, 0x87, 0x91, 0x5e, 0xac, 0x88, 0xce, 0x18, 0x33, 0xe8, 0x67, 0x90, 0xa7, 0xa3, - 0x2e, 0xc4, 0x68, 0x61, 0xaf, 0xe1, 0x4c, 0x18, 0xcc, 0x5e, 0x96, 0xa4, 0xb1, 0x87, 0x77, 0x59, - 0x2e, 0x18, 0xad, 0x78, 0x97, 0xe5, 0xc2, 0xf9, 0x49, 0x06, 0x3d, 0x03, 0x14, 0x1d, 0x82, 0xa0, - 0x85, 0xa8, 0x80, 0xe0, 0x70, 0x45, 0xb8, 0x31, 0x80, 0xc2, 0x13, 0xde, 0x81, 0x99, 0xf8, 0x11, - 0x08, 0xba, 0x19, 0x60, 0x4f, 0x18, 0xb1, 0x08, 0xb7, 0x2e, 0xa0, 0xf2, 0x14, 0x2d, 0x01, 0x6c, - 0x60, 0xd3, 0xed, 0x6b, 0xc7, 0x29, 0x1b, 0x69, 0x78, 0x85, 0x72, 0xb0, 0xa9, 0x15, 0x33, 0xe8, - 0x0f, 0x1c, 0xdc, 0x1e, 0x2e, 0x07, 0xa3, 0xf7, 0xc3, 0x19, 0x61, 0x98, 0xfc, 0x2f, 0xfc, 0x28, - 0x25, 0x97, 0xb7, 0x8f, 0xdf, 0x71, 0x70, 0xe3, 0xc2, 0xcc, 0x8b, 0xee, 0xc5, 0xdf, 0x83, 0xc4, - 0x5c, 0x2f, 0xbc, 0x37, 0x3c, 0x83, 0x6b, 0x4a, 0xe3, 0xbd, 0xaf, 0xdf, 0x54, 0x33, 0x7f, 0x7f, - 0x53, 0xcd, 0x7c, 0xfb, 0xa6, 0xca, 0xfd, 0xef, 0x4d, 0x95, 0xfb, 0xe2, 0xac, 0xca, 0xfd, 0xf9, - 0xac, 0xca, 0x7d, 0x75, 0x56, 0xe5, 0xbe, 0x3e, 0xab, 0x72, 0xff, 0x38, 0xab, 0x72, 0xff, 0x3a, - 0xab, 0x66, 0xbe, 0x3d, 0xab, 0x72, 0x5f, 0xfe, 0xb3, 0x9a, 0x39, 0x1c, 0x23, 0xb9, 0xfe, 0x87, - 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x47, 0xa5, 0x0c, 0xd4, 0x2e, 0x27, 0x00, 0x00, + 0x99, 0x10, 0x49, 0x91, 0xfc, 0x28, 0x53, 0xd4, 0xea, 0x05, 0xc1, 0x32, 0x29, 0x23, 0x71, 0xaa, + 0x24, 0x92, 0x9c, 0x51, 0xd3, 0x36, 0x6d, 0xc6, 0x8d, 0xf9, 0x90, 0x64, 0xd5, 0xaa, 0x24, 0x83, + 0x92, 0x9b, 0xda, 0x9d, 0x38, 0x10, 0xb5, 0xa2, 0x31, 0x26, 0x01, 0x06, 0x00, 0x5d, 0x2b, 0xa7, + 0x1c, 0x73, 0xcc, 0x4c, 0x0f, 0xed, 0xb1, 0xc7, 0x1e, 0x7b, 0xed, 0x0f, 0xe8, 0x34, 0xc7, 0x1c, + 0x7b, 0x52, 0x6a, 0xf5, 0xd2, 0x6a, 0x7a, 0xc8, 0x4c, 0x2f, 0x3d, 0x76, 0xb0, 0x58, 0x00, 0x8b, + 0x17, 0x45, 0xd8, 0x9a, 0xdc, 0xb0, 0xdf, 0x73, 0xf7, 0xc3, 0xb7, 0xdf, 0x6b, 0xa1, 0x38, 0x30, + 0xb0, 0x6e, 0xac, 0xf5, 0x75, 0xcd, 0xd4, 0x50, 0x96, 0x2c, 0x84, 0xd5, 0x8e, 0x62, 0x3e, 0x1d, + 0x1c, 0xad, 0xb5, 0xb5, 0xde, 0xed, 0x8e, 0xd6, 0xd1, 0x6e, 0x13, 0xec, 0xd1, 0xe0, 0x84, 0xac, + 0xc8, 0x82, 0x7c, 0xd9, 0x5c, 0x42, 0xb5, 0xa3, 0x69, 0x9d, 0x2e, 0xf6, 0xa8, 0x4c, 0xa5, 0x87, + 0x0d, 0x53, 0xee, 0xf5, 0x6d, 0x02, 0xf1, 0x77, 0x1c, 0x94, 0x77, 0x34, 0xed, 0xd9, 0xa0, 0xbf, + 0xa7, 0x77, 0x24, 0xfc, 0xd9, 0x00, 0x1b, 0x26, 0x9a, 0x83, 0xf1, 0x86, 0xa6, 0x3d, 0x53, 0x30, + 0xcf, 0x2d, 0x71, 0xcb, 0x05, 0x89, 0xae, 0xd0, 0x9b, 0x70, 0x6d, 0x4f, 0xef, 0x6c, 0xbc, 0x30, + 0xb1, 0xae, 0xca, 0xdd, 0xed, 0x26, 0x3f, 0x46, 0xd0, 0x7e, 0x20, 0xfa, 0x10, 0x26, 0x6a, 0x03, + 0xf3, 0xa9, 0xa6, 0x2b, 0x9f, 0xe3, 0x4d, 0x4d, 0xe7, 0x33, 0x4b, 0xdc, 0x72, 0x69, 0x7d, 0x7e, + 0xcd, 0x3e, 0x8d, 0x8b, 0x3a, 0xae, 0xb5, 0x4d, 0x45, 0x53, 0x25, 0x1f, 0xf1, 0x2f, 0x32, 0xf9, + 0x74, 0x39, 0x23, 0xfe, 0x8d, 0x83, 0x29, 0x66, 0x57, 0x46, 0x5f, 0x53, 0x0d, 0x8c, 0x9a, 0x50, + 0xda, 0xd3, 0x3b, 0xb2, 0xaa, 0x7c, 0x2e, 0x5b, 0x9c, 0xdb, 0x4d, 0x7b, 0x7b, 0xf5, 0xc5, 0x8b, + 0xb3, 0x2a, 0xaf, 0xf9, 0x30, 0x2b, 0x5a, 0x4f, 0x31, 0x71, 0xaf, 0x6f, 0x9e, 0x4a, 0x01, 0x1e, + 0xb4, 0x02, 0xe3, 0x87, 0x06, 0xd6, 0x9d, 0xdd, 0xd7, 0x67, 0x2e, 0xce, 0xaa, 0xe5, 0x01, 0x81, + 0x30, 0x5c, 0x94, 0x06, 0xfd, 0x1c, 0x26, 0x36, 0xb1, 0x6c, 0x0e, 0x74, 0xbc, 0xd9, 0x95, 0x3b, + 0x06, 0x9f, 0x5e, 0x4a, 0x2f, 0x17, 0xea, 0xc2, 0xc5, 0x59, 0x75, 0xee, 0x84, 0x81, 0x33, 0x9c, + 0x3e, 0x7a, 0xb1, 0x0b, 0xf3, 0xf6, 0x41, 0x0e, 0x0d, 0x45, 0xed, 0x1c, 0x68, 0xcf, 0xb0, 0xea, + 0x58, 0x79, 0x06, 0xb2, 0x64, 0x4d, 0x8d, 0x6c, 0x2f, 0x42, 0xd6, 0x1b, 0x4b, 0x60, 0x3d, 0xf1, + 0x8f, 0x1c, 0xf0, 0x61, 0x75, 0x57, 0x6a, 0xbe, 0xa0, 0x41, 0xc6, 0x12, 0x1a, 0x64, 0x05, 0x90, + 0xbd, 0xc3, 0xda, 0x71, 0x4f, 0x51, 0x2f, 0xf1, 0x38, 0x71, 0x13, 0xa6, 0x7d, 0xd4, 0xf4, 0x28, + 0xb7, 0x21, 0x47, 0x00, 0xee, 0x19, 0x66, 0x2f, 0xce, 0xaa, 0x53, 0xb2, 0x0d, 0x62, 0x54, 0x3b, + 0x54, 0xe2, 0xbb, 0x8e, 0x3f, 0x59, 0xbf, 0xf5, 0x32, 0xa5, 0x75, 0x67, 0x8b, 0x36, 0x31, 0xd5, + 0xe9, 0xf9, 0x0d, 0x77, 0xb9, 0xdf, 0x88, 0x7b, 0x30, 0xbf, 0x85, 0x4d, 0xd6, 0x76, 0x06, 0xf3, + 0xdf, 0x1f, 0x0c, 0xb0, 0x7e, 0xea, 0xfc, 0x77, 0xb2, 0x40, 0x15, 0x80, 0x7d, 0xb9, 0x83, 0x77, + 0x07, 0xbd, 0x23, 0x6c, 0xff, 0xf5, 0xac, 0xc4, 0x40, 0xc4, 0xc7, 0xc0, 0x87, 0x05, 0xd2, 0xad, + 0x7d, 0x44, 0xee, 0xa5, 0x87, 0xe0, 0xb9, 0xa5, 0xf4, 0x72, 0x71, 0x7d, 0x9a, 0x3a, 0x0d, 0x8b, + 0xab, 0x67, 0xbe, 0x3e, 0xab, 0xa6, 0x24, 0x3f, 0xbd, 0xf8, 0x6b, 0xa8, 0x6e, 0x61, 0xb3, 0xae, + 0x74, 0xbb, 0xf2, 0x51, 0x17, 0x47, 0xee, 0xfa, 0xc7, 0x90, 0xde, 0xd5, 0x7e, 0x4b, 0xf6, 0x5c, + 0x5c, 0x17, 0xd6, 0xec, 0xb8, 0xb2, 0xe6, 0xc4, 0x95, 0xb5, 0x03, 0x27, 0xae, 0xd4, 0xf3, 0x96, + 0x82, 0xaf, 0xbe, 0xad, 0x72, 0x92, 0xc5, 0x20, 0xb6, 0x61, 0x29, 0x5e, 0xf4, 0x55, 0xed, 0xff, + 0x21, 0x2c, 0x6e, 0x61, 0xf3, 0x40, 0x57, 0xe4, 0xee, 0x95, 0x6e, 0xfe, 0x53, 0xb8, 0x11, 0x23, + 0xf7, 0xaa, 0x76, 0xfe, 0x18, 0x6e, 0x6e, 0x61, 0xb3, 0x89, 0xbb, 0x8a, 0xfa, 0xd9, 0x00, 0xab, + 0xe6, 0x95, 0x6e, 0x1f, 0x83, 0x38, 0x4c, 0xf8, 0x55, 0x9d, 0xe1, 0x0f, 0x1c, 0xcc, 0x05, 0x7c, + 0xd3, 0xd9, 0xf9, 0x12, 0x00, 0x93, 0x2e, 0x88, 0xc3, 0xdf, 0x4b, 0x49, 0x0c, 0x0c, 0xbd, 0x0f, + 0x33, 0x5b, 0x8d, 0x7d, 0x07, 0x50, 0x6b, 0xb7, 0xb5, 0x81, 0x6a, 0x3a, 0xc1, 0xf9, 0x5e, 0x4a, + 0x8a, 0xc4, 0x5a, 0x72, 0xb7, 0x55, 0x57, 0x6e, 0xda, 0x91, 0xeb, 0xc1, 0xea, 0x19, 0x18, 0xdb, + 0x6e, 0x8a, 0x1f, 0x87, 0xae, 0xa1, 0x7b, 0xec, 0x3b, 0x30, 0xc1, 0xc2, 0xa9, 0x75, 0x87, 0x9c, + 0xda, 0x47, 0x2e, 0xfe, 0xa7, 0xe8, 0xe7, 0x47, 0x25, 0x4b, 0x21, 0xbd, 0xd3, 0x63, 0xdb, 0x4d, + 0xeb, 0x42, 0x87, 0x32, 0x25, 0x7b, 0x70, 0x04, 0x99, 0x5d, 0xb9, 0x87, 0xed, 0xcd, 0x4b, 0xe4, + 0x9b, 0x04, 0x01, 0x5d, 0x3b, 0xc2, 0x76, 0x5e, 0xc8, 0xd8, 0x3c, 0x1e, 0x04, 0xd5, 0xa1, 0xd0, + 0xd0, 0xb1, 0x6c, 0xe2, 0xe3, 0x9a, 0xc9, 0x67, 0x13, 0xb8, 0x83, 0xc7, 0x86, 0xc4, 0x40, 0x00, + 0x1f, 0xb7, 0x02, 0xb8, 0x3f, 0x48, 0xa3, 0x77, 0xa0, 0x2c, 0xe1, 0x93, 0x81, 0x81, 0x9b, 0xb2, + 0x29, 0xd7, 0xda, 0x6d, 0x6c, 0x18, 0x7c, 0x6e, 0x89, 0x5b, 0xce, 0x4b, 0x21, 0xb8, 0x9f, 0xf6, + 0xb0, 0xdf, 0xd5, 0xe4, 0x63, 0x3e, 0x1f, 0xa4, 0xb5, 0xe1, 0xe8, 0x63, 0x98, 0xd9, 0x54, 0x74, + 0xc3, 0x6c, 0x61, 0xac, 0x36, 0x34, 0x55, 0xc5, 0x6d, 0xfb, 0x28, 0x85, 0x91, 0x8e, 0xc2, 0x91, + 0xa3, 0x44, 0x4a, 0x40, 0x02, 0xe4, 0xf7, 0xbb, 0xb2, 0x79, 0xa2, 0xe9, 0x3d, 0x1e, 0x88, 0xdd, + 0xdc, 0x35, 0x5a, 0x82, 0xe2, 0x86, 0xfa, 0x5c, 0xd1, 0x35, 0xb5, 0x87, 0x55, 0x93, 0x2f, 0x12, + 0x34, 0x0b, 0x42, 0x3b, 0x50, 0x22, 0x97, 0x7c, 0xe3, 0x45, 0x5f, 0xd1, 0xb1, 0x51, 0x33, 0xf9, + 0x89, 0x04, 0xc6, 0x0d, 0xf0, 0xa2, 0x35, 0x40, 0x8f, 0x06, 0x9a, 0x2e, 0x53, 0x77, 0xa5, 0x21, + 0xfd, 0x1a, 0x51, 0x1b, 0x81, 0x41, 0x8f, 0x60, 0x96, 0x85, 0x7a, 0x7f, 0xb8, 0x94, 0xc0, 0x2c, + 0xd1, 0x22, 0xd0, 0x53, 0x58, 0x24, 0xbb, 0xdb, 0xc7, 0xea, 0xb1, 0xa2, 0x76, 0xc8, 0x26, 0x4f, + 0x77, 0x35, 0x53, 0x39, 0x51, 0x88, 0x8a, 0xc9, 0x04, 0x2a, 0x86, 0x4a, 0x42, 0xbf, 0x81, 0x39, + 0xc6, 0x0e, 0xc7, 0x8c, 0x8e, 0x72, 0x02, 0x1d, 0x31, 0x32, 0xd0, 0x0a, 0xa4, 0xb7, 0x1a, 0xfb, + 0xfc, 0x14, 0x15, 0x65, 0x5f, 0xd2, 0x2d, 0x22, 0xb0, 0xd1, 0xd5, 0x06, 0xc7, 0xce, 0xcf, 0x96, + 0x2c, 0x32, 0x2b, 0xb3, 0x1f, 0x60, 0xb9, 0xb7, 0xdd, 0xe4, 0x91, 0x9d, 0xd9, 0xed, 0x15, 0x7a, + 0x0b, 0x4a, 0xd6, 0x17, 0x73, 0x2f, 0xa7, 0x09, 0x3e, 0x00, 0xb5, 0xee, 0x59, 0x13, 0x77, 0xb1, + 0xfd, 0x17, 0x66, 0x92, 0xdc, 0x33, 0x97, 0x0d, 0xf1, 0x90, 0x6b, 0x74, 0xb1, 0xac, 0x0e, 0xfa, + 0xfc, 0x2c, 0xb9, 0x0e, 0xce, 0x12, 0x7d, 0x0a, 0xbc, 0xeb, 0xc3, 0x9b, 0xdd, 0xc1, 0x0b, 0xf6, + 0x26, 0xcc, 0x25, 0xb0, 0x55, 0xac, 0x14, 0xf4, 0x09, 0xcc, 0xbb, 0xb8, 0x5d, 0x6c, 0xb2, 0x0a, + 0xe6, 0x13, 0x28, 0x88, 0x13, 0xe2, 0x3b, 0xc1, 0xbe, 0xae, 0xf5, 0x58, 0x05, 0xfc, 0x2b, 0x9d, + 0x20, 0x20, 0x05, 0x1d, 0xc1, 0x82, 0x8b, 0x6b, 0xb5, 0xb5, 0x3e, 0x66, 0x55, 0x2c, 0x24, 0x50, + 0x11, 0x2f, 0xc6, 0x1f, 0xb9, 0x24, 0x2c, 0x1b, 0x9a, 0xca, 0x0b, 0xc4, 0x1f, 0x42, 0x70, 0xf1, + 0xdb, 0x31, 0x98, 0x8e, 0x70, 0xb7, 0x50, 0xd4, 0x5f, 0x81, 0xa9, 0x98, 0x5c, 0x26, 0x85, 0x11, + 0x68, 0x11, 0x0a, 0x56, 0x1d, 0xff, 0xdc, 0xba, 0xac, 0x24, 0x11, 0xe4, 0x25, 0x0f, 0xe0, 0x8f, + 0xf6, 0x99, 0x57, 0x8b, 0xf6, 0x15, 0x80, 0x86, 0xa6, 0x1a, 0x83, 0x1e, 0xa9, 0x5c, 0xb3, 0x76, + 0x46, 0xf1, 0x20, 0x96, 0x0d, 0x5a, 0x83, 0x23, 0xa3, 0xad, 0x2b, 0x7d, 0x2b, 0x8b, 0x91, 0x8c, + 0x34, 0x6e, 0xdb, 0x20, 0x08, 0xb7, 0xce, 0xc6, 0xc2, 0x76, 0xf0, 0x73, 0xdc, 0x25, 0x69, 0xa1, + 0x20, 0x85, 0x11, 0x56, 0x14, 0x64, 0x81, 0x2d, 0x53, 0x36, 0x07, 0x06, 0xc9, 0x0c, 0x05, 0x29, + 0x02, 0x23, 0xde, 0x81, 0x6b, 0x5b, 0xd8, 0xdc, 0x6a, 0xec, 0x3b, 0xb5, 0x43, 0xa4, 0x29, 0xb9, + 0x18, 0x53, 0x8a, 0x4d, 0x28, 0x39, 0xec, 0x34, 0xc1, 0xaf, 0xdb, 0x21, 0x83, 0xbb, 0x2c, 0x64, + 0xd0, 0xf4, 0x6e, 0x11, 0x8b, 0x77, 0xa1, 0x7c, 0xd8, 0x3f, 0x96, 0x4d, 0xec, 0xdb, 0xc7, 0x68, + 0x72, 0x6c, 0x09, 0xd3, 0x30, 0xc5, 0x48, 0xb0, 0xb7, 0x62, 0xf5, 0x65, 0x62, 0xcb, 0x5f, 0x87, + 0xb0, 0xe1, 0xda, 0xd1, 0x54, 0x09, 0x57, 0x4b, 0xbe, 0x92, 0x61, 0x0e, 0xc6, 0x99, 0xfe, 0xa0, + 0x20, 0xd1, 0x95, 0xdf, 0x51, 0xd2, 0x09, 0x2e, 0x87, 0xc7, 0x26, 0xde, 0x82, 0x37, 0x86, 0xee, + 0x90, 0x9e, 0xe4, 0x04, 0x84, 0x00, 0x99, 0x55, 0x31, 0x8c, 0x7a, 0x00, 0x04, 0x19, 0x8b, 0x9c, + 0x6e, 0x9f, 0x7c, 0x5b, 0xed, 0xd0, 0x43, 0xb9, 0x3b, 0xc0, 0xd4, 0xff, 0xed, 0x85, 0x78, 0x03, + 0xae, 0x47, 0xea, 0xa1, 0xdb, 0x58, 0x26, 0x7f, 0x3b, 0xd0, 0xcc, 0xb1, 0xed, 0x99, 0xdb, 0x88, + 0x7d, 0x00, 0x93, 0x2e, 0x25, 0x75, 0x8c, 0x5b, 0x90, 0xb1, 0xd6, 0xf4, 0x8f, 0x16, 0xe9, 0x1f, + 0xb5, 0x40, 0xd4, 0x15, 0x08, 0x5a, 0xfc, 0x73, 0xda, 0xa6, 0x43, 0xb3, 0xde, 0x1d, 0xaf, 0x67, + 0x2f, 0xce, 0xaa, 0xdc, 0x2a, 0xb9, 0xea, 0x55, 0xc8, 0x6e, 0xf4, 0x64, 0xa5, 0x4b, 0xe7, 0x08, + 0x85, 0x8b, 0xb3, 0x6a, 0x16, 0x5b, 0x00, 0xc9, 0x86, 0xa3, 0xeb, 0x4e, 0x83, 0x9f, 0x66, 0x59, + 0x69, 0x9f, 0xff, 0x00, 0x4a, 0xe4, 0x23, 0xc9, 0x0d, 0xbf, 0x66, 0xed, 0x8e, 0x48, 0xa1, 0x75, + 0x87, 0x4f, 0x00, 0xfa, 0x25, 0x4c, 0x90, 0x60, 0xb7, 0xa3, 0x75, 0x14, 0x75, 0xa4, 0x02, 0x31, + 0x20, 0xd0, 0xc7, 0x8e, 0xb6, 0x58, 0xaf, 0x1a, 0x4f, 0x2a, 0x8b, 0x89, 0x41, 0xd7, 0x21, 0x4b, + 0xfa, 0x70, 0xbb, 0x84, 0x74, 0xed, 0x40, 0x60, 0xe8, 0x3e, 0x14, 0x77, 0x64, 0x6f, 0xcf, 0xf9, + 0xa4, 0x7a, 0x58, 0x6e, 0xb1, 0x06, 0x55, 0x52, 0x33, 0x9c, 0x86, 0x2b, 0x95, 0x11, 0x5d, 0x54, + 0x14, 0x61, 0x29, 0x5e, 0x04, 0xf5, 0xbe, 0x0f, 0x61, 0x81, 0xa1, 0xa1, 0xc5, 0xca, 0xa8, 0x0a, + 0x16, 0x41, 0x88, 0x62, 0xa6, 0xa2, 0x3f, 0x82, 0x1b, 0x36, 0x36, 0x58, 0x3b, 0x8f, 0x2a, 0x7e, + 0x09, 0x2a, 0x71, 0x02, 0xa8, 0x8a, 0x7f, 0x67, 0x20, 0x63, 0xd5, 0x3b, 0x71, 0x7e, 0xbd, 0x40, + 0x1b, 0x93, 0x31, 0x16, 0x61, 0xf7, 0x27, 0xb7, 0x7c, 0xca, 0x7d, 0x6e, 0xcd, 0x5e, 0xf3, 0x9f, + 0x46, 0x16, 0xc0, 0x19, 0xfb, 0x9a, 0x58, 0xc1, 0xc7, 0x66, 0x89, 0xaa, 0x85, 0x9f, 0xc4, 0xd5, + 0xc2, 0xa3, 0x39, 0x33, 0xe7, 0x39, 0x46, 0x4c, 0x41, 0xfc, 0x20, 0x54, 0xea, 0x8f, 0x27, 0xbf, + 0x77, 0xfe, 0x7a, 0xbf, 0x77, 0x49, 0x8d, 0x9d, 0x4b, 0xba, 0xf5, 0xe1, 0x85, 0xb6, 0x1c, 0x5b, + 0x68, 0xe7, 0x93, 0x2a, 0x8a, 0xab, 0xb6, 0x7d, 0x57, 0xbf, 0xf0, 0xea, 0x57, 0x5f, 0xcc, 0x59, + 0x31, 0xb2, 0x6f, 0x9e, 0x8a, 0x1f, 0x40, 0xae, 0x35, 0xe8, 0xf5, 0x64, 0xfd, 0x14, 0xad, 0x42, + 0x6e, 0x43, 0x35, 0x75, 0x05, 0x07, 0x27, 0x0d, 0x94, 0xc0, 0x42, 0x9e, 0x4a, 0x0e, 0x8d, 0xf8, + 0x05, 0xc0, 0x04, 0x8b, 0x41, 0xab, 0xa1, 0x22, 0xde, 0xe7, 0xc2, 0xc1, 0x5a, 0xfe, 0x26, 0xe4, + 0x2d, 0x48, 0xd8, 0xa5, 0x5d, 0xb0, 0x15, 0xa0, 0xf6, 0xf4, 0x4e, 0xd0, 0xa3, 0x6d, 0x18, 0x7a, + 0x37, 0x38, 0xf4, 0xce, 0xb0, 0x44, 0x81, 0xd9, 0x77, 0x15, 0x72, 0x7b, 0x7a, 0x87, 0xe8, 0xca, + 0xb2, 0x64, 0x0e, 0xd4, 0x4a, 0x53, 0x24, 0x39, 0x38, 0x7d, 0x37, 0x5d, 0xa1, 0x7b, 0x64, 0x9a, + 0xe0, 0x19, 0x3d, 0x97, 0xa0, 0xdc, 0xf3, 0x71, 0xc6, 0xf6, 0xd8, 0xf9, 0x2b, 0xed, 0xb1, 0x0b, + 0xc3, 0x7b, 0x6c, 0x18, 0xa5, 0xc7, 0x2e, 0xbe, 0x46, 0x8f, 0x7d, 0x59, 0x5f, 0x3b, 0xf1, 0x3d, + 0xf4, 0xb5, 0xd7, 0xae, 0xa0, 0xaf, 0x5d, 0x85, 0x52, 0x5d, 0xe9, 0x76, 0x2d, 0xc5, 0xaa, 0x7c, + 0xd4, 0xc5, 0xc7, 0xa4, 0xe9, 0x77, 0x93, 0x64, 0x00, 0x19, 0x39, 0x98, 0x99, 0x4c, 0x30, 0x98, + 0x29, 0xc7, 0x0c, 0x66, 0xa2, 0x47, 0x16, 0x53, 0xc9, 0x47, 0x16, 0xe8, 0xf5, 0x47, 0x16, 0xeb, + 0x64, 0x22, 0x48, 0xc1, 0xa1, 0x56, 0x3d, 0x12, 0x87, 0x1e, 0xc2, 0xb4, 0x07, 0xf7, 0x76, 0x93, + 0xa4, 0x75, 0x8f, 0x12, 0x80, 0xee, 0xc2, 0x75, 0x0f, 0x1c, 0x6e, 0x7e, 0x66, 0xc9, 0x96, 0x86, + 0x91, 0xa0, 0x3a, 0x2c, 0x46, 0xa3, 0x69, 0x43, 0x34, 0x47, 0x44, 0x0c, 0xa5, 0x11, 0xff, 0x9b, + 0x86, 0xdc, 0xaf, 0xf0, 0xd1, 0x53, 0x4d, 0x7b, 0x16, 0x97, 0xb4, 0x57, 0x43, 0x8f, 0x3b, 0xbe, + 0x58, 0x17, 0x7c, 0xc5, 0xb9, 0x03, 0x93, 0xdb, 0xaa, 0x89, 0x3b, 0x3a, 0x01, 0x1c, 0x9c, 0xf6, + 0xe9, 0x1c, 0xb2, 0x3e, 0x7d, 0x71, 0x56, 0x9d, 0x54, 0xfc, 0x28, 0x29, 0x48, 0x8b, 0x96, 0x21, + 0xdf, 0xc2, 0x6d, 0x1d, 0x9b, 0x6e, 0x38, 0x9c, 0xb8, 0x38, 0xab, 0xe6, 0x0d, 0x0a, 0x93, 0x5c, + 0x2c, 0xba, 0x0b, 0x65, 0xfb, 0xbb, 0xa5, 0x74, 0x54, 0x45, 0xed, 0xdc, 0xc7, 0xa7, 0x34, 0x32, + 0x92, 0xf7, 0x13, 0x23, 0x80, 0x93, 0x42, 0xd4, 0x68, 0x2f, 0x59, 0x19, 0x3a, 0x4b, 0x73, 0x51, + 0xa1, 0xed, 0x30, 0x05, 0xcb, 0xd1, 0x3d, 0x76, 0xb8, 0x93, 0x1b, 0x49, 0xa0, 0x95, 0x32, 0x0b, + 0xc7, 0x0e, 0x53, 0x70, 0xd2, 0x73, 0x08, 0x45, 0x37, 0x5e, 0x8e, 0x14, 0x68, 0xe7, 0xa9, 0xc8, + 0xe2, 0x89, 0xc7, 0x66, 0x17, 0xb3, 0x8c, 0x1c, 0xf1, 0x3e, 0xac, 0xba, 0x6f, 0xa0, 0xee, 0xbf, + 0xa3, 0x6e, 0x40, 0x9e, 0xf7, 0x1c, 0x23, 0x3b, 0xa5, 0xa1, 0xc0, 0xfc, 0x15, 0xbb, 0x30, 0x74, + 0xd7, 0xe2, 0x23, 0x58, 0x1b, 0x55, 0x18, 0xed, 0x92, 0x96, 0x5d, 0x9f, 0xa3, 0x8d, 0x52, 0x89, + 0xa6, 0x69, 0x0a, 0x95, 0x1c, 0xb4, 0xb8, 0x09, 0xcb, 0x81, 0x5e, 0x8d, 0x62, 0x98, 0xd3, 0x8c, + 0xb2, 0x47, 0x03, 0xde, 0x1e, 0x41, 0x0e, 0xdd, 0xde, 0xa6, 0xdf, 0xe8, 0x5c, 0x82, 0xb8, 0xc3, + 0x32, 0xbe, 0xf3, 0x00, 0xca, 0xc1, 0x47, 0x55, 0x54, 0x80, 0xec, 0xde, 0xc1, 0xbd, 0x0d, 0xa9, + 0x9c, 0x42, 0x3c, 0xcc, 0x6c, 0xef, 0xb6, 0x0e, 0x6a, 0xbb, 0x8d, 0x8d, 0x27, 0xcd, 0xda, 0x41, + 0xed, 0x49, 0xad, 0xd1, 0xd8, 0x68, 0xb5, 0xca, 0x5c, 0x18, 0x73, 0xb8, 0xbf, 0xb3, 0x57, 0x6b, + 0x96, 0xc7, 0xd6, 0xff, 0x52, 0x82, 0xac, 0xd5, 0x38, 0x1a, 0xe8, 0x2e, 0x14, 0x5c, 0xab, 0x23, + 0xe7, 0x0d, 0x37, 0xf8, 0xdc, 0x2e, 0xf0, 0x61, 0x04, 0x2d, 0xd5, 0x53, 0xe8, 0xd0, 0x79, 0x9e, + 0xf7, 0x1e, 0x74, 0x51, 0xc5, 0x47, 0x1f, 0x7a, 0x58, 0x16, 0xaa, 0xb1, 0x78, 0x57, 0xec, 0x26, + 0x14, 0x99, 0x77, 0x55, 0xb4, 0xe0, 0xe3, 0x60, 0x5f, 0x66, 0x05, 0x21, 0x0a, 0xe5, 0xca, 0x69, + 0x00, 0x78, 0x4f, 0xa5, 0x88, 0x0f, 0x28, 0x76, 0xbb, 0x73, 0x61, 0x21, 0x02, 0xe3, 0x0a, 0xf9, + 0x3d, 0x07, 0x6f, 0x8d, 0xe6, 0x9c, 0xe8, 0xfd, 0xa0, 0xa9, 0x46, 0xb9, 0x18, 0xc2, 0x8f, 0x12, + 0x72, 0xb1, 0xd6, 0x0f, 0x3e, 0xba, 0xba, 0xd6, 0x8f, 0x79, 0xde, 0x75, 0xad, 0x1f, 0xf7, 0x5a, + 0x2b, 0xa6, 0x50, 0x8f, 0xbc, 0xe5, 0x46, 0xbe, 0x89, 0xa2, 0xb7, 0x3c, 0xf6, 0x61, 0xef, 0xb1, + 0xc2, 0x0f, 0x2e, 0xa5, 0x73, 0xd5, 0x1d, 0xc3, 0x6c, 0xe4, 0x2b, 0x26, 0x7a, 0xc3, 0x93, 0x11, + 0xfb, 0x76, 0x2a, 0xbc, 0x39, 0x9c, 0xc8, 0xd5, 0x62, 0x80, 0x10, 0xff, 0xd8, 0x88, 0x96, 0x3d, + 0x29, 0xc3, 0x1f, 0x3b, 0x85, 0xb7, 0x47, 0xa0, 0x74, 0x95, 0x4a, 0x64, 0xba, 0xe3, 0x7b, 0x87, + 0xbb, 0x11, 0x6d, 0x7f, 0x47, 0x7c, 0x25, 0x0e, 0xed, 0xca, 0xfc, 0x04, 0xa6, 0x23, 0x46, 0x4f, + 0xe8, 0xa6, 0xd3, 0xa5, 0xc4, 0x8e, 0xbf, 0x04, 0x71, 0x18, 0x89, 0x2b, 0xff, 0x79, 0x68, 0xb4, + 0xc5, 0xd6, 0x41, 0xe8, 0xed, 0x68, 0x21, 0x11, 0xf3, 0x42, 0xe1, 0x9d, 0x51, 0x48, 0x5d, 0xbd, + 0x3f, 0x81, 0x71, 0x7b, 0x42, 0x8a, 0x66, 0x3c, 0x1b, 0x78, 0x73, 0x4e, 0x61, 0x36, 0x00, 0x75, + 0x19, 0xef, 0x42, 0xc1, 0x1d, 0x69, 0xba, 0x51, 0x2c, 0x38, 0x26, 0x75, 0xa3, 0x58, 0x78, 0xfa, + 0x99, 0x42, 0x3f, 0x83, 0x1c, 0x1d, 0xc2, 0x21, 0x46, 0x0b, 0x1b, 0x20, 0xe6, 0x82, 0x60, 0xf6, + 0xb2, 0xc4, 0x0d, 0x64, 0xdc, 0xcb, 0x72, 0xc9, 0xd0, 0xc7, 0xbd, 0x2c, 0x97, 0x4e, 0x76, 0x52, + 0xe8, 0x31, 0xa0, 0xf0, 0x78, 0x06, 0x2d, 0x85, 0x05, 0xf8, 0xc7, 0x3e, 0xc2, 0xcd, 0x21, 0x14, + 0xae, 0xf0, 0x0e, 0xcc, 0x45, 0x0f, 0x67, 0xd0, 0x9b, 0x3e, 0xf6, 0x98, 0xe1, 0x8f, 0x70, 0xeb, + 0x12, 0x2a, 0x57, 0xd1, 0x0a, 0xc0, 0x16, 0x36, 0x9d, 0x8e, 0x7b, 0x82, 0xb2, 0x91, 0x56, 0x5c, + 0x28, 0xf9, 0xdb, 0x6d, 0x31, 0x85, 0xbe, 0xe4, 0xe0, 0xe6, 0xa5, 0x99, 0x17, 0xdd, 0x8e, 0xf6, + 0xb6, 0xd8, 0x5c, 0x2f, 0xbc, 0x37, 0x3a, 0x83, 0xb3, 0xf1, 0xf5, 0xbf, 0xa6, 0xa1, 0x68, 0xe5, + 0xe3, 0x16, 0xd6, 0x9f, 0x2b, 0x6d, 0x8c, 0x6a, 0x90, 0xb7, 0x96, 0xaf, 0x93, 0x5e, 0x36, 0xa0, + 0xe4, 0x88, 0xd8, 0xd4, 0xf4, 0x57, 0xce, 0xc4, 0x07, 0x30, 0x69, 0x89, 0x21, 0x99, 0x94, 0xca, + 0xb9, 0x82, 0x44, 0xfc, 0x25, 0x07, 0xf3, 0x96, 0x58, 0x6a, 0x14, 0x3b, 0x07, 0x51, 0xf1, 0xdf, + 0x73, 0xb2, 0xbb, 0x6f, 0x57, 0x42, 0xd4, 0x4e, 0xaf, 0x57, 0x18, 0xd4, 0xdf, 0xfb, 0xe6, 0x65, + 0x25, 0xf5, 0xf7, 0x97, 0x95, 0xd4, 0x77, 0x2f, 0x2b, 0xdc, 0xff, 0x5e, 0x56, 0xb8, 0x2f, 0xce, + 0x2b, 0xdc, 0x9f, 0xce, 0x2b, 0xdc, 0xd7, 0xe7, 0x15, 0xee, 0x9b, 0xf3, 0x0a, 0xf7, 0x8f, 0xf3, + 0x0a, 0xf7, 0xaf, 0xf3, 0x4a, 0xea, 0xbb, 0xf3, 0x0a, 0xf7, 0xd5, 0x3f, 0x2b, 0xa9, 0xa3, 0x71, + 0x52, 0xb3, 0xfd, 0xf0, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x10, 0xbb, 0xa3, 0xb2, 0xf6, 0x28, + 0x00, 0x00, } diff --git a/users/users.proto b/users/users.proto index 94cd8c2e7..052cc8f49 100644 --- a/users/users.proto +++ b/users/users.proto @@ -8,18 +8,6 @@ import "google/protobuf/timestamp.proto"; option (gogoproto.populate_all) = true; service Users { - // LookupOrg authenticates & authorizes a cookie for access to an org by extenal ID. - rpc LookupOrg(LookupOrgRequest) returns (LookupOrgResponse) {}; - - // LookupUsingToken authenticates & authorizes a token for access to an org. - rpc LookupUsingToken(LookupUsingTokenRequest) returns (LookupUsingTokenResponse) {}; - - // LookupAdmin authenticates & authorizes a cookie for admin access. - rpc LookupAdmin(LookupAdminRequest) returns (LookupAdminResponse) {}; - - // LookupUser authenticates a cookie. - rpc LookupUser(LookupUserRequest) returns (LookupUserResponse) {}; - // GetOrganizations returns a list of all organizations by default. See // GetOrganizationsRequest for more details. rpc GetOrganizations(GetOrganizationsRequest) returns (GetOrganizationsResponse) {}; @@ -66,11 +54,45 @@ service Users { // WARNING: this is a relatively expensive query, and basically exports the entire DB. rpc GetSummary(Empty) returns (Summary) {}; + // SetOrganizationWebhookFirstSeenAt sets the FirstSeenAt field on the webhook to the current time + rpc SetOrganizationWebhookFirstSeenAt(SetOrganizationWebhookFirstSeenAtRequest) returns (SetOrganizationWebhookFirstSeenAtResponse) {}; + + /** LEGACY remove these after all clients in production are upgraded **/ + + // LookupOrg authenticates & authorizes a cookie for access to an org by extenal ID. + rpc LookupOrg(LookupOrgRequest) returns (LookupOrgResponse) {}; + + // LookupUsingToken authenticates & authorizes a token for access to an org. + rpc LookupUsingToken(LookupUsingTokenRequest) returns (LookupUsingTokenResponse) {}; + + // LookupAdmin authenticates & authorizes a cookie for admin access. + rpc LookupAdmin(LookupAdminRequest) returns (LookupAdminResponse) {}; + + // LookupUser authenticates a cookie. + rpc LookupUser(LookupUserRequest) returns (LookupUserResponse) {}; + // LookupOrganizationWebhookUsingSecretID returns a Webhook given the external org ID and the webhook secret ID rpc LookupOrganizationWebhookUsingSecretID(LookupOrganizationWebhookUsingSecretIDRequest) returns (LookupOrganizationWebhookUsingSecretIDResponse) {}; + + /** END LEGACY **/ +} - // SetOrganizationWebhookFirstSeenAt sets the FirstSeenAt field on the webhook to the current time - rpc SetOrganizationWebhookFirstSeenAt(SetOrganizationWebhookFirstSeenAtRequest) returns (SetOrganizationWebhookFirstSeenAtResponse) {}; +// AuthService authenticates & authorizes other requests +service AuthService { + // AuthUser authenticates a cookie for validity. + rpc AuthUser(LookupUserRequest) returns (LookupUserResponse) {}; + + // AuthUserOrgRequest authenticates & authorizes a cookie for access to an org by extenal ID. + rpc AuthUserForOrg(LookupOrgRequest) returns (LookupOrgResponse) {}; + + // AuthTokenForOrg authenticates & authorizes a token for access to an org. + rpc AuthTokenForOrg(LookupUsingTokenRequest) returns (LookupUsingTokenResponse) {}; + + // AuthWebhookSecretForOrg returns a Webhook given the external org ID and the webhook secret ID + rpc AuthWebhookSecretForOrg(LookupOrganizationWebhookUsingSecretIDRequest) returns (LookupOrganizationWebhookUsingSecretIDResponse) {}; + + // AuthUserForAdmin authenticates & authorizes a cookie for weave cloud admin access. + rpc AuthUserForAdmin(LookupAdminRequest) returns (LookupAdminResponse) {}; } enum AuthorizedAction {