Skip to content

Commit 4f771fa

Browse files
authored
Merge pull request #13 from dlmelendez/rel/2.2
v2.2
2 parents d92bf9f + b20f7fb commit 4f771fa

File tree

9 files changed

+26
-126
lines changed

9 files changed

+26
-126
lines changed

PayPalCheckoutSdk/JsonSourceGenerator.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,6 @@ namespace PayPalCheckoutSdk
165165
//[JsonSerializable(typeof(PayPalCheckoutSdk.Webhooks.VerificationStatus))]
166166
[JsonSerializable(typeof(PayPalCheckoutSdk.Webhooks.VerifyWebhookSignature), TypeInfoPropertyName = "Webhooks_VerifyWebhookSignature")]
167167
//[JsonSerializable(typeof(PayPalCheckoutSdk.Webhooks.VerifyWebhookSignatureRequest))]
168-
[JsonSerializable(typeof(PayPalCheckoutSdk.Webhooks.VerifyWebhookSignatureResponse), TypeInfoPropertyName = "Webhooks_VerifyWebhookSignatureResponse")]
169168
[JsonSerializable(typeof(PayPalCheckoutSdk.Webhooks.Webhook), TypeInfoPropertyName = "Webhooks_Webhook")]
170169
//[JsonSerializable(typeof(PayPalCheckoutSdk.Webhooks.WebhookCreateRequest))]
171170
//[JsonSerializable(typeof(PayPalCheckoutSdk.Webhooks.WebhookDeleteRequest))]

PayPalCheckoutSdk/PayPalCheckoutSdk.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<PropertyGroup>
44
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
55
<LangVersion>11.0</LangVersion>
6-
<Version>2.1.0</Version>
6+
<Version>2.2.0</Version>
77
<Nullable>enable</Nullable>
88
<Owners>David Melendez</Owners>
99
<RepositoryType>git</RepositoryType>

PayPalCheckoutSdk/Webhooks/VerifyWebhookEvent.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ public static class VerifyWebhookEvent
1212
{
1313
private const string WithRSAToken = "withRSA";
1414

15+
private static string? _publicLocalCertificateThumbprint;
16+
1517
public static async Task<bool> ValidateReceivedEventAsync(VerifyWebhookSignature verifySignature)
1618
{
1719
if (string.IsNullOrWhiteSpace(verifySignature.TransmissionTime))
@@ -75,11 +77,15 @@ public static async Task<bool> ValidateReceivedEventAsync(VerifyWebhookSignature
7577
X509Certificate2Collection remoteCertificateCollection = new X509Certificate2Collection();
7678
remoteCertificateCollection.Import(certificateBytes);
7779

78-
using var publicCertStream = typeof(Event).Assembly.GetManifestResourceStream("PayPalCheckoutSdk.Webhooks.DigiCertSHA2ExtendedValidationServerCA.crt");
79-
byte[] resourceBytes = new byte[publicCertStream!.Length];
80-
_ = await publicCertStream.ReadAsync(resourceBytes, 0, resourceBytes.Length);
80+
if (string.IsNullOrWhiteSpace(_publicLocalCertificateThumbprint))
81+
{
82+
using var publicCertStream = typeof(Event).Assembly.GetManifestResourceStream("PayPalCheckoutSdk.Webhooks.DigiCertSHA2ExtendedValidationServerCA.crt");
83+
byte[] resourceBytes = new byte[publicCertStream!.Length];
84+
_ = await publicCertStream.ReadAsync(resourceBytes);
8185

82-
X509Certificate2 publicLocalCertificate = new X509Certificate2(resourceBytes);
86+
X509Certificate2 publicLocalCertificate = new X509Certificate2(resourceBytes);
87+
_publicLocalCertificateThumbprint = publicLocalCertificate.Thumbprint;
88+
}
8389
// Create and configure the X509Chain object
8490
using X509Chain chain = new X509Chain();
8591
chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
@@ -93,7 +99,7 @@ public static async Task<bool> ValidateReceivedEventAsync(VerifyWebhookSignature
9399
}
94100

95101
// Validate the certificate chain.
96-
bool validateChain = chain.ChainElements.Any(a => a.Certificate.Thumbprint == publicLocalCertificate.Thumbprint);
102+
bool validateChain = chain.ChainElements.Any(a => a.Certificate.Thumbprint == (_publicLocalCertificateThumbprint?? string.Empty));
97103
if (!validateChain)
98104
{
99105
throw new Exception($"Invalid remote certificate, public key not found in chain {verifySignature.CertUrl}");

PayPalCheckoutSdk/Webhooks/VerifyWebhookSignature.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ public class VerifyWebhookSignature
5252

5353
/// <summary>
5454
/// A webhook event notification.
55+
/// Please use the WebhooEventRequestBody property instead with <see cref="VerifyWebhookEvent.ValidateReceivedEventAsync"/>
5556
/// </summary>
56-
[Obsolete("Please use the WebhooEventRequestBody property instead with VerifyWebhookEvent.ValidateReceivedEventAsync")]
5757
[DataMember(Name = "webhook_event", EmitDefaultValue = false)]
5858
[JsonPropertyName("webhook_event")]
5959
public Event? WebhookEvent { get; set; }

PayPalCheckoutSdk/Webhooks/VerifyWebhookSignatureRequest.cs

Lines changed: 0 additions & 58 deletions
This file was deleted.

PayPalCheckoutSdk/Webhooks/VerifyWebhookSignatureResponse.cs

Lines changed: 0 additions & 31 deletions
This file was deleted.

Samples/Samples.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
55
<TargetFramework>net6.0</TargetFramework>
6-
<PackageVersion>2.1.0</PackageVersion>
6+
<PackageVersion>2.2.0</PackageVersion>
77
</PropertyGroup>
88

99
<ItemGroup>

Test/Test.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
5-
<PackageVersion>2.1.0</PackageVersion>
5+
<PackageVersion>2.2.0</PackageVersion>
66
<IsPackable>false</IsPackable>
77
<UserSecretsId>4dbe0d9e-0d79-4e71-b5dd-44b90dbe3ee9</UserSecretsId>
88
</PropertyGroup>

Test/Webhooks/EventTests.cs

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics;
34
using System.Net;
45
using System.Threading.Tasks;
56
using PayPalCheckoutSdk.Orders;
@@ -65,7 +66,7 @@ public async Task TestSimulateEvent()
6566
var simulateResult = simulateResponse.Result<Event>();
6667
Assert.Equal(HttpStatusCode.Accepted, simulateResponse.StatusCode);
6768

68-
Capture? capture = simulateResult.GetResource<Capture>();
69+
Capture capture = simulateResult.GetResource<Capture>();
6970
Assert.NotNull(capture);
7071
Assert.False(string.IsNullOrWhiteSpace(capture.Id));
7172
}
@@ -138,34 +139,10 @@ public async Task TestResendNegative()
138139
Assert.Equal(HttpStatusCode.NoContent, deleteResponse.StatusCode);
139140
}
140141

141-
}
142-
143-
[Fact]
144-
public async Task TestVerifySignatureEventNegative()
145-
{
146-
VerifyWebhookSignatureRequest simulateRequest = new VerifyWebhookSignatureRequest();
147-
148-
var verifySignature = new VerifyWebhookSignature()
149-
{
150-
CertUrl = "https://api.sandbox.paypal.com/v1/notifications/certs/CERT-360caa42-fca2a594-2d7ab011",
151-
AuthAlgo = "SHA256withRSA",
152-
TransmissionId = "d0a19f40-e46b-11ed-af6d-5d1995803275",
153-
TransmissionSig = "Tg9131sVOAPVYn5XjQsR8C/tcOWuPkc//VkifmPX7TZD24\u002BkuRLIZ\u002BzfbMxkeuS0er1EzLHw4MRG83xkYoEGLe9QWD4nfvg/HIAvXDNgEZCG2BrPIwPaiFrA9G0SX22\u002BvpOiy4\u002BbWNrKAFZdt/gobEairdaqVe1unsCxCJQT6czTFiOBBAn85yDCSIhctk6RbEkprxjwTrgLDf1Cq41AgxZ72RwVuZlJHbMQF5Dl/cRQ9pU38I0HOq0DRXiiaJwrp7UJXkLRdu3ge4ivN3Th1Wq8D\u002BL/0xYrub9lFB0TKI2a7XBKlaua9aT7XrtuwZeI1cNz/jr0luz7K6JYdiZSlQ==",
154-
TransmissionTime = "2023-04-26T19:52:03Z",
155-
WebhookId = "3RY87287BU229431J",
156-
WebhookEvent = new Event() { Id = Guid.NewGuid().ToString(), EventType = "PAYMENT.CAPTURE.COMPLETED" }
157-
};
158-
simulateRequest.RequestBody(verifySignature);
159-
160-
var createResponse = await TestHarness.client().Execute(simulateRequest);
161-
var createResult = createResponse.Result<VerifyWebhookSignatureResponse>();
162-
Assert.Equal(HttpStatusCode.OK, createResponse.StatusCode);
163-
164-
Assert.False(createResult.ValidSignature);
165-
}
142+
}
166143

167144
[Fact]
168-
public async Task TestVerifySignatureEventCert()
145+
public async Task TestVerifySignatureEventCertNegative()
169146
{
170147
var verifySignature = new VerifyWebhookSignature()
171148
{
@@ -178,7 +155,14 @@ public async Task TestVerifySignatureEventCert()
178155
WebhookEventRequestBody = "{\r\n \"create_time\": \"2023-04-26T19:51:57.324Z\",\r\n \"event_type\": \"BILLING.SUBSCRIPTION.ACTIVATED\",\r\n \"event_version\": \"1.0\",\r\n \"id\": \"WH-2GA799794C526164B-4HC631101W386110B\",\r\n \"links\": [\r\n {\r\n \"encType\": null,\r\n \"href\": \"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-2GA799794C526164B-4HC631101W386110B\",\r\n \"mediaType\": null,\r\n \"method\": \"GET\",\r\n \"rel\": \"self\",\r\n \"title\": null\r\n },\r\n {\r\n \"encType\": null,\r\n \"href\": \"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-2GA799794C526164B-4HC631101W386110B/resend\",\r\n \"mediaType\": null,\r\n \"method\": \"POST\",\r\n \"rel\": \"resend\",\r\n \"title\": null\r\n }\r\n ],\r\n \"resource\": {\r\n \"quantity\": \"1\",\r\n \"subscriber\": {\r\n \"email_address\": \"davem-buyer@opticnerve.ai\",\r\n \"payer_id\": \"P2DZ2LMXC5SY2\",\r\n \"name\": {\r\n \"given_name\": \"test\",\r\n \"surname\": \"buyer\"\r\n },\r\n \"shipping_address\": {\r\n \"address\": {\r\n \"address_line_1\": \"1 Main St\",\r\n \"admin_area_2\": \"San Jose\",\r\n \"admin_area_1\": \"CA\",\r\n \"postal_code\": \"95131\",\r\n \"country_code\": \"US\"\r\n }\r\n }\r\n },\r\n \"create_time\": \"2023-04-26T19:51:53Z\",\r\n \"plan_overridden\": false,\r\n \"shipping_amount\": {\r\n \"currency_code\": \"USD\",\r\n \"value\": \"0.0\"\r\n },\r\n \"start_time\": \"2023-04-26T19:51:38Z\",\r\n \"update_time\": \"2023-04-26T19:51:53Z\",\r\n \"billing_info\": {\r\n \"outstanding_balance\": {\r\n \"currency_code\": \"USD\",\r\n \"value\": \"0.0\"\r\n },\r\n \"cycle_executions\": [\r\n {\r\n \"tenure_type\": \"TRIAL\",\r\n \"sequence\": 1,\r\n \"cycles_completed\": 1,\r\n \"cycles_remaining\": 0,\r\n \"current_pricing_scheme_version\": 1,\r\n \"total_cycles\": 1\r\n },\r\n {\r\n \"tenure_type\": \"REGULAR\",\r\n \"sequence\": 2,\r\n \"cycles_completed\": 0,\r\n \"cycles_remaining\": 0,\r\n \"current_pricing_scheme_version\": 1,\r\n \"total_cycles\": 0\r\n }\r\n ],\r\n \"next_billing_time\": \"2023-05-10T10:00:00Z\",\r\n \"failed_payments_count\": 0\r\n },\r\n \"links\": [\r\n {\r\n \"href\": \"https://api.sandbox.paypal.com/v1/billing/subscriptions/I-B9YUUVSYXFX3/cancel\",\r\n \"rel\": \"cancel\",\r\n \"method\": \"POST\",\r\n \"encType\": \"application/json\"\r\n },\r\n {\r\n \"href\": \"https://api.sandbox.paypal.com/v1/billing/subscriptions/I-B9YUUVSYXFX3\",\r\n \"rel\": \"edit\",\r\n \"method\": \"PATCH\",\r\n \"encType\": \"application/json\"\r\n },\r\n {\r\n \"href\": \"https://api.sandbox.paypal.com/v1/billing/subscriptions/I-B9YUUVSYXFX3\",\r\n \"rel\": \"self\",\r\n \"method\": \"GET\",\r\n \"encType\": \"application/json\"\r\n },\r\n {\r\n \"href\": \"https://api.sandbox.paypal.com/v1/billing/subscriptions/I-B9YUUVSYXFX3/suspend\",\r\n \"rel\": \"suspend\",\r\n \"method\": \"POST\",\r\n \"encType\": \"application/json\"\r\n },\r\n {\r\n \"href\": \"https://api.sandbox.paypal.com/v1/billing/subscriptions/I-B9YUUVSYXFX3/capture\",\r\n \"rel\": \"capture\",\r\n \"method\": \"POST\",\r\n \"encType\": \"application/json\"\r\n }\r\n ],\r\n \"id\": \"I-B9YUUVSYXFX3\",\r\n \"plan_id\": \"P-11V96330AW144370PMBGAOEA\",\r\n \"status\": \"ACTIVE\",\r\n \"status_update_time\": \"2023-04-26T19:51:53Z\"\r\n },\r\n \"resource_type\": \"subscription\",\r\n \"resource_version\": \"2.0\",\r\n \"summary\": \"Subscription activated\"\r\n }",
179156
};
180157

158+
Stopwatch stopwatch = Stopwatch.StartNew();
181159
bool verified = await VerifyWebhookEvent.ValidateReceivedEventAsync(verifySignature);
160+
stopwatch.Stop();
161+
_output.WriteLine($"1st ValidateReceivedEventAsync {stopwatch.Elapsed.TotalMilliseconds} ms");
162+
stopwatch.Restart();
163+
verified = await VerifyWebhookEvent.ValidateReceivedEventAsync(verifySignature);
164+
stopwatch.Stop();
165+
_output.WriteLine($"2nd ValidateReceivedEventAsync {stopwatch.Elapsed.TotalMilliseconds} ms");
182166
//
183167
// Unfortunately, we it is too difficult to setup a positive test.
184168
// We are mainly checking for any exceptions during validation

0 commit comments

Comments
 (0)