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(®isterRequest); err != nil { c.JSON(http.StatusUnprocessableEntity, common.NewValidatorError(err)) return } if err := service.CreateUser(®isterRequest, *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(®isterRequest); err != nil { c.JSON(http.StatusUnprocessableEntity, common.NewValidatorError(err)) return } service.UpdateSettings(registerRequest.Currency, *registerRequest.DistanceUnit) if err := service.CreateUser(®isterRequest, 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 } if user.IsDisabled { c.JSON(http.StatusForbidden, common.NewError("login", errors.New("Your user has been disabled by the admin. Please contact them to get it re-enabled."))) 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) }