R9 Web Push, then the honest version: VAPID key, push subscriptions, encrypted pushes, 4.5.0 advertised
The server's VAPID key (PushKeys, made on first need, in Mongo) is the instance API's vapid.public_key and every app's vapid_key. /api/v1/push/subscription (POST, GET, PUT, DELETE) keeps one subscription per access token, so per persona; every notification kept (never a filtered one) is queued as a SendPush job for the subscriptions whose alert and policy admit it, and sent through the `push` client (the safe handler, https only) encrypted as RFC 8291 aes128gcm or the aesgcm draft with an ES256 VAPID JWT. 404/410 delete the subscription, 429/5xx/timeouts retry, other answers drop the push. Subscriptions end with their tokens (revocation, sessions ended, suspension, deletion, a restore); backups hold neither keys nor subscriptions. The walk of every Mastodon 4.3-4.5 client route (docs/MASTODON-API.md) added conversations/:id/unread, domain_blocks/preview, v2 notifications clear and PUT policy, /oauth/userinfo and stubs, so both instance APIs now say 4.5.0 (compatible; PrivaPub <release>). The pasture gets a push sink (pushsink.test) and scenarios/push.sh in batch A. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WpVCoDeM1qUTRp4fXQdfof
This commit is contained in:
1 parent
87529bca49
commit
9b792042e6
43 files changed
+2079
-49
No files matched your search
@@ -47,7 +47,8 @@ namespace PrivaPub.Api.Mastodon.Controllers
|
||||
_outbox = outbox;
|
||||
}
|
||||
|
||||
[HttpGet("/api/v1/accounts/verify_credentials"), Scope("read:accounts")]
|
||||
// Mastodon 4.4: a token with the profile scope alone may read it too
|
||||
[HttpGet("/api/v1/accounts/verify_credentials"), Scope("read:accounts|profile")]
|
||||
public async Task<IActionResult> VerifyCredentials(CancellationToken token) => Json(await _mapper.Local(Me, withSource: true, token));
|
||||
|
||||
[HttpPatch("/api/v1/accounts/update_credentials"), Scope("write:accounts"), EnableRateLimiting(RateLimiting.Uploads), RequestSizeLimit(20 * 1024 * 1024),
|
||||
@@ -398,6 +399,28 @@ namespace PrivaPub.Api.Mastodon.Controllers
|
||||
public async Task<IActionResult> DomainBlocks(CancellationToken token) =>
|
||||
Json((await DB.Default.Find<AccountDomainBlock>().Match(b => b.AvatarId == MyId).Sort(b => b.Domain, Order.Ascending).ExecuteAsync(token)).Select(b => b.Domain).ToList());
|
||||
|
||||
// Mastodon's preview of a server block: how many of the accounts the persona follows, and of those following it, the
|
||||
// block would take away, counted as BlockDomain takes them (an account on the server or a subdomain, or whose handle
|
||||
// is)
|
||||
[HttpGet("/api/v1/domain_blocks/preview"), Scope("write:blocks")]
|
||||
public async Task<IActionResult> PreviewDomainBlock(CancellationToken token)
|
||||
{
|
||||
var domain = Params.Get("domain")?.Trim().ToLowerInvariant();
|
||||
if (string.IsNullOrEmpty(domain))
|
||||
return Error(StatusCodes.Status400BadRequest, "Param is missing or the value is empty: domain");
|
||||
if (Uri.CheckHostName(domain) != UriHostNameType.Dns)
|
||||
return Error(StatusCodes.Status422UnprocessableEntity, "Validation failed: Domain is invalid");
|
||||
var followings = await _dbEntities.Followings.Match(f => f.AvatarId == MyId && !f.TargetIsLocal && f.State == FollowState.Accepted)
|
||||
.ExecuteAsync(token);
|
||||
var followers = await _dbEntities.Followers.Match(f => f.LocalActorId == MyId && f.IsAccepted).ExecuteAsync(token);
|
||||
var handles = await Hidden.HandleDomains(followings.Select(f => f.TargetActorURI).Concat(followers.Select(f => f.ActorURI)).ToList(), token);
|
||||
return Json(new
|
||||
{
|
||||
following_count = followings.Count(f => Hidden.Blocks(domain, f.TargetActorURI, handles.GetValueOrDefault(f.TargetActorURI))),
|
||||
followers_count = followers.Count(f => Hidden.Blocks(domain, f.ActorURI, handles.GetValueOrDefault(f.ActorURI)))
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost("/api/v1/domain_blocks"), Scope("write:blocks")]
|
||||
public async Task<IActionResult> BlockDomain(CancellationToken token)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user