diff --git a/services/skus/service.go b/services/skus/service.go index 77dff12a0..89a4f2a16 100644 --- a/services/skus/service.go +++ b/services/skus/service.go @@ -2105,17 +2105,7 @@ 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 { - if !shouldRetryRedeemFn(kind, cred.Issuer, err) { - return handleRedeemFnError(ctx, w, kind, cred, err) - } - - // TODO: remove this as there should be no credentials in Production signed by brave-leo-premium-year. - // - // 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 handleRedeemFnError(ctx, w, kind, cred, err) } // TODO(clD11): cleanup after quick fix @@ -2886,12 +2876,6 @@ func handleRedeemFnError(ctx context.Context, w http.ResponseWriter, kind string 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() -} - func newRadomGateway(env string) (*radom.Gateway, error) { switch env { case "development", "staging": diff --git a/services/skus/service_nonint_test.go b/services/skus/service_nonint_test.go index f364d14bb..de3890fad 100644 --- a/services/skus/service_nonint_test.go +++ b/services/skus/service_nonint_test.go @@ -6,6 +6,7 @@ import ( "encoding/json" "errors" "net/http" + "net/http/httptest" "net/url" "strconv" "testing" @@ -21,7 +22,10 @@ import ( "github.com/stripe/stripe-go/v72" "google.golang.org/api/androidpublisher/v3" + "github.com/brave-intl/bat-go/libs/clients/cbr" "github.com/brave-intl/bat-go/libs/datastore" + berrs "github.com/brave-intl/bat-go/libs/errors" + "github.com/brave-intl/bat-go/libs/handlers" "github.com/brave-intl/bat-go/services/skus/model" "github.com/brave-intl/bat-go/services/skus/radom" @@ -5649,6 +5653,118 @@ func TestService_setOrderTrialDaysTx(t *testing.T) { } } +func TestHandleRedeemFnError(t *testing.T) { + type tcGiven struct { + kind string + cred *cbr.CredentialRedemption + err error + } + + type testCase struct { + name string + given tcGiven + exp *handlers.AppError + } + + tests := []testCase{ + { + name: "500_tlv2_not_found", + given: tcGiven{ + kind: timeLimitedV2, + cred: &cbr.CredentialRedemption{TokenPreimage: "token_preimage"}, + err: berrs.New(model.Error("not found"), "cbr route not found", berrs.Codified{ + ErrCode: "cbr_path_not_found", + Retry: true, + }), + }, + exp: &handlers.AppError{ + Code: http.StatusInternalServerError, + Cause: berrs.New(model.Error("not found"), "cbr route not found", berrs.Codified{ + ErrCode: "cbr_path_not_found", + Retry: true, + }), + Message: "Error verifying credentials", + }, + }, + + { + name: "200_tlv2_duplicate", + given: tcGiven{ + kind: timeLimitedV2, + cred: &cbr.CredentialRedemption{TokenPreimage: "token_preimage"}, + err: berrs.New(model.Error("duplicate redemption"), "cbr duplicate redemption", berrs.Codified{ + ErrCode: "cbr_dup_redeem", + }), + }, + }, + + { + name: "403_tlv2_bad_request", + given: tcGiven{ + kind: timeLimitedV2, + cred: &cbr.CredentialRedemption{TokenPreimage: "token_preimage"}, + err: berrs.New(model.Error("bad request"), "cbr bad request", berrs.Codified{ + ErrCode: "cbr_bad_request", + }), + }, + exp: &handlers.AppError{ + Code: http.StatusForbidden, + Cause: berrs.New(model.Error("bad request"), "cbr bad request", berrs.Codified{ + ErrCode: "cbr_bad_request", + }), + Message: "invalid credentials", + }, + }, + + { + name: "403_tlv_duplicate", + given: tcGiven{ + kind: timeLimited, + cred: &cbr.CredentialRedemption{TokenPreimage: "token_preimage"}, + err: berrs.New(model.Error("duplicate redemption"), "cbr duplicate redemption", berrs.Codified{ + ErrCode: "cbr_dup_redeem", + }), + }, + exp: &handlers.AppError{ + Code: http.StatusForbidden, + Cause: berrs.New(model.Error("duplicate redemption"), "cbr duplicate redemption", berrs.Codified{ + ErrCode: "cbr_dup_redeem", + }), + Message: "invalid credentials", + }, + }, + } + + for i := range tests { + tc := tests[i] + + t.Run(tc.name, func(t *testing.T) { + ctx := context.Background() + + rw := httptest.NewRecorder() + rw.Header().Set("content-type", "application/json") + + actual := handleRedeemFnError(ctx, rw, tc.given.kind, tc.given.cred, tc.given.err) + if actual != nil { + should.Equal(t, tc.exp.Code, actual.Code) + should.Equal(t, tc.exp.Cause, actual.Cause) + should.Equal(t, tc.exp.Message, actual.Message) + + return + } + + must.Equal(t, http.StatusOK, rw.Code) + + resp := &blindedCredVrfResult{} + err := json.Unmarshal(rw.Body.Bytes(), resp) + must.NoError(t, err) + + should.Equal(t, tc.given.cred.TokenPreimage, resp.ID) + should.True(t, resp.Duplicate) + }) + } +} + type mockRadomClient struct { fnCreateCheckoutSession func(ctx context.Context, creq *radom.CheckoutSessionRequest) (radom.CheckoutSessionResponse, error) fnGetSubscription func(ctx context.Context, subID string) (*radom.SubscriptionResponse, error)