Skip to content

Commit 776abb7

Browse files
committed
fix(token): Enhance token creation logic and documentation
- Updated the New function to return nil if expiresOn is zero to prevent panic. - Added logic to set receivedAt to the current time and recalculate TTL if receivedAt is zero. - Improved documentation to clarify the responsibilities of the caller regarding token validity and behavior when parameters are zero.
1 parent 95b59c5 commit 776abb7

File tree

2 files changed

+25
-12
lines changed

2 files changed

+25
-12
lines changed

token/token.go

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,25 @@ import (
1010
var _ auth.Credentials = (*Token)(nil)
1111

1212
// New creates a new token with the specified username, password, raw token, expiration time, received at time, and time to live.
13-
// NOTE: This won't do any validation on the token, expiresOn, receivedAt, or ttl. It will simply create a new token instance.
14-
// The caller is responsible for ensuring the token is valid.
13+
// NOTE: The caller is responsible for ensuring the token is valid.
14+
// If the token is invalid, the behavior is undefined.
15+
// - if expiresOn is zero, New returns nil
16+
// - if receivedAt is zero, it will be set to the current time and TTL will be recalculated
1517
// Expiration time and TTL are used to determine when the token should be refreshed.
1618
// TTL is in milliseconds.
1719
// receivedAt + ttl should be within a millisecond of expiresOn
20+
// If receivedAt is zero, it will be set to the current time and TTL will be recalculated.
1821
func New(username, password, rawToken string, expiresOn, receivedAt time.Time, ttl int64) *Token {
22+
// If expiresOn is zero, return nil to avoid panic in ReceivedAt()
23+
if expiresOn.IsZero() {
24+
return nil
25+
}
26+
// If receivedAt is zero, set it to now and recalculate TTL to avoid race conditions in ReceivedAt()
27+
if receivedAt.IsZero() {
28+
receivedAt = time.Now()
29+
ttl = expiresOn.Sub(receivedAt).Milliseconds()
30+
}
31+
1932
return &Token{
2033
username: username,
2134
password: password,
@@ -28,6 +41,10 @@ func New(username, password, rawToken string, expiresOn, receivedAt time.Time, t
2841

2942
// Token represents parsed authentication token used to access the Redis server.
3043
// It implements the auth.Credentials interface.
44+
//
45+
// WARNING: Use New() to create a new token.
46+
// Creating a token with Token{} is invalid and will undefined behavior in the TokenManager.
47+
// The zero value of Token is not valid.
3148
type Token struct {
3249
// username is the username of the user.
3350
username string
@@ -60,11 +77,6 @@ func (t *Token) RawToken() string {
6077

6178
// ReceivedAt returns the time when the token was received.
6279
func (t *Token) ReceivedAt() time.Time {
63-
if t.receivedAt.IsZero() {
64-
// set it to now, recalculate ttl
65-
t.receivedAt = time.Now()
66-
t.ttl = t.expiresOn.Sub(t.receivedAt).Milliseconds()
67-
}
6880
return t.receivedAt
6981
}
7082

token/token_test.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,15 @@ func TestCopyToken(t *testing.T) {
9494
assert.NotEqual(t, token.expiresOn, copiedToken.expiresOn)
9595

9696
// copy nil
97-
copiedToken = copyToken(nil)
98-
assert.Nil(t, copiedToken)
97+
nilToken := copyToken(nil)
98+
assert.Nil(t, nilToken)
9999
// copy empty token
100-
copiedToken = copyToken(&Token{})
101-
assert.NotNil(t, copiedToken)
100+
emptyToken := copyToken(&Token{})
101+
assert.Nil(t, emptyToken)
102102
anotherCopy := copiedToken.Copy()
103103
anotherCopy.rawToken = "changed"
104104
assert.NotEqual(t, copiedToken, anotherCopy)
105+
assert.NotEqual(t, copiedToken.rawToken, anotherCopy.rawToken)
105106
}
106107

107108
func TestTokenReceivedAt(t *testing.T) {
@@ -124,7 +125,7 @@ func TestTokenReceivedAt(t *testing.T) {
124125
// Check if the copied token is a new instance
125126
assert.NotNil(t, tcopiedToken)
126127

127-
emptyRecievedAt := &Token{}
128+
emptyRecievedAt := New("username", "password", "rawToken", time.Now(), time.Time{}, time.Hour.Milliseconds())
128129
assert.True(t, emptyRecievedAt.ReceivedAt().After(time.Now().Add(-1*time.Hour)))
129130
assert.True(t, emptyRecievedAt.ReceivedAt().Before(time.Now().Add(1*time.Hour)))
130131
}

0 commit comments

Comments
 (0)