From 7c45fb14d5ec86f281818d66903f7ca1cff40130 Mon Sep 17 00:00:00 2001 From: Simon Esposito Date: Tue, 21 Mar 2023 17:12:13 +0000 Subject: [PATCH] Satori config checking improvements --- go.mod | 2 +- go.sum | 4 +- internal/satori/satori.go | 52 ++++++++++++------- server/config.go | 16 +++++- server/runtime_go_nakama.go | 2 +- server/runtime_javascript_nakama.go | 2 +- server/runtime_lua_nakama.go | 2 +- .../nakama-common/runtime/runtime.go | 2 + vendor/modules.txt | 2 +- 9 files changed, 56 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index 2b16d4392..0eeb6d6b9 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 - github.com/heroiclabs/nakama-common v1.26.1-0.20230321112911-d8dca07dc3ef + github.com/heroiclabs/nakama-common v1.26.1-0.20230321170403-7becee7153cf github.com/jackc/pgconn v1.13.0 github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa github.com/jackc/pgtype v1.12.0 diff --git a/go.sum b/go.sum index dbd1c2b87..80bb6878b 100644 --- a/go.sum +++ b/go.sum @@ -284,8 +284,8 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/heroiclabs/nakama-common v1.26.1-0.20230321112911-d8dca07dc3ef h1:+x1EN34iCl4xfwshomH8InLuYj7glBsKKDa1S6AoLWM= -github.com/heroiclabs/nakama-common v1.26.1-0.20230321112911-d8dca07dc3ef/go.mod h1:/znXrt+yd+i7WHvizD3SNeA4tTLl9PvVckHafUnLAi0= +github.com/heroiclabs/nakama-common v1.26.1-0.20230321170403-7becee7153cf h1:N+HC+zfBt3Vp0g3REss4CJIjETCNhGHBT3Pi2vDm4mw= +github.com/heroiclabs/nakama-common v1.26.1-0.20230321170403-7becee7153cf/go.mod h1:/znXrt+yd+i7WHvizD3SNeA4tTLl9PvVckHafUnLAi0= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= diff --git a/internal/satori/satori.go b/internal/satori/satori.go index ba1cde0e8..fa0ce3859 100644 --- a/internal/satori/satori.go +++ b/internal/satori/satori.go @@ -8,6 +8,7 @@ import ( "fmt" "github.com/golang-jwt/jwt/v4" "github.com/heroiclabs/nakama-common/runtime" + "go.uber.org/zap" "io" "net/http" "net/url" @@ -18,6 +19,7 @@ import ( var _ runtime.Satori = &SatoriClient{} type SatoriClient struct { + logger *zap.Logger httpc *http.Client url *url.URL urlString string @@ -25,11 +27,14 @@ type SatoriClient struct { apiKey string signingKey string tokenExpirySec int + invalidConfig bool } -func NewSatoriClient(satoriUrl, apiKeyName, apiKey, signingKey string) *SatoriClient { +func NewSatoriClient(logger *zap.Logger, satoriUrl, apiKeyName, apiKey, signingKey string) *SatoriClient { parsedUrl, _ := url.Parse(satoriUrl) - return &SatoriClient{ + + sc := &SatoriClient{ + logger: logger, urlString: satoriUrl, httpc: &http.Client{Timeout: 2 * time.Second}, url: parsedUrl, @@ -38,6 +43,13 @@ func NewSatoriClient(satoriUrl, apiKeyName, apiKey, signingKey string) *SatoriCl signingKey: strings.TrimSpace(signingKey), tokenExpirySec: 3600, } + + if err := sc.validateConfig(); err != nil { + sc.invalidConfig = true + logger.Warn(err.Error()) + } + + return sc } func (s *SatoriClient) validateConfig() error { @@ -47,17 +59,17 @@ func (s *SatoriClient) validateConfig() error { errorStrings = append(errorStrings, fmt.Sprintf("Invalid URL: %s", err.Error())) } if s.apiKeyName == "" { - errorStrings = append(errorStrings, "API key name not set.") + errorStrings = append(errorStrings, "api_key_name not set") } if s.apiKey == "" { - errorStrings = append(errorStrings, "API Key not set.") + errorStrings = append(errorStrings, "api_key not set") } if s.signingKey == "" { - errorStrings = append(errorStrings, "Signing Key not set.") + errorStrings = append(errorStrings, "signing_key not set") } if len(errorStrings) > 0 { - return fmt.Errorf("Satori configuration error: %s", strings.Join(errorStrings, ", ")) + return fmt.Errorf("Satori configuration invalid: %s.", strings.Join(errorStrings, ", ")) } return nil @@ -109,8 +121,8 @@ type authenticateBody struct { // @param id(type=string) The identifier of the identity. // @return error(error) An optional error value if an error occurred. func (s *SatoriClient) Authenticate(ctx context.Context, id string) error { - if err := s.validateConfig(); err != nil { - return err + if s.invalidConfig { + return runtime.ErrSatoriConfigurationInvalid } url := s.url.String() + "/v1/authenticate" @@ -149,8 +161,8 @@ func (s *SatoriClient) Authenticate(ctx context.Context, id string) error { // @return properties(type=*runtime.Properties) The identity properties. // @return error(error) An optional error value if an error occurred. func (s *SatoriClient) PropertiesGet(ctx context.Context, id string) (*runtime.Properties, error) { - if err := s.validateConfig(); err != nil { - return nil, err + if s.invalidConfig { + return nil, runtime.ErrSatoriConfigurationInvalid } url := s.url.String() + "/v1/properties" @@ -196,8 +208,8 @@ func (s *SatoriClient) PropertiesGet(ctx context.Context, id string) (*runtime.P // @param properties(type=*runtime.PropertiesUpdate) The identity properties to update. // @return error(error) An optional error value if an error occurred. func (s *SatoriClient) PropertiesUpdate(ctx context.Context, id string, properties *runtime.PropertiesUpdate) error { - if err := s.validateConfig(); err != nil { - return err + if s.invalidConfig { + return runtime.ErrSatoriConfigurationInvalid } url := s.url.String() + "/v1/properties" @@ -252,8 +264,8 @@ func (e *event) setTimestamp() { // @param events(type=[]*runtime.Event) An array of events to publish. // @return error(error) An optional error value if an error occurred. func (s *SatoriClient) EventsPublish(ctx context.Context, id string, events []*runtime.Event) error { - if err := s.validateConfig(); err != nil { - return err + if s.invalidConfig { + return runtime.ErrSatoriConfigurationInvalid } url := s.url.String() + "/v1/event" @@ -304,8 +316,8 @@ func (s *SatoriClient) EventsPublish(ctx context.Context, id string, events []*r // @return experiments(type=*runtime.ExperimentList) The experiment list. // @return error(error) An optional error value if an error occurred. func (s *SatoriClient) ExperimentsList(ctx context.Context, id string, names ...string) (*runtime.ExperimentList, error) { - if err := s.validateConfig(); err != nil { - return nil, err + if s.invalidConfig { + return nil, runtime.ErrSatoriConfigurationInvalid } url := s.url.String() + "/v1/experiment" @@ -360,8 +372,8 @@ func (s *SatoriClient) ExperimentsList(ctx context.Context, id string, names ... // @return flags(type=*runtime.FlagList) The flag list. // @return error(error) An optional error value if an error occurred. func (s *SatoriClient) FlagsList(ctx context.Context, id string, names ...string) (*runtime.FlagList, error) { - if err := s.validateConfig(); err != nil { - return nil, err + if s.invalidConfig { + return nil, runtime.ErrSatoriConfigurationInvalid } url := s.url.String() + "/v1/flag" @@ -416,8 +428,8 @@ func (s *SatoriClient) FlagsList(ctx context.Context, id string, names ...string // @return liveEvents(type=*runtime.LiveEventsList) The live event list. // @return error(error) An optional error value if an error occurred. func (s *SatoriClient) LiveEventsList(ctx context.Context, id string, names ...string) (*runtime.LiveEventList, error) { - if err := s.validateConfig(); err != nil { - return nil, err + if s.invalidConfig { + return nil, runtime.ErrSatoriConfigurationInvalid } url := s.url.String() + "/v1/live-event" diff --git a/server/config.go b/server/config.go index d48db1322..005db0779 100644 --- a/server/config.go +++ b/server/config.go @@ -1015,10 +1015,24 @@ func NewSatoriConfig() *SatoriConfig { } func (sc *SatoriConfig) Validate(logger *zap.Logger) { - _, err := url.Parse(sc.Url) + satoriUrl, err := url.Parse(sc.Url) // Empty string is a valid URL if err != nil { logger.Fatal("Satori URL is invalid", zap.String("satori_url", sc.Url), zap.Error(err)) } + + if satoriUrl.String() != "" { + if sc.ApiKeyName == "" { + logger.Fatal("Satori configuration incomplete: api_key_name not set") + } + if sc.ApiKey == "" { + logger.Fatal("Satori configuration incomplete: api_key not set") + } + if sc.SigningKey == "" { + logger.Fatal("Satori configuration incomplete: signing_key not set") + } + } else if sc.ApiKeyName != "" || sc.ApiKey != "" || sc.SigningKey != "" { + logger.Fatal("Satori configuration incomplete: url not set") + } } type IAPHuaweiConfig struct { diff --git a/server/runtime_go_nakama.go b/server/runtime_go_nakama.go index 30163222e..b6432b562 100644 --- a/server/runtime_go_nakama.go +++ b/server/runtime_go_nakama.go @@ -87,7 +87,7 @@ func NewRuntimeGoNakamaModule(logger *zap.Logger, db *sql.DB, protojsonMarshaler node: config.GetName(), - satori: satori.NewSatoriClient(config.GetSatori().Url, config.GetSatori().ApiKeyName, config.GetSatori().ApiKey, config.GetSatori().SigningKey), + satori: satori.NewSatoriClient(logger, config.GetSatori().Url, config.GetSatori().ApiKeyName, config.GetSatori().ApiKey, config.GetSatori().SigningKey), } } diff --git a/server/runtime_javascript_nakama.go b/server/runtime_javascript_nakama.go index d7343353d..bdfcb91e1 100644 --- a/server/runtime_javascript_nakama.go +++ b/server/runtime_javascript_nakama.go @@ -115,7 +115,7 @@ func NewRuntimeJavascriptNakamaModule(logger *zap.Logger, db *sql.DB, protojsonM eventFn: eventFn, matchCreateFn: matchCreateFn, - satori: satori.NewSatoriClient(config.GetSatori().Url, config.GetSatori().ApiKeyName, config.GetSatori().ApiKey, config.GetSatori().SigningKey), + satori: satori.NewSatoriClient(logger, config.GetSatori().Url, config.GetSatori().ApiKeyName, config.GetSatori().ApiKey, config.GetSatori().SigningKey), } } diff --git a/server/runtime_lua_nakama.go b/server/runtime_lua_nakama.go index 068138f70..fcce67bfd 100644 --- a/server/runtime_lua_nakama.go +++ b/server/runtime_lua_nakama.go @@ -124,7 +124,7 @@ func NewRuntimeLuaNakamaModule(logger *zap.Logger, db *sql.DB, protojsonMarshale matchCreateFn: matchCreateFn, eventFn: eventFn, - satori: satori.NewSatoriClient(config.GetSatori().Url, config.GetSatori().ApiKeyName, config.GetSatori().ApiKey, config.GetSatori().SigningKey), + satori: satori.NewSatoriClient(logger, config.GetSatori().Url, config.GetSatori().ApiKeyName, config.GetSatori().ApiKey, config.GetSatori().SigningKey), } } diff --git a/vendor/github.com/heroiclabs/nakama-common/runtime/runtime.go b/vendor/github.com/heroiclabs/nakama-common/runtime/runtime.go index 5a9787c04..eb0c87c71 100644 --- a/vendor/github.com/heroiclabs/nakama-common/runtime/runtime.go +++ b/vendor/github.com/heroiclabs/nakama-common/runtime/runtime.go @@ -217,6 +217,8 @@ var ( ErrMatchStateFailed = errors.New("match did not return state") ErrMatchLabelTooLong = errors.New("match label too long, must be 0-2048 bytes") ErrDeferredBroadcastFull = errors.New("too many deferred message broadcasts per tick") + + ErrSatoriConfigurationInvalid = errors.New("satori configuration is invalid") ) const ( diff --git a/vendor/modules.txt b/vendor/modules.txt index 308f0bf41..1d88d1075 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -143,7 +143,7 @@ github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/internal/genopena github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options github.com/grpc-ecosystem/grpc-gateway/v2/runtime github.com/grpc-ecosystem/grpc-gateway/v2/utilities -# github.com/heroiclabs/nakama-common v1.26.1-0.20230321112911-d8dca07dc3ef +# github.com/heroiclabs/nakama-common v1.26.1-0.20230321170403-7becee7153cf ## explicit; go 1.19 github.com/heroiclabs/nakama-common/api github.com/heroiclabs/nakama-common/rtapi