diff --git a/README.md b/README.md index 5c0c52f..26ca9e6 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,27 @@ unbanned, err := client.Players.Unban(ctx, rudder.UnbanPlayersParameters{ err = client.Players.Delete(ctx, rudder.DeletePlayersParameters{ PlayerIDs: []string{"p3"}, }) +``` + +## Верификация авторизации + +`Players.VerifyAuth` — одиночный (не batch) вызов `POST /players/auth/verify`: +проверяет access token игрока и возвращает `playerId`, `projectId` и `status` +(`active`/`banned`/`deleted`). + +```go +verification, err := client.Players.VerifyAuth(ctx, accessToken) +// verification.PlayerID, verification.ProjectID, verification.Status +``` + +`VerifyWebhookSignature` — пакетный хелпер для приёма webhook'ов с подписью +`X-Signature` (hex HMAC-SHA256 от сырого тела, ключ — webhook secret проекта): + +```go +if !rudder.VerifyWebhookSignature(secret, body, r.Header.Get("X-Signature")) { + // подпись не сошлась — отклонить запрос +} +``` err = client.Quests.Reset(ctx, rudder.PlayerQuestsParameters{ Items: []rudder.PlayerQuestRef{ diff --git a/models/verifyplayerauthrequest.go b/models/verifyplayerauthrequest.go new file mode 100644 index 0000000..eaa61e9 --- /dev/null +++ b/models/verifyplayerauthrequest.go @@ -0,0 +1,7 @@ +// Code generated by apigen. DO NOT EDIT. + +package models + +type VerifyPlayerAuthRequest struct { + AccessToken string `json:"accessToken,omitempty"` +} diff --git a/models/verifyplayerauthresponse.go b/models/verifyplayerauthresponse.go new file mode 100644 index 0000000..3c3ba64 --- /dev/null +++ b/models/verifyplayerauthresponse.go @@ -0,0 +1,9 @@ +// Code generated by apigen. DO NOT EDIT. + +package models + +type VerifyPlayerAuthResponse struct { + PlayerID string `json:"playerId,omitempty"` + ProjectID string `json:"projectId,omitempty"` + Status string `json:"status,omitempty"` +} diff --git a/players.go b/players.go index 14ba979..d11cd60 100644 --- a/players.go +++ b/players.go @@ -46,6 +46,16 @@ func (s *PlayersService) Get(ctx context.Context, playerID string) (*PlayerDetai return &response, nil } +func (s *PlayersService) VerifyAuth(ctx context.Context, accessToken string) (*PlayerAuthVerification, error) { + body := models.VerifyPlayerAuthRequest{AccessToken: accessToken} + + var response PlayerAuthVerification + if err := s.transport.do(ctx, http.MethodPost, "/players/auth/verify", nil, body, &response); err != nil { + return nil, err + } + return &response, nil +} + type UpdatePlayersParameters struct { IdempotencyKey string Items []PlayerUpdate diff --git a/types.go b/types.go index 3be66fe..af5ba46 100644 --- a/types.go +++ b/types.go @@ -10,6 +10,7 @@ type PlayerDetails = models.AdminPlayerDetails type PlayerList = models.ListPlayersResponse type PlayerUpdate = models.BatchUpdatePlayersItem type PlayerBan = models.BatchBanPlayersItem +type PlayerAuthVerification = models.VerifyPlayerAuthResponse type WalletBalance = models.WalletDetails type WalletTransaction = models.WalletAudit diff --git a/webhook.go b/webhook.go new file mode 100644 index 0000000..f6d62ea --- /dev/null +++ b/webhook.go @@ -0,0 +1,18 @@ +package rudder + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/hex" +) + +func VerifyWebhookSignature(secret string, body []byte, signature string) bool { + mac := hmac.New(sha256.New, []byte(secret)) + mac.Write(body) + + expected, err := hex.DecodeString(signature) + if err != nil { + return false + } + return hmac.Equal(mac.Sum(nil), expected) +}