From 70260967beda731d17a8f6408611f53986937d67 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Tue, 30 Dec 2025 00:08:04 +0800 Subject: [PATCH] :bug: Better override host --- .../ActivityPub/ActivityPubDeliveryService.cs | 146 +++++++++--------- .../ActivityPubSignatureService.cs | 56 +++---- DysonNetwork.sln.DotSettings.user | 1 + 3 files changed, 100 insertions(+), 103 deletions(-) diff --git a/DysonNetwork.Sphere/ActivityPub/ActivityPubDeliveryService.cs b/DysonNetwork.Sphere/ActivityPub/ActivityPubDeliveryService.cs index ed7650a..b7c9414 100644 --- a/DysonNetwork.Sphere/ActivityPub/ActivityPubDeliveryService.cs +++ b/DysonNetwork.Sphere/ActivityPub/ActivityPubDeliveryService.cs @@ -16,7 +16,16 @@ public class ActivityPubDeliveryService( ) { private string Domain => configuration["ActivityPub:Domain"] ?? "localhost"; - private HttpClient HttpClient => httpClientFactory.CreateClient(); + + private HttpClient HttpClient + { + get + { + var client = httpClientFactory.CreateClient(); + client.DefaultRequestHeaders.Clear(); + return client; + } + } public async Task SendAcceptActivityAsync( Guid publisherId, @@ -27,17 +36,17 @@ public class ActivityPubDeliveryService( var publisher = await db.Publishers.FindAsync(publisherId); if (publisher == null) return false; - + var actorUrl = $"https://{Domain}/activitypub/actors/{publisher.Name}"; var followerActor = await db.FediverseActors .FirstOrDefaultAsync(a => a.Uri == followerActorUri); - + if (followerActor?.InboxUri == null) { logger.LogWarning("Follower actor or inbox not found: {Uri}", followerActorUri); return false; } - + var activity = new Dictionary { ["@context"] = "https://www.w3.org/ns/activitystreams", @@ -46,7 +55,7 @@ public class ActivityPubDeliveryService( ["actor"] = actorUrl, ["object"] = followActivityId }; - + return await SendActivityToInboxAsync(activity, followerActor.InboxUri, actorUrl); } @@ -58,17 +67,17 @@ public class ActivityPubDeliveryService( var publisher = await db.Publishers.FindAsync(publisherId); if (publisher == null) return false; - + var actorUrl = $"https://{Domain}/activitypub/actors/{publisher.Name}"; var targetActor = await GetOrFetchActorAsync(targetActorUri); var localActor = await GetOrCreateLocalActorAsync(publisher); - + if (targetActor?.InboxUri == null || localActor == null) { logger.LogWarning("Target actor or inbox not found: {Uri}", targetActorUri); return false; } - + var activity = new Dictionary { ["@context"] = "https://www.w3.org/ns/activitystreams", @@ -77,7 +86,7 @@ public class ActivityPubDeliveryService( ["actor"] = actorUrl, ["object"] = targetActorUri }; - + await db.FediverseRelationships.AddAsync(new SnFediverseRelationship { IsLocalActor = true, @@ -88,9 +97,9 @@ public class ActivityPubDeliveryService( IsFollowing = true, IsFollowedBy = false }); - + await db.SaveChangesAsync(); - + return await SendActivityToInboxAsync(activity, targetActor.InboxUri, actorUrl); } @@ -99,10 +108,10 @@ public class ActivityPubDeliveryService( var publisher = await db.Publishers.FindAsync(post.PublisherId); if (publisher == null) return false; - + var actorUrl = $"https://{Domain}/activitypub/actors/{publisher.Name}"; var postUrl = $"https://{Domain}/posts/{post.Id}"; - + var activity = new Dictionary { ["@context"] = "https://www.w3.org/ns/activitystreams", @@ -129,23 +138,21 @@ public class ActivityPubDeliveryService( }).ToList() } }; - + var followers = await GetRemoteFollowersAsync(publisher.Id); var successCount = 0; - + foreach (var follower in followers) { - if (follower.InboxUri != null) - { - var success = await SendActivityToInboxAsync(activity, follower.InboxUri, actorUrl); - if (success) - successCount++; - } + if (follower.InboxUri == null) continue; + var success = await SendActivityToInboxAsync(activity, follower.InboxUri, actorUrl); + if (success) + successCount++; } - - logger.LogInformation("Sent Create activity to {Count}/{Total} followers", + + logger.LogInformation("Sent Create activity to {Count}/{Total} followers", successCount, followers.Count); - + return successCount > 0; } @@ -159,17 +166,17 @@ public class ActivityPubDeliveryService( .Include(p => p.Members) .Where(p => p.Members.Any(m => m.AccountId == accountId)) .FirstOrDefaultAsync(); - + if (publisher == null) return false; - + var actorUrl = $"https://{Domain}/activitypub/actors/{publisher.Name}"; var postUrl = $"https://{Domain}/posts/{postId}"; var targetActor = await GetOrFetchActorAsync(targetActorUri); - + if (targetActor?.InboxUri == null) return false; - + var activity = new Dictionary { ["@context"] = "https://www.w3.org/ns/activitystreams", @@ -178,7 +185,7 @@ public class ActivityPubDeliveryService( ["actor"] = actorUrl, ["object"] = postUrl }; - + return await SendActivityToInboxAsync(activity, targetActor.InboxUri, actorUrl); } @@ -191,10 +198,10 @@ public class ActivityPubDeliveryService( var publisher = await db.Publishers.FindAsync(publisherId); if (publisher == null) return false; - + var actorUrl = $"https://{Domain}/activitypub/actors/{publisher.Name}"; var followers = await GetRemoteFollowersAsync(publisher.Id); - + var activity = new Dictionary { ["@context"] = "https://www.w3.org/ns/activitystreams", @@ -207,7 +214,7 @@ public class ActivityPubDeliveryService( ["object"] = objectUri } }; - + var successCount = 0; foreach (var follower in followers) { @@ -218,7 +225,7 @@ public class ActivityPubDeliveryService( successCount++; } } - + return successCount > 0; } @@ -232,48 +239,45 @@ public class ActivityPubDeliveryService( { var json = JsonSerializer.Serialize(activity); var request = new HttpRequestMessage(HttpMethod.Post, inboxUrl); - + request.Content = new StringContent(json, Encoding.UTF8, "application/activity+json"); request.Headers.Date = DateTimeOffset.UtcNow; - + var bodyBytes = Encoding.UTF8.GetBytes(json); - using var sha256 = SHA256.Create(); - var hash = sha256.ComputeHash(bodyBytes); + var hash = SHA256.HashData(bodyBytes); var digest = $"SHA-256={Convert.ToBase64String(hash)}"; request.Headers.Add("Digest", digest); - request.Headers.Add("Host", new Uri(inboxUrl).Host); - + request.Headers.Host = new Uri(inboxUrl).Host; + logger.LogInformation("Preparing request to {Inbox}", inboxUrl); - logger.LogInformation("Request body (truncated): {Body}", json.Substring(0, Math.Min(200, json.Length)) + "..."); - logger.LogInformation("Request headers before signing: Date={Date}, Digest={Digest}, Host={Host}", + logger.LogInformation("Request body (truncated): {Body}", json[..Math.Min(200, json.Length)] + "..."); + logger.LogInformation("Request headers before signing: Date={Date}, Digest={Digest}, Host={Host}", request.Headers.Date, digest, request.Headers.Host); - + var signatureHeaders = await signatureService.SignOutgoingRequest(request, actorUri); var signatureString = $"keyId=\"{signatureHeaders["keyId"]}\"," + $"algorithm=\"{signatureHeaders["algorithm"]}\"," + $"headers=\"{signatureHeaders["headers"]}\"," + $"signature=\"{signatureHeaders["signature"]}\""; - + request.Headers.Add("Signature", signatureString); - + logger.LogInformation("Full signature header: {Signature}", signatureString); logger.LogInformation("Request headers after signing:"); foreach (var header in request.Headers) { var value = header.Value.Any() ? header.Value.First() : string.Empty; if (header.Key == "signature") - { - value = value.Substring(0, Math.Min(100, value.Length)) + "..."; - } + value = value[..Math.Min(100, value.Length)] + "..."; logger.LogInformation(" {Key}: {Value}", header.Key, value); } - + var response = await HttpClient.SendAsync(request); var responseContent = await response.Content.ReadAsStringAsync(); - + logger.LogInformation("Response from {Inbox}. Status: {Status}", inboxUrl, response.StatusCode); - + if (!response.IsSuccessStatusCode) { logger.LogError("Failed to send activity to {Inbox}. Status: {Status}, Response: {Response}", @@ -282,7 +286,7 @@ public class ActivityPubDeliveryService( request.Method, request.RequestUri, request.Content?.Headers.ContentType); return false; } - + logger.LogInformation("Successfully sent activity to {Inbox}", inboxUrl); return true; } @@ -297,9 +301,9 @@ public class ActivityPubDeliveryService( { return await db.FediverseRelationships .Include(r => r.TargetActor) - .Where(r => - r.LocalPublisherId == publisherId && - r.IsFollowedBy && + .Where(r => + r.LocalPublisherId == publisherId && + r.IsFollowedBy && r.IsLocalActor) .Select(r => r.TargetActor) .ToListAsync(); @@ -308,16 +312,16 @@ public class ActivityPubDeliveryService( private async Task GetOrCreateLocalActorAsync(SnPublisher publisher) { var actorUrl = $"https://{Domain}/activitypub/actors/{publisher.Name}"; - + var localActor = await db.FediverseActors .FirstOrDefaultAsync(a => a.Uri == actorUrl); - + if (localActor != null) return localActor; - + var instance = await db.FediverseInstances .FirstOrDefaultAsync(i => i.Domain == Domain); - + if (instance == null) { instance = new SnFediverseInstance @@ -330,7 +334,7 @@ public class ActivityPubDeliveryService( } var assetsBaseUrl = configuration["ActivityPub:FileBaseUrl"] ?? $"https://{Domain}/files"; - + localActor = new SnFediverseActor { Uri = actorUrl, @@ -345,10 +349,10 @@ public class ActivityPubDeliveryService( HeaderUrl = publisher.Background != null ? $"{assetsBaseUrl}/{publisher.Background.Id}" : null, InstanceId = instance.Id }; - + db.FediverseActors.Add(localActor); await db.SaveChangesAsync(); - + return localActor; } @@ -356,26 +360,26 @@ public class ActivityPubDeliveryService( { var actor = await db.FediverseActors .FirstOrDefaultAsync(a => a.Uri == actorUri); - + if (actor != null) return actor; - + try { var response = await HttpClient.GetAsync(actorUri); if (!response.IsSuccessStatusCode) return null; - + var json = await response.Content.ReadAsStringAsync(); var actorData = JsonSerializer.Deserialize>(json); - + if (actorData == null) return null; - + var domain = new Uri(actorUri).Host; var instance = await db.FediverseInstances .FirstOrDefaultAsync(i => i.Domain == domain); - + if (instance == null) { instance = new SnFediverseInstance @@ -387,7 +391,7 @@ public class ActivityPubDeliveryService( await db.SaveChangesAsync(); await discoveryService.FetchInstanceMetadataAsync(instance); } - + actor = new SnFediverseActor { Uri = actorUri, @@ -401,10 +405,10 @@ public class ActivityPubDeliveryService( AvatarUrl = actorData.GetValueOrDefault("icon")?.ToString(), InstanceId = instance.Id }; - + db.FediverseActors.Add(actor); await db.SaveChangesAsync(); - + return actor; } catch (Exception ex) @@ -418,4 +422,4 @@ public class ActivityPubDeliveryService( { return actorUri.Split('/').Last(); } -} +} \ No newline at end of file diff --git a/DysonNetwork.Sphere/ActivityPub/ActivityPubSignatureService.cs b/DysonNetwork.Sphere/ActivityPub/ActivityPubSignatureService.cs index ba18b42..1c1010f 100644 --- a/DysonNetwork.Sphere/ActivityPub/ActivityPubSignatureService.cs +++ b/DysonNetwork.Sphere/ActivityPub/ActivityPubSignatureService.cs @@ -1,8 +1,5 @@ -using System.Security.Cryptography; using System.Text; using DysonNetwork.Shared.Models; -using DysonNetwork.Sphere.ActivityPub; -using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using NodaTime; @@ -105,7 +102,7 @@ public class ActivityPubSignatureService( logger.LogInformation("Signing outgoing request. ActorUri: {ActorUri}, PublisherId: {PublisherId}", actorUri, publisher.Id); - var headersToSign = new[] { "(request-target)", "host", "date", "digest" }; + var headersToSign = new[] { RequestTarget, "host", "date", "digest" }; var signingString = BuildSigningStringForRequest(request, headersToSign); logger.LogInformation("Signing string for outgoing request: {SigningString}", signingString); @@ -215,7 +212,7 @@ public class ActivityPubSignatureService( sb.Append(header.ToLower()); sb.Append(": "); - if (header == "(request-target)") + if (header == RequestTarget) { var method = context.Request.Method.ToLower(); var path = context.Request.Path.Value ?? ""; @@ -244,56 +241,51 @@ public class ActivityPubSignatureService( foreach (var header in headers) { if (sb.Length > 0) - sb.Append("\n"); + sb.Append('\n'); sb.Append(header.ToLower()); sb.Append(": "); - if (header == "(request-target)") + switch (header) { - var method = request.Method.Method.ToLower(); - var path = request.RequestUri?.PathAndQuery ?? "/"; - sb.Append($"{method} {path}"); - logger.LogInformation(" (request-target): {Value}", $"{method} {path}"); - } - else if (header == "host") - { - if (request.Headers.Contains("Host")) + case RequestTarget: + { + var method = request.Method.Method.ToLower(); + var path = request.RequestUri?.PathAndQuery ?? "/"; + sb.Append($"{method} {path}"); + logger.LogInformation(" {Key}: {Value}", RequestTarget, $"{method} {path}"); + break; + } + case "host" when request.Headers.Contains("Host"): { var value = request.Headers.GetValues("Host").First(); sb.Append(value); logger.LogInformation(" host: {Value}", value); + break; } - else - { + case "host": logger.LogWarning("Host header not found in request"); - } - } - else if (header == "date") - { - if (request.Headers.Contains("Date")) + break; + case "date" when request.Headers.Contains("Date"): { var value = request.Headers.GetValues("Date").First(); sb.Append(value); logger.LogInformation(" date: {Value}", value); + break; } - else - { + case "date": logger.LogWarning("Date header not found in request"); - } - } - else if (header == "digest") - { - if (request.Headers.Contains("Digest")) + break; + case "digest" when request.Headers.Contains("Digest"): { var value = request.Headers.GetValues("Digest").First(); sb.Append(value); logger.LogInformation(" digest: {Value}", value); + break; } - else - { + case "digest": logger.LogWarning("Digest header not found in request"); - } + break; } } diff --git a/DysonNetwork.sln.DotSettings.user b/DysonNetwork.sln.DotSettings.user index 16bf3b6..05654e4 100644 --- a/DysonNetwork.sln.DotSettings.user +++ b/DysonNetwork.sln.DotSettings.user @@ -68,6 +68,7 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded