♻️ Update verify signature code in ap

This commit is contained in:
2025-12-30 19:17:22 +08:00
parent 30cbbf0139
commit f42fc1da1c
3 changed files with 84 additions and 15 deletions

View File

@@ -465,6 +465,8 @@ public class ActivityPubActivityProcessor(
}; };
db.FediverseActors.Add(actor); db.FediverseActors.Add(actor);
await db.SaveChangesAsync(); await db.SaveChangesAsync();
await discoveryService.FetchActorDataAsync(actor);
} }
return actor; return actor;

View File

@@ -38,16 +38,24 @@ public class ActivityPubKeyService(ILogger<ActivityPubKeyService> logger)
{ {
using var rsa = CreateRsaFromPublicKeyPem(publicKeyPem); using var rsa = CreateRsaFromPublicKeyPem(publicKeyPem);
var signature = Convert.FromBase64String(signatureBase64); var signature = Convert.FromBase64String(signatureBase64);
return rsa.VerifyData(
logger.LogDebug("Attempting signature verification. Key starts with: {KeyStart}",
publicKeyPem.Substring(0, Math.Min(50, publicKeyPem.Length)));
var result = rsa.VerifyData(
Encoding.UTF8.GetBytes(data), Encoding.UTF8.GetBytes(data),
signature, signature,
HashAlgorithmName.SHA256, HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1 RSASignaturePadding.Pkcs1
); );
logger.LogDebug("Signature verification result: {Result}", result);
return result;
} }
catch (Exception ex) catch (Exception ex)
{ {
logger.LogError(ex, "Failed to verify signature"); logger.LogError(ex, "Failed to verify signature. KeyLength: {KeyLength}, DataLength: {DataLength}, SignatureLength: {SigLength}",
publicKeyPem.Length, data.Length, signatureBase64.Length);
return false; return false;
} }
} }
@@ -84,7 +92,17 @@ public class ActivityPubKeyService(ILogger<ActivityPubKeyService> logger)
.ToArray(); .ToArray();
var keyBytes = Convert.FromBase64String(string.Join("", lines)); var keyBytes = Convert.FromBase64String(string.Join("", lines));
rsa.ImportRSAPublicKey(keyBytes, out _);
var isRsaPublicKey = publicKeyPem.Contains("-----BEGIN RSA PUBLIC KEY-----");
if (isRsaPublicKey)
{
rsa.ImportRSAPublicKey(keyBytes, out _);
}
else
{
rsa.ImportSubjectPublicKeyInfo(keyBytes, out _);
}
return rsa; return rsa;
} }

View File

@@ -1,4 +1,5 @@
using System.Text; using System.Text;
using DysonNetwork.Shared.Cache;
using DysonNetwork.Shared.Models; using DysonNetwork.Shared.Models;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NodaTime; using NodaTime;
@@ -8,11 +9,14 @@ namespace DysonNetwork.Sphere.ActivityPub;
public class ActivityPubSignatureService( public class ActivityPubSignatureService(
AppDatabase db, AppDatabase db,
ActivityPubKeyService keyService, ActivityPubKeyService keyService,
ActivityPubDiscoveryService discoveryService,
ICacheService cache,
ILogger<ActivityPubSignatureService> logger, ILogger<ActivityPubSignatureService> logger,
IConfiguration configuration IConfiguration configuration
) )
{ {
private const string RequestTarget = "(request-target)"; private const string RequestTarget = "(request-target)";
private const string PublicKeyCachePrefix = "ap:publickey:";
private string Domain => configuration["ActivityPub:Domain"] ?? "localhost"; private string Domain => configuration["ActivityPub:Domain"] ?? "localhost";
public bool VerifyIncomingRequest(HttpContext context, out string? actorUri) public bool VerifyIncomingRequest(HttpContext context, out string? actorUri)
@@ -47,16 +51,10 @@ public class ActivityPubSignatureService(
logger.LogInformation("Verifying signature for actor: {ActorUri}", actorUri); logger.LogInformation("Verifying signature for actor: {ActorUri}", actorUri);
var actor = GetActorByKeyId(actorUri); var publicKey = GetOrFetchPublicKeyAsync(actorUri).GetAwaiter().GetResult();
if (actor == null) if (string.IsNullOrEmpty(publicKey))
{ {
logger.LogWarning("Actor not found for keyId: {KeyId}", actorUri); logger.LogWarning("Could not fetch public key for actor: {ActorUri}", actorUri);
return false;
}
if (string.IsNullOrEmpty(actor.PublicKey))
{
logger.LogWarning("Actor has no public key. ActorId: {ActorId}, Uri: {Uri}", actor.Id, actor.Uri);
return false; return false;
} }
@@ -72,7 +70,7 @@ public class ActivityPubSignatureService(
return false; return false;
} }
var isValid = keyService.Verify(actor.PublicKey, signingString, signature); var isValid = keyService.Verify(publicKey, signingString, signature);
if (!isValid) if (!isValid)
{ {
@@ -120,10 +118,61 @@ public class ActivityPubSignatureService(
}; };
} }
private SnFediverseActor? GetActorByKeyId(string keyId) private async Task<string?> GetOrFetchPublicKeyAsync(string keyId)
{ {
var actorUri = keyId.Split('#')[0]; var actorUri = keyId.Split('#')[0];
return db.FediverseActors.FirstOrDefault(a => a.Uri == actorUri); var cacheKey = $"{PublicKeyCachePrefix}{actorUri}";
var cachedKey = await cache.GetAsync<string>(cacheKey);
if (!string.IsNullOrEmpty(cachedKey))
{
logger.LogInformation("Using cached public key for actor: {ActorUri}", actorUri);
return cachedKey;
}
var actor = db.FediverseActors.FirstOrDefault(a => a.Uri == actorUri);
if (actor == null)
{
var instance = await db.FediverseInstances.FirstOrDefaultAsync(i => i.Domain == new Uri(actorUri).Host);
if (instance == null)
{
instance = new SnFediverseInstance
{
Domain = new Uri(actorUri).Host,
Name = new Uri(actorUri).Host
};
db.FediverseInstances.Add(instance);
await db.SaveChangesAsync();
}
actor = new SnFediverseActor
{
Uri = actorUri,
Username = actorUri.Split('/').Last(),
DisplayName = actorUri.Split('/').Last(),
InstanceId = instance.Id
};
db.FediverseActors.Add(actor);
await db.SaveChangesAsync();
await discoveryService.FetchActorDataAsync(actor);
}
else if (string.IsNullOrEmpty(actor.PublicKey))
{
await discoveryService.FetchActorDataAsync(actor);
}
if (string.IsNullOrEmpty(actor.PublicKey))
{
logger.LogWarning("Still no public key after fetch for actor: {ActorUri}", actorUri);
return null;
}
await cache.SetAsync(cacheKey, actor.PublicKey, TimeSpan.FromHours(24));
logger.LogInformation("Cached public key for actor: {ActorUri}", actorUri);
return actor.PublicKey;
} }
private async Task<SnPublisher?> GetPublisherByActorUri(string actorUri) private async Task<SnPublisher?> GetPublisherByActorUri(string actorUri)