template-monorepo/internal/model/member/usecase/step_up_usecase.go

85 lines
2.6 KiB
Go

package usecase
import (
"context"
"errors"
"time"
memberdomain "gateway/internal/model/member/domain"
domrepo "gateway/internal/model/member/domain/repository"
domusecase "gateway/internal/model/member/domain/usecase"
memberconfig "gateway/internal/model/member/config"
"github.com/google/uuid"
)
type stepUpUseCase struct {
store domrepo.StepUpStore
config memberconfig.Config
}
// StepUpUseCaseParam wires StepUpUseCase.
type StepUpUseCaseParam struct {
Store domrepo.StepUpStore
Config memberconfig.Config
}
// MustStepUpUseCase constructs StepUpUseCase.
func MustStepUpUseCase(param StepUpUseCaseParam) domusecase.StepUpUseCase {
if param.Store == nil {
panic("member: step-up store is required")
}
return &stepUpUseCase{store: param.Store, config: param.Config.Defaults()}
}
func (uc *stepUpUseCase) Issue(ctx context.Context, req *domusecase.IssueStepUpRequest) (*domusecase.StepUpView, error) {
if req == nil || req.TenantID == "" || req.UID == "" {
return nil, errb.InputMissingRequired("tenant_id, uid and purpose are required")
}
if !req.Purpose.Valid() {
return nil, errb.InputInvalidFormat("unsupported step-up purpose")
}
ttl := req.TTL
if ttl <= 0 {
ttl = time.Duration(uc.config.TOTP.StepUpTTLSeconds) * time.Second
}
tokenID := uuid.NewString()
if err := uc.store.Save(ctx, &domrepo.StepUpSession{
TokenID: tokenID,
TenantID: req.TenantID,
UID: req.UID,
Purpose: req.Purpose.String(),
}, ttl); err != nil {
return nil, wrapRepoErr(err, "save step-up session failed")
}
return &domusecase.StepUpView{
StepUpToken: tokenID,
ExpiresIn: int(ttl.Seconds()),
}, nil
}
func (uc *stepUpUseCase) Consume(ctx context.Context, req *domusecase.ConsumeStepUpRequest) error {
if req == nil || req.TokenID == "" || req.TenantID == "" || req.UID == "" {
return errb.InputMissingRequired("step_up_token, tenant_id and uid are required")
}
if !req.Purpose.Valid() {
return errb.InputInvalidFormat("unsupported step-up purpose")
}
session, err := uc.store.Get(ctx, req.TokenID)
if err != nil {
if errors.Is(err, memberdomain.ErrStepUpNotFound) {
return errb.ResNotFound("step-up session", req.TokenID).WithCause(err)
}
return wrapRepoErr(err, "read step-up session failed")
}
if session.TenantID != req.TenantID || session.UID != req.UID || session.Purpose != req.Purpose.String() {
return errb.AuthForbidden("step-up token mismatch")
}
if err := uc.store.Delete(ctx, req.TokenID); err != nil {
return wrapRepoErr(err, "delete step-up session failed")
}
return nil
}
var _ domusecase.StepUpUseCase = (*stepUpUseCase)(nil)