From 7df21e9e27246223db86d1c4bb7ca13fdb82d035 Mon Sep 17 00:00:00 2001 From: clD11 <23483715+clD11@users.noreply.github.com> Date: Wed, 16 Oct 2024 22:30:50 +0100 Subject: [PATCH] fix: change order of get tlv2 credentials (#2664) * fix: reorder get tlv2 * refactor: add nil check --- services/skus/datastore.go | 6 +-- services/skus/service.go | 29 ++++++++---- services/skus/service_test.go | 85 +++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 12 deletions(-) diff --git a/services/skus/datastore.go b/services/skus/datastore.go index 07e2a1afb..75efe6cfd 100644 --- a/services/skus/datastore.go +++ b/services/skus/datastore.go @@ -983,15 +983,15 @@ func (pg *Postgres) GetTLV2Creds(ctx context.Context, dbi sqlx.QueryerContext, o order_id, item_id, issuer_id, blinded_creds, signed_creds, batch_proof, public_key, valid_from, valid_to FROM time_limited_v2_order_creds - WHERE order_id = $1 AND item_id = $2 AND request_id = $3 AND valid_to > now()` + WHERE order_id = $1 AND item_id = $2 AND request_id = $3` creds := make([]TimeAwareSubIssuedCreds, 0) if err := sqlx.SelectContext(ctx, dbi, &creds, q, ordID, itemID, reqID); err != nil { - return nil, err + return &TimeLimitedV2Creds{}, err } if len(creds) == 0 { - return nil, errNoTLV2Creds + return &TimeLimitedV2Creds{}, nil } result := &TimeLimitedV2Creds{ diff --git a/services/skus/service.go b/services/skus/service.go index 318191d19..cbaa556a4 100644 --- a/services/skus/service.go +++ b/services/skus/service.go @@ -1228,6 +1228,16 @@ func (s *Service) GetSingleUseCreds(ctx context.Context, orderID, itemID, reqID // // Browser's api_request_helper does not understand Go's nil slices, hence explicit empty slice is returned. func (s *Service) GetTimeLimitedV2Creds(ctx context.Context, orderID, itemID, reqID uuid.UUID) ([]TimeAwareSubIssuedCreds, int, error) { + creds, err := s.Datastore.GetTLV2Creds(ctx, s.Datastore.RawDB(), orderID, itemID, reqID) + if err != nil { + return []TimeAwareSubIssuedCreds{}, http.StatusInternalServerError, fmt.Errorf("error getting credentials: %w", err) + } + + // We found creds so filter active. + if creds != nil && len(creds.Credentials) > 0 { + return filterActiveCreds(creds.Credentials, time.Now().UTC()), http.StatusOK, nil + } + obmsg, err := s.Datastore.GetSigningOrderRequestOutboxByRequestID(ctx, s.Datastore.RawDB(), reqID) if err != nil { if errors.Is(err, sql.ErrNoRows) { @@ -1242,21 +1252,22 @@ func (s *Service) GetTimeLimitedV2Creds(ctx context.Context, orderID, itemID, re } if obmsg.CompletedAt == nil { - // Get average of last 10 outbox messages duration as the retry after. return []TimeAwareSubIssuedCreds{}, http.StatusAccepted, errSetRetryAfter } - creds, err := s.Datastore.GetTLV2Creds(ctx, s.Datastore.RawDB(), orderID, itemID, reqID) - if err != nil { - if errors.Is(err, errNoTLV2Creds) { - // Credentials could be signed, but nothing to return as they are all expired. - return []TimeAwareSubIssuedCreds{}, http.StatusOK, nil - } + // We have neither credentials nor a signing request so return an error. + return []TimeAwareSubIssuedCreds{}, http.StatusInternalServerError, fmt.Errorf("error getting credentials: %w", err) +} - return []TimeAwareSubIssuedCreds{}, http.StatusInternalServerError, fmt.Errorf("error getting credentials: %w", err) +func filterActiveCreds(creds []TimeAwareSubIssuedCreds, now time.Time) []TimeAwareSubIssuedCreds { + act := make([]TimeAwareSubIssuedCreds, 0) + for i := range creds { + if creds[i].ValidTo.After(now) { + act = append(act, creds[i]) + } } - return creds.Credentials, http.StatusOK, nil + return act } // GetActiveCredentialSigningKey get the current active signing key for this merchant diff --git a/services/skus/service_test.go b/services/skus/service_test.go index c39c50000..c49b1952b 100644 --- a/services/skus/service_test.go +++ b/services/skus/service_test.go @@ -293,6 +293,91 @@ func TestCreateOrderItem(t *testing.T) { } } +func TestFilterActiveCreds(t *testing.T) { + type tcGiven struct { + creds []TimeAwareSubIssuedCreds + now time.Time + } + + type tcExpected struct { + activeCreds []TimeAwareSubIssuedCreds + } + + type testCase struct { + name string + given tcGiven + exp tcExpected + } + + tests := []testCase{ + { + name: "valid_creds", + given: tcGiven{ + creds: []TimeAwareSubIssuedCreds{ + { + ValidTo: time.Date(2025, time.January, 20, 0, 0, 0, 0, time.UTC), + }, + }, + now: time.Now(), + }, + exp: tcExpected{ + activeCreds: []TimeAwareSubIssuedCreds{ + { + ValidTo: time.Date(2025, time.January, 20, 0, 0, 0, 0, time.UTC), + }, + }, + }, + }, + + { + name: "expired_creds", + given: tcGiven{ + creds: []TimeAwareSubIssuedCreds{ + { + ValidTo: time.Date(2020, time.January, 20, 0, 0, 0, 0, time.UTC), + }, + }, + now: time.Now(), + }, + exp: tcExpected{ + activeCreds: []TimeAwareSubIssuedCreds{}, + }, + }, + + { + name: "expired_and_active_mix", + given: tcGiven{ + creds: []TimeAwareSubIssuedCreds{ + { + ValidTo: time.Date(2020, time.January, 20, 0, 0, 0, 0, time.UTC), + }, + + { + ValidTo: time.Date(2025, time.January, 20, 0, 0, 0, 0, time.UTC), + }, + }, + now: time.Now(), + }, + exp: tcExpected{ + activeCreds: []TimeAwareSubIssuedCreds{ + { + ValidTo: time.Date(2025, time.January, 20, 0, 0, 0, 0, time.UTC), + }, + }, + }, + }, + } + + for i := range tests { + tc := tests[i] + + t.Run(tc.name, func(t *testing.T) { + actual := filterActiveCreds(tc.given.creds, tc.given.now) + should.Equal(t, tc.exp.activeCreds, actual) + }) + } +} + func mustDurationFromISO(v string) *time.Duration { result, err := durationFromISO(v) if err != nil {