up
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
SDK Publish & Sign / sdk-publish (push) Has been cancelled
sdk-generator-smoke / sdk-smoke (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
SDK Publish & Sign / sdk-publish (push) Has been cancelled
sdk-generator-smoke / sdk-smoke (push) Has been cancelled
This commit is contained in:
@@ -1,22 +1,32 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.Notify.Models;
|
||||
using StellaOps.Notifier.Worker.Security;
|
||||
|
||||
namespace StellaOps.Notifier.Worker.Channels;
|
||||
|
||||
/// <summary>
|
||||
/// Channel adapter for webhook (HTTP POST) delivery with retry support.
|
||||
/// Channel adapter for webhook (HTTP POST) delivery with retry support and HMAC signing.
|
||||
/// </summary>
|
||||
public sealed class WebhookChannelAdapter : INotifyChannelAdapter
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly IWebhookSecurityService? _securityService;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly ILogger<WebhookChannelAdapter> _logger;
|
||||
|
||||
public WebhookChannelAdapter(HttpClient httpClient, ILogger<WebhookChannelAdapter> logger)
|
||||
public WebhookChannelAdapter(
|
||||
HttpClient httpClient,
|
||||
ILogger<WebhookChannelAdapter> logger,
|
||||
IWebhookSecurityService? securityService = null,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_securityService = securityService;
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
public NotifyChannelType ChannelType => NotifyChannelType.Webhook;
|
||||
@@ -52,17 +62,30 @@ public sealed class WebhookChannelAdapter : INotifyChannelAdapter
|
||||
timestamp = DateTimeOffset.UtcNow
|
||||
};
|
||||
|
||||
var jsonOptions = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
|
||||
var payloadJson = JsonSerializer.Serialize(payload, jsonOptions);
|
||||
var payloadBytes = Encoding.UTF8.GetBytes(payloadJson);
|
||||
|
||||
try
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Post, uri);
|
||||
request.Content = JsonContent.Create(payload, options: new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
});
|
||||
request.Content = new StringContent(payloadJson, Encoding.UTF8, "application/json");
|
||||
|
||||
// Add HMAC signature header if secret is available (placeholder for KMS integration)
|
||||
// Add version header
|
||||
request.Headers.Add("X-StellaOps-Notifier", "1.0");
|
||||
|
||||
// Add HMAC signature if security service is available
|
||||
if (_securityService is not null)
|
||||
{
|
||||
var timestamp = _timeProvider.GetUtcNow();
|
||||
var signature = _securityService.SignPayload(
|
||||
channel.TenantId,
|
||||
channel.ChannelId,
|
||||
payloadBytes,
|
||||
timestamp);
|
||||
request.Headers.Add("X-StellaOps-Signature", signature);
|
||||
}
|
||||
|
||||
using var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
var statusCode = (int)response.StatusCode;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user