unified code verification service
This commit is contained in:
@@ -6,9 +6,12 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrTokenNotFound = errors.New("vtNotFound")
|
||||
ErrTokenAlreadyUsed = errors.New("vtAlreadyUsed")
|
||||
ErrTokenExpired = errors.New("vtExpired")
|
||||
ErrTokenNotFound = errors.New("vtNotFound")
|
||||
ErrTokenAlreadyUsed = errors.New("vtAlreadyUsed")
|
||||
ErrTokenExpired = errors.New("vtExpired")
|
||||
ErrTokenAttemptsExceeded = errors.New("vtAttemptsExceeded")
|
||||
ErrCooldownActive = errors.New("vtCooldownActive")
|
||||
ErrIdempotencyConflict = errors.New("vtIdempotencyConflict")
|
||||
)
|
||||
|
||||
func wrap(err error, msg string) error {
|
||||
@@ -26,3 +29,15 @@ func ErorrTokenAlreadyUsed() error {
|
||||
func ErorrTokenExpired() error {
|
||||
return wrap(ErrTokenExpired, "verification token expired")
|
||||
}
|
||||
|
||||
func ErrorCooldownActive() error {
|
||||
return wrap(ErrCooldownActive, "token creation cooldown is active")
|
||||
}
|
||||
|
||||
func ErrorTokenAttemptsExceeded() error {
|
||||
return wrap(ErrTokenAttemptsExceeded, "verification token max attempts exceeded")
|
||||
}
|
||||
|
||||
func ErrorIdempotencyConflict() error {
|
||||
return wrap(ErrIdempotencyConflict, "verification token request idempotency key has already been used")
|
||||
}
|
||||
|
||||
70
api/pkg/db/verification/request.go
Normal file
70
api/pkg/db/verification/request.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package verification
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
type TokenKind = string
|
||||
|
||||
const (
|
||||
TokenKindOTP TokenKind = "otp"
|
||||
TokenKindLink TokenKind = "link"
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
AccountRef bson.ObjectID
|
||||
Purpose model.VerificationPurpose
|
||||
Target string
|
||||
Ttl time.Duration
|
||||
Kind TokenKind
|
||||
MaxRetries *int
|
||||
Cooldown *time.Duration
|
||||
IdempotencyKey *string // Optional key to make Create idempotent for retries.
|
||||
}
|
||||
|
||||
func newRequest(accountRef bson.ObjectID, purpose model.VerificationPurpose, target string, kind TokenKind) *Request {
|
||||
return &Request{
|
||||
AccountRef: accountRef,
|
||||
Purpose: purpose,
|
||||
Target: target,
|
||||
Kind: kind,
|
||||
Ttl: 15 * time.Minute, // default TTL for verification tokens
|
||||
}
|
||||
}
|
||||
|
||||
func NewLinkRequest(accountRef bson.ObjectID, purpose model.VerificationPurpose, target string) *Request {
|
||||
return newRequest(accountRef, purpose, target, TokenKindLink)
|
||||
}
|
||||
|
||||
func NewOTPRequest(accountRef bson.ObjectID, purpose model.VerificationPurpose, target string) *Request {
|
||||
return newRequest(accountRef, purpose, target, TokenKindOTP)
|
||||
}
|
||||
|
||||
func (r *Request) WithTTL(ttl time.Duration) *Request {
|
||||
r.Ttl = ttl
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Request) WithMaxRetries(maxRetries int) *Request {
|
||||
r.MaxRetries = &maxRetries
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Request) WithCooldown(cooldown time.Duration) *Request {
|
||||
r.Cooldown = &cooldown
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Request) WithIdempotencyKey(key string) *Request {
|
||||
normalized := strings.TrimSpace(key)
|
||||
if normalized == "" {
|
||||
r.IdempotencyKey = nil
|
||||
return r
|
||||
}
|
||||
r.IdempotencyKey = &normalized
|
||||
return r
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package verification
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
@@ -10,12 +9,6 @@ import (
|
||||
|
||||
type DB interface {
|
||||
// template.DB[*model.VerificationToken]
|
||||
Create(
|
||||
ctx context.Context,
|
||||
accountRef bson.ObjectID,
|
||||
purpose model.VerificationPurpose,
|
||||
target string,
|
||||
ttl time.Duration,
|
||||
) (rawToken string, err error)
|
||||
Consume(ctx context.Context, rawToken string) (*model.VerificationToken, error)
|
||||
Create(ctx context.Context, request *Request) (verificationToken string, err error)
|
||||
Consume(ctx context.Context, accountRef bson.ObjectID, purpose model.VerificationPurpose, verificationToken string) (*model.VerificationToken, error)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user