using MongoDB.Entities; using PrivaPub.Federation.Actors; using PrivaPub.Federation.Objects; using PrivaPub.Models.Social; using PrivaPub.Models.User; using PrivaPub.StaticServices; using System.Text.Json.Nodes; using static PrivaPub.Federation.Objects.ActivityJson; namespace PrivaPub.Federation.Inbox.Handlers { // Lemmy 1.0 tells a report's sender that it was dealt with: Resolve{Flag}, the Flag being one we sent // (`/grunts/flag-`). It is believed from the server holding what was reported, or the community it was // reported to, and kept on the report beside our own moderators' resolution, which it never replaces. public class ResolveHandler : IActivityHandler { const string FlagMarker = "/grunts/flag-"; readonly DbEntities _dbEntities; readonly ILocalActorService _localActors; public ResolveHandler(DbEntities dbEntities, ILocalActorService localActors) { _dbEntities = dbEntities; _localActors = localActors; } public string Type => "Resolve"; public async Task Handle(JsonNode activity, ForeignAvatar actor, CancellationToken token) { var flag = activity["object"]; var flagId = Id(flag); var marker = flagId?.IndexOf(FlagMarker, StringComparison.Ordinal) ?? -1; if (flag is JsonObject && Value(flag, "type") != "Flag" || marker < 0 || !flagId.StartsWith(_localActors.BaseAddress + "/", StringComparison.OrdinalIgnoreCase)) { Arrival.Drop("not-ours"); return; } var reportId = flagId[(marker + FlagMarker.Length)..].Split('-')[0]; var report = await DB.Default.Find().MatchID(reportId).ExecuteFirstAsync(token); if (report == default) { Arrival.Drop("unknown-object"); return; } var concerned = new List(report.ObjectURIs) { report.TargetActorURI }; foreach (var post in report.PostIds.Count == 0 ? new List() : await _dbEntities.Posts.Match(p => report.PostIds.Contains(p.ID)).ExecuteAsync(token)) concerned.Add(await Communities.Of(post, _dbEntities, token)); if (!concerned.Any(uri => Origin.Same(uri, actor.ActorURI))) { Arrival.Drop("misattributed"); return; } await DB.Default.Update().MatchID(report.ID) .Modify(r => r.RemoteResolvedAt, DateTime.UtcNow) .Modify(r => r.RemoteResolvedBy, actor.ActorURI) .ExecuteAsync(token); Arrival.Accept("resolved"); } } }