Bootstrap copied BFF and local accounts with public Sendico contracts (#34)
This commit is contained in:
1 parent
67dc5b5b1e
commit
7062672a87
556 files changed
+42291
-777
No files matched your search
@@ -0,0 +1,183 @@
|
||||
package verification
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"git.sendico.io/tech/sxchnge/bff/pkg/db/repository"
|
||||
"git.sendico.io/tech/sxchnge/bff/pkg/db/repository/builder"
|
||||
"git.sendico.io/tech/sxchnge/bff/pkg/merrors"
|
||||
"git.sendico.io/tech/sxchnge/bff/pkg/model"
|
||||
mutil "git.sendico.io/tech/sxchnge/bff/pkg/mutil/db"
|
||||
"git.sendico.io/tech/sxchnge/bff/pkg/mutil/mzap"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type consumeMissError struct {
|
||||
cause error
|
||||
tokenIDs []bson.ObjectID
|
||||
}
|
||||
|
||||
func newConsumeMissError(tokens []model.VerificationToken) consumeMissError {
|
||||
tokenIDs := make([]bson.ObjectID, 0, len(tokens))
|
||||
for i := range tokens {
|
||||
if tokens[i].ID != bson.NilObjectID {
|
||||
tokenIDs = append(tokenIDs, tokens[i].ID)
|
||||
}
|
||||
}
|
||||
return consumeMissError{
|
||||
cause: ErorrTokenNotFound(),
|
||||
tokenIDs: tokenIDs,
|
||||
}
|
||||
}
|
||||
|
||||
func (e consumeMissError) Error() string {
|
||||
return e.cause.Error()
|
||||
}
|
||||
|
||||
func (e consumeMissError) Unwrap() error {
|
||||
return e.cause
|
||||
}
|
||||
|
||||
func (db *verificationDB) lookupConsumeToken(
|
||||
ctx context.Context,
|
||||
scope consumeScope,
|
||||
) (*model.VerificationToken, error) {
|
||||
scopeFilter := scope.scopeFilter()
|
||||
db.Logger.Debug("Verification consume scope filter prepared", scope.logFields()...)
|
||||
|
||||
token, err := db.lookupConsumeMagicToken(ctx, scope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if token != nil {
|
||||
return token, nil
|
||||
}
|
||||
|
||||
if !scope.accountScoped {
|
||||
db.Logger.Debug("Verification consume rejected unscoped OTP scan", scope.logFields()...)
|
||||
return nil, ErorrTokenNotFound()
|
||||
}
|
||||
|
||||
return db.lookupConsumeOTPToken(ctx, scope, scopeFilter)
|
||||
}
|
||||
|
||||
func (db *verificationDB) lookupConsumeMagicToken(
|
||||
ctx context.Context,
|
||||
scope consumeScope,
|
||||
) (*model.VerificationToken, error) {
|
||||
magicFilter := repository.Query().And(
|
||||
append(
|
||||
scope.scopeFilters(),
|
||||
repository.Filter("verifyTokenHash", tokenHash(scope.rawToken)),
|
||||
)...,
|
||||
)
|
||||
db.Logger.Debug("Verification consume magic path lookup", scope.logFields()...)
|
||||
|
||||
var direct model.VerificationToken
|
||||
err := db.FindOne(ctx, magicFilter, &direct)
|
||||
switch {
|
||||
case err == nil:
|
||||
db.Logger.Debug("Verification consume matched by magic hash path",
|
||||
scope.tokenLogFields(&direct)...,
|
||||
)
|
||||
return &direct, nil
|
||||
case errors.Is(err, merrors.ErrNoData):
|
||||
db.Logger.Debug("Verification consume no direct magic match", scope.logFields()...)
|
||||
return nil, nil
|
||||
default:
|
||||
db.Logger.Warn("Verification consume magic path lookup failed",
|
||||
scope.logFields(zap.Error(err))...,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (db *verificationDB) lookupConsumeOTPToken(
|
||||
ctx context.Context,
|
||||
scope consumeScope,
|
||||
scopeFilter builder.Query,
|
||||
) (*model.VerificationToken, error) {
|
||||
db.Logger.Debug("Verification consume OTP fallback lookup started",
|
||||
scope.logFields(zap.Any("scope_filter", scopeFilter.BuildQuery()))...,
|
||||
)
|
||||
tokens, err := mutil.GetObjects[model.VerificationToken](
|
||||
ctx, db.Logger, scopeFilter, nil, db.Repository,
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, merrors.ErrNoData) {
|
||||
db.Logger.Debug("Verification consume OTP fallback found no scoped tokens", scope.logFields()...)
|
||||
return nil, ErorrTokenNotFound()
|
||||
}
|
||||
db.Logger.Warn("Verification consume OTP fallback query failed",
|
||||
scope.logFields(zap.Error(err))...,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
db.Logger.Debug("Verification consume OTP fallback loaded candidates",
|
||||
scope.logFields(zap.Int("candidate_count", len(tokens)))...,
|
||||
)
|
||||
|
||||
for i := range tokens {
|
||||
token := &tokens[i]
|
||||
hash := hasherFor(token).Hash(scope.rawToken, token)
|
||||
match := hash == token.VerifyTokenHash
|
||||
db.Logger.Debug("Verification consume OTP candidate evaluated",
|
||||
zap.Int("candidate_index", i),
|
||||
zap.Int("candidate_total", len(tokens)),
|
||||
mzap.ObjRef("candidate_ref", token.ID),
|
||||
zap.Bool("candidate_has_salt", token.Salt != nil),
|
||||
zap.Bool("candidate_used", token.UsedAt != nil),
|
||||
zap.Time("candidate_expires_at", token.ExpiresAt),
|
||||
zap.Int("candidate_attempts", token.Attempts),
|
||||
zap.Bool("candidate_has_max_retries", token.MaxRetries != nil),
|
||||
zap.String("candidate_stored_hash_prefix", hashPreview(token.VerifyTokenHash)),
|
||||
zap.String("candidate_computed_hash_prefix", hashPreview(hash)),
|
||||
zap.Bool("candidate_match", match),
|
||||
)
|
||||
if match {
|
||||
return token, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, newConsumeMissError(tokens)
|
||||
}
|
||||
|
||||
func (db *verificationDB) incrementConsumeAttemptsForTokenIDs(
|
||||
ctx context.Context,
|
||||
scope consumeScope,
|
||||
tokenIDs []bson.ObjectID,
|
||||
) {
|
||||
if len(tokenIDs) == 0 {
|
||||
return
|
||||
}
|
||||
db.Logger.Debug("Verification consume no OTP candidate matched, incrementing attempts for active scoped tokens",
|
||||
scope.logFields(zap.Int("candidate_count", len(tokenIDs)))...,
|
||||
)
|
||||
|
||||
filters := append(
|
||||
scope.scopeFilters(),
|
||||
repository.Query().Comparison(repository.IDField(), builder.In, tokenIDs),
|
||||
repository.Filter("usedAt", nil),
|
||||
repository.Query().Comparison(repository.Field("expiresAt"), builder.Gt, scope.now),
|
||||
)
|
||||
incremented, err := db.PatchMany(
|
||||
ctx,
|
||||
repository.Query().And(filters...),
|
||||
repository.Patch().Inc(repository.Field("attempts"), 1),
|
||||
)
|
||||
if err != nil {
|
||||
db.Logger.Warn("Verification consume failed to increment attempts for unmatched token",
|
||||
scope.logFields(zap.Error(err))...,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
db.Logger.Debug("Verification consume attempts increment for unmatched token executed",
|
||||
scope.logFields(
|
||||
zap.Int("updated_count", incremented),
|
||||
zap.String("transaction_note", "this update occurs after failed consume transaction so not_found does not roll it back"),
|
||||
)...,
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user