You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

266 lines
6.6 KiB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. package server
  2. import (
  3. "context"
  4. "errors"
  5. "log"
  6. "time"
  7. "github.com/google/uuid"
  8. "golang.org/x/crypto/bcrypt"
  9. "gorm.io/gorm"
  10. "git.chrishayward.xyz/x/users/proto"
  11. "git.chrishayward.xyz/x/users/server/models"
  12. )
  13. type usersServer struct {
  14. proto.UsersServer
  15. secret *string
  16. db *gorm.DB
  17. }
  18. func NewUsersServer(secret *string, db *gorm.DB) proto.UsersServer {
  19. db.AutoMigrate(&models.User{}, &models.Role{}, &models.Session{}, &models.PasswordToken{})
  20. return &usersServer{
  21. secret: secret,
  22. db: db,
  23. }
  24. }
  25. func (m *usersServer) Register(ctx context.Context, in *proto.RegisterRequest) (*proto.RegisterResponse, error) {
  26. // Make sure both passwords are included and match.
  27. if in.Form.Password == nil || in.Form.PasswordAgain == nil {
  28. return nil, errors.New("Must include password(s).")
  29. }
  30. if *in.Form.Password != *in.Form.PasswordAgain {
  31. return nil, errors.New("Passwords do not match.")
  32. }
  33. // Check for an existing user.
  34. var u models.User
  35. tx := m.db.First(&u, "email = ?", in.Form.Email)
  36. if tx.RowsAffected != 0 {
  37. return nil, errors.New("User already exists.")
  38. }
  39. // Encode the password.
  40. bytes, err := bcrypt.GenerateFromPassword([]byte(*in.Form.Password), bcrypt.MaxCost)
  41. if err != nil {
  42. log.Fatalf("Failed to encode password: %v", err)
  43. return nil, errors.New("Failed to encode password.")
  44. }
  45. // Create the new user.
  46. u.Email = in.Form.Email
  47. u.Password = string(bytes)
  48. tx = m.db.Create(&u)
  49. if tx.RowsAffected == 0 {
  50. log.Fatalf("Failed to save user: %v", err)
  51. return nil, errors.New("Failed to save user.")
  52. }
  53. // Return the response.
  54. return &proto.RegisterResponse{}, nil
  55. }
  56. func (m *usersServer) Login(ctx context.Context, in *proto.LoginRequest) (*proto.LoginResponse, error) {
  57. // Make sure the password is included.
  58. if in.Form.Password == nil {
  59. return nil, errors.New("Password must be included.")
  60. }
  61. // Find the user.
  62. var u models.User
  63. tx := m.db.First(&u, "email = ?", in.Form.Email)
  64. if tx.RowsAffected == 0 {
  65. return nil, errors.New("User not found.")
  66. }
  67. // Compare the passwords.
  68. if err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(*in.Form.Password)); err != nil {
  69. return nil, errors.New("Passwords do not match.")
  70. }
  71. // Create a session.
  72. s := &models.Session{
  73. Token: uuid.NewString(),
  74. Expires: time.Now().AddDate(0, 0, 1).UnixNano(),
  75. UserID: u.ID,
  76. }
  77. // Save the token.
  78. tx = m.db.Create(&s)
  79. if tx.RowsAffected == 0 {
  80. return nil, errors.New("Failed to create session.")
  81. }
  82. // Return the response.
  83. return &proto.LoginResponse{
  84. Token: &proto.UserToken{
  85. Token: s.Token,
  86. Expires: &s.Expires,
  87. },
  88. }, nil
  89. }
  90. func (m *usersServer) Authorize(ctx context.Context, in *proto.AuthorizeRequest) (*proto.AuthorizeResponse, error) {
  91. // Make sure the secrets match.
  92. if in.Secret != *m.secret {
  93. return nil, errors.New("Secrets do not match.")
  94. }
  95. // Find the session.
  96. var s models.Session
  97. tx := m.db.First(&s, "token = ?", in.Token.Token)
  98. if tx.RowsAffected == 0 {
  99. return nil, errors.New("Session not found.")
  100. }
  101. // Make sure the session hasn't expired.
  102. if time.Now().UnixNano() > s.Expires {
  103. return nil, errors.New("Token is expired.")
  104. }
  105. // Find the user.
  106. var u models.User
  107. tx = m.db.Model(&models.User{}).Preload("Roles").First(&u, "id = ?", s.UserID)
  108. if tx.RowsAffected == 0 {
  109. return nil, errors.New("Failed to load roles.")
  110. }
  111. // Return the response.
  112. res := &proto.AuthorizeResponse{
  113. User: &proto.UserInfo{},
  114. }
  115. for _, r := range u.Roles {
  116. res.Roles = append(res.Roles, &proto.UserRole{
  117. Id: int64(r.ID),
  118. Name: r.Name,
  119. })
  120. }
  121. return &proto.AuthorizeResponse{
  122. User: &proto.UserInfo{
  123. Id: int64(s.UserID),
  124. },
  125. }, nil
  126. }
  127. func (m *usersServer) ResetPassword(ctx context.Context, in *proto.ResetPasswordRequest) (*proto.ResetPasswordResponse, error) {
  128. // Find the u.
  129. var u models.User
  130. tx := m.db.First(&u, "email = ?", in.Form.Email)
  131. if tx.RowsAffected == 0 {
  132. return nil, errors.New("User not found.")
  133. }
  134. // Generate a reset token.
  135. rt := &models.PasswordToken{
  136. UserID: u.ID,
  137. Token: uuid.NewString(),
  138. Expires: time.Now().UnixNano(),
  139. }
  140. // Save the token.
  141. tx = m.db.Create(rt)
  142. if tx.RowsAffected == 0 {
  143. return nil, errors.New("Failed to create token.")
  144. }
  145. // Return the response.
  146. return &proto.ResetPasswordResponse{
  147. Token: &proto.UserToken{
  148. Token: rt.Token,
  149. },
  150. }, nil
  151. }
  152. func (m *usersServer) ChangePassword(ctx context.Context, in *proto.ChangePasswordRequest) (*proto.ChangePasswordResponse, error) {
  153. // Find the reset token.
  154. var rt models.PasswordToken
  155. tx := m.db.First(&rt, "token = ?", in.Token.Token)
  156. if tx.RowsAffected == 0 {
  157. return nil, errors.New("Token not found.")
  158. }
  159. // Find the user.
  160. var u models.User
  161. tx = m.db.First(&u, "id = ?", rt.UserID)
  162. if tx.RowsAffected == 0 {
  163. return nil, errors.New("User not found.")
  164. }
  165. // Update the password.
  166. bytes, err := bcrypt.GenerateFromPassword([]byte(*in.Form.Password), bcrypt.MaxCost)
  167. if err != nil {
  168. log.Fatalf("Failed to encode password: %v", err)
  169. return nil, errors.New("Failed to encode password.")
  170. }
  171. u.Password = string(bytes)
  172. if tx = m.db.Save(u); tx.RowsAffected == 0 {
  173. return nil, errors.New("Failed to update password.")
  174. }
  175. // Expire current token.
  176. rt.Expires = time.Now().UnixNano()
  177. if tx = m.db.Save(&rt); tx.RowsAffected == 0 {
  178. return nil, errors.New("Failed to update password.")
  179. }
  180. // Return the response.
  181. return nil, nil
  182. }
  183. func (m *usersServer) ListRoles(ctx context.Context, in *proto.ListRolesRequest) (*proto.ListRolesResponse, error) {
  184. // Make sure the secrets match.
  185. if in.Secret != *m.secret {
  186. return nil, errors.New("Secrets do not match.")
  187. }
  188. // Get all of the available roles.
  189. var roles []models.Role
  190. if tx := m.db.Find(&roles); tx.RowsAffected == 0 {
  191. return nil, errors.New("Failed to find roles.")
  192. }
  193. // Return the response.
  194. res := &proto.ListRolesResponse{}
  195. for _, r := range roles {
  196. res.Roles = append(res.Roles, &proto.UserRole{
  197. Id: int64(r.ID),
  198. Name: r.Name,
  199. })
  200. }
  201. return res, nil
  202. }
  203. func (m *usersServer) SetRoles(ctx context.Context, in *proto.SetRolesRequest) (*proto.SetRolesResponse, error) {
  204. // Make sure the secrets match.
  205. if in.Secret != *m.secret {
  206. return nil, errors.New("Secrets do not match.")
  207. }
  208. // Find the user.
  209. var u models.User
  210. if tx := m.db.First(&u, "id = ?", in.User.Id); tx.RowsAffected == 0 {
  211. return nil, errors.New("User not found.")
  212. }
  213. // Add the roles.
  214. var r models.Role
  215. for _, x := range in.Roles {
  216. if tx := m.db.First(&r, "id = ?", x.Id); tx.RowsAffected != 0 {
  217. u.Roles = append(u.Roles, r)
  218. }
  219. }
  220. // Save the user.
  221. if tx := m.db.Save(&u); tx.RowsAffected == 0 {
  222. return nil, errors.New("Failed to add roles.")
  223. }
  224. return nil, nil
  225. }