1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-21 12:05:42 +01:00

Remove positive number restriction on microdeposit verification and improve error handling

This commit is contained in:
Alex Morask 2024-11-18 08:53:36 -05:00
parent e16cad50b1
commit 5cef7457d2
No known key found for this signature in database
GPG Key ID: 23E38285B743E3A8
4 changed files with 53 additions and 21 deletions

View File

@ -4,8 +4,8 @@ namespace Bit.Api.Billing.Models.Requests;
public class VerifyBankAccountRequestBody public class VerifyBankAccountRequestBody
{ {
[Range(0, 99)] [Range(-99, 99)]
public long Amount1 { get; set; } public long Amount1 { get; set; }
[Range(0, 99)] [Range(-99, 99)]
public long Amount2 { get; set; } public long Amount2 { get; set; }
} }

View File

@ -5,5 +5,7 @@ public class BillingException(
string message = null, string message = null,
Exception innerException = null) : Exception(message, innerException) Exception innerException = null) : Exception(message, innerException)
{ {
public string Response { get; } = response ?? "Something went wrong with your request. Please contact support."; public const string DefaultMessage = "Something went wrong with your request. Please contact support.";
public string Response { get; } = response ?? DefaultMessage;
} }

View File

@ -25,6 +25,16 @@ public static class StripeConstants
public static class ErrorCodes public static class ErrorCodes
{ {
public const string CustomerTaxLocationInvalid = "customer_tax_location_invalid"; public const string CustomerTaxLocationInvalid = "customer_tax_location_invalid";
public const string PaymentMethodMicroDepositVerificationAmountsInvalid =
"payment_method_microdeposit_verification_amounts_invalid";
public const string PaymentMethodMicroDepositVerificationAmountsMismatch =
"payment_method_microdeposit_verification_amounts_mismatch";
public const string PaymentMethodMicroDepositVerificationAttemptsExceeded =
"payment_method_microdeposit_verification_attempts_exceeded";
public const string PaymentMethodMicroDepositVerificationDescriptorCodeMismatch =
"payment_method_microdeposit_verification_descriptor_code_mismatch";
public const string PaymentMethodMicroDepositVerificationTimeout =
"payment_method_microdeposit_verification_timeout";
public const string TaxIdInvalid = "tax_id_invalid"; public const string TaxIdInvalid = "tax_id_invalid";
} }

View File

@ -3,6 +3,7 @@ using Bit.Core.Billing.Constants;
using Bit.Core.Billing.Models; using Bit.Core.Billing.Models;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Services; using Bit.Core.Services;
using Bit.Core.Settings; using Bit.Core.Settings;
using Bit.Core.Utilities; using Bit.Core.Utilities;
@ -651,39 +652,58 @@ public class SubscriberService(
ISubscriber subscriber, ISubscriber subscriber,
(long, long) microdeposits) (long, long) microdeposits)
{ {
ArgumentNullException.ThrowIfNull(subscriber);
var setupIntentId = await setupIntentCache.Get(subscriber.Id); var setupIntentId = await setupIntentCache.Get(subscriber.Id);
if (string.IsNullOrEmpty(setupIntentId)) if (string.IsNullOrEmpty(setupIntentId))
{ {
logger.LogError("No setup intent ID exists to verify for subscriber with ID ({SubscriberID})", subscriber.Id); logger.LogError("No setup intent ID exists to verify for subscriber with ID ({SubscriberID})", subscriber.Id);
throw new BillingException(); throw new BillingException();
} }
var (amount1, amount2) = microdeposits; var (amount1, amount2) = microdeposits;
await stripeAdapter.SetupIntentVerifyMicroDeposit(setupIntentId, new SetupIntentVerifyMicrodepositsOptions try
{ {
Amounts = [amount1, amount2] await stripeAdapter.SetupIntentVerifyMicroDeposit(setupIntentId,
}); new SetupIntentVerifyMicrodepositsOptions { Amounts = [amount1, amount2] });
var setupIntent = await stripeAdapter.SetupIntentGet(setupIntentId); var setupIntent = await stripeAdapter.SetupIntentGet(setupIntentId);
await stripeAdapter.PaymentMethodAttachAsync(setupIntent.PaymentMethodId, new PaymentMethodAttachOptions await stripeAdapter.PaymentMethodAttachAsync(setupIntent.PaymentMethodId,
{ new PaymentMethodAttachOptions { Customer = subscriber.GatewayCustomerId });
Customer = subscriber.GatewayCustomerId
});
await stripeAdapter.CustomerUpdateAsync(subscriber.GatewayCustomerId, await stripeAdapter.CustomerUpdateAsync(subscriber.GatewayCustomerId,
new CustomerUpdateOptions new CustomerUpdateOptions
{
InvoiceSettings = new CustomerInvoiceSettingsOptions
{ {
DefaultPaymentMethod = setupIntent.PaymentMethodId InvoiceSettings = new CustomerInvoiceSettingsOptions
} {
}); DefaultPaymentMethod = setupIntent.PaymentMethodId
}
});
}
catch (StripeException stripeException)
{
if (!string.IsNullOrEmpty(stripeException.StripeError?.Code))
{
var response = stripeException.StripeError.Code switch
{
StripeConstants.ErrorCodes.PaymentMethodMicroDepositVerificationAmountsInvalid =>
"The two micro-deposit amounts you provided were invalid. Please try again or contact support.",
StripeConstants.ErrorCodes.PaymentMethodMicroDepositVerificationAmountsMismatch =>
"The two micro-deposit amounts you provided did not match the amounts we sent. Please try again or contact support.",
StripeConstants.ErrorCodes.PaymentMethodMicroDepositVerificationAttemptsExceeded =>
"You have reached the maximum number of attempts to verify your bank account. Please contact support.",
StripeConstants.ErrorCodes.PaymentMethodMicroDepositVerificationTimeout =>
"Your bank account was not verified within the required time period. Please contact support.",
_ => BillingException.DefaultMessage
};
throw new BadRequestException(response);
}
logger.LogError(stripeException, "Encountered an unhandled Stripe exception when trying to verify bank account for subscriber ({SubscriberID})", subscriber.Id);
throw new BillingException();
}
} }
#region Shared Utilities #region Shared Utilities