diff --git a/apps/tokens/cmd/decode/decode.go b/apps/tokens/cmd/decode/decode.go new file mode 100644 index 000000000..934c4d83b --- /dev/null +++ b/apps/tokens/cmd/decode/decode.go @@ -0,0 +1,25 @@ +package main + +import ( + "fmt" + "log" + "os" + + "github.com/satont/twir/libs/crypto" +) + +func main() { + args := os.Args + if len(args) < 3 { + log.Fatal("Wrong number of arguments") + } + + cipherKey := args[1] + + encoded, err := crypto.Decrypt(args[2], cipherKey) + if err != nil { + log.Fatal(err) + } + + fmt.Println("encoded: ", encoded) +} diff --git a/apps/tokens/internal/grpc_impl/grpc_impl.go b/apps/tokens/internal/grpc_impl/grpc_impl.go index ffd4e6a29..36c82d183 100644 --- a/apps/tokens/internal/grpc_impl/grpc_impl.go +++ b/apps/tokens/internal/grpc_impl/grpc_impl.go @@ -53,12 +53,33 @@ type tokensGrpcImpl struct { redSync *redsync.Redsync } +func rateLimitFunc(lastResponse *helix.Response) error { + if lastResponse.GetRateLimitRemaining() > 0 { + return nil + } + + var reset64 int64 + reset64 = int64(lastResponse.GetRateLimitReset()) + + currentTime := time.Now().UTC().Unix() + + if currentTime < reset64 { + timeDiff := time.Duration(reset64 - currentTime) + if timeDiff > 0 { + time.Sleep(timeDiff * time.Second) + } + } + + return nil +} + func NewTokens(opts Opts) error { helixClient, err := helix.NewClient( &helix.Options{ - ClientID: opts.Config.TwitchClientId, - ClientSecret: opts.Config.TwitchClientSecret, - RedirectURI: opts.Config.TwitchCallbackUrl, + ClientID: opts.Config.TwitchClientId, + ClientSecret: opts.Config.TwitchClientSecret, + RedirectURI: opts.Config.TwitchCallbackUrl, + RateLimitFunc: rateLimitFunc, }, ) if err != nil { @@ -161,6 +182,10 @@ func (c *tokensGrpcImpl) RequestUserToken( return nil, err } + if decryptedRefreshToken == "" { + return nil, errors.New("refresh token is empty") + } + if isTokenExpired(int(user.Token.ExpiresIn), user.Token.ObtainmentTimestamp) { newToken, err := c.globalClient.RefreshUserAccessToken(decryptedRefreshToken) if err != nil { @@ -170,6 +195,10 @@ func (c *tokensGrpcImpl) RequestUserToken( return nil, fmt.Errorf("refresh token error: %s", newToken.ErrorMessage) } + if newToken.StatusCode != 200 || newToken.Data.AccessToken == "" { + return nil, fmt.Errorf("refresh token status code: %d", newToken.StatusCode) + } + newRefreshToken, err := crypto.Encrypt(newToken.Data.RefreshToken, c.config.TokensCipherKey) if err != nil { return nil, err @@ -191,7 +220,6 @@ func (c *tokensGrpcImpl) RequestUserToken( c.log.Info( "user token refreshed", - slog.Any("twitchResponse", newToken), slog.String("user_id", user.ID), slog.Int("expires_in", int(user.Token.ExpiresIn)), slog.String("access_token", newAccessToken),