Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions AccessGridTest/ConsoleServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@
}
""";

string capturedBody = null;

Check warning on line 267 in AccessGridTest/ConsoleServiceTests.cs

View workflow job for this annotation

GitHub Actions / test (8.0.x)

Converting null literal or possible null value to non-nullable type.
_mockHttpClient
.Setup(x => x.SendAsync(It.IsAny<HttpRequestMessage>()))
.Returns<HttpRequestMessage>(async req =>
Expand Down Expand Up @@ -349,7 +349,7 @@
{
var json = """{ "id": "tmpl-123", "name": "Test" }""";

string capturedBody = null;

Check warning on line 352 in AccessGridTest/ConsoleServiceTests.cs

View workflow job for this annotation

GitHub Actions / test (8.0.x)

Converting null literal or possible null value to non-nullable type.
_mockHttpClient
.Setup(x => x.SendAsync(It.IsAny<HttpRequestMessage>()))
.Returns<HttpRequestMessage>(async req =>
Expand Down Expand Up @@ -865,6 +865,21 @@
)), Times.Once);
}

[Test]
public async Task WebhooksDeleteAsync_IncludesSigPayloadQueryParam()
{
// DELETE requests have no body, so the server looks for `sig_payload` in
// the query string and verifies the signature against that.
StubHttpResponse("{}");

await _client.Console.Webhooks.DeleteAsync("wh_123");

_mockHttpClient.Verify(x => x.SendAsync(It.Is<HttpRequestMessage>(req =>
req.Method == HttpMethod.Delete &&
req.RequestUri!.ToString().Contains("sig_payload=")
)), Times.Once);
}

#endregion

#region HIDOrgsService
Expand Down
13 changes: 10 additions & 3 deletions src/AccessGrid/AccessGridClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ private async Task<T> MakeRequestAsync<T>(HttpMethod method, string endpoint, ob
{
// Extract resource ID from the endpoint if needed for signature
string resourceId = null;
if (method == HttpMethod.Get || (method == HttpMethod.Post && data == null))
if (method == HttpMethod.Get || method == HttpMethod.Delete || (method == HttpMethod.Post && data == null))
{
// Extract the ID from the endpoint - patterns like /resource/{id} or /resource/{id}/action
var parts = endpoint.Trim('/').Split('/');
Expand All @@ -186,8 +186,9 @@ private async Task<T> MakeRequestAsync<T>(HttpMethod method, string endpoint, ob
// Special handling for requests with no payload:
// 1. POST requests with empty body (like unlink/suspend/resume)
// 2. GET requests
// 3. DELETE requests (always have no body)
string payload;
if ((method == HttpMethod.Post && data == null) || method == HttpMethod.Get)
if ((method == HttpMethod.Post && data == null) || method == HttpMethod.Get || method == HttpMethod.Delete)
{
// For listing cards endpoint (like what the Python list.py script does)
if (method == HttpMethod.Get && endpoint == "/v1/key-cards")
Expand Down Expand Up @@ -228,7 +229,7 @@ private async Task<T> MakeRequestAsync<T>(HttpMethod method, string endpoint, ob

// For GET requests or POST requests with empty bodies that need the sig_payload parameter
// Note: We've already added sig_payload for /v1/key-cards endpoint above
if ((method == HttpMethod.Get || (method == HttpMethod.Post && data == null)) && !finalQueryParams.ContainsKey("sig_payload"))
if ((method == HttpMethod.Get || method == HttpMethod.Delete || (method == HttpMethod.Post && data == null)) && !finalQueryParams.ContainsKey("sig_payload"))
{
if (!string.IsNullOrEmpty(resourceId) && resourceId != "key-cards" && !resourceId.Contains("templates"))
{
Expand Down Expand Up @@ -298,6 +299,12 @@ private async Task<T> MakeRequestAsync<T>(HttpMethod method, string endpoint, ob
return (T)(object)responseContent;
}

// Empty response bodies (e.g. DELETE 204) have nothing to deserialize.
if (string.IsNullOrWhiteSpace(responseContent))
{
return default;
}

// Deserialize the response
try
{
Expand Down
Loading