1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-24 12:35:25 +01:00

Upgrade Stripe.net to 45.7.0 (#4744)

This commit is contained in:
Alex Morask 2024-09-06 13:30:39 -04:00 committed by GitHub
parent fc587847c3
commit dd6bc89b19
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 89 additions and 37 deletions

View File

@ -6,6 +6,7 @@ public class BillingSettings
public virtual string StripeWebhookKey { get; set; } public virtual string StripeWebhookKey { get; set; }
public virtual string StripeWebhookSecret { get; set; } public virtual string StripeWebhookSecret { get; set; }
public virtual string StripeWebhookSecret20231016 { get; set; } public virtual string StripeWebhookSecret20231016 { get; set; }
public virtual string StripeWebhookSecret20240620 { get; set; }
public virtual string BitPayWebhookKey { get; set; } public virtual string BitPayWebhookKey { get; set; }
public virtual string AppleWebhookKey { get; set; } public virtual string AppleWebhookKey { get; set; }
public virtual FreshDeskSettings FreshDesk { get; set; } = new FreshDeskSettings(); public virtual FreshDeskSettings FreshDesk { get; set; } = new FreshDeskSettings();

View File

@ -37,13 +37,18 @@ public class StripeController : Controller
{ {
if (!CoreHelpers.FixedTimeEquals(key, _billingSettings.StripeWebhookKey)) if (!CoreHelpers.FixedTimeEquals(key, _billingSettings.StripeWebhookKey))
{ {
_logger.LogError("Stripe webhook key does not match configured webhook key");
return new BadRequestResult(); return new BadRequestResult();
} }
var parsedEvent = await TryParseEventFromRequestBodyAsync(); var parsedEvent = await TryParseEventFromRequestBodyAsync();
if (parsedEvent is null) if (parsedEvent is null)
{ {
return Ok(); return Ok(new
{
Processed = false,
Message = "Could not find a configured webhook secret to process this event with"
});
} }
if (StripeConfiguration.ApiVersion != parsedEvent.ApiVersion) if (StripeConfiguration.ApiVersion != parsedEvent.ApiVersion)
@ -54,7 +59,11 @@ public class StripeController : Controller
parsedEvent.ApiVersion, parsedEvent.ApiVersion,
StripeConfiguration.ApiVersion); StripeConfiguration.ApiVersion);
return new OkResult(); return Ok(new
{
Processed = false,
Message = "SDK API version does not match the event's API version"
});
} }
if (string.IsNullOrWhiteSpace(parsedEvent?.Id)) if (string.IsNullOrWhiteSpace(parsedEvent?.Id))
@ -72,11 +81,19 @@ public class StripeController : Controller
// If the customer and server cloud regions don't match, early return 200 to avoid unnecessary errors // If the customer and server cloud regions don't match, early return 200 to avoid unnecessary errors
if (!await _stripeEventService.ValidateCloudRegion(parsedEvent)) if (!await _stripeEventService.ValidateCloudRegion(parsedEvent))
{ {
return new OkResult(); return Ok(new
{
Processed = false,
Message = "Event is not for this cloud region"
});
} }
await _stripeEventProcessor.ProcessEventAsync(parsedEvent); await _stripeEventProcessor.ProcessEventAsync(parsedEvent);
return Ok(); return Ok(new
{
Processed = true,
Message = "Processed"
});
} }
/// <summary> /// <summary>
@ -89,19 +106,49 @@ public class StripeController : Controller
/// </returns> /// </returns>
private string PickStripeWebhookSecret(string webhookBody) private string PickStripeWebhookSecret(string webhookBody)
{ {
var versionContainer = JsonSerializer.Deserialize<StripeWebhookVersionContainer>(webhookBody); var deliveryContainer = JsonSerializer.Deserialize<StripeWebhookDeliveryContainer>(webhookBody);
return versionContainer.ApiVersion switch _logger.LogInformation(
"Picking secret for Stripe webhook | {EventID}: {EventType} | Version: {APIVersion} | Initiating Request ID: {RequestID}",
deliveryContainer.Id,
deliveryContainer.Type,
deliveryContainer.ApiVersion,
deliveryContainer.Request?.Id);
return deliveryContainer.ApiVersion switch
{ {
"2023-10-16" => _billingSettings.StripeWebhookSecret20231016, "2024-06-20" => HandleVersionWith(_billingSettings.StripeWebhookSecret20240620),
"2022-08-01" => _billingSettings.StripeWebhookSecret, "2023-10-16" => HandleVersionWith(_billingSettings.StripeWebhookSecret20231016),
_ => HandleDefault(versionContainer.ApiVersion) "2022-08-01" => HandleVersionWith(_billingSettings.StripeWebhookSecret),
_ => HandleDefault(deliveryContainer.ApiVersion)
}; };
string HandleVersionWith(string secret)
{
if (string.IsNullOrEmpty(secret))
{
_logger.LogError("No webhook secret is configured for API version {APIVersion}", deliveryContainer.ApiVersion);
return null;
}
if (!secret.StartsWith("whsec_"))
{
_logger.LogError("Webhook secret configured for API version {APIVersion} does not start with whsec_",
deliveryContainer.ApiVersion);
return null;
}
var truncatedSecret = secret[..10];
_logger.LogInformation("Picked webhook secret {TruncatedSecret}... for API version {APIVersion}", truncatedSecret, deliveryContainer.ApiVersion);
return secret;
}
string HandleDefault(string version) string HandleDefault(string version)
{ {
_logger.LogWarning( _logger.LogWarning(
"Stripe webhook contained an recognized 'api_version': {ApiVersion}", "Stripe webhook contained an API version ({APIVersion}) we do not process",
version); version);
return null; return null;
@ -121,22 +168,13 @@ public class StripeController : Controller
if (string.IsNullOrEmpty(webhookSecret)) if (string.IsNullOrEmpty(webhookSecret))
{ {
_logger.LogDebug("Unable to parse event. No webhook secret.");
return null; return null;
} }
var parsedEvent = EventUtility.ConstructEvent( return EventUtility.ConstructEvent(
json, json,
Request.Headers["Stripe-Signature"], Request.Headers["Stripe-Signature"],
webhookSecret, webhookSecret,
throwOnApiVersionMismatch: false); throwOnApiVersionMismatch: false);
if (parsedEvent is not null)
{
return parsedEvent;
}
_logger.LogDebug("Stripe-Signature request header doesn't match configured Stripe webhook secret");
return null;
} }
} }

View File

@ -0,0 +1,21 @@
using System.Text.Json.Serialization;
namespace Bit.Billing.Models;
public class StripeWebhookDeliveryContainer
{
[JsonPropertyName("id")]
public string Id { get; set; }
[JsonPropertyName("api_version")]
public string ApiVersion { get; set; }
[JsonPropertyName("request")]
public StripeWebhookRequestData Request { get; set; }
[JsonPropertyName("type")]
public string Type { get; set; }
}
public class StripeWebhookRequestData
{
[JsonPropertyName("id")]
public string Id { get; set; }
}

View File

@ -1,9 +0,0 @@
using System.Text.Json.Serialization;
namespace Bit.Billing.Models;
public class StripeWebhookVersionContainer
{
[JsonPropertyName("api_version")]
public string ApiVersion { get; set; }
}

View File

@ -59,6 +59,7 @@
"stripeWebhookKey": "SECRET", "stripeWebhookKey": "SECRET",
"stripeWebhookSecret": "SECRET", "stripeWebhookSecret": "SECRET",
"stripeWebhookSecret20231016": "SECRET", "stripeWebhookSecret20231016": "SECRET",
"stripeWebhookSecret20240620": "SECRET",
"bitPayWebhookKey": "SECRET", "bitPayWebhookKey": "SECRET",
"appleWebhookKey": "SECRET", "appleWebhookKey": "SECRET",
"payPal": { "payPal": {

View File

@ -55,7 +55,7 @@
<PackageReference Include="Serilog.Sinks.SyslogMessages" Version="3.0.2" /> <PackageReference Include="Serilog.Sinks.SyslogMessages" Version="3.0.2" />
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" /> <PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
<PackageReference Include="Braintree" Version="5.26.0" /> <PackageReference Include="Braintree" Version="5.26.0" />
<PackageReference Include="Stripe.net" Version="43.20.0" /> <PackageReference Include="Stripe.net" Version="45.7.0" />
<PackageReference Include="Otp.NET" Version="1.4.0" /> <PackageReference Include="Otp.NET" Version="1.4.0" />
<PackageReference Include="YubicoDotNetClient" Version="1.2.0" /> <PackageReference Include="YubicoDotNetClient" Version="1.2.0" />
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.8" /> <PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.8" />

View File

@ -1,7 +1,7 @@
{ {
"id": "evt_3NvKgBIGBnsLynRr0pJJqudS", "id": "evt_3NvKgBIGBnsLynRr0pJJqudS",
"object": "event", "object": "event",
"api_version": "2023-10-16", "api_version": "2024-06-20",
"created": 1695909300, "created": 1695909300,
"data": { "data": {
"object": { "object": {

View File

@ -1,7 +1,7 @@
{ {
"id": "evt_1NvLMDIGBnsLynRr6oBxebrE", "id": "evt_1NvLMDIGBnsLynRr6oBxebrE",
"object": "event", "object": "event",
"api_version": "2023-10-16", "api_version": "2024-06-20",
"created": 1695911902, "created": 1695911902,
"data": { "data": {
"object": { "object": {

View File

@ -2,7 +2,7 @@
"id": "evt_1NvKjSIGBnsLynRrS3MTK4DZ", "id": "evt_1NvKjSIGBnsLynRrS3MTK4DZ",
"object": "event", "object": "event",
"account": "acct_19smIXIGBnsLynRr", "account": "acct_19smIXIGBnsLynRr",
"api_version": "2023-10-16", "api_version": "2024-06-20",
"created": 1695909502, "created": 1695909502,
"data": { "data": {
"object": { "object": {

View File

@ -1,7 +1,7 @@
{ {
"id": "evt_1NvKzfIGBnsLynRr0SkwrlkE", "id": "evt_1NvKzfIGBnsLynRr0SkwrlkE",
"object": "event", "object": "event",
"api_version": "2023-10-16", "api_version": "2024-06-20",
"created": 1695910506, "created": 1695910506,
"data": { "data": {
"object": { "object": {

View File

@ -2,7 +2,7 @@
"id": "evt_1PQaABIGBnsLynRrhoJjGnyz", "id": "evt_1PQaABIGBnsLynRrhoJjGnyz",
"object": "event", "object": "event",
"account": "acct_19smIXIGBnsLynRr", "account": "acct_19smIXIGBnsLynRr",
"api_version": "2023-10-16", "api_version": "2024-06-20",
"created": 1718133319, "created": 1718133319,
"data": { "data": {
"object": { "object": {

View File

@ -1,7 +1,7 @@
{ {
"id": "evt_1Nv0w8IGBnsLynRrZoDVI44u", "id": "evt_1Nv0w8IGBnsLynRrZoDVI44u",
"object": "event", "object": "event",
"api_version": "2023-10-16", "api_version": "2024-06-20",
"created": 1695833408, "created": 1695833408,
"data": { "data": {
"object": { "object": {

View File

@ -1,7 +1,7 @@
{ {
"id": "evt_1NvKzcIGBnsLynRrPJ3hybkd", "id": "evt_1NvKzcIGBnsLynRrPJ3hybkd",
"object": "event", "object": "event",
"api_version": "2023-10-16", "api_version": "2024-06-20",
"created": 1695910504, "created": 1695910504,
"data": { "data": {
"object": { "object": {