A follow of a persona's profile page; an Update under its Create's id
Forte follows a persona by its profile page (/@name, WebFinger's alias) rather than its actor's id: Follow and
Undo{Follow} now find the persona by either (it was a 404). Forte also sends an edit only added to the thread's context
(FEP-171b), under the same activity id as the post's Create: the unwrapping now tells two activities that share an id
apart by what they carry, as the inbox does, so the Update is not taken for a copy.
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
d06f684f0d
commit
99b5e2dbf3
6 files changed
+67
-8
No files matched your search
@@ -32,9 +32,13 @@ namespace PrivaPub.Federation.Inbox
|
||||
Arrival.Drop("container-unusable");
|
||||
return true;
|
||||
}
|
||||
var payload = new InboxPayload(actorUri, inner.ToJsonString(), "shared", ReceivedAt: DateTime.UtcNow, ForwardedBy: owner.ActorURI);
|
||||
var queued = await queue.Enqueue(JobKind.ProcessInbox, JsonSerializer.Serialize(payload), new Uri(actorUri).Host.ToLowerInvariant(),
|
||||
"inbox|forwarded|" + innerId, token);
|
||||
var payload = JsonSerializer.Serialize(new InboxPayload(actorUri, inner.ToJsonString(), "shared", ReceivedAt: DateTime.UtcNow, ForwardedBy: owner.ActorURI));
|
||||
var host = new Uri(actorUri).Host.ToLowerInvariant();
|
||||
var dedupe = "inbox|forwarded|" + innerId;
|
||||
var queued = await queue.Enqueue(JobKind.ProcessInbox, payload, host, dedupe, token);
|
||||
// one id for two activities (Forte's Update of a post has its Create's id): what each carries tells them apart
|
||||
if (!queued && InboxReceiver.CarriesOther(await queue.Payload(dedupe, token), inner))
|
||||
queued = await queue.Enqueue(JobKind.ProcessInbox, payload, host, $"{dedupe}|{InboxReceiver.Digest(inner)}", token);
|
||||
if (queued)
|
||||
Arrival.Accept("unwrapped");
|
||||
else
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace PrivaPub.Federation.Inbox.Handlers
|
||||
var follow = activity;
|
||||
var follower = actor;
|
||||
|
||||
var target = await _localActors.FindByUri(Id(follow["object"]), token);
|
||||
var target = await _localActors.FindByAddress(Id(follow["object"]), token);
|
||||
if (target is not { IsFederated: true } || target.Kind == LocalActorKind.Application)
|
||||
{
|
||||
Arrival.Drop("unknown-recipient");
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace PrivaPub.Federation.Inbox.Handlers
|
||||
{
|
||||
var followers = await _dbEntities.Followers.Match(f => f.ActorURI == actor.ActorURI).ExecuteAsync(token);
|
||||
var targetUri = inner is JsonObject ? Id(inner["object"]) : default;
|
||||
var target = targetUri == default ? default : await _localActors.FindByUri(targetUri, token);
|
||||
var target = targetUri == default ? default : await _localActors.FindByAddress(targetUri, token);
|
||||
var undone = false;
|
||||
foreach (var follower in followers)
|
||||
{
|
||||
|
||||
@@ -225,7 +225,7 @@ namespace PrivaPub.Federation.Inbox
|
||||
|
||||
static string HostOf(string uri) => Uri.TryCreate(uri, UriKind.Absolute, out var parsed) ? parsed.Host.ToLowerInvariant() : default;
|
||||
|
||||
static bool CarriesOther(string earlierPayload, JsonNode activity)
|
||||
public static bool CarriesOther(string earlierPayload, JsonNode activity)
|
||||
{
|
||||
if (earlierPayload == default)
|
||||
return false;
|
||||
@@ -235,7 +235,7 @@ namespace PrivaPub.Federation.Inbox
|
||||
}
|
||||
|
||||
// what an activity carries, short: its type, actor and object
|
||||
static string Digest(JsonNode activity) =>
|
||||
public static string Digest(JsonNode activity) =>
|
||||
Convert.ToHexString(System.Security.Cryptography.SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(
|
||||
$"{Value(activity, "type")}\n{Id(activity["actor"])}\n{activity["object"]?.ToJsonString()}")))[..16].ToLowerInvariant();
|
||||
|
||||
@@ -252,7 +252,8 @@ namespace PrivaPub.Federation.Inbox
|
||||
switch (type)
|
||||
{
|
||||
case "Follow":
|
||||
var target = await _localActors.FindByUri(Id(inner), token);
|
||||
// (by its actor's id, or the profile page Forte names instead)
|
||||
var target = await _localActors.FindByAddress(Id(inner), token);
|
||||
if (target is not { IsFederated: true } || target.Kind == LocalActorKind.Application)
|
||||
return new(StatusCodes.Status404NotFound, "no such local actor", Reason: "unknown-recipient");
|
||||
break;
|
||||
|
||||
Reference in new issue
Block a user