[backend/federation] Enforce matching activity actor & auth fetch signature user
This commit is contained in:
parent
0d5f987a8d
commit
69610a61d1
3 changed files with 19 additions and 3 deletions
|
@ -65,7 +65,11 @@ public class ActivityPubController : Controller {
|
|||
using var reader = new StreamReader(Request.Body, Encoding.UTF8, true, 1024, true);
|
||||
var body = await reader.ReadToEndAsync();
|
||||
Request.Body.Position = 0;
|
||||
await queues.InboxQueue.EnqueueAsync(new InboxJob { Body = body, InboxUserId = id });
|
||||
await queues.InboxQueue.EnqueueAsync(new InboxJob {
|
||||
Body = body,
|
||||
InboxUserId = id,
|
||||
AuthFetchUserId = HttpContext.GetActor()?.Id
|
||||
});
|
||||
return Accepted();
|
||||
}
|
||||
}
|
|
@ -18,17 +18,19 @@ namespace Iceshrimp.Backend.Core.Federation.ActivityPub;
|
|||
public class ActivityHandlerService(
|
||||
ILogger<ActivityHandlerService> logger,
|
||||
NoteService noteSvc,
|
||||
UserService userSvc,
|
||||
UserResolver userResolver,
|
||||
DatabaseContext db,
|
||||
QueueService queueService,
|
||||
ActivityRenderer activityRenderer,
|
||||
IOptions<Config.InstanceSection> config,
|
||||
IOptions<Config.SecuritySection> security,
|
||||
FederationControlService federationCtrl,
|
||||
ObjectResolver resolver,
|
||||
NotificationService notificationSvc,
|
||||
ActivityDeliverService deliverSvc
|
||||
) {
|
||||
public async Task PerformActivityAsync(ASActivity activity, string? inboxUserId) {
|
||||
public async Task PerformActivityAsync(ASActivity activity, string? inboxUserId, string? authFetchUserId) {
|
||||
logger.LogDebug("Processing activity: {activity}", activity.Id);
|
||||
if (activity.Actor == null)
|
||||
throw GracefulException.UnprocessableEntity("Cannot perform activity as actor 'null'");
|
||||
|
@ -37,6 +39,15 @@ public class ActivityHandlerService(
|
|||
if (activity.Object == null)
|
||||
throw GracefulException.UnprocessableEntity("Activity object is null");
|
||||
|
||||
var resolvedActor = await userResolver.ResolveAsync(activity.Actor.Id);
|
||||
|
||||
if (security.Value.AuthorizedFetch && authFetchUserId == null)
|
||||
throw GracefulException
|
||||
.UnprocessableEntity("Refusing to process activity without authFetchUserId in authorized fetch mode");
|
||||
if (resolvedActor.Id != authFetchUserId && authFetchUserId != null)
|
||||
throw GracefulException
|
||||
.UnprocessableEntity($"Authorized fetch user id {authFetchUserId} doesn't match resolved actor id {resolvedActor.Id}");
|
||||
|
||||
// Resolve object & children
|
||||
activity.Object = await resolver.ResolveObject(activity.Object) ??
|
||||
throw GracefulException.UnprocessableEntity("Failed to resolve activity object");
|
||||
|
|
|
@ -30,7 +30,7 @@ public class InboxQueue {
|
|||
var logger = scope.GetRequiredService<ILogger<InboxQueue>>();
|
||||
|
||||
logger.LogTrace("Preparation took {ms} ms", job.Duration);
|
||||
await apHandler.PerformActivityAsync(activity, job.InboxUserId);
|
||||
await apHandler.PerformActivityAsync(activity, job.InboxUserId, job.AuthFetchUserId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,4 +38,5 @@ public class InboxQueue {
|
|||
public class InboxJob : Job {
|
||||
[ProtoMember(1)] public required string Body;
|
||||
[ProtoMember(2)] public required string? InboxUserId;
|
||||
[ProtoMember(3)] public required string? AuthFetchUserId;
|
||||
}
|
Loading…
Add table
Reference in a new issue