diff --git a/CHANGELOG.md b/CHANGELOG.md index f318bc0b..03b212e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.23.0] - 2024-07-10 + +### Breaking Changes + +- Removes the default `maxAgeInSeconds` value (previously 300 seconds) in EmailVerification Claim. If the claim value is true and `maxAgeInSeconds` is not provided, it will not be refetched. + ## [0.22.1] - 2024-07-09 ### Changes diff --git a/recipe/emailverification/emailverificationClaim.go b/recipe/emailverification/emailverificationClaim.go index 94e615b2..b3e147b8 100644 --- a/recipe/emailverification/emailverificationClaim.go +++ b/recipe/emailverification/emailverificationClaim.go @@ -34,8 +34,7 @@ func NewEmailVerificationClaim() (*claims.TypeSessionClaim, evclaims.TypeEmailVe } } - var defaultMaxAge int64 = 300 - evClaim, booleanClaimValidators := claims.BooleanClaim("st-ev", fetchValue, &defaultMaxAge) + evClaim, booleanClaimValidators := claims.BooleanClaim("st-ev", fetchValue, nil) getLastRefetchTime := func(payload map[string]interface{}, userContext supertokens.UserContext) *int64 { if value, ok := payload[evClaim.Key].(map[string]interface{}); ok { @@ -57,15 +56,31 @@ func NewEmailVerificationClaim() (*claims.TypeSessionClaim, evclaims.TypeEmailVe var defaultTimeout int64 = 10 refetchTimeOnFalseInSeconds = &defaultTimeout } - if maxAgeInSeconds == nil { - var defaultTimeout int64 = 300 - maxAgeInSeconds = &defaultTimeout - } claimValidator := booleanClaimValidators.HasValue(true, maxAgeInSeconds, nil) claimValidator.ShouldRefetch = func(payload map[string]interface{}, userContext supertokens.UserContext) bool { value := evClaim.GetValueFromPayload(payload, userContext) - return value == nil || (*getLastRefetchTime(payload, userContext) < time.Now().UnixNano()/1000000-*maxAgeInSeconds*1000) || (value == false && *getLastRefetchTime(payload, userContext) < time.Now().UnixNano()/1000000-*refetchTimeOnFalseInSeconds*1000) + + if value == nil { + return true + } + + currentTime := time.Now().UnixNano() / 1000000 + lastRefetchTime := getLastRefetchTime(payload, userContext) + + if maxAgeInSeconds != nil { + if lastRefetchTime != nil && *lastRefetchTime < currentTime-*maxAgeInSeconds*1000 { + return true + } + } + + if value == false { + if lastRefetchTime != nil && *lastRefetchTime < currentTime-*refetchTimeOnFalseInSeconds*1000 { + return true + } + } + + return false } return claimValidator }, diff --git a/recipe/emailverification/emailverificationClaim_test.go b/recipe/emailverification/emailverificationClaim_test.go new file mode 100644 index 00000000..ee9ad897 --- /dev/null +++ b/recipe/emailverification/emailverificationClaim_test.go @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package emailverification + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/supertokens/supertokens-golang/recipe/emailverification/evclaims" +) + +func TestEmailVerificationClaim(t *testing.T) { + t.Run("value should be fetched if it is nil", func(t *testing.T) { + validator := evclaims.EmailVerificationClaimValidators.IsVerified(nil, nil) + + shouldRefreshNil := validator.ShouldRefetch(nil, nil) + + assert.True(t, shouldRefreshNil) + }) + + t.Run("value should be fetched as per maxAgeInSeconds if it is provided", func(t *testing.T) { + refetchTimeOnFalseInSeconds := int64(10) + maxAgeInSeconds := int64(200) + validator := evclaims.EmailVerificationClaimValidators.IsVerified(&refetchTimeOnFalseInSeconds, &maxAgeInSeconds) + + payload := map[string]interface{}{ + "st-ev": map[string]interface{}{ + "v": true, + "t": time.Now().UnixMilli() - 199*1000, + }, + } + + shouldRefreshValid := validator.ShouldRefetch(payload, nil) + + assert.False(t, shouldRefreshValid) + + payload = map[string]interface{}{ + "st-ev": map[string]interface{}{ + "v": true, + "t": time.Now().UnixMilli() - 201*1000, + }, + } + + shouldRefreshExpired := validator.ShouldRefetch(payload, nil) + assert.True(t, shouldRefreshExpired) + }) + + t.Run("value should be fetched as per refetchTimeOnFalseInSeconds if it is provided", func(t *testing.T) { + refetchTimeOnFalseInSeconds := int64(8) + validator := evclaims.EmailVerificationClaimValidators.IsVerified(&refetchTimeOnFalseInSeconds, nil) + + payload := map[string]interface{}{ + "st-ev": map[string]interface{}{ + "v": false, + "t": time.Now().UnixMilli() - 7*1000, + }, + } + + shouldRefreshValid := validator.ShouldRefetch(payload, nil) + + assert.False(t, shouldRefreshValid) + + payload = map[string]interface{}{ + "st-ev": map[string]interface{}{ + "v": false, + "t": time.Now().UnixMilli() - 9*1000, + }, + } + + shouldRefreshExpired := validator.ShouldRefetch(payload, nil) + assert.True(t, shouldRefreshExpired) + }) + + t.Run("value should be fetched as per default the refetchTimeOnFalseInSeconds if it is not provided", func(t *testing.T) { + validator := evclaims.EmailVerificationClaimValidators.IsVerified(nil, nil) + + // NOTE: the default value of refetchTimeOnFalseInSeconds is 10 seconds + payload := map[string]interface{}{ + "st-ev": map[string]interface{}{ + "v": false, + "t": time.Now().UnixMilli() - 9*1000, + }, + } + + shouldRefreshValid := validator.ShouldRefetch(payload, nil) + + assert.False(t, shouldRefreshValid) + + payload = map[string]interface{}{ + "st-ev": map[string]interface{}{ + "v": false, + "t": time.Now().UnixMilli() - 11*1000, + }, + } + + shouldRefreshExpired := validator.ShouldRefetch(payload, nil) + assert.True(t, shouldRefreshExpired) + }) +} diff --git a/supertokens/constants.go b/supertokens/constants.go index 0bac26fb..0b154170 100644 --- a/supertokens/constants.go +++ b/supertokens/constants.go @@ -21,7 +21,7 @@ const ( ) // VERSION current version of the lib -const VERSION = "0.22.1" +const VERSION = "0.23.0" var ( cdiSupported = []string{"3.0"}