package utils import ( "errors" "git.bvbej.com/bvbej/base-golang/pkg/hash" "git.bvbej.com/bvbej/base-golang/pkg/hmac" "git.bvbej.com/bvbej/base-golang/pkg/time_parse" "time" ) var _ UserToken = (*userToken)(nil) type UserToken interface { i() Generate(id uint64, platform string) (userID, token string, err error) Validate(userID, token, platform string) (id uint64, err error) } type userToken struct { hashidsSecret string hashidsLength int hmacSecret string ttl time.Duration } func NewUserToken(hashidsSecret, hmacSecret string, ttl time.Duration) UserToken { return &userToken{ hashidsSecret: hashidsSecret, hashidsLength: 32, hmacSecret: hmacSecret, ttl: time.Minute * ttl, } } func (t *userToken) i() {} func (t *userToken) Generate(id uint64, platform string) (userID, token string, err error) { hashidsPtr := hash.New(t.hashidsSecret, t.hashidsLength) userID, err = hashidsPtr.HashidsEncode([]int{int(int64(id)), int(time.Now().Unix())}) if err != nil { return "", "", err } hmacPtr := hmac.New(t.hmacSecret) token = hmacPtr.Sha256ToString(userID + platform) return } func (t *userToken) Validate(userID, token, platform string) (id uint64, err error) { hashidsPtr := hash.New(t.hashidsSecret, t.hashidsLength) hmacPtr := hmac.New(t.hmacSecret) if hmacPtr.Sha256ToString(userID+platform) != token { return id, errors.New("token invalid") } hashidsDecode, err := hashidsPtr.HashidsDecode(userID) if err != nil { return id, err } if len(hashidsDecode) == 2 { if time_parse.SubInLocation(time.Unix(int64(hashidsDecode[1]), 0)) > float64(t.ttl/time.Second) { return id, errors.New("token expired") } } return uint64(hashidsDecode[0]), nil }