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 { hashids hash.Hash hmac hmac.HMAC ttl time.Duration } func NewUserToken(secret string, ttl time.Duration) UserToken { return &userToken{ hashids: hash.New(secret, 32), hmac: hmac.New(secret), ttl: time.Minute * ttl, } } func (t *userToken) i() {} func (t *userToken) Generate(id uint64, platform string) (userID, token string, err error) { userID, err = t.hashids.HashidsEncode([]int{int(int64(id)), int(time.Now().Unix())}) if err != nil { return "", "", err } token = t.hmac.Sha1ToString(userID + platform) return } func (t *userToken) Validate(userID, token, platform string) (id uint64, err error) { if t.hmac.Sha1ToString(userID+platform) != token { return id, errors.New("token invalid") } hashidsDecode, err := t.hashids.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 }