- PersonaSeparationTests: two personas of one login follow the same account and post; nothing the API maps for one contains the other's id, username or the root id. - tools/smoke/mastodon-api.sh checks what a client meets first (instance v1/v2, discovery, app registration, client credentials, an app token refused by a user endpoint, the public timeline, revocation) and, given a persona token, verify_credentials, home and notifications. deploy.yml runs it after every deploy. - OAuthPruner removes invalid tokens and authorizations older than two weeks, every six hours. - The consent page no longer sets form-action, which browsers apply to the redirect back to the client after the form is posted. CLAUDE.md gains the Mastodon API layout and invariants. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012CzABvBkbcFqoHdmi8b9WB
45 lines
1.4 KiB
C#
45 lines
1.4 KiB
C#
using OpenIddict.Abstractions;
|
|
|
|
namespace PrivaPub.Api.Mastodon.Auth
|
|
{
|
|
public class OAuthPruner : BackgroundService
|
|
{
|
|
static readonly TimeSpan Interval = TimeSpan.FromHours(6);
|
|
static readonly TimeSpan Threshold = TimeSpan.FromDays(14);
|
|
|
|
readonly IServiceProvider _services;
|
|
readonly ILogger<OAuthPruner> _logger;
|
|
|
|
public OAuthPruner(IServiceProvider services, ILogger<OAuthPruner> logger)
|
|
{
|
|
_services = services;
|
|
_logger = logger;
|
|
}
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
{
|
|
while (!stoppingToken.IsCancellationRequested)
|
|
{
|
|
try
|
|
{
|
|
await Task.Delay(Interval, stoppingToken);
|
|
using var scope = _services.CreateScope();
|
|
var threshold = DateTimeOffset.UtcNow - Threshold;
|
|
var tokens = await scope.ServiceProvider.GetRequiredService<IOpenIddictTokenManager>().PruneAsync(threshold, stoppingToken);
|
|
var authorizations = await scope.ServiceProvider.GetRequiredService<IOpenIddictAuthorizationManager>().PruneAsync(threshold, stoppingToken);
|
|
if (tokens + authorizations > 0)
|
|
_logger.LogInformation("{Service} removed {Tokens} tokens and {Authorizations} authorizations", nameof(OAuthPruner), tokens, authorizations);
|
|
}
|
|
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
|
|
{
|
|
return;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "{Service} pass failed", nameof(OAuthPruner));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|