using PrivaPub.Federation.Actors; using PrivaPub.Federation.Objects; using PrivaPub.Models.User; using GroupEntity = PrivaPub.Models.Group.Group; namespace PrivaPub.Federation.Signing { public interface ISignedFetchAuthorizer { Task Requester(HttpRequest request, CancellationToken token); } public class SignedFetchAuthorizer : ISignedFetchAuthorizer { readonly IRemoteActorService _remoteActors; public SignedFetchAuthorizer(IRemoteActorService remoteActors) { _remoteActors = remoteActors; } public async Task Requester(HttpRequest request, CancellationToken token) { var parameters = HttpSignatures.Parse(request.Headers["Signature"].ToString()); if (parameters == default || HttpSignatures.CheckRequest(request, parameters, body: default) != default) return default; var signingString = HttpSignatures.SigningString(request, parameters); var actor = await _remoteActors.GetActorByKeyId(parameters.KeyId, refresh: false, token); if (actor != default && HttpSignatures.Verify(actor.PublicKey, signingString, parameters.Signature)) return actor; actor = await _remoteActors.GetActorByKeyId(parameters.KeyId, refresh: true, token); return actor != default && HttpSignatures.Verify(actor.PublicKey, signingString, parameters.Signature) ? actor : default; } public static bool MayReadCircle(GroupEntity circle, ForeignAvatar requester) => requester != default && circle.Members.Any(m => m.IsForeign && (m.AvatarId == requester.ActorURI || requester.AvatarType == AvatarType.Application && Origin.Same(m.AvatarId, requester.ActorURI))); } }