2025-05-02 00:10:16 +03:00

130 lines
4.0 KiB
Go

package main
import (
"log/slog"
"net/http"
"os"
"time"
"github.com/gin-gonic/gin"
"golang.org/x/crypto/bcrypt"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
type User struct {
ID uint `gorm:"primaryKey"` // Standard field for the primary key
Username string // A regular string field
Password *[]byte
Email string // A pointer to a string, allowing for null values
Updated int64 `gorm:"autoUpdateTime:milli"` // Use unix milli seconds as updating time
Created int64 `gorm:"autoCreateTime"` // Use unix seconds as creating time
Deleted gorm.DeletedAt `gorm:"index"`
}
type Login struct {
Email string `form:"email" json:"email" xml:"email" binding:"required"`
Password string `form:"password" json:"password" xml:"password" binding:"required"`
}
type Register struct {
Email string `form:"email" json:"email" xml:"email" binding:"required"`
Password string `form:"password" json:"password" xml:"password" binding:"required"`
PasswordConfirmation string `form:"password_confirm" json:"password_confirm" xml:"password_confirm" binding:"required"`
Username string `form:"username" json:"username" xml:"username" binding:"required"`
}
func main() {
jsonHandler := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{
Level: slog.LevelDebug,
AddSource: true,
})
myslog := slog.New(jsonHandler)
dsn := "host=localhost user=postgres password=asd dbname=postgres port=5432"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
myslog.Error("Could not establish connection to database!")
panic("Could not establish connection to database!")
}
db.AutoMigrate(&User{})
sqlDB, err := db.DB()
if err != nil {
myslog.Error("Could not create connection pool for database!")
panic("Could not create connection pool for database!")
}
// SetMaxIdleConns sets the maximum number of connections in the idle connection pool.
sqlDB.SetMaxIdleConns(10)
// SetMaxOpenConns sets the maximum number of open connections to the database.
sqlDB.SetMaxOpenConns(100)
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
sqlDB.SetConnMaxLifetime(time.Hour)
password := "asd" // Replace this with the password you want to encrypt
hashedPassword, err := hashPassword(password)
if err != nil {
myslog.Info("Encryption failed:", "err", err)
return
}
myslog.Info("Hashed Password:", "password", string(hashedPassword))
router := gin.Default()
router.POST("/login", func(c *gin.Context) {
var json Login
if err := c.ShouldBindJSON(&json); err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized: payload mismatch"})
myslog.Info("Payload:", "json", &c.Request.Body)
return
}
var user *User
user, exists := userExists(json.Email, "", db)
if exists || !doPasswordsMatch(*user.Password, json.Password) {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized: email or password incorrect"})
return
}
c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
})
router.POST("/register", func(c *gin.Context) {
var json Register
if err := c.ShouldBindJSON(&json); err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized: payload mismatch"})
myslog.Info("Payload:", "json", &c.Request.Body)
return
}
c.JSON(http.StatusOK, gin.H{"status": "registration complete"})
})
// Listen and serve on 0.0.0.0:8080
router.Run(":8080")
}
func doPasswordsMatch(hashedPassword []byte, currPassword string) bool {
err := bcrypt.CompareHashAndPassword(hashedPassword, []byte(currPassword))
return err == nil
}
func hashPassword(password string) ([]byte, error) {
return bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
}
func userExists(username string, email string, db *gorm.DB) (*User, bool) {
var user = User{Username: username, Email: email}
result := db.Where("username = ? OR email = ?", username, email).First(&user)
if result.Error != nil {
return &user, true
}
return nil, false
}