Skip to content

Commit

Permalink
Merge pull request #2648 from brave-intl/master
Browse files Browse the repository at this point in the history
fix: use leo annual issuer if redemption fails for regular leo (#2647)
  • Loading branch information
pavelbrm authored Aug 26, 2024
2 parents f47a4e6 + a9fc2ea commit cd5f926
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 31 deletions.
7 changes: 3 additions & 4 deletions services/skus/controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -943,14 +943,13 @@ func MerchantTransactions(service *Service) handlers.AppHandler {
})
}

// VerifyCredentialV2 - version 2 of verify credential
func VerifyCredentialV2(service *Service) handlers.AppHandler {
return func(w http.ResponseWriter, r *http.Request) *handlers.AppError {

ctx := r.Context()
l := logging.Logger(ctx, "VerifyCredentialV2")

var req = new(VerifyCredentialRequestV2)
l := logging.Logger(ctx, "skus").With().Str("func", "VerifyCredentialV2").Logger()

req := &VerifyCredentialRequestV2{}
if err := inputs.DecodeAndValidateReader(ctx, req, r.Body); err != nil {
l.Error().Err(err).Msg("failed to read request")
return handlers.WrapError(err, "Error in request body", http.StatusBadRequest)
Expand Down
62 changes: 35 additions & 27 deletions services/skus/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -1415,32 +1415,21 @@ func (s *Service) verifyCredential(ctx context.Context, cred credential, w http.
return handlers.WrapError(err, "Error getting auth merchant", http.StatusInternalServerError)
}

logger.Debug().Str("merchant", merchant).Msg("got merchant from the context")

caveats := caveatsFromCtx(ctx)

if cred.GetMerchantID(ctx) != merchant {
logger.Warn().
Str("req.MerchantID", cred.GetMerchantID(ctx)).
Str("merchant", merchant).
Msg("merchant does not match the key's merchant")
if merchID := cred.GetMerchantID(ctx); merchID != merchant {
logger.Warn().Str("req.MerchantID", merchID).Str("merchant", merchant).Msg("merchant does not match the key's merchant")
return handlers.WrapError(nil, "Verify request merchant does not match authentication", http.StatusForbidden)
}

logger.Debug().Str("merchant", merchant).Msg("merchant matches the key's merchant")

if caveats != nil {
if sku, ok := caveats["sku"]; ok {
if cred.GetSku(ctx) != sku {
logger.Warn().
Str("req.SKU", cred.GetSku(ctx)).
Str("sku", sku).
Msg("sku caveat does not match")
if csku := cred.GetSku(ctx); csku != sku {
logger.Warn().Str("req.SKU", csku).Str("sku", sku).Msg("sku caveat does not match")
return handlers.WrapError(nil, "Verify request sku does not match authentication", http.StatusForbidden)
}
}
}
logger.Debug().Msg("caveats validated")

kind := cred.GetType(ctx)
switch kind {
Expand Down Expand Up @@ -1958,27 +1947,22 @@ func (s *Service) redeemBlindedCred(ctx context.Context, w http.ResponseWriter,
// FIXME: we shouldn't be using the issuer as the payload, it ideally would be a unique request identifier
// to allow for more flexible idempotent behavior.
if err := redeemFn(ctx, cred.Issuer, cred.TokenPreimage, cred.Signature, cred.Issuer); err != nil {
msg := err.Error()

// Time limited v2: Expose a credential id so the caller can decide whether to allow multiple redemptions.
if kind == timeLimitedV2 && msg == cbr.ErrDupRedeem.Error() {
data := &blindedCredVrfResult{ID: cred.TokenPreimage, Duplicate: true}

return handlers.RenderContent(ctx, data, w, http.StatusOK)
if !shouldRetryRedeemFn(kind, cred.Issuer, err) {
return handleRedeemFnError(ctx, w, kind, cred, err)
}

// Duplicate redemptions are not verified.
if msg == cbr.ErrDupRedeem.Error() || msg == cbr.ErrBadRequest.Error() {
return handlers.WrapError(err, "invalid credentials", http.StatusForbidden)
// Fix for https://github.com/brave-intl/challenge-bypass-server/pull/371.
const leoa = "brave.com?sku=brave-leo-premium-year"
if err := redeemFn(ctx, leoa, cred.TokenPreimage, cred.Signature, cred.Issuer); err != nil {
return handleRedeemFnError(ctx, w, kind, cred, err)
}

return handlers.WrapError(err, "Error verifying credentials", http.StatusInternalServerError)
}

// TODO(clD11): cleanup after quick fix
if kind == timeLimitedV2 {
return handlers.RenderContent(ctx, &blindedCredVrfResult{ID: cred.TokenPreimage}, w, http.StatusOK)
}

return handlers.RenderContent(ctx, "Credentials successfully verified", w, http.StatusOK)
}

Expand Down Expand Up @@ -2575,3 +2559,27 @@ func buildStripeLineItems(items []model.OrderItem) []*stripe.CheckoutSessionLine

return result
}

func handleRedeemFnError(ctx context.Context, w http.ResponseWriter, kind string, cred *cbr.CredentialRedemption, err error) *handlers.AppError {
msg := err.Error()

// Time limited v2: Expose a credential id so the caller can decide whether to allow multiple redemptions.
if kind == timeLimitedV2 && msg == cbr.ErrDupRedeem.Error() {
data := &blindedCredVrfResult{ID: cred.TokenPreimage, Duplicate: true}

return handlers.RenderContent(ctx, data, w, http.StatusOK)
}

// Duplicate redemptions are not verified.
if msg == cbr.ErrDupRedeem.Error() || msg == cbr.ErrBadRequest.Error() {
return handlers.WrapError(err, "invalid credentials", http.StatusForbidden)
}

return handlers.WrapError(err, "Error verifying credentials", http.StatusInternalServerError)
}

func shouldRetryRedeemFn(kind, issuer string, err error) bool {
const leo = "brave.com?sku=brave-leo-premium"

return kind == timeLimitedV2 && issuer == leo && err.Error() == cbr.ErrBadRequest.Error()
}

0 comments on commit cd5f926

Please sign in to comment.