diff --git a/LiteCharms.Features.MidrandBooks/LiteCharms.Features.MidrandBooks.csproj b/LiteCharms.Features.MidrandBooks/LiteCharms.Features.MidrandBooks.csproj index c2f0ac7..564430a 100644 --- a/LiteCharms.Features.MidrandBooks/LiteCharms.Features.MidrandBooks.csproj +++ b/LiteCharms.Features.MidrandBooks/LiteCharms.Features.MidrandBooks.csproj @@ -148,6 +148,7 @@ + diff --git a/LiteCharms.Features.MidrandBooks/Payments/PayfastService.cs b/LiteCharms.Features.MidrandBooks/Payments/PayfastService.cs index 5cb585c..cbca90d 100644 --- a/LiteCharms.Features.MidrandBooks/Payments/PayfastService.cs +++ b/LiteCharms.Features.MidrandBooks/Payments/PayfastService.cs @@ -3,6 +3,7 @@ using LiteCharms.Features.Api.Configuration; using LiteCharms.Features.Hasher; using LiteCharms.Features.MidrandBooks.Payments.Models; using LiteCharms.Features.MidrandBooks.Postgres; +using Microsoft.AspNetCore.Http; namespace LiteCharms.Features.MidrandBooks.Payments; @@ -48,6 +49,35 @@ public sealed partial class PayfastService(IDbContextFactory x.Key, x => x.Value.ToString()); + + if (!formFields.TryGetValue("signature", out string? incomingSignature)) + return false; + + var stringBuilder = new StringBuilder(); + + foreach (var key in formFields.Keys) + { + if (key.Equals("signature", StringComparison.OrdinalIgnoreCase)) + continue; + + string encodedVal = HttpUtility.UrlEncode(formFields[key].Trim()); + string cleanVal = PercentEncodingRegex.Replace(encodedVal, m => m.Value.ToUpperInvariant()); + + stringBuilder.Append($"{key}={cleanVal}&"); + } + + string encodedPassphrase = HttpUtility.UrlEncode(passphrase.Trim()); + string safePassphrase = PercentEncodingRegex.Replace(encodedPassphrase, m => m.Value.ToUpperInvariant()); + + stringBuilder.Append($"passphrase={safePassphrase}"); + + string generatedSignature = HashService.ToMd5Hash(stringBuilder.ToString()).Value; + return incomingSignature.Equals(generatedSignature, StringComparison.OrdinalIgnoreCase); + } + public async ValueTask> ValidateReferrerIpAsync(string remoteIpAddress, bool allowLoopback = false, CancellationToken cancellationToken = default) { if(payfastOptions.Value?.ValidHosts?.Length == 0)