thread-master/old/backend/internal/middleware/emailverified_middleware.go

77 lines
2.1 KiB
Go
Raw Normal View History

2026-07-09 03:45:28 +00:00
package middleware
import (
"net/http"
"haixun-backend/internal/library/authctx"
app "haixun-backend/internal/library/errors"
"haixun-backend/internal/library/errors/code"
"haixun-backend/internal/model/member/domain/entity"
memberdomain "haixun-backend/internal/model/member/domain/usecase"
"haixun-backend/internal/response"
)
var emailVerificationBypass = map[string]map[string]struct{}{
http.MethodGet: {
"/api/v1/members/me": {},
},
http.MethodPost: {
"/api/v1/auth/logout": {},
"/api/v1/auth/verify-email": {},
"/api/v1/auth/resend-verification-email": {},
},
}
// EmailVerifiedMiddleware blocks native members who have not verified email yet.
// Third-party (oauth) origins skip this gate.
type EmailVerifiedMiddleware struct {
members memberdomain.UseCase
}
func NewEmailVerifiedMiddleware(members memberdomain.UseCase) *EmailVerifiedMiddleware {
return &EmailVerifiedMiddleware{members: members}
}
func (m *EmailVerifiedMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
actor, ok := authctx.ActorFromContext(r.Context())
if !ok {
next(w, r)
return
}
if emailVerificationBypassed(r.Method, r.URL.Path) {
next(w, r)
return
}
if m.members == nil {
response.Write(r.Context(), w, nil, app.For(code.Auth).SysNotImplemented("member usecase is not configured"))
return
}
member, err := m.members.GetByUID(r.Context(), actor.TenantID, actor.UID)
if err != nil {
response.Write(r.Context(), w, nil, err)
return
}
if !requiresNativeEmailVerification(member) || member.EmailVerified {
next(w, r)
return
}
response.Write(r.Context(), w, nil, app.For(code.Auth).AuthForbidden("email verification required"))
}
}
func emailVerificationBypassed(method, path string) bool {
routes, ok := emailVerificationBypass[method]
if !ok {
return false
}
_, ok = routes[path]
return ok
}
func requiresNativeEmailVerification(member *entity.Member) bool {
if member == nil {
return false
}
return member.Origin == "" || member.Origin == entity.OriginNative
}