Forwarded activities are believed as far as their origin vouches
A thread's server passes on what happens in it, signed with its own key: Mastodon forwards the replies to its accounts' posts and their deletions, Friendica every activity in its threads. PrivaPub answered them 401, which also tells a sender its signature failed. Now they get 202 and nothing in them is believed: a forwarded Create or Update is taken as its object reads at the actor's origin, a Delete of a public or unlisted copy once that origin answers 404 or 410 (RemoteActorService.IsGone; FederationHttp remembers the status of a refusal), anything else is let go, and our own activities coming back are ignored. A forwarded copy has its own dedupe key, so one that failed never hides the author's own delivery. A reply in the thread of someone followed here is kept, as Mastodon keeps them. Mastodon delivers a reply to the followers of the account it answers; PrivaPub dropped those as unaddressed, which the pasture showed: the outsider's reply its Mastodon scenario said was never delivered had been, and was thrown away. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
01808fa644
commit
7eb7c017a5
12 files changed
+334
-21
No files matched your search
@@ -23,6 +23,7 @@ namespace PrivaPub.Infrastructure.Http
|
||||
{
|
||||
bool IsAllowed(Uri target);
|
||||
Task<FetchedJson> GetJson(string url, string accept, Action<HttpRequestMessage> sign, CancellationToken token);
|
||||
Task<(int Status, FetchedJson Json)> GetJsonStatus(string url, string accept, Action<HttpRequestMessage> sign, CancellationToken token);
|
||||
bool FailedTemporarily(string url);
|
||||
Task<(Uri FinalUri, string Html)> GetPage(string url, CancellationToken token);
|
||||
Task<HttpResponseMessage> OpenMedia(string url, System.Net.Http.Headers.RangeHeaderValue range, CancellationToken token);
|
||||
@@ -295,6 +296,24 @@ namespace PrivaPub.Infrastructure.Http
|
||||
}
|
||||
}
|
||||
|
||||
// the document and the status its origin answered with (a refusal remembered from the last five minutes keeps its
|
||||
// status; 0 when it never answered)
|
||||
public async Task<(int Status, FetchedJson Json)> GetJsonStatus(string url, string accept, Action<HttpRequestMessage> sign, CancellationToken token)
|
||||
{
|
||||
if (Uri.TryCreate(url, UriKind.Absolute, out var target) && _cache.TryGetValue(NegativeKey(target), out Refusal remembered))
|
||||
return (remembered.Status, default);
|
||||
var exchange = new Exchange(url, HttpScope.Purpose ?? "object");
|
||||
try
|
||||
{
|
||||
var json = await GetJson(url, accept, sign, exchange, token);
|
||||
return (exchange.Status ?? 0, json);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Record(exchange);
|
||||
}
|
||||
}
|
||||
|
||||
async Task<FetchedJson> GetJson(string url, string accept, Action<HttpRequestMessage> sign, Exchange exchange, CancellationToken token)
|
||||
{
|
||||
if (!Uri.TryCreate(url, UriKind.Absolute, out var target) || !IsAllowed(target))
|
||||
@@ -367,7 +386,7 @@ namespace PrivaPub.Infrastructure.Http
|
||||
}
|
||||
|
||||
public bool FailedTemporarily(string url) =>
|
||||
Uri.TryCreate(url, UriKind.Absolute, out var target) && _cache.TryGetValue(NegativeKey(target), out bool transient) && transient;
|
||||
Uri.TryCreate(url, UriKind.Absolute, out var target) && _cache.TryGetValue(NegativeKey(target), out Refusal refusal) && refusal.Transient;
|
||||
|
||||
public async Task<(byte[] Bytes, string ContentType)> GetMedia(string url, long maxBytes, CancellationToken token)
|
||||
{
|
||||
@@ -610,13 +629,15 @@ namespace PrivaPub.Infrastructure.Http
|
||||
|
||||
static string NegativeKey(Uri target) => "federation-http:refused:" + target.AbsoluteUri;
|
||||
|
||||
sealed record Refusal(bool Transient, int Status);
|
||||
|
||||
FetchedJson Refuse(string negativeKey, string url, string reason, Exchange exchange, string code, bool transient = false)
|
||||
{
|
||||
if (transient)
|
||||
exchange.Failed(code);
|
||||
else
|
||||
exchange.Refused(code);
|
||||
_cache.Set(negativeKey, transient, NegativeCacheLifetime);
|
||||
_cache.Set(negativeKey, new Refusal(transient, exchange.Status ?? 0), NegativeCacheLifetime);
|
||||
_logger.LogInformation("GET {Url} refused: {Reason}", url, reason);
|
||||
return default;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user