From d704eaddcb833b14b5e18756925a47081b429163 Mon Sep 17 00:00:00 2001 From: pg9182 <96569817+pg9182@users.noreply.github.com> Date: Mon, 27 Feb 2023 00:38:33 -0500 Subject: pkg/api/api0: Implement EAX username source --- pkg/api/api0/api.go | 4 +++ pkg/api/api0/client.go | 94 +++++++++++++++++++++++++++++++++++++++++++++++++ pkg/api/api0/metrics.go | 12 +++++++ 3 files changed, 110 insertions(+) diff --git a/pkg/api/api0/api.go b/pkg/api/api0/api.go index 3ed5999..afce1d4 100644 --- a/pkg/api/api0/api.go +++ b/pkg/api/api0/api.go @@ -26,6 +26,7 @@ import ( "github.com/klauspost/compress/gzip" "github.com/pg9182/ip2x" + "github.com/r2northstar/atlas/pkg/eax" "github.com/r2northstar/atlas/pkg/metricsx" "github.com/r2northstar/atlas/pkg/origin" "github.com/rs/zerolog/hlog" @@ -50,6 +51,9 @@ type Handler struct { // usernames. OriginAuthMgr *origin.AuthMgr + // EAXClient makes requests to the EAX API. + EAXClient *eax.Client + // CleanBadWords is used to filter bad words from server names and // descriptions. If not provided, words will not be filtered. CleanBadWords func(s string) string diff --git a/pkg/api/api0/client.go b/pkg/api/api0/client.go index 9b1408f..45f006b 100644 --- a/pkg/api/api0/client.go +++ b/pkg/api/api0/client.go @@ -12,6 +12,7 @@ import ( "time" "github.com/r2northstar/atlas/pkg/api/api0/api0gameserver" + "github.com/r2northstar/atlas/pkg/eax" "github.com/r2northstar/atlas/pkg/origin" "github.com/r2northstar/atlas/pkg/pdata" "github.com/r2northstar/atlas/pkg/stryder" @@ -27,6 +28,19 @@ const ( // Get the username from the Origin API. UsernameSourceOrigin UsernameSource = "origin" + + // Get the username from the Origin API, but fall back to EAX on failure. + UsernameSourceOriginEAX UsernameSource = "origin-eax" + + // Get the username from EAX. + UsernameSourceEAX UsernameSource = "eax" + + // Get the username from the Origin API, but also check EAX and warn if it's + // different. + UsernameSourceOriginEAXDebug UsernameSource = "origin-eax-debug" + + // Get the username from EAX, but fall back to the Origin API on failure. + UsernameSourceEAXOrigin UsernameSource = "eax-origin" ) type MainMenuPromos struct { @@ -276,6 +290,46 @@ func (h *Handler) lookupUsername(r *http.Request, uid uint64) (username string) break case UsernameSourceOrigin: username, _ = h.lookupUsernameOrigin(r, uid) + case UsernameSourceOriginEAX: + username, _ = h.lookupUsernameOrigin(r, uid) + if username == "" { + if eaxUsername, ok := h.lookupUsernameEAX(r, uid); ok { + username = eaxUsername + hlog.FromRequest(r).Warn(). + Uint64("uid", uid). + Str("origin_username", eaxUsername). + Msgf("failed to get username from origin, but got it from eax") + } + } + case UsernameSourceOriginEAXDebug: + username, _ = h.lookupUsernameOrigin(r, uid) + if eaxUsername, ok := h.lookupUsernameEAX(r, uid); ok { + if eaxUsername != username { + hlog.FromRequest(r).Warn(). + Uint64("uid", uid). + Str("origin_username", username). + Str("eax_username", eaxUsername). + Msgf("got username from origin and eax, but they don't match; using the origin one") + } + } else { + hlog.FromRequest(r).Warn(). + Uint64("uid", uid). + Str("origin_username", username). + Msgf("got username from origin, but failed to get username from eax") + } + case UsernameSourceEAX: + username, _ = h.lookupUsernameEAX(r, uid) + case UsernameSourceEAXOrigin: + username, _ = h.lookupUsernameEAX(r, uid) + if username == "" { + if originUsername, ok := h.lookupUsernameOrigin(r, uid); ok { + username = originUsername + hlog.FromRequest(r).Warn(). + Uint64("uid", uid). + Str("origin_username", originUsername). + Msgf("failed to get username from eax, but got it from origin") + } + } default: hlog.FromRequest(r).Error(). Msgf("unknown username source %q", h.UsernameSource) @@ -345,6 +399,46 @@ func (h *Handler) lookupUsernameOrigin(r *http.Request, uid uint64) (username st return } +// lookupUsernameEAX gets the username for uid from the EAX API, returning an +// empty string if a username does not exist for the uid, and false on error. +func (h *Handler) lookupUsernameEAX(r *http.Request, uid uint64) (username string, ok bool) { + if h.EAXClient == nil { + hlog.FromRequest(r).Error(). + Str("username_source", "eax"). + Msgf("no eax client available for username lookup") + return + } + eaxStart := time.Now() + if p, err := h.EAXClient.PlayerIDByPD(r.Context(), uid); err == nil { + if p != nil { + username = p.DisplayName + h.m().client_originauth_eax_username_lookup_calls_total.success.Inc() + } else { + hlog.FromRequest(r).Warn(). + Err(err). + Uint64("uid", uid). + Str("username_source", "eax"). + Msgf("no eax username found for uid") + h.m().client_originauth_eax_username_lookup_calls_total.notfound.Inc() + } + ok = true + } else if errors.Is(err, eax.ErrVersionRequired) || errors.Is(err, eax.ErrAutoUpdateBackoff) { + hlog.FromRequest(r).Error(). + Err(err). + Str("username_source", "eax"). + Msgf("eax update check failure") + h.m().client_originauth_eax_username_lookup_calls_total.fail_update_check.Inc() + } else if !errors.Is(err, context.Canceled) { + hlog.FromRequest(r).Error(). + Err(err). + Str("username_source", "eax"). + Msgf("failed to get eax player info") + h.m().client_originauth_eax_username_lookup_calls_total.fail_other_error.Inc() + } + h.m().client_originauth_eax_username_lookup_duration_seconds.UpdateDuration(eaxStart) + return +} + func (h *Handler) handleClientAuthWithServer(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodOptions && r.Method != http.MethodPost { h.m().client_authwithserver_requests_total.http_method_not_allowed.Inc() diff --git a/pkg/api/api0/metrics.go b/pkg/api/api0/metrics.go index 8f9a0b5..46c8615 100644 --- a/pkg/api/api0/metrics.go +++ b/pkg/api/api0/metrics.go @@ -79,6 +79,13 @@ type apiMetrics struct { fail_authtok_refresh *metrics.Counter fail_other_error *metrics.Counter } + client_originauth_eax_username_lookup_duration_seconds *metrics.Histogram + client_originauth_eax_username_lookup_calls_total struct { + success *metrics.Counter + notfound *metrics.Counter + fail_update_check *metrics.Counter + fail_other_error *metrics.Counter + } client_authwithserver_requests_total struct { success *metrics.Counter reject_bad_request *metrics.Counter @@ -246,6 +253,11 @@ func (h *Handler) m() *apiMetrics { mo.client_originauth_origin_username_lookup_calls_total.notfound = mo.set.NewCounter(`atlas_api0_client_originauth_origin_username_lookup_calls_total{result="notfound"}`) mo.client_originauth_origin_username_lookup_calls_total.fail_authtok_refresh = mo.set.NewCounter(`atlas_api0_client_originauth_origin_username_lookup_calls_total{result="fail_authtok_refresh"}`) mo.client_originauth_origin_username_lookup_calls_total.fail_other_error = mo.set.NewCounter(`atlas_api0_client_originauth_origin_username_lookup_calls_total{result="fail_other_error"}`) + mo.client_originauth_eax_username_lookup_duration_seconds = mo.set.NewHistogram(`atlas_api0_client_originauth_eax_username_lookup_duration_seconds`) + mo.client_originauth_eax_username_lookup_calls_total.success = mo.set.NewCounter(`atlas_api0_client_originauth_eax_username_lookup_calls_total{result="success"}`) + mo.client_originauth_eax_username_lookup_calls_total.notfound = mo.set.NewCounter(`atlas_api0_client_originauth_eax_username_lookup_calls_total{result="notfound"}`) + mo.client_originauth_eax_username_lookup_calls_total.fail_update_check = mo.set.NewCounter(`atlas_api0_client_originauth_eax_username_lookup_calls_total{result="fail_update_check"}`) + mo.client_originauth_eax_username_lookup_calls_total.fail_other_error = mo.set.NewCounter(`atlas_api0_client_originauth_eax_username_lookup_calls_total{result="fail_other_error"}`) mo.client_authwithserver_requests_total.success = mo.set.NewCounter(`atlas_api0_client_authwithserver_requests_total{result="success"}`) mo.client_authwithserver_requests_total.reject_bad_request = mo.set.NewCounter(`atlas_api0_client_authwithserver_requests_total{result="reject_bad_request"}`) mo.client_authwithserver_requests_total.reject_versiongate = mo.set.NewCounter(`atlas_api0_client_authwithserver_requests_total{result="reject_versiongate"}`) -- cgit v1.2.3