130 lines
4.0 KiB
Go
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
|
|
}
|