2023-10-28 17:50:44 -04:00
|
|
|
package controllers
|
|
|
|
|
|
|
|
import (
|
2023-11-03 01:01:33 -04:00
|
|
|
"crypto/sha256"
|
2023-11-03 20:00:14 -04:00
|
|
|
"encoding/hex"
|
2023-10-28 17:50:44 -04:00
|
|
|
"fmt"
|
2023-10-30 20:11:15 -04:00
|
|
|
"regexp"
|
2023-10-28 17:50:44 -04:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/config"
|
|
|
|
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/db/models"
|
|
|
|
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/templates"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/golang-jwt/jwt/v5"
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
|
)
|
|
|
|
|
2023-11-03 01:01:33 -04:00
|
|
|
const AUTH_COOKIE_NAME = "authorization"
|
|
|
|
|
2023-10-30 20:11:15 -04:00
|
|
|
var VALIDATE_EMAIL_REGEX = regexp.MustCompile(`^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$`)
|
|
|
|
|
2023-10-28 17:50:44 -04:00
|
|
|
type LoginPostBody struct {
|
2023-11-01 22:40:50 -04:00
|
|
|
Email string `json:"email"`
|
2023-10-28 17:50:44 -04:00
|
|
|
Password string `json:"password"`
|
|
|
|
}
|
|
|
|
|
2023-11-01 22:40:50 -04:00
|
|
|
func SignUpHandler(c *gin.Context) {
|
2023-10-28 17:50:44 -04:00
|
|
|
//get uname and password.
|
|
|
|
conf := config.Config()
|
|
|
|
reqBody := &LoginPostBody{}
|
|
|
|
c.Request.ParseForm()
|
|
|
|
reqBody.Email = c.Request.FormValue("email")
|
|
|
|
reqBody.Password = c.Request.FormValue("password")
|
|
|
|
|
|
|
|
if reqBody.Email == "" {
|
2023-10-28 18:29:57 -04:00
|
|
|
log.Warn("Request contained no email")
|
2023-10-28 17:50:44 -04:00
|
|
|
renderTempl(c, templates.SignupPage("Please provide an email"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if reqBody.Password == "" {
|
2023-10-28 18:29:57 -04:00
|
|
|
log.Warn("Request contained no password")
|
2023-10-28 17:50:44 -04:00
|
|
|
renderTempl(c, templates.SignupPage("Please provide a password"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
//Verify username and password
|
2023-10-30 20:11:15 -04:00
|
|
|
if ok := VALIDATE_EMAIL_REGEX.Match([]byte(reqBody.Email)); !ok {
|
|
|
|
log.Warnf("User provided email field is not valid: %s", reqBody.Email)
|
|
|
|
renderTempl(c, templates.SignupPage("You eamil is invalid. Please try again"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-10-28 17:50:44 -04:00
|
|
|
user, err := mongo.FindUserByEmail(reqBody.Email)
|
|
|
|
if err != nil {
|
2023-10-28 18:29:57 -04:00
|
|
|
log.WithError(err).Errorf("Failed to lookup user: %s", reqBody.Email)
|
2023-10-28 17:50:44 -04:00
|
|
|
renderTempl(c, templates.SignupPage("Error occured. Please try again later"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if user != nil {
|
2023-10-28 18:29:57 -04:00
|
|
|
log.Warnf("User: %s, already exists", reqBody.Email)
|
2023-10-28 17:50:44 -04:00
|
|
|
renderTempl(c, templates.SignupPage(fmt.Sprintf("user already exists for %s", reqBody.Email)))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-10-31 21:31:26 -04:00
|
|
|
//create new user
|
2023-10-28 17:50:44 -04:00
|
|
|
user = &models.User{}
|
|
|
|
|
|
|
|
passHash, err := bcrypt.GenerateFromPassword([]byte(reqBody.Password), 10)
|
|
|
|
if err != nil {
|
2023-10-28 18:29:57 -04:00
|
|
|
log.WithError(err).Errorf("Passowrd hash failed for user: %s", reqBody.Email)
|
2023-10-28 17:50:44 -04:00
|
|
|
renderTempl(c, templates.SignupPage("Signup failed. Please try again later"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
user.PassowrdHash = string(passHash)
|
|
|
|
user.Email = reqBody.Email
|
|
|
|
|
|
|
|
err = mongo.SaveModel(user)
|
|
|
|
if err != nil {
|
2023-10-28 18:29:57 -04:00
|
|
|
log.WithError(err).Errorf("Failed to write user to DB for user: %s", reqBody.Email)
|
2023-10-28 17:50:44 -04:00
|
|
|
renderTempl(c, templates.SignupPage("Signup failed. Please try again later"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-10-28 19:25:51 -04:00
|
|
|
now := time.Now().Unix()
|
|
|
|
exp := time.Now().Add(12 * time.Hour).Unix()
|
2023-10-28 17:50:44 -04:00
|
|
|
//build jwt
|
|
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256,
|
2023-10-28 19:25:51 -04:00
|
|
|
AuthClaims{
|
2023-11-02 19:23:07 -04:00
|
|
|
Subject: user.MongoId().Hex(),
|
2023-10-28 19:25:51 -04:00
|
|
|
Expires: exp,
|
|
|
|
IssuedAt: now,
|
|
|
|
NotBefore: now,
|
|
|
|
Issuer: "capstone.preston-baxter.com",
|
|
|
|
Audience: "capstone.preston-baxter.com",
|
2023-10-28 17:50:44 -04:00
|
|
|
},
|
|
|
|
)
|
|
|
|
|
2023-10-28 18:29:57 -04:00
|
|
|
jwtStr, err := token.SignedString([]byte(conf.JwtSecret))
|
2023-10-28 17:50:44 -04:00
|
|
|
if err != nil {
|
2023-10-28 18:29:57 -04:00
|
|
|
log.WithError(err).Errorf("Failed to encode jwt for user: %s", reqBody.Email)
|
2023-10-28 17:50:44 -04:00
|
|
|
renderTempl(c, templates.SignupPage("Signup failed. Please try again later"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
//store jwt as cookie
|
|
|
|
//TODO: Make sure set secure for prd deployment
|
2023-11-03 01:01:33 -04:00
|
|
|
c.SetCookie(AUTH_COOKIE_NAME, jwtStr, 3600*24, "", "", false, true)
|
2023-10-28 17:50:44 -04:00
|
|
|
|
|
|
|
c.Redirect(302, "/dashboard")
|
|
|
|
}
|
|
|
|
|
|
|
|
func LoginHandler(c *gin.Context) {
|
|
|
|
//get uname and password.
|
|
|
|
conf := config.Config()
|
|
|
|
reqBody := &LoginPostBody{}
|
|
|
|
c.Request.ParseForm()
|
|
|
|
reqBody.Email = c.Request.FormValue("email")
|
|
|
|
reqBody.Password = c.Request.FormValue("password")
|
|
|
|
|
|
|
|
if reqBody.Email == "" {
|
2023-10-28 18:29:57 -04:00
|
|
|
log.Warn("Request contained no email")
|
2023-10-28 17:50:44 -04:00
|
|
|
renderTempl(c, templates.LoginPage("Please provide an email"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if reqBody.Password == "" {
|
2023-10-28 18:29:57 -04:00
|
|
|
log.Warn("Request contained no password")
|
2023-10-28 17:50:44 -04:00
|
|
|
renderTempl(c, templates.LoginPage("Please provide a password"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
//Verify username and password
|
2023-10-30 20:11:15 -04:00
|
|
|
if ok := VALIDATE_EMAIL_REGEX.Match([]byte(reqBody.Email)); !ok {
|
|
|
|
log.Warnf("User provided email field is not valid: %s", reqBody.Email)
|
|
|
|
renderTempl(c, templates.SignupPage("You eamil is invalid. Please try again"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-10-28 17:50:44 -04:00
|
|
|
user, err := mongo.FindUserByEmail(reqBody.Email)
|
|
|
|
if err != nil {
|
2023-10-28 18:29:57 -04:00
|
|
|
log.WithError(err).Errorf("Failed to lookup user: %s", reqBody.Email)
|
2023-10-28 17:50:44 -04:00
|
|
|
renderTempl(c, templates.LoginPage(err.Error()))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-11-03 01:01:33 -04:00
|
|
|
|
2023-10-28 17:50:44 -04:00
|
|
|
if user == nil {
|
2023-10-28 18:29:57 -04:00
|
|
|
log.Warnf("No user was found for: %s", reqBody.Email)
|
2023-10-28 17:50:44 -04:00
|
|
|
renderTempl(c, templates.LoginPage(fmt.Sprintf("No user found for %s", reqBody.Email)))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := bcrypt.CompareHashAndPassword([]byte(user.PassowrdHash), []byte(reqBody.Password)); err != nil {
|
2023-10-28 18:29:57 -04:00
|
|
|
log.Warnf("Password does not match for user: %s", reqBody.Email)
|
|
|
|
renderTempl(c, templates.LoginPage("Email or password are incorrect"))
|
2023-10-28 17:50:44 -04:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-10-28 19:25:51 -04:00
|
|
|
now := time.Now().Unix()
|
|
|
|
exp := time.Now().Add(12 * time.Hour).Unix()
|
2023-10-28 17:50:44 -04:00
|
|
|
//build jwt
|
|
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256,
|
2023-10-28 19:25:51 -04:00
|
|
|
AuthClaims{
|
2023-11-02 19:23:07 -04:00
|
|
|
Subject: user.MongoId().Hex(),
|
2023-10-28 19:25:51 -04:00
|
|
|
Expires: exp,
|
|
|
|
IssuedAt: now,
|
|
|
|
NotBefore: now,
|
|
|
|
Issuer: "capstone.preston-baxter.com",
|
|
|
|
Audience: "capstone.preston-baxter.com",
|
2023-10-28 17:50:44 -04:00
|
|
|
},
|
|
|
|
)
|
|
|
|
|
2023-10-28 18:29:57 -04:00
|
|
|
jwtStr, err := token.SignedString([]byte(conf.JwtSecret))
|
2023-10-28 17:50:44 -04:00
|
|
|
if err != nil {
|
|
|
|
renderTempl(c, templates.LoginPage("An error occured. Please try again later"))
|
|
|
|
}
|
|
|
|
|
|
|
|
//store jwt as cookie
|
|
|
|
var secure bool
|
|
|
|
if conf.Env == "dev" {
|
|
|
|
secure = false
|
|
|
|
} else {
|
|
|
|
secure = true
|
|
|
|
}
|
2023-11-03 01:01:33 -04:00
|
|
|
c.SetCookie(AUTH_COOKIE_NAME, jwtStr, 3600*24, "", "", secure, true)
|
2023-10-28 17:50:44 -04:00
|
|
|
|
|
|
|
c.Redirect(302, "/dashboard")
|
|
|
|
}
|
|
|
|
|
|
|
|
func LogoutHandler(c *gin.Context) {
|
|
|
|
conf := config.Config()
|
|
|
|
|
|
|
|
var secure bool
|
|
|
|
if conf.Env == "dev" {
|
|
|
|
secure = false
|
|
|
|
} else {
|
|
|
|
secure = true
|
|
|
|
}
|
2023-11-01 22:40:50 -04:00
|
|
|
c.SetCookie("authorization", "", 3600*24, "", "", secure, true)
|
2023-10-28 17:50:44 -04:00
|
|
|
|
|
|
|
c.Redirect(302, "/login")
|
|
|
|
}
|
2023-11-03 01:01:33 -04:00
|
|
|
|
|
|
|
func getAuthHash(c *gin.Context) string {
|
|
|
|
jwtToken, err := c.Cookie(AUTH_COOKIE_NAME)
|
|
|
|
if err != nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
h := sha256.New()
|
|
|
|
h.Write([]byte(jwtToken))
|
|
|
|
|
2023-11-03 20:00:14 -04:00
|
|
|
return hex.EncodeToString(h.Sum(nil))
|
2023-11-03 01:01:33 -04:00
|
|
|
}
|