M2: every inbox answer is recorded
InboxReceiver records each answer once, in a finally, with a reason: too-large, not-json, not-activity, missing-type-or-actor, no-signature, the signature check's own codes (headers-unsigned, digest-mismatch, header-unreadable, date-skew, expired, algorithm-unsupported), signature-invalid, actor-not-key-owner, key-unavailable, id-cross-origin, undo-foreign, misattributed, unknown-recipient, and for 202s queued, duplicate, suspended or self-delete-unknown-key. Each event carries the activity and object type, the inbox, the signature scheme, the bytes and the time taken. A 404 for an unknown /mouth and a rate-limited inbox (429, from OnRejected) are recorded too. Until the signature verifies, the host is only claimed, so it is kept only if the server is already known. A suspended server is recorded under its own name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ELjqpznMFMNrJoJUj6K5p2
This commit is contained in:
1 parent
15cd034b29
commit
4fa53f63bd
7 files changed
+385
-24
No files matched your search
@@ -2,6 +2,8 @@ using Microsoft.AspNetCore.RateLimiting;
|
||||
|
||||
using PrivaPub.Federation.Objects;
|
||||
using PrivaPub.Federation.Signing;
|
||||
using PrivaPub.Infrastructure.Statistics;
|
||||
using PrivaPub.Models.Statistics;
|
||||
|
||||
using System.Threading.RateLimiting;
|
||||
|
||||
@@ -16,6 +18,25 @@ namespace PrivaPub.Infrastructure
|
||||
service.AddRateLimiter(options =>
|
||||
{
|
||||
options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
|
||||
options.OnRejected = (context, _) =>
|
||||
{
|
||||
var http = context.HttpContext;
|
||||
var ledger = http.RequestServices.GetService<IInteractionLedger>();
|
||||
var policy = http.GetEndpoint()?.Metadata.GetMetadata<EnableRateLimitingAttribute>()?.PolicyName;
|
||||
if (policy == Inbox)
|
||||
ledger?.Record(new InteractionEvent
|
||||
{
|
||||
Channel = Interactions.Receive,
|
||||
Host = Interactions.HostOf(SenderOrigin(http.Request)),
|
||||
Status = StatusCodes.Status429TooManyRequests,
|
||||
Outcome = Interactions.Refused,
|
||||
Reason = "rate-limited",
|
||||
Inbox = http.Request.Path.Value?.EndsWith("/mouth", StringComparison.Ordinal) == true ? "personal" : "shared"
|
||||
}, hostClaimed: true);
|
||||
else
|
||||
ledger?.CountServer(ServerSections.Client, $"{policy ?? "unknown"}:429");
|
||||
return ValueTask.CompletedTask;
|
||||
};
|
||||
options.AddPolicy(Accounts, context => RateLimitPartition.GetFixedWindowLimiter(
|
||||
context.Connection.RemoteIpAddress?.ToString() ?? "unknown",
|
||||
_ => new FixedWindowRateLimiterOptions { PermitLimit = 10, Window = TimeSpan.FromMinutes(1), QueueLimit = 0 }));
|
||||
|
||||
Reference in new issue
Block a user