token.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package token
  2. import (
  3. "fmt"
  4. "strconv"
  5. "time"
  6. "github.com/dgrijalva/jwt-go"
  7. )
  8. type Subject string
  9. const (
  10. User Subject = "user"
  11. API Subject = "api"
  12. )
  13. type TokenGeneratorConf struct {
  14. TokenSecret string
  15. }
  16. type Token struct {
  17. SubKind Subject `json:"sub_kind"`
  18. Sub string `json:"sub"`
  19. ProjectID uint `json:"project_id"`
  20. IBy uint `json:"iby"`
  21. IAt *time.Time `json:"iat"`
  22. // Additional fields that may or may not be set
  23. TokenID string `json:"token_id"`
  24. Secret string `json:"secret"`
  25. }
  26. func GetTokenForUser(userID uint) (*Token, error) {
  27. if userID == 0 {
  28. return nil, fmt.Errorf("id cannot be 0")
  29. }
  30. iat := time.Now()
  31. return &Token{
  32. SubKind: User,
  33. Sub: fmt.Sprintf("%d", userID),
  34. IBy: userID,
  35. IAt: &iat,
  36. }, nil
  37. }
  38. func GetTokenForAPI(userID, projID uint) (*Token, error) {
  39. if userID == 0 || projID == 0 {
  40. return nil, fmt.Errorf("id cannot be 0")
  41. }
  42. iat := time.Now()
  43. return &Token{
  44. SubKind: API,
  45. Sub: string(API),
  46. ProjectID: projID,
  47. IBy: userID,
  48. IAt: &iat,
  49. }, nil
  50. }
  51. func GetStoredTokenForAPI(userID, projID uint, tokenID, secret string) (*Token, error) {
  52. if userID == 0 || projID == 0 {
  53. return nil, fmt.Errorf("id cannot be 0")
  54. }
  55. iat := time.Now()
  56. return &Token{
  57. SubKind: API,
  58. Sub: string(API),
  59. ProjectID: projID,
  60. IBy: userID,
  61. IAt: &iat,
  62. TokenID: tokenID,
  63. Secret: secret,
  64. }, nil
  65. }
  66. func (t *Token) EncodeToken(conf *TokenGeneratorConf) (string, error) {
  67. token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
  68. "sub_kind": t.SubKind,
  69. "sub": t.Sub,
  70. "iby": t.IBy,
  71. "iat": fmt.Sprintf("%d", t.IAt.Unix()),
  72. "project_id": t.ProjectID,
  73. "token_id": t.TokenID,
  74. "secret": t.Secret,
  75. })
  76. // Sign and get the complete encoded token as a string using the secret
  77. return token.SignedString([]byte(conf.TokenSecret))
  78. }
  79. func GetTokenFromEncoded(tokenString string, conf *TokenGeneratorConf) (*Token, error) {
  80. token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
  81. if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
  82. return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
  83. }
  84. return []byte(conf.TokenSecret), nil
  85. })
  86. if err != nil {
  87. return nil, fmt.Errorf("could not parse token: %v", err)
  88. }
  89. if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
  90. var iby uint64
  91. if _, ok := claims["iby"]; ok {
  92. iby, err = strconv.ParseUint(fmt.Sprintf("%v", claims["iby"]), 10, 64)
  93. if err != nil {
  94. return nil, fmt.Errorf("invalid iby claim: %v", err)
  95. }
  96. }
  97. projID, err := strconv.ParseUint(fmt.Sprintf("%v", claims["project_id"]), 10, 64)
  98. if err != nil {
  99. return nil, fmt.Errorf("invalid project_id claim: %v", err)
  100. }
  101. iatUnix, err := strconv.ParseInt(fmt.Sprintf("%v", claims["iat"]), 10, 64)
  102. if err != nil {
  103. return nil, fmt.Errorf("invalid iat claim: %v", err)
  104. }
  105. iat := time.Unix(iatUnix, 0)
  106. res := &Token{
  107. SubKind: Subject(fmt.Sprintf("%v", claims["sub_kind"])),
  108. Sub: fmt.Sprintf("%v", claims["sub"]),
  109. IBy: uint(iby),
  110. IAt: &iat,
  111. ProjectID: uint(projID),
  112. }
  113. if tokenIDInter, ok := claims["token_id"]; ok {
  114. tokenID, ok := tokenIDInter.(string)
  115. if ok {
  116. res.TokenID = tokenID
  117. }
  118. }
  119. if secretInter, ok := claims["secret"]; ok {
  120. secret, ok := secretInter.(string)
  121. if ok {
  122. res.Secret = secret
  123. }
  124. }
  125. supportID := "3140"
  126. if res.Sub == supportID && res.IAt.Before(time.Date(2023, 0o1, 31, 14, 30, 0, 0, time.UTC)) {
  127. return nil, fmt.Errorf("error with token. Please contact your admin or trying logging in again")
  128. }
  129. return res, nil
  130. }
  131. return nil, fmt.Errorf("invalid token")
  132. }