113 lines
3.4 KiB
Go
113 lines
3.4 KiB
Go
package verification
|
|
|
|
import (
|
|
verificationmodel "git.sendico.io/tech/sxchnge/product/verification/model"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.sendico.io/tech/sxchnge/shared/database/repository"
|
|
"git.sendico.io/tech/sxchnge/shared/database/repository/builder"
|
|
"go.mongodb.org/mongo-driver/v2/bson"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type consumeScope struct {
|
|
now time.Time
|
|
accountRef bson.ObjectID
|
|
purpose verificationmodel.VerificationPurpose
|
|
contextRef string
|
|
rawToken string
|
|
trimmedRawToken string
|
|
accountScoped bool
|
|
accountRefHex string
|
|
}
|
|
|
|
func newConsumeScope(
|
|
accountRef bson.ObjectID,
|
|
purpose verificationmodel.VerificationPurpose,
|
|
contextRef string,
|
|
rawToken string,
|
|
) (consumeScope, error) {
|
|
normalizedContextRef, err := normalizeContextRef(purpose, contextRef)
|
|
if err != nil {
|
|
return consumeScope{}, err
|
|
}
|
|
|
|
accountScoped := accountRef != bson.NilObjectID
|
|
accountRefHex := "<nil>"
|
|
if accountScoped {
|
|
accountRefHex = accountRef.Hex()
|
|
}
|
|
|
|
return consumeScope{
|
|
now: time.Now().UTC(),
|
|
accountRef: accountRef,
|
|
purpose: purpose,
|
|
contextRef: normalizedContextRef,
|
|
rawToken: rawToken,
|
|
trimmedRawToken: strings.TrimSpace(rawToken),
|
|
accountScoped: accountScoped,
|
|
accountRefHex: accountRefHex,
|
|
}, nil
|
|
}
|
|
|
|
func (scope consumeScope) logFields(extra ...zap.Field) []zap.Field {
|
|
fields := []zap.Field{
|
|
zap.String("purpose", string(scope.purpose)),
|
|
zap.Bool("account_scoped", scope.accountScoped),
|
|
zap.String("account_ref", scope.accountRefHex),
|
|
}
|
|
return append(fields, extra...)
|
|
}
|
|
|
|
func (scope consumeScope) tokenLogFields(token *verificationmodel.VerificationToken, extra ...zap.Field) []zap.Field {
|
|
fields := scope.logFields(extra...)
|
|
return append(fields, tokenStateFields(token)...)
|
|
}
|
|
|
|
func (scope consumeScope) startFields() []zap.Field {
|
|
return scope.logFields(
|
|
zap.Time("now_utc", scope.now),
|
|
zap.Int("raw_token_len", len(scope.rawToken)),
|
|
zap.Int("raw_token_trimmed_len", len(scope.trimmedRawToken)),
|
|
zap.Bool("raw_token_digits_only", tokenIsDigitsOnly(scope.rawToken)),
|
|
zap.Bool("raw_token_has_edge_whitespace", scope.rawToken != scope.trimmedRawToken),
|
|
zap.String("raw_token_hash_prefix", hashPreview(tokenHash(scope.rawToken))),
|
|
)
|
|
}
|
|
|
|
func (scope consumeScope) scopeFilters() []builder.Query {
|
|
filters := []builder.Query{
|
|
repository.Filter("purpose", scope.purpose),
|
|
}
|
|
if scope.accountScoped {
|
|
filters = append(filters, repository.Filter("accountRef", scope.accountRef))
|
|
}
|
|
filters = appendContextRefFilter(filters, scope.purpose, scope.contextRef)
|
|
return filters
|
|
}
|
|
|
|
func (scope consumeScope) scopeFilter() builder.Query {
|
|
return repository.Query().And(scope.scopeFilters()...)
|
|
}
|
|
|
|
func (scope consumeScope) consumeFilter(token *verificationmodel.VerificationToken) builder.Query {
|
|
filters := []builder.Query{
|
|
repository.IDFilter(token.ID),
|
|
repository.Filter("purpose", scope.purpose),
|
|
repository.Filter("usedAt", nil),
|
|
repository.Query().Comparison(repository.Field("expiresAt"), builder.Gt, scope.now),
|
|
}
|
|
filters = appendContextRefFilter(filters, scope.purpose, scope.contextRef)
|
|
if scope.accountScoped {
|
|
filters = append(filters, repository.Filter("accountRef", scope.accountRef))
|
|
}
|
|
if token.MaxRetries != nil {
|
|
filters = append(
|
|
filters,
|
|
repository.Query().Comparison(repository.Field("attempts"), builder.Lt, *token.MaxRetries),
|
|
)
|
|
}
|
|
return repository.Query().And(filters...)
|
|
}
|