58 lines
2.0 KiB
Go
58 lines
2.0 KiB
Go
package verificationimp
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"github.com/tech/sendico/pkg/api/http/response"
|
|
"github.com/tech/sendico/pkg/db/verification"
|
|
"github.com/tech/sendico/pkg/model"
|
|
"github.com/tech/sendico/pkg/mutil/mask"
|
|
"github.com/tech/sendico/pkg/mutil/mzap"
|
|
emodel "github.com/tech/sendico/server/interface/model"
|
|
mutil "github.com/tech/sendico/server/internal/mutil/verification"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
func (a *VerificationAPI) requestCode(r *http.Request, account *model.Account, token *emodel.AccountToken) http.HandlerFunc {
|
|
var req verificationCodeRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
a.logger.Warn("Failed to decode confirmation resend request", zap.Error(err))
|
|
return response.BadPayload(a.logger, a.Name(), err)
|
|
}
|
|
|
|
purpose, err := model.VPFromString(req.Purpose)
|
|
if err != nil {
|
|
return response.BadRequest(a.logger, a.Name(), "invalid_target", err.Error())
|
|
}
|
|
|
|
if purpose == model.PurposeLogin && (token == nil || !token.Pending) {
|
|
return response.Forbidden(a.logger, a.Name(), "pending_token_required", "login confirmation requires pending token")
|
|
}
|
|
|
|
target := a.resolveTarget(req.Target, account)
|
|
if target == "" {
|
|
return response.BadRequest(a.logger, a.Name(), "missing_destination", "email destination is required")
|
|
}
|
|
vReq := verification.NewOTPRequest(account.ID, purpose, target).
|
|
WithTTL(a.config.TTL).
|
|
WithCooldown(a.config.Cooldown).
|
|
WithMaxRetries(a.config.ResendLimit).
|
|
WithIdempotencyKey(req.IdempotencyKey)
|
|
|
|
otp, err := a.store.Create(r.Context(), vReq)
|
|
if err != nil {
|
|
a.logger.Warn("Failed to create confirmation code for resend", zap.Error(err), mzap.AccRef(account.ID))
|
|
return mutil.MapTokenErrorToResponse(a.logger, a.Name(), err)
|
|
}
|
|
|
|
a.sendCode(account, purpose, target, otp)
|
|
|
|
return response.Accepted(a.logger, verificationResponse{
|
|
TTLSeconds: int(vReq.Ttl.Seconds()),
|
|
CooldownSeconds: int(a.config.Cooldown.Seconds()),
|
|
Target: mask.Email(target),
|
|
IdempotencyKey: req.IdempotencyKey,
|
|
})
|
|
}
|