🐛 Better override host

This commit is contained in:
2025-12-30 00:08:04 +08:00
parent db94b21aef
commit 70260967be
3 changed files with 100 additions and 103 deletions

View File

@@ -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<bool> 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<string, object>
{
["@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<string, object>
{
["@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<string, object>
{
["@context"] = "https://www.w3.org/ns/activitystreams",
@@ -129,23 +138,21 @@ public class ActivityPubDeliveryService(
}).ToList<object>()
}
};
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<string, object>
{
["@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<string, object>
{
["@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<SnFediverseActor?> 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<Dictionary<string, object>>(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();
}
}
}