package handlers import ( "fmt" "github.com/gofiber/fiber/v2" "github.com/golang-jwt/jwt/v5" "golang.org/x/crypto/bcrypt" "os" "relay-server/config" "relay-server/database" "relay-server/helpers" "relay-server/model" "time" ) func Signup(c *fiber.Ctx) error { db := database.DB u := new(model.SignupStruct) if err := c.BodyParser(u); err != nil { return err } // Checks if username or passwords are empty if u.Username == "" { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "username is empty"}) } else if u.Password == "" { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "password is empty"}) } // Checks if passwords or username have valid length and characters if !helpers.IsValidPassword(u.Password) { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid password"}) } else if !helpers.IsValidUsername(u.Username) { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid username"}) } // Checks if username already exist in database exist, _ := database.CheckUserExists(db, u.Username) if exist { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "user already exists"}) } // Create password hash passwordHash, err := bcrypt.GenerateFromPassword([]byte(u.Password), config.BCRYPT_COST) if err != nil { fmt.Printf("error hashing password: %v\n", err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "internal server error"}) } // Insert username and password hash to database userId, err := database.InsertUser(db, u.Username, string(passwordHash)) if err != nil { fmt.Printf("error inserting user: %v\n", err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal server error"}) } // Generate token with user id and username token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "user_id": userId, "username": u.Username, }) // Sign token signedToken, err := token.SignedString([]byte(os.Getenv("JWT_SECRET"))) // Set token to cookies tokenCookie := new(fiber.Cookie) tokenCookie.Name = "token" tokenCookie.Value = signedToken tokenCookie.Expires = time.Now().Add(30 * 24 * time.Hour) //tokenCookie.HTTPOnly = true c.Cookie(tokenCookie) // If everything went well sent username and user_id assigned by database return c.Status(fiber.StatusOK).JSON(fiber.Map{"message": "Successfully signed up", "username": u.Username, "user_id": userId}) } func Login(c *fiber.Ctx) error { db := database.DB u := new(model.LoginStruct) if err := c.BodyParser(u); err != nil { return err } // Checks if username or passwords are empty if u.Username == "" { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "username is empty"}) } else if u.Password == "" { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "password is empty"}) } // Checks if username or passwords have valid length and characters if !helpers.IsValidUsername(u.Username) { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid username"}) } else if !helpers.IsValidPassword(u.Password) { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid password"}) } // Checks if username exist in database exist, _ := database.CheckUserExists(db, u.Username) if !exist { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "user does not exists"}) } // Verifies password matching passwordHash, _ := database.GetPasswordHash(db, u.Username) if bcrypt.CompareHashAndPassword([]byte(passwordHash), []byte(u.Password)) != nil { return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "invalid password"}) } userId, err := database.GetUserId(db, u.Username) if err != nil { fmt.Printf("error getting user id: %v\n", err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "internal server error"}) } // Generate token with user id and username token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "user_id": userId, "username": u.Username, }) // Sign token signedToken, err := token.SignedString([]byte(os.Getenv("JWT_SECRET"))) // Set token to cookies tokenCookie := new(fiber.Cookie) tokenCookie.Name = "token" tokenCookie.Value = signedToken tokenCookie.Expires = time.Now().Add(30 * 24 * time.Hour) //tokenCookie.HTTPOnly = true c.Cookie(tokenCookie) return c.Status(fiber.StatusOK).JSON(fiber.Map{"message": "Successfully logged in", "username": u.Username, "user_id": userId}) } //func ValidateToken(c *fiber.Ctx) error { // //}