First release of open core
This commit is contained in:
140
pkg/auth/auth_handlers.go
Normal file
140
pkg/auth/auth_handlers.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const SessionCookieName = "session_token"
|
||||
|
||||
// RegisterRequest represents the JSON payload expected for user registration.
|
||||
type RegisterRequest struct {
|
||||
Email string `json:"email"`
|
||||
FullName string `json:"full_name"`
|
||||
Password string `json:"password"`
|
||||
GlobalRole string `json:"global_role"`
|
||||
}
|
||||
|
||||
// LoginRequest represents the JSON payload expected for user login.
|
||||
type LoginRequest struct {
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
// HandleRegister processes new user signups.
|
||||
func (h *Handler) HandleRegister(w http.ResponseWriter, r *http.Request) {
|
||||
var req RegisterRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
count, err := h.Store.GetUserCount(r.Context())
|
||||
if err != nil {
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if count > 0 {
|
||||
http.Error(w, "Forbidden: System already initialized. Contact your Sheriff for an account.", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
req.GlobalRole = "Sheriff"
|
||||
|
||||
if req.Email == "" || req.Password == "" || req.FullName == "" {
|
||||
http.Error(w, "Missing required fields", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
hashedPassword, err := HashPassword(req.Password)
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to hash password", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.Store.CreateUser(r.Context(), req.Email, req.FullName, hashedPassword, req.GlobalRole)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "UNIQUE constraint failed") {
|
||||
http.Error(w, "Email already exists", http.StatusConflict)
|
||||
return
|
||||
}
|
||||
http.Error(w, "Failed to create user", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
json.NewEncoder(w).Encode(user)
|
||||
}
|
||||
|
||||
// HandleLogin authenticates a user and issues a session cookie.
|
||||
func (h *Handler) HandleLogin(w http.ResponseWriter, r *http.Request) {
|
||||
var req LoginRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http.Error(w, "Invalid JSON payload", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.Store.GetUserByEmail(r.Context(), req.Email)
|
||||
if err != nil {
|
||||
http.Error(w, "Invalid credentials", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
if !CheckPasswordHash(req.Password, user.PasswordHash) {
|
||||
http.Error(w, "Invalid credentials", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
token, err := GenerateSessionToken()
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to generate session", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
expiresAt := time.Now().Add(24 * time.Hour)
|
||||
if err := h.Store.CreateSession(r.Context(), token, user.ID, expiresAt); err != nil {
|
||||
http.Error(w, "Failed to persist session", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "session_token",
|
||||
Value: token,
|
||||
Expires: expiresAt,
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
Secure: false, // Set to TRUE in production for HTTPS!
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
})
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(user)
|
||||
}
|
||||
|
||||
// HandleLogout destroys the user's session in the database and clears their cookie.
|
||||
func (h *Handler) HandleLogout(w http.ResponseWriter, r *http.Request) {
|
||||
cookie, err := r.Cookie(SessionCookieName)
|
||||
|
||||
if err == nil && cookie.Value != "" {
|
||||
_ = h.Store.DeleteSession(r.Context(), cookie.Value)
|
||||
}
|
||||
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: SessionCookieName,
|
||||
Value: "",
|
||||
Path: "/",
|
||||
Expires: time.Unix(0, 0),
|
||||
MaxAge: -1,
|
||||
HttpOnly: true,
|
||||
Secure: true, // Ensures it's only sent over HTTPS
|
||||
SameSite: http.SameSiteStrictMode,
|
||||
})
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"message": "Successfully logged out",
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user