Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Production 2024-08-14_01 #2641

Merged
merged 3 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions libs/httpsignature/httpsignature.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ type ParameterizedSignator struct {
// Keystore provides a way to lookup a public key based on the keyID a request was signed with
type Keystore interface {
// LookupVerifier based on the keyID
LookupVerifier(ctx context.Context, keyID string) (context.Context, *Verifier, error)
LookupVerifier(ctx context.Context, keyID string) (context.Context, Verifier, error)
}

// StaticKeystore is a keystore that always returns a static verifier independent of keyID
Expand Down Expand Up @@ -85,8 +85,8 @@ var (
)

// LookupVerifier by returning a static verifier
func (sk *StaticKeystore) LookupVerifier(ctx context.Context, keyID string) (context.Context, *Verifier, error) {
return ctx, &sk.Verifier, nil
func (sk *StaticKeystore) LookupVerifier(ctx context.Context, keyID string) (context.Context, Verifier, error) {
return ctx, sk.Verifier, nil
}

// TODO Add New function
Expand Down Expand Up @@ -236,7 +236,7 @@ func (pkv *ParameterizedKeystoreVerifier) VerifyRequest(req *http.Request) (cont
sp.Algorithm = pkv.SignatureParams.Algorithm
sp.Headers = pkv.SignatureParams.Headers

valid, err := sp.Verify(*verifier, pkv.Opts, req)
valid, err := sp.Verify(verifier, pkv.Opts, req)
if err != nil {
return nil, "", err
}
Expand Down
4 changes: 2 additions & 2 deletions libs/middleware/http_signed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ type mockKeystore struct {
httpsignature.Verifier
}

func (m *mockKeystore) LookupVerifier(ctx context.Context, keyID string) (context.Context, *httpsignature.Verifier, error) {
func (m *mockKeystore) LookupVerifier(ctx context.Context, keyID string) (context.Context, httpsignature.Verifier, error) {
if keyID == "primary" {
return ctx, &m.Verifier, nil
return ctx, m.Verifier, nil
}
return nil, nil, nil
}
Expand Down
5 changes: 2 additions & 3 deletions services/promotion/controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func WalletEventRouter(service *Service, vbatExpires time.Time) chi.Router {
}

// LookupVerifier based on the HTTP signing keyID, which in our case is the walletID
func (service *Service) LookupVerifier(ctx context.Context, keyID string) (context.Context, *httpsignature.Verifier, error) {
func (service *Service) LookupVerifier(ctx context.Context, keyID string) (context.Context, httpsignature.Verifier, error) {
walletID, err := uuid.FromString(keyID)
if err != nil {
return nil, nil, errorutils.Wrap(err, "KeyID format is invalid")
Expand All @@ -144,8 +144,7 @@ func (service *Service) LookupVerifier(ctx context.Context, keyID string) (conte
return nil, nil, err
}
}
tmp := httpsignature.Verifier(publicKey)
return ctx, &tmp, nil
return ctx, publicKey, nil
}

// PromotionsResponse is a list of known promotions to be consumed by the browser
Expand Down
36 changes: 18 additions & 18 deletions services/skus/controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func Router(
{
corsMwrGet := NewCORSMwr(copts, http.MethodGet)
r.Method(http.MethodOptions, "/{orderID}", metricsMwr("GetOrderOptions", corsMwrGet(nil)))
r.Method(http.MethodGet, "/{orderID}", metricsMwr("GetOrder", corsMwrGet(GetOrder(svc))))
r.Method(http.MethodGet, "/{orderID}", metricsMwr("GetOrder", corsMwrGet(handleGetOrder(svc))))
}

r.Method(
Expand Down Expand Up @@ -370,30 +370,30 @@ func CancelOrder(service *Service) handlers.AppHandler {
})
}

// GetOrder is the handler for getting an order
func GetOrder(service *Service) handlers.AppHandler {
func handleGetOrder(svc *Service) handlers.AppHandler {
return handlers.AppHandler(func(w http.ResponseWriter, r *http.Request) *handlers.AppError {
var orderID = new(inputs.ID)
if err := inputs.DecodeAndValidateString(context.Background(), orderID, chi.URLParam(r, "orderID")); err != nil {
return handlers.ValidationError(
"Error validating request url parameter",
map[string]interface{}{
"orderID": err.Error(),
},
)
}
ctx := r.Context()

order, err := service.GetOrder(*orderID.UUID())
orderID, err := uuid.FromString(chi.URLParamFromCtx(ctx, "orderID"))
if err != nil {
return handlers.WrapError(err, "Error retrieving the order", http.StatusInternalServerError)
return handlers.ValidationError("request", map[string]interface{}{"orderID": err.Error()})
}

status := http.StatusOK
if order == nil {
status = http.StatusNotFound
order, err := svc.getTransformOrder(ctx, orderID)
if err != nil {
switch {
case errors.Is(err, context.Canceled):
return handlers.WrapError(model.ErrSomethingWentWrong, "request has been cancelled", model.StatusClientClosedConn)

case errors.Is(err, model.ErrOrderNotFound):
return handlers.WrapError(err, "order not found", http.StatusNotFound)

default:
return handlers.WrapError(err, "Error retrieving the order", http.StatusInternalServerError)
}
}

return handlers.RenderContent(r.Context(), order, w, status)
return handlers.RenderContent(ctx, order, w, http.StatusOK)
})
}

Expand Down
4 changes: 2 additions & 2 deletions services/skus/controllers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ func (suite *ControllersTestSuite) TestGetOrder() {
req, err := http.NewRequest("GET", "/v1/orders/{orderID}", nil)
suite.Require().NoError(err)

getOrderHandler := GetOrder(suite.service)
getOrderHandler := handleGetOrder(suite.service)
rctx := chi.NewRouteContext()
rctx.URLParams.Add("orderID", order.ID.String())
getReq := req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx))
Expand Down Expand Up @@ -435,7 +435,7 @@ func (suite *ControllersTestSuite) TestGetMissingOrder() {
req, err := http.NewRequest("GET", "/v1/orders/{orderID}", nil)
suite.Require().NoError(err)

getOrderHandler := GetOrder(suite.service)
getOrderHandler := handleGetOrder(suite.service)
rctx := chi.NewRouteContext()
rctx.URLParams.Add("orderID", "9645ca16-bc93-4e37-8edf-cb35b1763216")
getReq := req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx))
Expand Down
5 changes: 2 additions & 3 deletions services/skus/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func GenerateSecret() (secret string, nonce string, err error) {
}

// LookupVerifier returns the merchant key corresponding to the keyID used for verifying requests
func (s *Service) LookupVerifier(ctx context.Context, keyID string) (context.Context, *httpsignature.Verifier, error) {
func (s *Service) LookupVerifier(ctx context.Context, keyID string) (context.Context, httpsignature.Verifier, error) {
rootKeyIDStr, caveats, err := cryptography.DecodeKeyID(keyID)
if err != nil {
return nil, nil, err
Expand Down Expand Up @@ -139,8 +139,7 @@ func (s *Service) LookupVerifier(ctx context.Context, keyID string) (context.Con

ctx = context.WithValue(ctx, merchantCtxKey{}, key.Merchant)

verifier := httpsignature.Verifier(httpsignature.HMACKey(secretKeyStr))
return ctx, &verifier, nil
return ctx, httpsignature.HMACKey(secretKeyStr), nil
}

// caveatsFromCtx returns authorized caveats from ctx.
Expand Down
110 changes: 21 additions & 89 deletions services/skus/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ import (
"github.com/lib/pq"
uuid "github.com/satori/go.uuid"
"github.com/shopspring/decimal"
"github.com/stripe/stripe-go/v72"
"github.com/stripe/stripe-go/v72/checkout/session"
"github.com/stripe/stripe-go/v72/customer"

"github.com/brave-intl/bat-go/libs/clients/radom"
"github.com/brave-intl/bat-go/libs/datastore"
Expand Down Expand Up @@ -138,71 +135,6 @@ func (o *Order) ShouldSetTrialDays() bool {
return !o.IsPaid() && o.IsStripePayable()
}

// CreateStripeCheckoutSession creates a Stripe checkout session for the order.
//
// Deprecated: Use CreateStripeCheckoutSession function instead of this method.
func (o *Order) CreateStripeCheckoutSession(
email, successURI, cancelURI string,
freeTrialDays int64,
) (CreateCheckoutSessionResponse, error) {
return CreateStripeCheckoutSession(o.ID.String(), email, successURI, cancelURI, freeTrialDays, o.Items)
}

// CreateStripeCheckoutSession creates a Stripe checkout session for the order.
func CreateStripeCheckoutSession(
oid, email, successURI, cancelURI string,
trialDays int64,
items []OrderItem,
) (CreateCheckoutSessionResponse, error) {
var custID string
if email != "" {
// Find the existing customer by email to use the customer id instead email.
l := customer.List(&stripe.CustomerListParams{
Email: stripe.String(email),
})

for l.Next() {
custID = l.Customer().ID
}
}

params := &stripe.CheckoutSessionParams{
// TODO: Get rid of this stripe.* nonsense, and use ptrTo instead.
PaymentMethodTypes: stripe.StringSlice([]string{"card"}),
Mode: stripe.String(string(stripe.CheckoutSessionModeSubscription)),
SuccessURL: stripe.String(successURI),
CancelURL: stripe.String(cancelURI),
ClientReferenceID: stripe.String(oid),
SubscriptionData: &stripe.CheckoutSessionSubscriptionDataParams{},
LineItems: OrderItemList(items).stripeLineItems(),
}

// If a free trial is set, apply it.
if trialDays > 0 {
params.SubscriptionData.TrialPeriodDays = &trialDays
}

if custID != "" {
// Use existing customer if found.
params.Customer = stripe.String(custID)
} else if email != "" {
// Otherwise, create a new using email.
params.CustomerEmail = stripe.String(email)
}
// Otherwise, we have no record of this email for this checkout session.
// ? The user will be asked for the email, we cannot send an empty customer email as a param.

params.SubscriptionData.AddMetadata("orderID", oid)
params.AddExtra("allow_promotion_codes", "true")

session, err := session.New(params)
if err != nil {
return EmptyCreateCheckoutSessionResponse(), fmt.Errorf("failed to create stripe session: %w", err)
}

return CreateCheckoutSessionResponse{SessionID: session.ID}, nil
}

// CreateRadomCheckoutSession creates a Radom checkout session for o.
func (o *Order) CreateRadomCheckoutSession(
ctx context.Context,
Expand Down Expand Up @@ -341,6 +273,12 @@ func (o *Order) StripeSubID() (string, bool) {
return sid, ok
}

func (o *Order) StripeSessID() (string, bool) {
sessID, ok := o.Metadata["stripeCheckoutSessionId"].(string)

return sessID, ok
}

func (o *Order) IsIOS() bool {
pp, ok := o.PaymentProc()
if !ok {
Expand Down Expand Up @@ -369,6 +307,15 @@ func (o *Order) IsAndroid() bool {
return pp == "android" && vn == VendorGoogle
}

func (o *Order) IsStripe() bool {
pp, ok := o.PaymentProc()
if !ok {
return false
}

return pp == StripePaymentMethod
}

func (o *Order) PaymentProc() (string, bool) {
pp, ok := o.Metadata["paymentProcessor"].(string)

Expand Down Expand Up @@ -417,6 +364,12 @@ func (x *OrderItem) IsLeo() bool {
return x.SKU == "brave-leo-premium"
}

func (x *OrderItem) StripeItemID() (string, bool) {
itemID, ok := x.Metadata["stripe_item_id"].(string)

return itemID, ok
}

// OrderNew represents a request to create an order in the database.
type OrderNew struct {
MerchantID string `db:"merchant_id"`
Expand Down Expand Up @@ -466,27 +419,6 @@ func (l OrderItemList) HasItem(id uuid.UUID) (*OrderItem, bool) {

}

func (l OrderItemList) stripeLineItems() []*stripe.CheckoutSessionLineItemParams {
result := make([]*stripe.CheckoutSessionLineItemParams, 0, len(l))

for _, item := range l {
// Obtain the item id from the metadata.
priceID, ok := item.Metadata["stripe_item_id"].(string)
if !ok {
continue
}

// Assume that the stripe product is embedded in macaroon as metadata
// because a stripe line item is being created.
result = append(result, &stripe.CheckoutSessionLineItemParams{
Price: stripe.String(priceID),
Quantity: stripe.Int64(int64(item.Quantity)),
})
}

return result
}

type Error string

func (e Error) Error() string {
Expand Down
Loading
Loading