2022-11-18 02:56:06 -06:00
|
|
|
package usertoken
|
|
|
|
|
2022-11-30 08:33:19 -06:00
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
2023-03-23 08:39:04 -05:00
|
|
|
"time"
|
2022-11-30 08:33:19 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
var ErrInvalidSessionToken = errors.New("invalid session token")
|
|
|
|
|
2022-11-18 02:56:06 -06:00
|
|
|
type TokenRevokedError struct {
|
|
|
|
UserID int64
|
|
|
|
TokenID int64
|
|
|
|
MaxConcurrentSessions int64
|
|
|
|
}
|
|
|
|
|
2022-11-30 08:33:19 -06:00
|
|
|
func (e *TokenRevokedError) Error() string {
|
|
|
|
return fmt.Sprintf("%s: user token revoked", ErrInvalidSessionToken)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *TokenRevokedError) Unwrap() error { return ErrInvalidSessionToken }
|
2022-11-18 02:56:06 -06:00
|
|
|
|
|
|
|
// UserToken represents a user token
|
|
|
|
type UserToken struct {
|
|
|
|
Id int64
|
|
|
|
UserId int64
|
|
|
|
AuthToken string
|
|
|
|
PrevAuthToken string
|
|
|
|
UserAgent string
|
|
|
|
ClientIp string
|
|
|
|
AuthTokenSeen bool
|
|
|
|
SeenAt int64
|
|
|
|
RotatedAt int64
|
|
|
|
CreatedAt int64
|
|
|
|
UpdatedAt int64
|
|
|
|
RevokedAt int64
|
|
|
|
UnhashedToken string
|
|
|
|
}
|
2023-03-23 08:39:04 -05:00
|
|
|
|
|
|
|
const UrgentRotateTime = 1 * time.Minute
|
|
|
|
|
|
|
|
func (t *UserToken) NeedsRotation(rotationInterval time.Duration) bool {
|
|
|
|
rotatedAt := time.Unix(t.RotatedAt, 0)
|
|
|
|
if !t.AuthTokenSeen {
|
|
|
|
return rotatedAt.Before(time.Now().Add(-UrgentRotateTime))
|
|
|
|
}
|
|
|
|
|
|
|
|
return rotatedAt.Before(time.Now().Add(-rotationInterval))
|
|
|
|
}
|
|
|
|
|
|
|
|
const rotationLeeway = 5 * time.Second
|
|
|
|
|
|
|
|
func (t *UserToken) NextRotation(rotationInterval time.Duration) time.Time {
|
|
|
|
rotatedAt := time.Unix(t.RotatedAt, 0)
|
|
|
|
return rotatedAt.Add(rotationInterval - rotationLeeway)
|
|
|
|
}
|