PageRenderTime 42ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/models/user.go

https://gitlab.com/willjharmer/kanban
Go | 220 lines | 176 code | 34 blank | 10 comment | 27 complexity | 4490f912d33b91c120572574d26b0552 MD5 | raw file
  1. package models
  2. import (
  3. "crypto/sha512"
  4. "encoding/base64"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "github.com/dgrijalva/jwt-go"
  9. "github.com/spf13/viper"
  10. "gitlab.com/leanlabsio/kanban/modules/gitlab"
  11. "golang.org/x/oauth2"
  12. "strings"
  13. "time"
  14. )
  15. type User struct {
  16. Id int64
  17. Name string
  18. IsAdmin bool
  19. Token *jwt.Token
  20. Credential map[string]*Credential
  21. AvatarUrl string
  22. State string
  23. Username string
  24. Passwd string
  25. Salt string
  26. Email string
  27. }
  28. type UserNotFound struct {
  29. msg string
  30. }
  31. type Credential struct {
  32. PrivateToken string `json:"private_access_token"`
  33. Token *oauth2.Token
  34. }
  35. type ResponseUser struct {
  36. Id int64 `json:"id"`
  37. Name string `json:"name"`
  38. Token string `json:"token"`
  39. Success bool `json:"success"`
  40. }
  41. // LoadUserByUsername is
  42. func LoadUserByUsername(uname string) (*User, error) {
  43. cmd := c.HGetAllMap(fmt.Sprintf("kanban:users:%s", strings.ToLower(uname)))
  44. val, err := cmd.Result()
  45. if err != nil {
  46. panic(fmt.Sprintf("Redis unrecoverable error: %s", err))
  47. }
  48. if len(val) == 0 {
  49. return nil, &UserNotFound{msg: "User not found"}
  50. }
  51. u := User{
  52. Username: val["username"],
  53. Passwd: val["password"],
  54. Email: val["email"],
  55. Name: val["name"],
  56. }
  57. if val["credentials"] != "" {
  58. var cr map[string]*Credential
  59. err = json.Unmarshal([]byte(val["credentials"]), &cr)
  60. if err != nil {
  61. return nil, err
  62. }
  63. u.Credential = cr
  64. }
  65. return &u, nil
  66. }
  67. // LoadByToken is
  68. func LoadByToken(u *User, provider string) (*User, error) {
  69. var user *User
  70. switch provider {
  71. case "gitlab":
  72. c := gitlab.NewContext(u.Credential["gitlab"].Token, u.Credential["gitlab"].PrivateToken)
  73. r, err := c.CurrentUser()
  74. if err != nil {
  75. return nil, err
  76. }
  77. user = mapUserFromGitlab(r)
  78. user.Credential = u.Credential
  79. user.Credential[provider].PrivateToken = r.PrivateToken
  80. }
  81. return user, nil
  82. }
  83. // CreateUser creates new user
  84. func CreateUser(u *User) (*User, error) {
  85. usr, _ := LoadUserByUsername(u.Username)
  86. if usr != nil {
  87. return nil, errors.New("User already exists")
  88. }
  89. u.EncodePasswd()
  90. return saveUser(u)
  91. }
  92. // UpdateUser updates user's information.
  93. func UpdateUser(u *User) (*User, error) {
  94. user, err := LoadUserByUsername(u.Username)
  95. if err != nil {
  96. return user, err
  97. }
  98. if user == nil {
  99. return user, errors.New(fmt.Sprintf("User with username %s does not exists", u.Username))
  100. }
  101. user.Credential = u.Credential
  102. return saveUser(user)
  103. }
  104. // saveUser saved user's information.
  105. func saveUser(u *User) (*User, error) {
  106. val, err := json.Marshal(u.Credential)
  107. if err != nil {
  108. return nil, err
  109. }
  110. _, err = c.HMSet("kanban:users:"+strings.ToLower(u.Username),
  111. "credentials", string(val),
  112. "name", u.Name,
  113. "username", u.Username,
  114. "password", u.Passwd,
  115. "email", u.Email,
  116. ).Result()
  117. if err != nil {
  118. return nil, err
  119. }
  120. return &User{
  121. Name: u.Name,
  122. Username: u.Username,
  123. Credential: u.Credential,
  124. Passwd: u.Passwd,
  125. Email: u.Email,
  126. }, nil
  127. }
  128. // SignedString returns user token for access
  129. func (u *User) SignedString() (string, error) {
  130. if u.Token == nil {
  131. token := jwt.New(jwt.SigningMethodHS256)
  132. token.Claims["name"] = u.Username
  133. token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
  134. return token.SignedString([]byte(viper.GetString("security.secret_key")))
  135. }
  136. return u.Token.SigningString()
  137. }
  138. // ValidatePassword checks if given password matches the one belongs to the user.
  139. func (u *User) ValidatePassword(pass string) bool {
  140. newUser := &User{Passwd: pass, Salt: ""}
  141. newUser.EncodePasswd()
  142. return u.Passwd == newUser.Passwd
  143. }
  144. // EncodePasswd encodes password to safe format.
  145. func (u *User) EncodePasswd() {
  146. hash := []byte(u.Passwd)
  147. dig := sha512.Sum512(hash)
  148. for i := 1; i < 5000; i++ {
  149. dig = sha512.Sum512(append(dig[:], hash[:]...))
  150. }
  151. newPasswd := base64.StdEncoding.EncodeToString(dig[:])
  152. u.Passwd = fmt.Sprintf("%s", newPasswd)
  153. }
  154. // mapUserFromGitlab mapped data from gitlab user to kanban user
  155. func mapUserFromGitlab(u *gitlab.User) *User {
  156. if u == nil {
  157. return nil
  158. }
  159. return &User{
  160. Id: u.Id,
  161. Name: u.Name,
  162. Username: u.Username,
  163. AvatarUrl: u.AvatarUrl,
  164. State: u.State,
  165. }
  166. }
  167. // MarshalJSON returns the JSON encoding value.
  168. func (u *User) MarshalJSON() ([]byte, error) {
  169. type Alias User
  170. return json.Marshal(struct {
  171. Id int64 `json:"id"`
  172. Name string `json:"name,omitempty"`
  173. Username string `json:"username,omitempty"`
  174. AvatarUrl string `json:"avatar_url,nil,omitempty"`
  175. State string `json:"state,omitempty"`
  176. }{
  177. Id: u.Id,
  178. Name: u.Name,
  179. Username: u.Username,
  180. AvatarUrl: u.AvatarUrl,
  181. State: u.State,
  182. })
  183. }
  184. func (e *UserNotFound) Error() string {
  185. return e.msg
  186. }