♻️ Update verify signature code in ap
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user