satellite/payments: restrict addition of duplicate credit cards
By this change we don't allow users to add credit cards that are already bind to their account. We still allow the same CC number but with a different expiration date. Issue: https://github.com/storj/storj/issues/5597 Change-Id: Ifeb0cc5ae0c2f0f7596af4dead70ae7d20d30613
This commit is contained in:
parent
3119b614ae
commit
c31fb9c1cf
@ -22,6 +22,7 @@ import (
|
||||
"storj.io/storj/satellite/payments"
|
||||
"storj.io/storj/satellite/payments/billing"
|
||||
"storj.io/storj/satellite/payments/paymentsconfig"
|
||||
"storj.io/storj/satellite/payments/stripe"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -209,6 +210,11 @@ func (p *Payments) AddCreditCard(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if stripe.ErrDuplicateCard.Has(err) {
|
||||
p.serveJSONError(ctx, w, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
p.serveJSONError(ctx, w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ var (
|
||||
ErrCardNotFound = errs.Class("card not found")
|
||||
// ErrDefaultCard is returned when a user tries to delete their default card.
|
||||
ErrDefaultCard = errs.Class("default card")
|
||||
// ErrDuplicateCard is returned when a user tries to add duplicate card.
|
||||
ErrDuplicateCard = errs.Class("duplicate card")
|
||||
)
|
||||
|
||||
// creditCards is an implementation of payments.CreditCards.
|
||||
@ -94,6 +96,27 @@ func (creditCards *creditCards) Add(ctx context.Context, userID uuid.UUID, cardT
|
||||
return payments.CreditCard{}, Error.Wrap(err)
|
||||
}
|
||||
|
||||
listParams := &stripe.PaymentMethodListParams{
|
||||
ListParams: stripe.ListParams{Context: ctx},
|
||||
Customer: &customerID,
|
||||
Type: stripe.String(string(stripe.PaymentMethodTypeCard)),
|
||||
}
|
||||
|
||||
paymentMethodsIterator := creditCards.service.stripeClient.PaymentMethods().List(listParams)
|
||||
for paymentMethodsIterator.Next() {
|
||||
stripeCard := paymentMethodsIterator.PaymentMethod()
|
||||
|
||||
if stripeCard.Card.Fingerprint == card.Card.Fingerprint &&
|
||||
stripeCard.Card.ExpMonth == card.Card.ExpMonth &&
|
||||
stripeCard.Card.ExpYear == card.Card.ExpYear {
|
||||
return payments.CreditCard{}, ErrDuplicateCard.New("this card is already on file for your account.")
|
||||
}
|
||||
}
|
||||
|
||||
if err = paymentMethodsIterator.Err(); err != nil {
|
||||
return payments.CreditCard{}, Error.Wrap(err)
|
||||
}
|
||||
|
||||
attachParams := &stripe.PaymentMethodAttachParams{
|
||||
Params: stripe.Params{Context: ctx},
|
||||
Customer: &customerID,
|
||||
|
@ -85,6 +85,35 @@ func TestCreditCards_Add(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestCreditCards_AddDuplicateCard(t *testing.T) {
|
||||
testplanet.Run(t, testplanet.Config{
|
||||
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 1,
|
||||
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
||||
satellite := planet.Satellites[0]
|
||||
|
||||
u, err := satellite.AddUser(ctx, console.CreateUser{
|
||||
FullName: "Test User",
|
||||
Email: "test@storj.test",
|
||||
}, 1)
|
||||
require.NoError(t, err)
|
||||
|
||||
cardToken := "testToken"
|
||||
|
||||
card, err := satellite.API.Payments.Accounts.CreditCards().Add(ctx, u.ID, cardToken)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, card)
|
||||
|
||||
card, err = satellite.API.Payments.Accounts.CreditCards().Add(ctx, u.ID, cardToken)
|
||||
require.Error(t, err)
|
||||
require.True(t, stripe.ErrDuplicateCard.Has(err))
|
||||
require.Empty(t, card)
|
||||
|
||||
cards, err := satellite.API.Payments.Accounts.CreditCards().List(ctx, u.ID)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, cards, 1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCreditCards_Remove(t *testing.T) {
|
||||
testplanet.Run(t, testplanet.Config{
|
||||
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 2,
|
||||
|
@ -446,6 +446,7 @@ func (m *mockPaymentMethods) New(params *stripe.PaymentMethodParams) (*stripe.Pa
|
||||
Brand: "Mastercard",
|
||||
Last4: "4444",
|
||||
Description: randID,
|
||||
Fingerprint: "fingerprint" + *params.Card.Token,
|
||||
},
|
||||
Type: stripe.PaymentMethodTypeCard,
|
||||
}
|
||||
|
@ -133,9 +133,14 @@ export class PaymentsHttpApi implements PaymentsApi {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
const errorMsg = result.error.includes('duplicate card') ?
|
||||
'This card is already on file for your account' :
|
||||
'Can not add credit card';
|
||||
|
||||
throw new APIError({
|
||||
status: response.status,
|
||||
message: 'Can not add credit card',
|
||||
message: errorMsg,
|
||||
requestID: response.headers.get('x-request-id'),
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user