120 lines
3.2 KiB
Go
120 lines
3.2 KiB
Go
package auth
|
|
|
|
import (
|
|
"RenewCMS/api/pkg/apperr"
|
|
"RenewCMS/api/pkg/claims"
|
|
validator "RenewCMS/api/pkg/validator"
|
|
"RenewCMS/internal/domain/user"
|
|
"RenewCMS/internal/infrastructure/useCases"
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
type VerificationHandler struct {
|
|
VerifyUseCase *useCases.VerifyUserUseCase
|
|
CancelUseCase *useCases.CancelRegistrationUseCase
|
|
IsProduction bool
|
|
}
|
|
|
|
type VerifyCredentials struct {
|
|
Code string `json:"code" validate:"required"`
|
|
}
|
|
|
|
type PublicUser struct {
|
|
ID uint32 `json:"id"`
|
|
Username string `json:"username"`
|
|
Email string `json:"email"`
|
|
IsVerified bool `json:"is_verified"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
func newPublicUser(u user.User) PublicUser {
|
|
return PublicUser{
|
|
ID: u.ID,
|
|
Username: u.Username,
|
|
Email: u.Email,
|
|
IsVerified: u.IsVerified,
|
|
CreatedAt: u.CreatedAt,
|
|
UpdatedAt: u.UpdatedAt,
|
|
}
|
|
}
|
|
|
|
func NewVerificationHandler(verify *useCases.VerifyUserUseCase, cancel *useCases.CancelRegistrationUseCase, isProduction bool) *VerificationHandler {
|
|
return &VerificationHandler{
|
|
VerifyUseCase: verify,
|
|
CancelUseCase: cancel,
|
|
IsProduction: isProduction,
|
|
}
|
|
}
|
|
|
|
func (h *VerificationHandler) 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, err := json.Marshal(newPublicUser(verifiedUser))
|
|
if err != nil {
|
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
_, _ = w.Write(body)
|
|
}
|
|
|
|
func (h *VerificationHandler) 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
|
|
}
|
|
|
|
removeJwtCookie(w, h.IsProduction)
|
|
message, _ := json.Marshal(map[string]any{"message": "Registration cancelled! Account deleted and HTTPonly jwt cookie cleared"})
|
|
_, _ = w.Write(message)
|
|
}
|