From 2f1882387b375742360ada136ac69c584e55265d Mon Sep 17 00:00:00 2001 From: Andrei Mihu Date: Sat, 11 Nov 2023 18:34:21 +0000 Subject: [PATCH] Add support for optional client IP address passthrough to runtime Satori client. --- CHANGELOG.md | 1 + go.mod | 2 +- go.sum | 4 ++-- internal/satori/satori.go | 11 ++++++++++- server/api_test.go | 2 +- server/match_common_test.go | 1 + server/runtime_javascript_nakama.go | 7 ++++++- server/runtime_lua_nakama.go | 3 ++- server/storage_index_test.go | 10 +++++----- .../heroiclabs/nakama-common/runtime/runtime.go | 2 +- vendor/modules.txt | 2 +- 11 files changed, 31 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e2b30600..80f1bcd92 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [keep a changelog](http://keepachangelog.com) and this pr - Added JavaScript runtime function to clear all localcache data. - Added support for per-key TTL in Lua runtime localcache. - Added support for per-key TTL in JavaScript runtime localcache. +- Add support for optional client IP address passthrough to runtime Satori client. ### Changed - Remove unused config 'matchmaker.batch_pool_size'. diff --git a/go.mod b/go.mod index d73729a52..d9c164d31 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 - github.com/heroiclabs/nakama-common v0.0.0-20231110231506-a6d791dbc20f + github.com/heroiclabs/nakama-common v0.0.0-20231111182915-5206c3ece9b0 github.com/jackc/pgconn v1.14.0 github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa github.com/jackc/pgtype v1.14.0 diff --git a/go.sum b/go.sum index f5c0b02ec..2c6c9a82f 100644 --- a/go.sum +++ b/go.sum @@ -302,8 +302,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 v0.0.0-20231110231506-a6d791dbc20f h1:sthlTetnKYxex7iS4BgW5S49s5zqPtBzg2XN1NPfvq0= -github.com/heroiclabs/nakama-common v0.0.0-20231110231506-a6d791dbc20f/go.mod h1:Os8XeXGvHAap/p6M/8fQ3gle4eEXDGRQmoRNcPQTjXs= +github.com/heroiclabs/nakama-common v0.0.0-20231111182915-5206c3ece9b0 h1:iGR26K0+AIhf5pJuRsDeDxTt6BeVJfyv6ys94xgiEnY= +github.com/heroiclabs/nakama-common v0.0.0-20231111182915-5206c3ece9b0/go.mod h1:Os8XeXGvHAap/p6M/8fQ3gle4eEXDGRQmoRNcPQTjXs= 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 3781a96d3..594a17512 100644 --- a/internal/satori/satori.go +++ b/internal/satori/satori.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "io" + "net" "net/http" "net/url" "strings" @@ -141,8 +142,9 @@ type authenticateBody struct { // @summary Create a new identity. // @param ctx(type=context.Context) The context object represents information about the server and requester. // @param id(type=string) The identifier of the identity. +// @param ipAddress(type=string, optional=true) An optional client IP address to pass on to Satori for geo-IP lookup. // @return error(error) An optional error value if an error occurred. -func (s *SatoriClient) Authenticate(ctx context.Context, id string) error { +func (s *SatoriClient) Authenticate(ctx context.Context, id string, ipAddress ...string) error { if s.invalidConfig { return runtime.ErrSatoriConfigurationInvalid } @@ -162,6 +164,13 @@ func (s *SatoriClient) Authenticate(ctx context.Context, id string) error { } req.Header.Set("Content-Type", "application/json") req.SetBasicAuth(s.apiKey, "") + if len(ipAddress) > 0 && ipAddress[0] != "" { + if ipAddr := net.ParseIP(ipAddress[0]); ipAddr != nil { + req.Header.Set("X-Forwarded-For", ipAddr.String()) + } + } else if ipAddr, ok := ctx.Value(runtime.RUNTIME_CTX_CLIENT_IP).(string); ok { + req.Header.Set("X-Forwarded-For", ipAddr) + } res, err := s.httpc.Do(req) if err != nil { diff --git a/server/api_test.go b/server/api_test.go index 8ce8961ab..90503e7b8 100644 --- a/server/api_test.go +++ b/server/api_test.go @@ -53,7 +53,7 @@ var ( DiscardUnknown: false, } metrics = NewLocalMetrics(logger, logger, nil, cfg) - storageIdx, _ = NewLocalStorageIndex(logger, nil, &StorageConfig{DisableIndexOnly: false}) + storageIdx, _ = NewLocalStorageIndex(logger, nil, &StorageConfig{DisableIndexOnly: false}, metrics) _ = CheckConfig(logger, cfg) ) diff --git a/server/match_common_test.go b/server/match_common_test.go index 91689eea7..4d6f64efa 100644 --- a/server/match_common_test.go +++ b/server/match_common_test.go @@ -180,6 +180,7 @@ func (s *testMetrics) GaugeRuntimes(value float64) func (s *testMetrics) GaugeLuaRuntimes(value float64) {} func (s *testMetrics) GaugeJsRuntimes(value float64) {} func (s *testMetrics) GaugeAuthoritativeMatches(value float64) {} +func (s *testMetrics) GaugeStorageIndexEntries(indexName string, value float64) {} func (s *testMetrics) CountDroppedEvents(delta int64) {} func (s *testMetrics) CountWebsocketOpened(delta int64) {} func (s *testMetrics) CountWebsocketClosed(delta int64) {} diff --git a/server/runtime_javascript_nakama.go b/server/runtime_javascript_nakama.go index 46b569ad5..4af5af79b 100644 --- a/server/runtime_javascript_nakama.go +++ b/server/runtime_javascript_nakama.go @@ -8390,7 +8390,12 @@ func (n *runtimeJavascriptNakamaModule) satoriAuthenticate(r *goja.Runtime) func return func(f goja.FunctionCall) goja.Value { id := getJsString(r, f.Argument(0)) - if err := n.satori.Authenticate(n.ctx, id); err != nil { + var ip string + if f.Argument(1) != goja.Undefined() && f.Argument(1) != goja.Null() { + ip = getJsString(r, f.Argument(1)) + } + + if err := n.satori.Authenticate(n.ctx, id, ip); err != nil { n.logger.Error("Failed to Satori Authenticate.", zap.Error(err)) panic(r.NewGoError(fmt.Errorf("failed to satori authenticate: %s", err.Error()))) } diff --git a/server/runtime_lua_nakama.go b/server/runtime_lua_nakama.go index c52975fe9..6400c359e 100644 --- a/server/runtime_lua_nakama.go +++ b/server/runtime_lua_nakama.go @@ -10058,8 +10058,9 @@ func (n *RuntimeLuaNakamaModule) getSatori(l *lua.LState) int { // @return error(error) An optional error value if an error occurred. func (n *RuntimeLuaNakamaModule) satoriAuthenticate(l *lua.LState) int { identifier := l.CheckString(1) + ip := l.OptString(2, "") - if err := n.satori.Authenticate(l.Context(), identifier); err != nil { + if err := n.satori.Authenticate(l.Context(), identifier, ip); err != nil { l.RaiseError("failed to satori authenticate: %v", err.Error()) return 0 } diff --git a/server/storage_index_test.go b/server/storage_index_test.go index a651eb9cc..90c61dece 100644 --- a/server/storage_index_test.go +++ b/server/storage_index_test.go @@ -55,7 +55,7 @@ func TestLocalStorageIndex_Write(t *testing.T) { }) valueThree := string(valueThreeBytes) - storageIdx, err := NewLocalStorageIndex(logger, db, &StorageConfig{}) + storageIdx, err := NewLocalStorageIndex(logger, db, &StorageConfig{}, metrics) if err != nil { t.Fatal(err.Error()) } @@ -207,7 +207,7 @@ func TestLocalStorageIndex_Write(t *testing.T) { UpdateTime: timestamppb.New(ts), } - storageIdx, err := NewLocalStorageIndex(logger, db, &StorageConfig{}) + storageIdx, err := NewLocalStorageIndex(logger, db, &StorageConfig{}, metrics) if err != nil { t.Fatal(err.Error()) } @@ -331,7 +331,7 @@ func TestLocalStorageIndex_List(t *testing.T) { }) valueThree := string(valueThreeBytes) - storageIdx, err := NewLocalStorageIndex(logger, db, &StorageConfig{}) + storageIdx, err := NewLocalStorageIndex(logger, db, &StorageConfig{}, metrics) if err != nil { t.Fatal(err.Error()) } @@ -424,7 +424,7 @@ func TestLocalStorageIndex_List(t *testing.T) { }) valueThree := string(valueThreeBytes) - storageIdx, err := NewLocalStorageIndex(logger, db, &StorageConfig{}) + storageIdx, err := NewLocalStorageIndex(logger, db, &StorageConfig{}, metrics) if err != nil { t.Fatal(err.Error()) } @@ -508,7 +508,7 @@ func TestLocalStorageIndex_Delete(t *testing.T) { }) valueOne := string(valueOneBytes) - storageIdx, err := NewLocalStorageIndex(logger, db, &StorageConfig{}) + storageIdx, err := NewLocalStorageIndex(logger, db, &StorageConfig{}, metrics) if err != nil { t.Fatal(err.Error()) } diff --git a/vendor/github.com/heroiclabs/nakama-common/runtime/runtime.go b/vendor/github.com/heroiclabs/nakama-common/runtime/runtime.go index ba5ddbf26..5522a1bf7 100644 --- a/vendor/github.com/heroiclabs/nakama-common/runtime/runtime.go +++ b/vendor/github.com/heroiclabs/nakama-common/runtime/runtime.go @@ -1159,7 +1159,7 @@ type NakamaModule interface { Satori runtime integration defintions. */ type Satori interface { - Authenticate(ctx context.Context, id string) error + Authenticate(ctx context.Context, id string, ipAddress ...string) error PropertiesGet(ctx context.Context, id string) (*Properties, error) PropertiesUpdate(ctx context.Context, id string, properties *PropertiesUpdate) error EventsPublish(ctx context.Context, id string, events []*Event) error diff --git a/vendor/modules.txt b/vendor/modules.txt index 46346b547..faa0309ee 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -156,7 +156,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 v0.0.0-20231110231506-a6d791dbc20f +# github.com/heroiclabs/nakama-common v0.0.0-20231111182915-5206c3ece9b0 ## explicit; go 1.19 github.com/heroiclabs/nakama-common/api github.com/heroiclabs/nakama-common/rtapi -- GitLab