Skip to content

Commit

Permalink
allow single device refresh (#2163)
Browse files Browse the repository at this point in the history
  • Loading branch information
evq authored Oct 25, 2023
1 parent cc9860c commit a470833
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 44 deletions.
37 changes: 3 additions & 34 deletions services/skus/controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"github.com/go-chi/chi"
"github.com/go-chi/cors"
uuid "github.com/satori/go.uuid"
"github.com/stripe/stripe-go/v72"
stripe "github.com/stripe/stripe-go/v72"
"github.com/stripe/stripe-go/v72/webhook"

"github.com/brave-intl/bat-go/libs/clients/radom"
Expand Down Expand Up @@ -571,40 +571,9 @@ func CreateOrderCreds(service *Service) handlers.AppHandler {
)
}

orderItem, err := service.Datastore.GetOrderItem(ctx, req.ItemID)
if err != nil {
logger.Error().Err(err).Msg("error getting the order item for creds")
return handlers.WrapError(err, "Error validating no credentials exist for order", http.StatusBadRequest)
}

// TLV2 check to see if we have credentials signed that match incoming blinded tokens
if orderItem.CredentialType == timeLimitedV2 {
alreadySubmitted, err := service.Datastore.AreTimeLimitedV2CredsSubmitted(ctx, req.BlindedCreds...)
if err != nil {
// This is an existing error message so don't want to change it incase client are relying on it.
return handlers.WrapError(err, "Error validating credentials exist for order", http.StatusBadRequest)
}
if alreadySubmitted {
// since these are already submitted, no need to create order credentials
// return ok
return handlers.RenderContent(ctx, nil, w, http.StatusOK)
}
}

// check if we already have a signing request for this order, delete order creds will
// delete the prior signing request. this allows subscriptions to manage how many
// order creds are handed out.
signingOrderRequests, err := service.Datastore.GetSigningOrderRequestOutboxByOrderItem(ctx, req.ItemID)
if err != nil {
// This is an existing error message so don't want to change it incase client are relying on it.
return handlers.WrapError(err, "Error validating no credentials exist for order", http.StatusBadRequest)
}

if len(signingOrderRequests) > 0 {
return handlers.WrapError(err, "There are existing order credentials created for this order", http.StatusConflict)
}
requestID := uuid.NewV4()

if err := service.CreateOrderItemCredentials(ctx, *orderID.UUID(), req.ItemID, req.BlindedCreds); err != nil {
if err := service.CreateOrderItemCredentials(ctx, *orderID.UUID(), req.ItemID, requestID, req.BlindedCreds); err != nil {
logger.Error().Err(err).Msg("failed to create the order credentials")
return handlers.WrapError(err, "Error creating order creds", http.StatusBadRequest)
}
Expand Down
6 changes: 3 additions & 3 deletions services/skus/controllers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1815,14 +1815,14 @@ func (suite *ControllersTestSuite) TestCreateOrderCreds_SingleUse_ExistingOrderC
order.ID), bytes.NewBuffer(payload)).WithContext(ctx)

server.Handler.ServeHTTP(rw, r)
suite.Assert().Equal(http.StatusConflict, rw.Code)
suite.Assert().Equal(http.StatusBadRequest, rw.Code)

var appError handlers.AppError
err = json.NewDecoder(rw.Body).Decode(&appError)
suite.Require().NoError(err)

suite.Assert().Equal(http.StatusConflict, appError.Code)
suite.Assert().Contains(appError.Error(), "There are existing order credentials created for this order")
suite.Assert().Equal(http.StatusBadRequest, appError.Code)
suite.Assert().Contains(appError.Error(), ErrCredsAlreadyExist.Error())
}

// ReadSigningOrderRequestMessage reads messages from the unsigned order request topic
Expand Down
55 changes: 49 additions & 6 deletions services/skus/credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/jmoiron/sqlx"
"github.com/linkedin/goavro"
uuid "github.com/satori/go.uuid"
"github.com/segmentio/kafka-go"
kafka "github.com/segmentio/kafka-go"

"github.com/brave-intl/bat-go/libs/backoff/retrypolicy"
"github.com/brave-intl/bat-go/libs/clients"
Expand All @@ -33,8 +33,9 @@ const (
)

var (
ErrOrderUnpaid = errors.New("order not paid")
ErrOrderHasNoItems = errors.New("order has no items")
ErrOrderUnpaid = errors.New("order not paid")
ErrOrderHasNoItems = errors.New("order has no items")
ErrCredsAlreadyExist = errors.New("credentials already exist")

errInvalidIssuerResp model.Error = "invalid issuer response"
errInvalidNCredsSingleUse model.Error = "submitted more blinded creds than quantity of order item"
Expand Down Expand Up @@ -223,7 +224,7 @@ type TimeLimitedCreds struct {

// CreateOrderItemCredentials creates the order credentials for the given order id using the supplied blinded credentials.
// If the order is unpaid an error ErrOrderUnpaid is returned.
func (s *Service) CreateOrderItemCredentials(ctx context.Context, orderID uuid.UUID, itemID uuid.UUID, blindedCreds []string) error {
func (s *Service) CreateOrderItemCredentials(ctx context.Context, orderID, itemID, requestID uuid.UUID, blindedCreds []string) error {
order, err := s.Datastore.GetOrder(orderID)
if err != nil {
return fmt.Errorf("error retrieving order: %w", err)
Expand All @@ -249,6 +250,50 @@ func (s *Service) CreateOrderItemCredentials(ctx context.Context, orderID uuid.U
return errors.New("order item does not exist for order")
}

if orderItem.CredentialType == timeLimitedV2 {
// TLV2 check to see if we have credentials signed that match incoming blinded tokens
alreadySubmitted, err := s.Datastore.AreTimeLimitedV2CredsSubmitted(ctx, blindedCreds...)
if err != nil {
return fmt.Errorf("Error validating credentials exist for order item: %w", err)
}
if alreadySubmitted {
// since these are already submitted, no need to create order credentials
// return ok
return nil
}

// check if we have signed credentials for this order item
// if there is no order and we have no creds, we can submit again
// similar to the outbox check case below, delete order creds will
// wipe out any already signed order creds
creds, err := s.Datastore.GetTimeLimitedV2OrderCredsByOrderItem(itemID)
if err != nil {
return fmt.Errorf("Error validating no credentials exist for order item: %w", err)
}
if creds != nil {
return ErrCredsAlreadyExist
}
// NOTE: this creates a possible race to submit between clients.
// multiple signing request outboxes can be created since their
// uniqueness constraint is on the request id.
// despite this, the uniqueness constraint of time_limited_v2_order_creds ensures that
// only one set of credentials is written for each order / item & time interval.
// as a result, one client will successfully unblind the credentials and
// the others will fail.
} else {
// check if we already have a signing request for this order, delete order creds will
// delete the prior signing request. this allows subscriptions to manage how many
// order creds are handed out.
signingOrderRequests, err := s.Datastore.GetSigningOrderRequestOutboxByOrderItem(ctx, itemID)
if err != nil {
return fmt.Errorf("Error validating no credentials exist for order item: %w", err)
}

if len(signingOrderRequests) > 0 {
return ErrCredsAlreadyExist
}
}

if err := checkNumBlindedCreds(order, orderItem, len(blindedCreds)); err != nil {
return err
}
Expand All @@ -275,8 +320,6 @@ func (s *Service) CreateOrderItemCredentials(ctx context.Context, orderID uuid.U
return fmt.Errorf("error serializing associated data: %w", err)
}

requestID := uuid.NewV4()

signingOrderRequest := SigningOrderRequest{
RequestID: requestID.String(),
Data: []SigningOrder{
Expand Down
2 changes: 1 addition & 1 deletion services/skus/datastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,7 @@ func (pg *Postgres) GetTimeLimitedV2OrderCredsByOrderItem(itemID uuid.UUID) (*Ti
select 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 item_id = $1
where item_id = $1 and valid_to > now()
`

var timeAwareSubIssuedCreds []TimeAwareSubIssuedCreds
Expand Down

0 comments on commit a470833

Please sign in to comment.