Files
hammond/server/controllers/auth.go
2021-06-01 21:43:41 +05:30

180 lines
4.9 KiB
Go

package controllers
import (
"errors"
"fmt"
"net/http"
"os"
"github.com/akhilrex/hammond/common"
"github.com/akhilrex/hammond/db"
"github.com/akhilrex/hammond/models"
"github.com/akhilrex/hammond/service"
"github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
)
func RegisterAnonController(router *gin.RouterGroup) {
router.POST("/login", userLogin)
router.POST("/auth/initialize", initializeSystem)
}
func RegisterAuthController(router *gin.RouterGroup) {
router.POST("/refresh", refresh)
router.GET("/me", me)
router.POST("/register", ShouldBeAdmin(), userRegister)
router.POST("/changePassword", changePassword)
}
func ShouldBeAdmin() gin.HandlerFunc {
return func(c *gin.Context) {
model := c.MustGet("userModel").(db.User)
if model.Role != db.ADMIN {
c.JSON(http.StatusUnauthorized, gin.H{})
} else {
c.Next()
}
}
}
func me(c *gin.Context) {
user, err := service.GetUserById(c.MustGet("userId").(string))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{})
}
c.JSON(http.StatusOK, user)
}
func userRegister(c *gin.Context) {
var registerRequest models.RegisterRequest
if err := c.ShouldBind(&registerRequest); err != nil {
c.JSON(http.StatusUnprocessableEntity, common.NewValidatorError(err))
return
}
if err := service.CreateUser(&registerRequest, *registerRequest.Role); err != nil {
c.JSON(http.StatusUnprocessableEntity, common.NewError("database", err))
return
}
c.JSON(http.StatusCreated, gin.H{"success": true})
}
func initializeSystem(c *gin.Context) {
canInitialize, err := service.CanInitializeSystem()
if !canInitialize {
c.JSON(http.StatusUnprocessableEntity, err)
}
var registerRequest models.RegisterRequest
if err := c.ShouldBind(&registerRequest); err != nil {
c.JSON(http.StatusUnprocessableEntity, common.NewValidatorError(err))
return
}
if err := service.CreateUser(&registerRequest, db.ADMIN); err != nil {
c.JSON(http.StatusUnprocessableEntity, common.NewError("initializeSystem", err))
return
}
service.UpdateSettings(registerRequest.Currency, *registerRequest.DistanceUnit)
c.JSON(http.StatusCreated, gin.H{"success": true})
}
func userLogin(c *gin.Context) {
var loginRequest models.LoginRequest
if err := c.ShouldBind(&loginRequest); err != nil {
c.JSON(http.StatusUnprocessableEntity, common.NewValidatorError(err))
return
}
user, err := db.FindOneUser(&db.User{Email: loginRequest.Email})
if err != nil {
c.JSON(http.StatusForbidden, common.NewError("login", errors.New("Not Registered email or invalid password")))
return
}
if user.CheckPassword(loginRequest.Password) != nil {
c.JSON(http.StatusForbidden, common.NewError("login", errors.New("Not Registered email or invalid password")))
return
}
UpdateContextUserModel(c, user.ID)
token, refreshToken := common.GenToken(user.ID, user.Role)
response := models.LoginResponse{
Name: user.Name,
Email: user.Email,
Token: token,
RefreshToken: refreshToken,
Role: user.RoleDetail().Long,
}
c.JSON(http.StatusOK, response)
}
func refresh(c *gin.Context) {
type tokenReqBody struct {
RefreshToken string `json:"refreshToken"`
}
tokenReq := tokenReqBody{}
c.Bind(&tokenReq)
token, _ := jwt.Parse(tokenReq.RefreshToken, func(token *jwt.Token) (interface{}, error) {
// Don't forget to validate the alg is what you expect:
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
return []byte(os.Getenv("JWT_SECRET")), nil
})
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
// Get the user record from database or
// run through your business logic to verify if the user can log in
user, err := service.GetUserById(claims["id"].(string))
if err == nil {
token, refreshToken := common.GenToken(user.ID, user.Role)
response := models.LoginResponse{
Name: user.Name,
Email: user.Email,
Token: token,
RefreshToken: refreshToken,
Role: user.RoleDetail().Long,
}
c.JSON(http.StatusOK, response)
} else {
c.JSON(http.StatusUnauthorized, gin.H{})
}
} else {
c.JSON(http.StatusUnauthorized, gin.H{})
}
}
func changePassword(c *gin.Context) {
var request models.ChangePasswordRequest
if err := c.ShouldBind(&request); err != nil {
c.JSON(http.StatusUnprocessableEntity, common.NewValidatorError(err))
return
}
user, err := service.GetUserById(c.GetString("userId"))
if err != nil {
c.JSON(http.StatusForbidden, common.NewError("changePassword", errors.New("Not Registered email or invalid password")))
return
}
if user.CheckPassword(request.OldPassword) != nil {
c.JSON(http.StatusForbidden, common.NewError("changePassword", errors.New("Incorrect old password")))
return
}
user.SetPassword(request.NewPassword)
success, err := service.UpdatePassword(user.ID, request.NewPassword)
c.JSON(http.StatusOK, success)
}