package auth import ( "encoding/json" "fmt" "log" "math/rand" "net/http" "time" "gitea.local/admin/hspguard/internal/util" "gitea.local/admin/hspguard/internal/web" "github.com/google/uuid" ) func (h *AuthHandler) requestEmailOtp(w http.ResponseWriter, r *http.Request) { userId, ok := util.GetRequestUserId(r.Context()) if !ok { web.Error(w, "failed to get user id from auth session", http.StatusInternalServerError) return } user, err := h.repo.FindUserId(r.Context(), uuid.MustParse(userId)) if err != nil { web.Error(w, "user with provided id does not exist", http.StatusUnauthorized) return } if user.EmailVerified { web.Error(w, "email is already verified", http.StatusBadRequest) return } number := rand.Intn(1000000) // 0 to 999999 padded := fmt.Sprintf("%06d", number) // Always 6 characters if _, err := h.cache.Set(r.Context(), fmt.Sprintf("otp-%s", user.ID.String()), padded, 5*time.Minute).Result(); err != nil { log.Println("ERR: Failed to save OTP in cache:", err) web.Error(w, "failed to generate otp", http.StatusInternalServerError) return } log.Printf("INFO: Saved OTP %s\n", padded) w.WriteHeader(http.StatusCreated) } type ConfirmOtpRequest struct { OTP string `json:"otp"` } func (h *AuthHandler) confirmOtp(w http.ResponseWriter, r *http.Request) { userId, ok := util.GetRequestUserId(r.Context()) if !ok { web.Error(w, "failed to get user id from auth session", http.StatusInternalServerError) return } user, err := h.repo.FindUserId(r.Context(), uuid.MustParse(userId)) if err != nil { web.Error(w, "user with provided id does not exist", http.StatusUnauthorized) return } if user.EmailVerified { web.Error(w, "email is already verified", http.StatusBadRequest) return } var req ConfirmOtpRequest decoder := json.NewDecoder(r.Body) if err := decoder.Decode(&req); err != nil { web.Error(w, "invalid request", http.StatusBadRequest) return } val, err := h.cache.Get(r.Context(), fmt.Sprintf("otp-%s", user.ID.String())).Result() if err != nil { web.Error(w, "otp verification session not found", http.StatusNotFound) return } log.Printf("INFO: Comparing OTP %s == %s\n", req.OTP, val) if req.OTP == val { err := h.repo.UserVerifyEmail(r.Context(), user.ID) if err != nil { log.Println("ERR: Failed to update email_verified:", err) web.Error(w, "failed to verify email", http.StatusInternalServerError) return } } else { web.Error(w, "otp verification failed", http.StatusBadRequest) return } w.WriteHeader(http.StatusOK) }