Files
Hyperia/server/handlers/login.go
metacryst faf2041b7f signins
2025-09-30 17:44:39 -05:00

101 lines
2.3 KiB
Go

package handlers
import (
"errors"
"log"
"net/http"
"os"
"strings"
"strconv"
"hyperia/db"
"github.com/alexedwards/argon2id"
)
type loginRequest struct {
Email string `json:"email"`
Password string `json:"password"`
}
type user struct {
ID int `json:"id"`
Email string `json:"email"`
}
func HandleLogin(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Only POST allowed", http.StatusMethodNotAllowed)
return
}
var creds loginRequest
if err := r.ParseForm(); err != nil {
http.Error(w, "Unable to parse form", http.StatusBadRequest)
return
}
email := r.FormValue("email")
password := r.FormValue("password")
creds.Email = email
creds.Password = password
user, err := getUserByCredentials(creds)
if err != nil || user == nil {
http.Error(w, "Unauthorized: "+ err.Error(), http.StatusUnauthorized)
return
}
keyInt, err := strconv.Atoi(user["key"].(string))
if err != nil {
// This means the string couldn't be parsed as an int — handle it
log.Println("user['key'] is not a valid int:", err)
http.Error(w, "internal server error", http.StatusInternalServerError)
return
}
jwtToken, err := GenerateJWT(keyInt)
if err != nil {
log.Println("JWT generation error:", err)
http.Error(w, "Failed to generate auth token", http.StatusInternalServerError)
return
}
cookie := &http.Cookie{
Name: "auth_token",
Value: jwtToken,
Path: "/",
HttpOnly: true,
Domain: "." + os.Getenv("BASE_URL"), // or ".localhost" — this allows subdomains
Secure: true, // default to true (production)
MaxAge: 2 * 60 * 60,
SameSite: http.SameSiteLaxMode,
}
http.SetCookie(w, cookie)
http.Redirect(w, r, "/", http.StatusSeeOther)
}
func getUserByCredentials(loginCreds loginRequest) (map[string]interface{}, error) {
email := strings.TrimSpace(strings.ToLower(loginCreds.Email))
user, err := db.Get.UserByEmail(email)
if err != nil {
return nil, errors.New("user not found")
}
dbPassword, ok := user["password"].(string)
if !ok {
return nil, errors.New("password format is invalid")
}
log.Println("pass: ", loginCreds, loginCreds.Password, dbPassword)
match, err := argon2id.ComparePasswordAndHash(loginCreds.Password, dbPassword)
if err != nil || !match {
return nil, errors.New("invalid password")
}
return user, nil
}