Votes a community relays count
Lemmy, PieFed and Mbin relay their members' votes, and the undoing of them, inside the community's Announce; PrivaPub dropped them all as unsupported (G-0003, the Lemmy scenario's expected failures). A relayed Like, Dislike or Undo from a community a persona follows is now handled as if its actor had sent it. The community vouches for what accounts on its own server do and for what is done to its own posts, as Lemmy trusts it (refetching every vote would not scale); a vote from elsewhere on anything else is believed only once fetched from its own origin. Moderation relayed the same way is still open. 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
2873344690
commit
ed08f80f05
4 files changed
+104
-6
No files matched your search
@@ -31,10 +31,16 @@ namespace PrivaPub.Federation.Inbox.Handlers
|
||||
|
||||
readonly IObjectRecords _records;
|
||||
readonly IQuoteService _quotes;
|
||||
readonly IServiceProvider _services;
|
||||
|
||||
// the handlers a community's relayed votes go to (Like, Dislike, Undo); resolved when first needed, since this
|
||||
// handler is one of them; tests set it
|
||||
public IEnumerable<IActivityHandler> Relays { get; set; }
|
||||
|
||||
public AnnounceHandler(DbEntities dbEntities, ILocalActorService localActors, IRemotePosts remotePosts, IFanout fanout, IRemoteActorService remoteActors,
|
||||
IObjectRecords records, IQuoteService quotes)
|
||||
IObjectRecords records, IQuoteService quotes, IServiceProvider services = default)
|
||||
{
|
||||
_services = services;
|
||||
_records = records;
|
||||
_quotes = quotes;
|
||||
_remoteActors = remoteActors;
|
||||
@@ -199,12 +205,59 @@ namespace PrivaPub.Federation.Inbox.Handlers
|
||||
Arrival.Accept("removed");
|
||||
await RemoteDeletes.Remove(deleted, objectUri, token);
|
||||
break;
|
||||
case "Like" or "Dislike" or "Undo":
|
||||
await Relayed(inner, group, token);
|
||||
break;
|
||||
default:
|
||||
Arrival.Drop("unsupported");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// A vote, or its undoing, that a community relays (Lemmy, PieFed and Mbin send them so). The community vouches for
|
||||
// what accounts on its own server do and for what is done to its own posts, as Lemmy trusts it (refetching every vote
|
||||
// would not scale); anything else is believed only once fetched from its own origin. It is then handled as if its
|
||||
// actor had delivered it.
|
||||
async Task Relayed(JsonNode inner, ForeignAvatar group, CancellationToken token)
|
||||
{
|
||||
var actorUri = Id(inner["actor"]);
|
||||
var type = Value(inner, "type");
|
||||
var handlers = Relays ?? _services?.GetService(typeof(IEnumerable<IActivityHandler>)) as IEnumerable<IActivityHandler>;
|
||||
var handler = handlers?.FirstOrDefault(h => h.Type == type);
|
||||
if (actorUri == default || handler == default)
|
||||
{
|
||||
Arrival.Drop("unparseable");
|
||||
return;
|
||||
}
|
||||
var activity = inner;
|
||||
var target = Id(Value(inner, "type") == "Undo" ? (inner["object"] as JsonObject)?["object"] : inner["object"]);
|
||||
var ownPost = target != default
|
||||
&& await _dbEntities.Posts.Match(p => p.ObjectURI == target && p.AudienceURI == group.ActorURI).ExecuteAnyAsync(token);
|
||||
if (!Origin.Same(actorUri, group.ActorURI) && !ownPost)
|
||||
{
|
||||
var id = Id(inner);
|
||||
if (id == default || !Origin.Same(id, actorUri))
|
||||
{
|
||||
Arrival.Drop("misattributed");
|
||||
return;
|
||||
}
|
||||
using var fetched = await _remoteActors.FetchObject(id, token);
|
||||
activity = fetched == default ? default : JsonNode.Parse(fetched.Root.GetRawText());
|
||||
if (activity == default || Value(activity, "type") != type || Id(activity["actor"]) != actorUri)
|
||||
{
|
||||
Arrival.Drop(activity == default ? "fetch-failed" : "misattributed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
var actor = await _remoteActors.GetActor(actorUri, refresh: false, token);
|
||||
if (actor == default)
|
||||
{
|
||||
Arrival.Drop("unknown-actor");
|
||||
return;
|
||||
}
|
||||
await handler.Handle(activity, actor, token);
|
||||
}
|
||||
|
||||
static List<string> Strings(JsonNode node) => node switch
|
||||
{
|
||||
JsonArray array => array.Select(Id).Where(id => id != default).ToList(),
|
||||
|
||||
Reference in new issue
Block a user