fix game zeeone expired session lookup
This commit is contained in:
parent
2a7fff405d
commit
2f3af25c0c
@ -1260,6 +1260,68 @@ func TestHandleZeeOneAccessTokenIgnoresStaleLaunchSessionGameID(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHandleZeeOneExpiredAccessTokenUsesScopedLaunchSession(t *testing.T) {
|
||||||
|
secret := "zeeone-test-secret"
|
||||||
|
userID := int64(328141720820654080)
|
||||||
|
token := leaderccTestAccessToken(t, "lalu", userID, "1010", 1700000300)
|
||||||
|
repo := &fakeRepository{
|
||||||
|
platform: gamedomain.Platform{
|
||||||
|
PlatformCode: "zeeone",
|
||||||
|
AdapterType: gamedomain.AdapterZeeOneV1,
|
||||||
|
CallbackSecretCiphertext: secret,
|
||||||
|
AdapterConfigJSON: `{"merchant_id":307715,"platform_id":2032,"uid_mode":"display_user_id"}`,
|
||||||
|
},
|
||||||
|
sessions: []gamedomain.LaunchSession{
|
||||||
|
{
|
||||||
|
AppCode: "lalu",
|
||||||
|
SessionID: "launch_session_1035",
|
||||||
|
UserID: userID,
|
||||||
|
DisplayUserID: "1010",
|
||||||
|
PlatformCode: "zeeone",
|
||||||
|
GameID: "zeeone_1035",
|
||||||
|
ProviderGameID: "1035",
|
||||||
|
LaunchTokenHash: stableHash(token),
|
||||||
|
Status: gamedomain.SessionActive,
|
||||||
|
ExpiresAtMS: 1700086800000,
|
||||||
|
CreatedAtMS: 1700000000000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AppCode: "lalu",
|
||||||
|
SessionID: "newer_wrong_game_session",
|
||||||
|
UserID: userID,
|
||||||
|
DisplayUserID: "1010",
|
||||||
|
PlatformCode: "zeeone",
|
||||||
|
GameID: "zeeone_1021",
|
||||||
|
ProviderGameID: "1021",
|
||||||
|
LaunchTokenHash: stableHash(token),
|
||||||
|
Status: gamedomain.SessionActive,
|
||||||
|
ExpiresAtMS: 1700086800000,
|
||||||
|
CreatedAtMS: 1700000100000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
wallet := &fakeWallet{balanceAfter: 777}
|
||||||
|
svc := New(Config{}, repo, wallet, &fakeUser{})
|
||||||
|
svc.now = func() time.Time { return time.UnixMilli(1700000400000) }
|
||||||
|
|
||||||
|
changeBody := `{"appId":"M307715_P2032","userId":"1010","sessionId":"` + token + `","currency_diff":-50000,"diff_msg":"bet","game_id":1035,"room_id":"3255","change_time_at":1700000400,"order_id":"zee_order_expired_token_scoped"}`
|
||||||
|
raw, _, err := svc.HandleCallback(context.Background(), &gamev1.CallbackRequest{
|
||||||
|
Meta: &gamev1.RequestMeta{RequestId: "req-zeeone-expired-scoped", AppCode: "lalu"},
|
||||||
|
PlatformCode: "zeeone",
|
||||||
|
Operation: "change_balance",
|
||||||
|
RawBody: zeeoneTestEnvelope(t, secret, changeBody, 1700000400000),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("HandleCallback change failed: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(raw), `"code":0`) || strings.Contains(string(raw), "sessionId invalid") {
|
||||||
|
t.Fatalf("zeeone expired JWT must fall back to scoped launch session: %s", raw)
|
||||||
|
}
|
||||||
|
if wallet.lastApply.GetUserId() != userID || wallet.lastApply.GetGameId() != "zeeone_1035" || wallet.lastApply.GetCoinAmount() != 50000 {
|
||||||
|
t.Fatalf("zeeone scoped launch session must drive wallet command, got %+v", wallet.lastApply)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestHandleZeeOneAllowsDebitAndCreditWithSameProviderOrderID(t *testing.T) {
|
func TestHandleZeeOneAllowsDebitAndCreditWithSameProviderOrderID(t *testing.T) {
|
||||||
secret := "zeeone-test-secret"
|
secret := "zeeone-test-secret"
|
||||||
token := leaderccTestAccessToken(t, "lalu", 123456, "123456", 1700003600)
|
token := leaderccTestAccessToken(t, "lalu", 123456, "123456", 1700003600)
|
||||||
|
|||||||
@ -143,7 +143,7 @@ func (s *Service) handleZeeOneOperation(ctx context.Context, app string, platfor
|
|||||||
case "change_balance", "change_coin", "update_coin":
|
case "change_balance", "change_coin", "update_coin":
|
||||||
return s.handleZeeOneChangeBalance(ctx, app, config, req, body, requestHash)
|
return s.handleZeeOneChangeBalance(ctx, app, config, req, body, requestHash)
|
||||||
case "update_session", "refresh_session":
|
case "update_session", "refresh_session":
|
||||||
return s.handleZeeOneUpdateSession(ctx, app, config, body)
|
return s.handleZeeOneUpdateSession(ctx, app, req.GetPlatformCode(), config, body)
|
||||||
case "repair_order", "repair":
|
case "repair_order", "repair":
|
||||||
return s.handleZeeOneRepairOrder(ctx, app, platform, body)
|
return s.handleZeeOneRepairOrder(ctx, app, platform, body)
|
||||||
default:
|
default:
|
||||||
@ -232,7 +232,7 @@ func validateZeeOneAppID(config zeeoneAdapterConfig, appID string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) handleZeeOneUserInfo(ctx context.Context, app string, config zeeoneAdapterConfig, req *gamev1.CallbackRequest, body zeeoneBusinessBody) ([]byte, string, string, bool, string, error) {
|
func (s *Service) handleZeeOneUserInfo(ctx context.Context, app string, config zeeoneAdapterConfig, req *gamev1.CallbackRequest, body zeeoneBusinessBody) ([]byte, string, string, bool, string, error) {
|
||||||
session, err := s.validZeeOneSession(ctx, app, body.SessionID)
|
session, err := s.validZeeOneSession(ctx, app, req.GetPlatformCode(), body.SessionID, body.GameID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return zeeoneAdapterError(zeeoneCodeFromError(err), zeeoneMessageFromError(err), true, "")
|
return zeeoneAdapterError(zeeoneCodeFromError(err), zeeoneMessageFromError(err), true, "")
|
||||||
}
|
}
|
||||||
@ -262,7 +262,7 @@ func (s *Service) handleZeeOneChangeBalance(ctx context.Context, app string, con
|
|||||||
if body.OrderID == "" || body.UserID == "" || body.SessionID == "" || body.GameID <= 0 || body.DiffMsg == "" {
|
if body.OrderID == "" || body.UserID == "" || body.SessionID == "" || body.GameID <= 0 || body.DiffMsg == "" {
|
||||||
return zeeoneAdapterError(zeeoneCodeInvalidArgument, "invalid argument", true, body.OrderID)
|
return zeeoneAdapterError(zeeoneCodeInvalidArgument, "invalid argument", true, body.OrderID)
|
||||||
}
|
}
|
||||||
session, err := s.validZeeOneSession(ctx, app, body.SessionID)
|
session, err := s.validZeeOneSession(ctx, app, req.GetPlatformCode(), body.SessionID, body.GameID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return zeeoneAdapterError(zeeoneCodeFromError(err), zeeoneMessageFromError(err), true, body.OrderID)
|
return zeeoneAdapterError(zeeoneCodeFromError(err), zeeoneMessageFromError(err), true, body.OrderID)
|
||||||
}
|
}
|
||||||
@ -288,8 +288,8 @@ func (s *Service) handleZeeOneChangeBalance(ctx context.Context, app string, con
|
|||||||
return raw, contentType, strconv.Itoa(zeeoneCodeOK), true, body.OrderID, nil
|
return raw, contentType, strconv.Itoa(zeeoneCodeOK), true, body.OrderID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) handleZeeOneUpdateSession(ctx context.Context, app string, config zeeoneAdapterConfig, body zeeoneBusinessBody) ([]byte, string, string, bool, string, error) {
|
func (s *Service) handleZeeOneUpdateSession(ctx context.Context, app string, platformCode string, config zeeoneAdapterConfig, body zeeoneBusinessBody) ([]byte, string, string, bool, string, error) {
|
||||||
session, err := s.validZeeOneSession(ctx, app, body.SessionID)
|
session, err := s.validZeeOneSession(ctx, app, platformCode, body.SessionID, body.GameID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return zeeoneAdapterError(zeeoneCodeFromError(err), zeeoneMessageFromError(err), true, "")
|
return zeeoneAdapterError(zeeoneCodeFromError(err), zeeoneMessageFromError(err), true, "")
|
||||||
}
|
}
|
||||||
@ -321,7 +321,7 @@ func (s *Service) handleZeeOneRepairOrder(ctx context.Context, app string, platf
|
|||||||
return raw, contentType, strconv.Itoa(zeeoneCodeOK), true, body.OrderID, nil
|
return raw, contentType, strconv.Itoa(zeeoneCodeOK), true, body.OrderID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) validZeeOneSession(ctx context.Context, app string, sessionID string) (gamedomain.LaunchSession, error) {
|
func (s *Service) validZeeOneSession(ctx context.Context, app string, platformCode string, sessionID string, gameID int64) (gamedomain.LaunchSession, error) {
|
||||||
sessionID = strings.TrimSpace(sessionID)
|
sessionID = strings.TrimSpace(sessionID)
|
||||||
if sessionID == "" {
|
if sessionID == "" {
|
||||||
return gamedomain.LaunchSession{}, xerr.New(xerr.Unauthorized, "sessionId not found")
|
return gamedomain.LaunchSession{}, xerr.New(xerr.Unauthorized, "sessionId not found")
|
||||||
@ -333,7 +333,13 @@ func (s *Service) validZeeOneSession(ctx context.Context, app string, sessionID
|
|||||||
return session, nil
|
return session, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if session, err := s.validYomiSession(ctx, app, sessionID); err == nil {
|
providerGameID := ""
|
||||||
|
if gameID > 0 {
|
||||||
|
providerGameID = strconv.FormatInt(gameID, 10)
|
||||||
|
}
|
||||||
|
// App access token 过期后仍可能处于三方游戏局中;启动链路已经把同一 token 的厂商、游戏和 24h TTL
|
||||||
|
// 落到 game_launch_sessions。这里必须按平台和游戏收窄,避免同一 access token 打开多款 ZeeOne 游戏时拿到旧会话。
|
||||||
|
if session, err := s.validScopedYomiSession(ctx, app, platformCode, sessionID, providerGameID); err == nil {
|
||||||
return session, nil
|
return session, nil
|
||||||
}
|
}
|
||||||
if strings.Count(sessionID, ".") == 2 {
|
if strings.Count(sessionID, ".") == 2 {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user