240 lines
6.1 KiB
Go
240 lines
6.1 KiB
Go
package controllers
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/SowinskiBraeden/BugBeGone/database"
|
|
"github.com/SowinskiBraeden/BugBeGone/models"
|
|
"github.com/google/uuid"
|
|
"github.com/joho/godotenv"
|
|
|
|
"github.com/dgrijalva/jwt-go"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
"go.mongodb.org/mongo-driver/mongo"
|
|
)
|
|
|
|
var userCollection *mongo.Collection = database.OpenCollection(database.Client, "users")
|
|
var SecretKey string
|
|
|
|
func Init() {
|
|
godotenv.Load(".env")
|
|
SecretKey = os.Getenv("secret")
|
|
}
|
|
|
|
func Register(c *fiber.Ctx) error {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
firstname := c.FormValue("firstname")
|
|
lastname := c.FormValue("lastname")
|
|
username := c.FormValue("username")
|
|
email := c.FormValue("email")
|
|
password := c.FormValue("password")
|
|
|
|
if email == "" {
|
|
cancel()
|
|
return c.Status(fiber.StatusBadRequest).Render("register", fiber.Map{
|
|
"errorMsg": "Missing Email",
|
|
})
|
|
}
|
|
if password == "" {
|
|
cancel()
|
|
return c.Status(fiber.StatusBadRequest).Render("register", fiber.Map{
|
|
"errorMsg": "Please enter your password",
|
|
})
|
|
}
|
|
if username == "" {
|
|
cancel()
|
|
return c.Status(fiber.StatusBadRequest).Render("register", fiber.Map{
|
|
"errorMsg": "Missing Username",
|
|
})
|
|
}
|
|
|
|
// Check if email or username is previously registered
|
|
count, err := userCollection.CountDocuments(ctx, bson.M{
|
|
"$or": []bson.M{
|
|
bson.M{"email": email},
|
|
bson.M{"username": username},
|
|
}},
|
|
)
|
|
if err != nil {
|
|
cancel()
|
|
return c.Status(fiber.StatusInternalServerError).Render("register", fiber.Map{
|
|
"errorMsg": "Failed to search database",
|
|
})
|
|
}
|
|
if count > 0 {
|
|
cancel()
|
|
return c.Status(fiber.StatusInternalServerError).Render("register", fiber.Map{
|
|
"errorMsg": "An account already exists with that email or username",
|
|
})
|
|
}
|
|
|
|
var user models.User
|
|
if user.CheckPasswordStrength(password) {
|
|
cancel()
|
|
return c.Status(fiber.StatusBadRequest).Render("register", fiber.Map{
|
|
"errorMsg": "Your password must contain at least 1 lowercase, 1 uppercase & 1 special character",
|
|
"username": username,
|
|
"email": email,
|
|
})
|
|
}
|
|
|
|
user.UID = uuid.New().String()
|
|
user.Username = username
|
|
user.Firstname = firstname
|
|
user.Lastname = lastname
|
|
user.Email = email
|
|
user.Password = user.HashPassword(password)
|
|
user.TempPassword = false
|
|
user.Attempts = 0
|
|
user.Disabled = false
|
|
user.ID = primitive.NewObjectID()
|
|
user.Created_at, _ = time.Parse(time.RFC3339, time.Now().Format(time.RFC3339))
|
|
user.Updated_at, _ = time.Parse(time.RFC3339, time.Now().Format(time.RFC3339))
|
|
|
|
_, insertErr := userCollection.InsertOne(ctx, user)
|
|
if insertErr != nil {
|
|
cancel()
|
|
return c.Status(fiber.StatusInternalServerError).Render("register", fiber.Map{
|
|
"errorMsg": "the user could not be inserted",
|
|
})
|
|
}
|
|
|
|
defer cancel()
|
|
|
|
return c.Render("login", fiber.Map{
|
|
"msg": "Successfully registered an account",
|
|
"errorMsg": "",
|
|
})
|
|
}
|
|
|
|
func Login(c *fiber.Ctx) error {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
username := c.FormValue("username")
|
|
password := c.FormValue("password")
|
|
|
|
if username == "" && password == "" {
|
|
cancel()
|
|
return c.Status(fiber.StatusBadRequest).Render("login", fiber.Map{
|
|
"msg": "",
|
|
"errorMsg": "Username and password can't be blank",
|
|
})
|
|
}
|
|
if username == "" {
|
|
cancel()
|
|
return c.Status(fiber.StatusBadRequest).Render("login", fiber.Map{
|
|
"msg": "",
|
|
"errorMsg": "Username can't be blank",
|
|
})
|
|
}
|
|
if password == "" {
|
|
cancel()
|
|
return c.Status(fiber.StatusBadRequest).Render("login", fiber.Map{
|
|
"msg": "",
|
|
"errorMsg": "Password can't be blank",
|
|
})
|
|
}
|
|
|
|
var user models.User
|
|
err := userCollection.FindOne(ctx, bson.M{"username": username}).Decode(&user)
|
|
defer cancel()
|
|
|
|
if err != nil {
|
|
cancel()
|
|
return c.Status(fiber.StatusInternalServerError).Render("login", fiber.Map{
|
|
"msg": "",
|
|
"errorMsg": "user not found",
|
|
})
|
|
}
|
|
|
|
var localAccountDisabled = false
|
|
if user.Attempts >= 5 {
|
|
localAccountDisabled = true // Catches newly disbaled account before student obj is updated
|
|
update_time, _ := time.Parse(time.RFC3339, time.Now().Format(time.RFC3339))
|
|
update := bson.M{
|
|
"$set": bson.M{
|
|
"disabled": true,
|
|
"attempts": 0,
|
|
"updated_at": update_time,
|
|
},
|
|
}
|
|
|
|
_, updateErr := userCollection.UpdateOne(
|
|
ctx,
|
|
bson.M{"username": username},
|
|
update,
|
|
)
|
|
if updateErr != nil {
|
|
cancel()
|
|
return c.Status(fiber.StatusInternalServerError).Render("login", fiber.Map{
|
|
"msg": "",
|
|
"errorMsg": "the user could not be updated",
|
|
})
|
|
}
|
|
}
|
|
|
|
if localAccountDisabled || user.Disabled {
|
|
cancel()
|
|
return c.Status(fiber.StatusForbidden).Render("login", fiber.Map{
|
|
"msg": "Account is Disabled, contact support",
|
|
"errorMsg": "Account is Disabled, contact support",
|
|
})
|
|
}
|
|
|
|
var verified bool = user.ComparePasswords(password)
|
|
if verified == false {
|
|
update_time, _ := time.Parse(time.RFC3339, time.Now().Format(time.RFC3339))
|
|
update := bson.M{
|
|
"$set": bson.M{
|
|
"Attempts": user.Attempts + 1,
|
|
"updated_at": update_time,
|
|
},
|
|
}
|
|
|
|
_, updateErr := userCollection.UpdateOne(
|
|
ctx,
|
|
bson.M{"username": username},
|
|
update,
|
|
)
|
|
cancel()
|
|
if updateErr != nil {
|
|
return c.Status(fiber.StatusInternalServerError).Render("login", fiber.Map{
|
|
"msg": "",
|
|
"errorMsg": "the student could not be updated",
|
|
})
|
|
}
|
|
return c.Status(fiber.StatusBadRequest).Render("login", fiber.Map{
|
|
"msg": "",
|
|
"errorMsg": "incorrect password",
|
|
})
|
|
}
|
|
defer cancel()
|
|
|
|
claims := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{
|
|
Issuer: user.UID,
|
|
ExpiresAt: time.Now().Add(time.Hour * 24).Unix(), // 1 Day
|
|
})
|
|
token, err := claims.SignedString([]byte(SecretKey))
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).Render("login", fiber.Map{
|
|
"msg": "",
|
|
"errorMsg": "could not log in",
|
|
})
|
|
}
|
|
|
|
cookie := fiber.Cookie{
|
|
Name: "jwt",
|
|
Value: token,
|
|
Expires: time.Now().Add(time.Hour * 24),
|
|
HTTPOnly: true,
|
|
}
|
|
c.Cookie(&cookie)
|
|
|
|
return c.Status(fiber.StatusNotImplemented).Render("dasboard", fiber.Map{})
|
|
}
|