Skip to content

Commit 9a33ce3

Browse files
Only process the webhook body once
1 parent f78866b commit 9a33ce3

File tree

1 file changed

+24
-29
lines changed

1 file changed

+24
-29
lines changed

src/Umbraco.Commerce.PaymentProviders.Quickpay/QuickpayCheckoutPaymentProvider.cs

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public override async Task<PaymentFormResult> GenerateFormAsync(PaymentProviderC
127127
Currency = currencyCode,
128128
Variables = metaData
129129
},
130-
cancellationToken).ConfigureAwait(false);
130+
cancellationToken);
131131

132132
quickPayPaymentId = GetTransactionId(payment);
133133

@@ -144,7 +144,7 @@ public override async Task<PaymentFormResult> GenerateFormAsync(PaymentProviderC
144144
Framed = ctx.Settings.Framed
145145

146146
},
147-
cancellationToken).ConfigureAwait(false);
147+
cancellationToken);
148148

149149
paymentFormLink = paymentLink.Url;
150150

@@ -181,15 +181,21 @@ public override async Task<CallbackResult> ProcessCallbackAsync(PaymentProviderC
181181
{
182182
ArgumentNullException.ThrowIfNull(context);
183183

184-
if (!await ValidateChecksumAsync(context.HttpContext.Request, context.Settings.PrivateKey, cancellationToken).ConfigureAwait(false))
184+
var webhookBody = await GetJsonBodyAsync(context.HttpContext.Request, cancellationToken);
185+
186+
if (!await ValidateChecksumAsync(
187+
context.HttpContext.Request.Headers["Quickpay-Checksum-Sha256"],
188+
webhookBody,
189+
context.Settings.PrivateKey,
190+
cancellationToken))
185191
{
186192
Logger.Warn($"Quickpay [{context.Order.OrderNumber}] - Checksum validation failed");
187193
return CallbackResult.BadRequest();
188194
}
189195

190196
QuickpayPayment payment = await ParseCallbackAsync(
191-
context.HttpContext.Request,
192-
cancellationToken).ConfigureAwait(false);
197+
webhookBody,
198+
cancellationToken);
193199

194200
if (!VerifyOrder(context.Order, payment))
195201
{
@@ -273,7 +279,7 @@ public override async Task<ApiResult> FetchPaymentStatusAsync(PaymentProviderCon
273279
var clientConfig = GetQuickpayClientConfig(ctx.Settings);
274280
var client = new QuickpayClient(clientConfig);
275281

276-
var payment = await client.GetPaymentAsync(id, cancellationToken).ConfigureAwait(false);
282+
var payment = await client.GetPaymentAsync(id, cancellationToken);
277283

278284
Operation lastCompletedOperation = payment.Operations.LastOrDefault(o => !o.Pending && o.QuickpayStatusCode == "20000");
279285

@@ -310,7 +316,7 @@ public override async Task<ApiResult> CancelPaymentAsync(PaymentProviderContext<
310316
var clientConfig = GetQuickpayClientConfig(ctx.Settings);
311317
var client = new QuickpayClient(clientConfig);
312318

313-
var payment = await client.CancelPaymentAsync(id, cancellationToken).ConfigureAwait(false);
319+
var payment = await client.CancelPaymentAsync(id, cancellationToken);
314320

315321
Operation lastCompletedOperation = payment.Operations.LastOrDefault(o => !o.Pending && o.QuickpayStatusCode == "20000");
316322

@@ -351,7 +357,7 @@ public override async Task<ApiResult> CapturePaymentAsync(PaymentProviderContext
351357
{
352358
amount = AmountToMinorUnits(ctx.Order.TransactionInfo.AmountAuthorized.Value)
353359
},
354-
cancellationToken).ConfigureAwait(false);
360+
cancellationToken);
355361

356362
Operation lastCompletedOperation = payment.Operations.LastOrDefault(o => !o.Pending && o.QuickpayStatusCode == "20000");
357363

@@ -392,7 +398,7 @@ public override async Task<ApiResult> RefundPaymentAsync(PaymentProviderContext<
392398
{
393399
amount = AmountToMinorUnits(ctx.Order.TransactionInfo.AmountAuthorized.Value)
394400
},
395-
cancellationToken).ConfigureAwait(false);
401+
cancellationToken);
396402

397403
Operation lastCompletedOperation = payment.Operations.LastOrDefault(o => !o.Pending && o.QuickpayStatusCode == "20000");
398404

@@ -418,39 +424,28 @@ public override async Task<ApiResult> RefundPaymentAsync(PaymentProviderContext<
418424
return ApiResult.Empty;
419425
}
420426

421-
private async Task<QuickpayPayment> ParseCallbackAsync(HttpRequest request, CancellationToken cancellationToken = default)
427+
private async Task<string> GetJsonBodyAsync(HttpRequest request, CancellationToken cancellationToken = default)
422428
{
423429
if (request.Body.CanSeek)
424430
{
425431
request.Body.Seek(0, SeekOrigin.Begin);
426432
}
427433

428-
// Get quickpay callback body text - See parameters: https://learn.quickpay.net/tech-talk/api/callback/
429-
430434
using var reader = new StreamReader(request.Body);
431-
var json = await reader.ReadToEndAsync(cancellationToken);
432-
433-
// Deserialize json body text
434-
return JsonSerializer.Deserialize<QuickpayPayment>(json);
435+
return await reader.ReadToEndAsync(cancellationToken);
435436
}
436437

437-
private async Task<bool> ValidateChecksumAsync(HttpRequest request, string privateAccountKey, CancellationToken cancellationToken = default)
438-
{
439-
if (request.Body.CanSeek)
440-
{
441-
request.Body.Seek(0, SeekOrigin.Begin);
442-
}
438+
private Task<QuickpayPayment> ParseCallbackAsync(string webhookBody, CancellationToken cancellationToken = default)
439+
=> Task.FromResult(JsonSerializer.Deserialize<QuickpayPayment>(webhookBody));
443440

444-
using var reader = new StreamReader(request.Body);
445-
var json = await reader.ReadToEndAsync(cancellationToken);
446-
var checkSum = request.Headers["Quickpay-Checksum-Sha256"].FirstOrDefault();
447-
448-
if (string.IsNullOrEmpty(checkSum))
441+
private async Task<bool> ValidateChecksumAsync(string checksum, string webhookBody, string privateAccountKey, CancellationToken cancellationToken = default)
442+
{
443+
if (string.IsNullOrEmpty(checksum))
449444
return false;
450445

451-
var calculatedChecksum = Checksum(json, privateAccountKey);
446+
var calculatedChecksum = Checksum(webhookBody, privateAccountKey);
452447

453-
return checkSum.Equals(calculatedChecksum);
448+
return checksum.Equals(calculatedChecksum);
454449
}
455450

456451
private string Checksum(string content, string privateKey)

0 commit comments

Comments
 (0)