NeverFiveHundredTests walks every endpoint the server maps and fills each route parameter
with junk ('x', zeroed and random ObjectIds, a dot-dot segment, 5000 characters). It calls
each one anonymously, as a persona, and with a junk token, and asserts that nothing
answers 5xx or throws, and that every /api error carries a Mastodon error body.
It found two bugs:
- A junk 'Authorization: Bearer' on any non-/api route, anonymous ones included
(/build.json, /peasants/*, inboxes), broke the response. JwtEvents.AuthenticationFailed
wrote a body during authentication and the endpoint then wrote its own. The 401 body now
comes from the Challenge event, which runs only when an endpoint needs a user.
- /api answered 401, 404 and 429 with no body. UseMastodonErrorBodies gives any /api error
that leaves without a body Mastodon's {"error": ...}.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ELjqpznMFMNrJoJUj6K5p2
30 lines
1.2 KiB
C#
30 lines
1.2 KiB
C#
using System.Text.Json;
|
|
|
|
namespace PrivaPub.Api.Mastodon.Infrastructure
|
|
{
|
|
public static class MastodonErrors
|
|
{
|
|
public static IApplicationBuilder UseMastodonErrorBodies(this IApplicationBuilder app) =>
|
|
app.UseWhen(context => context.Request.Path.StartsWithSegments("/api"), api => api.UseStatusCodePages(async pages =>
|
|
{
|
|
var response = pages.HttpContext.Response;
|
|
response.ContentType = "application/json; charset=utf-8";
|
|
await response.WriteAsync(JsonSerializer.Serialize(new { error = Message(response.StatusCode) }, MastodonJson.Options));
|
|
}));
|
|
|
|
public static string Message(int status) => status switch
|
|
{
|
|
StatusCodes.Status401Unauthorized => "The access token is invalid",
|
|
StatusCodes.Status403Forbidden => "This action is outside the authorized scopes",
|
|
StatusCodes.Status404NotFound => "Record not found",
|
|
StatusCodes.Status405MethodNotAllowed => "Method not allowed",
|
|
StatusCodes.Status413PayloadTooLarge => "Payload too large",
|
|
StatusCodes.Status415UnsupportedMediaType => "Unsupported media type",
|
|
StatusCodes.Status422UnprocessableEntity => "Validation failed",
|
|
StatusCodes.Status429TooManyRequests => "Too many requests",
|
|
>= 500 => "Something went wrong.",
|
|
_ => "Bad request"
|
|
};
|
|
}
|
|
}
|