-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathWebhookOptions.cs
More file actions
71 lines (59 loc) · 2.74 KB
/
Copy pathWebhookOptions.cs
File metadata and controls
71 lines (59 loc) · 2.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
using Microsoft.Extensions.Options;
namespace LicenseManagement.Client;
/// <summary>
/// Configuration options for webhook signature verification.
/// </summary>
public sealed class WebhookOptions
{
/// <summary>
/// The configuration section name for binding from appsettings.
/// </summary>
public const string SectionName = "LicenseManagement:Webhook";
/// <summary>
/// Default maximum body size accepted by the webhook filter.
/// </summary>
public const int DefaultMaxBodyBytes = 1 * 1024 * 1024;
/// <summary>
/// The primary webhook signing secret.
/// This is provided when you create a webhook and should be stored securely.
/// </summary>
public string Secret { get; set; } = string.Empty;
/// <summary>
/// The secondary webhook signing secret, used during secret rotation.
/// When rotating secrets, both the old and new secrets are valid during the transition period.
/// </summary>
public string? SecondarySecret { get; set; }
/// <summary>
/// The tolerance for timestamp validation.
/// Requests with timestamps outside this window will be rejected to prevent replay attacks.
/// Must be greater than zero and less than 1 hour. Default: 5 minutes.
/// </summary>
public TimeSpan? TimestampTolerance { get; set; }
/// <summary>
/// Maximum allowed size of an inbound webhook body, in bytes. Requests exceeding this limit are
/// rejected with HTTP 413 before the body is read. Default: 1 MB.
/// </summary>
public int MaxBodyBytes { get; set; } = DefaultMaxBodyBytes;
}
/// <summary>
/// Validates <see cref="WebhookOptions"/> at startup so misconfiguration is caught early.
/// </summary>
internal sealed class WebhookOptionsValidator : IValidateOptions<WebhookOptions>
{
private static readonly TimeSpan MaxAllowedTolerance = TimeSpan.FromHours(1);
public ValidateOptionsResult Validate(string? name, WebhookOptions options)
{
if (options is null)
return ValidateOptionsResult.Fail($"{nameof(WebhookOptions)} is null.");
if (options.TimestampTolerance is { } tolerance)
{
if (tolerance <= TimeSpan.Zero)
return ValidateOptionsResult.Fail($"{nameof(WebhookOptions)}.{nameof(WebhookOptions.TimestampTolerance)} must be greater than zero.");
if (tolerance > MaxAllowedTolerance)
return ValidateOptionsResult.Fail($"{nameof(WebhookOptions)}.{nameof(WebhookOptions.TimestampTolerance)} must be less than 1 hour.");
}
if (options.MaxBodyBytes <= 0)
return ValidateOptionsResult.Fail($"{nameof(WebhookOptions)}.{nameof(WebhookOptions.MaxBodyBytes)} must be greater than zero.");
return ValidateOptionsResult.Success;
}
}