1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-17 20:36:21 +02:00

[SG-72] Sync changed email address with stripe (#2042)

* sync changed email address with strip

* sync changed email address with strip

* fixed formatting

* throw exception if not successful

* Added revert if stripe sync fails

* Added revert if stripe sync fails

* Added revert if stripe sync fails

* created stripe sync service

* fixed lint issue

* reverted to use stripe exception message

* added null checks to customer id and email address

* added braces

* removed empty email
This commit is contained in:
Gbubemi Smith 2022-06-16 17:45:26 +01:00 committed by GitHub
parent b39a43210d
commit 8e79c20dce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 107 additions and 1 deletions

View File

@ -0,0 +1,13 @@
using System;
namespace Bit.Core.Exceptions
{
public class InvalidEmailException : Exception
{
public InvalidEmailException()
: base("Invalid email.")
{
}
}
}

View File

@ -0,0 +1,13 @@
using System;
namespace Bit.Core.Exceptions
{
public class InvalidGatewayCustomerIdException : Exception
{
public InvalidGatewayCustomerIdException()
: base("Invalid gateway customerId.")
{
}
}
}

View File

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace Bit.Core.Services
{
public interface IStripeSyncService
{
Task UpdateCustomerEmailAddress(string gatewayCustomerId, string emailAddress);
}
}

View File

@ -0,0 +1,33 @@
using System.Threading.Tasks;
using Bit.Core.Exceptions;
namespace Bit.Core.Services
{
public class StripeSyncService : IStripeSyncService
{
private readonly IStripeAdapter _stripeAdapter;
public StripeSyncService(IStripeAdapter stripeAdapter)
{
_stripeAdapter = stripeAdapter;
}
public async Task UpdateCustomerEmailAddress(string gatewayCustomerId, string emailAddress)
{
if (string.IsNullOrWhiteSpace(gatewayCustomerId))
{
throw new InvalidGatewayCustomerIdException();
}
if (string.IsNullOrWhiteSpace(emailAddress))
{
throw new InvalidEmailException();
}
var customer = await _stripeAdapter.CustomerGetAsync(gatewayCustomerId);
await _stripeAdapter.CustomerUpdateAsync(customer.Id,
new Stripe.CustomerUpdateOptions { Email = emailAddress });
}
}
}

View File

@ -52,6 +52,7 @@ namespace Bit.Core.Services
private readonly IOrganizationService _organizationService;
private readonly IProviderUserRepository _providerUserRepository;
private readonly IDeviceRepository _deviceRepository;
private readonly IStripeSyncService _stripeSyncService;
public UserService(
IUserRepository userRepository,
@ -81,7 +82,8 @@ namespace Bit.Core.Services
IGlobalSettings globalSettings,
IOrganizationService organizationService,
IProviderUserRepository providerUserRepository,
IDeviceRepository deviceRepository)
IDeviceRepository deviceRepository,
IStripeSyncService stripeSyncService)
: base(
store,
optionsAccessor,
@ -117,6 +119,7 @@ namespace Bit.Core.Services
_organizationService = organizationService;
_providerUserRepository = providerUserRepository;
_deviceRepository = deviceRepository;
_stripeSyncService = stripeSyncService;
}
public Guid? GetProperUserId(ClaimsPrincipal principal)
@ -543,6 +546,14 @@ namespace Bit.Core.Services
return IdentityResult.Failed(_identityErrorDescriber.DuplicateEmail(newEmail));
}
var previousState = new
{
Key = user.Key,
MasterPassword = user.MasterPassword,
SecurityStamp = user.SecurityStamp,
Email = user.Email
};
var result = await UpdatePasswordHash(user, newMasterPassword);
if (!result.Succeeded)
{
@ -554,6 +565,32 @@ namespace Bit.Core.Services
user.EmailVerified = true;
user.RevisionDate = user.AccountRevisionDate = DateTime.UtcNow;
await _userRepository.ReplaceAsync(user);
if (user.Gateway == GatewayType.Stripe)
{
try
{
await _stripeSyncService.UpdateCustomerEmailAddress(user.GatewayCustomerId,
user.BillingEmailAddress());
}
catch (Exception ex)
{
//if sync to strip fails, update email and securityStamp to previous
user.Key = previousState.Key;
user.Email = previousState.Email;
user.RevisionDate = user.AccountRevisionDate = DateTime.UtcNow;
user.MasterPassword = previousState.MasterPassword;
user.SecurityStamp = previousState.SecurityStamp;
await _userRepository.ReplaceAsync(user);
return IdentityResult.Failed(new IdentityError
{
Description = ex.Message
});
}
}
await _pushService.PushLogOutAsync(user.Id);
return IdentityResult.Success;

View File

@ -148,6 +148,7 @@ namespace Bit.SharedWeb.Utilities
};
});
services.AddSingleton<IPaymentService, StripePaymentService>();
services.AddSingleton<IStripeSyncService, StripeSyncService>();
services.AddSingleton<IMailService, HandlebarsMailService>();
services.AddSingleton<ILicensingService, LicensingService>();
services.AddTokenizers();