refac: reamaining auth surface rewrite, T0

This commit is contained in:
fsylvain committed 2026-09-24 05:11:49 +02:00
1 parent 6d510d2805
commit aa865af2e9
50 files changed
+3723 -149

No files matched your search

+148 -28
View File
@@ -2,6 +2,7 @@ package auth
import (
"RenewCMS/api/pkg/apperr"
"RenewCMS/api/pkg/claims"
validator "RenewCMS/api/pkg/validator"
"RenewCMS/internal/domain/user"
"RenewCMS/internal/infrastructure/useCases"
@@ -14,12 +15,16 @@ import (
)
type Handler struct {
Token *jwtauth.JWTAuth
GetUseCase *useCases.GetUserUseCase
ListUseCase *useCases.ListUsersUseCase
CreateUseCase *useCases.CreateUserUseCase
AuthenticateUseCase *useCases.AuthenticateUserUseCase
IsProduction bool
Token *jwtauth.JWTAuth
GetUseCase *useCases.GetUserUseCase
ListUseCase *useCases.ListUsersUseCase
CreateUseCase *useCases.CreateUserUseCase
AuthenticateUseCase *useCases.AuthenticateUserUseCase
VerifyUseCase *useCases.VerifyUserUseCase
CancelUseCase *useCases.CancelRegistrationUseCase
RequestPasswordResetUseCase *useCases.RequestPasswordResetUseCase
ResetPasswordUseCase *useCases.ResetPasswordUseCase
IsProduction bool
}
type RegisterCredentials struct {
@@ -33,6 +38,20 @@ type LoginCredentials struct {
Password string `json:"password" validate:"required,min=8"`
}
type VerifyCredentials struct {
Code string `json:"code" validate:"required"`
}
type RequestPasswordResetCredentials struct {
Email string `json:"email" validate:"required,email"`
}
type ResetPasswordCredentials struct {
Email string `json:"email" validate:"required,email"`
Code string `json:"code" validate:"required"`
Password string `json:"password" validate:"required,min=8"`
}
func (h *Handler) removeJwtCookie(w http.ResponseWriter) {
http.SetCookie(w, &http.Cookie{
Name: "jwt",
@@ -45,14 +64,18 @@ func (h *Handler) removeJwtCookie(w http.ResponseWriter) {
})
}
func NewHandler(token *jwtauth.JWTAuth, get *useCases.GetUserUseCase, list *useCases.ListUsersUseCase, create *useCases.CreateUserUseCase, authenticate *useCases.AuthenticateUserUseCase, isProduction bool) *Handler {
func NewHandler(token *jwtauth.JWTAuth, get *useCases.GetUserUseCase, list *useCases.ListUsersUseCase, create *useCases.CreateUserUseCase, authenticate *useCases.AuthenticateUserUseCase, verify *useCases.VerifyUserUseCase, cancel *useCases.CancelRegistrationUseCase, requestPasswordReset *useCases.RequestPasswordResetUseCase, resetPassword *useCases.ResetPasswordUseCase, isProduction bool) *Handler {
return &Handler{
Token: token,
GetUseCase: get,
ListUseCase: list,
CreateUseCase: create,
AuthenticateUseCase: authenticate,
IsProduction: isProduction,
Token: token,
GetUseCase: get,
ListUseCase: list,
CreateUseCase: create,
AuthenticateUseCase: authenticate,
VerifyUseCase: verify,
CancelUseCase: cancel,
RequestPasswordResetUseCase: requestPasswordReset,
ResetPasswordUseCase: resetPassword,
IsProduction: isProduction,
}
}
@@ -87,21 +110,6 @@ func (h *Handler) IsLoggedIn(r *http.Request) bool {
return token != nil && err == nil
}
func (h *Handler) IsVerified(r *http.Request) bool {
token, err := jwtauth.VerifyRequest(
h.Token,
r,
jwtauth.TokenFromCookie,
jwtauth.TokenFromHeader,
jwtauth.TokenFromQuery)
if err != nil {
return false
}
userId := token.PrivateClaims()["user_id"].(float64)
currentUser, _ := h.GetUseCase.GetUser(uint32(userId))
return currentUser.IsVerified
}
func (h *Handler) Login(w http.ResponseWriter, r *http.Request) {
var credentials LoginCredentials
@@ -163,6 +171,118 @@ func (h *Handler) Register(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write(message)
}
func (h *Handler) Verify(w http.ResponseWriter, r *http.Request) {
var credentials VerifyCredentials
err := json.NewDecoder(r.Body).Decode(&credentials)
if err != nil {
http.Error(w, apperr.BodyErrorMessage, http.StatusBadRequest)
return
}
err = validator.Validate.Struct(credentials)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
userId, ok := claims.UserId(r)
if !ok {
http.Error(w, apperr.UnauthorizedErrorMessage, http.StatusUnauthorized)
return
}
verifiedUser, err := h.VerifyUseCase.Verify(userId, credentials.Code)
if err != nil {
if errors.Is(err, user.ErrUserNotFound) {
http.Error(w, apperr.UnauthorizedErrorMessage, http.StatusUnauthorized)
return
}
if errors.Is(err, user.ErrInvalidVerificationCode) || errors.Is(err, user.ErrVerificationCodeExpired) {
http.Error(w, apperr.VerificationFailedErrorMessage, http.StatusForbidden)
return
}
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
body, _ := json.Marshal(verifiedUser)
_, _ = w.Write(body)
}
func (h *Handler) CancelRegistration(w http.ResponseWriter, r *http.Request) {
userId, ok := claims.UserId(r)
if !ok {
http.Error(w, apperr.UnauthorizedErrorMessage, http.StatusUnauthorized)
return
}
err := h.CancelUseCase.CancelRegistration(userId)
if err != nil {
if errors.Is(err, user.ErrUserNotFound) {
http.Error(w, apperr.UnauthorizedErrorMessage, http.StatusUnauthorized)
return
}
if errors.Is(err, user.ErrAlreadyVerified) {
http.Error(w, apperr.AlreadyVerifiedErrorMessage, http.StatusForbidden)
return
}
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
h.removeJwtCookie(w)
message, _ := json.Marshal(map[string]any{"message": "Registration cancelled! Account deleted and HTTPonly jwt cookie cleared"})
_, _ = w.Write(message)
}
func (h *Handler) RequestPasswordReset(w http.ResponseWriter, r *http.Request) {
var credentials RequestPasswordResetCredentials
err := json.NewDecoder(r.Body).Decode(&credentials)
if err != nil {
http.Error(w, apperr.BodyErrorMessage, http.StatusBadRequest)
return
}
err = validator.Validate.Struct(credentials)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
_ = h.RequestPasswordResetUseCase.RequestPasswordReset(credentials.Email)
message, _ := json.Marshal(map[string]any{"message": apperr.PasswordResetRequestedMessage})
_, _ = w.Write(message)
}
func (h *Handler) ResetPassword(w http.ResponseWriter, r *http.Request) {
var credentials ResetPasswordCredentials
err := json.NewDecoder(r.Body).Decode(&credentials)
if err != nil {
http.Error(w, apperr.BodyErrorMessage, http.StatusBadRequest)
return
}
err = validator.Validate.Struct(credentials)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
err = h.ResetPasswordUseCase.ResetPassword(credentials.Email, credentials.Code, credentials.Password)
if err != nil {
if errors.Is(err, user.ErrInvalidPasswordResetCode) || errors.Is(err, user.ErrPasswordResetCodeExpired) {
http.Error(w, apperr.PasswordResetFailedErrorMessage, http.StatusForbidden)
return
}
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
message, _ := json.Marshal(map[string]any{"message": "Your password has been reset. You can now log in."})
_, _ = w.Write(message)
}
func (h *Handler) Logout(w http.ResponseWriter, _ *http.Request) {
h.removeJwtCookie(w)
message, _ := json.Marshal(map[string]any{"message": "User logged out! HTTPonly jwt cookie deleted"})