1- using System . Net . Http . Headers ;
2- using System . Net . Http . Json ;
31using System . Text . Json ;
4- using Broca . ActivityPub . Client . Services ;
52using Broca . ActivityPub . Core . Interfaces ;
63using Broca . ActivityPub . Core . Models ;
74using Broca . ActivityPub . Server . Services ;
@@ -21,10 +18,8 @@ public class InboxController : ActivityPubControllerBase
2118 private readonly IInboxHandler _inboxHandler ;
2219 private readonly IActivityRepository _activityRepository ;
2320 private readonly IActorRepository _actorRepository ;
24- private readonly HttpSignatureService _signatureService ;
25- private readonly IActivityPubClient _activityPubClient ;
26- private readonly ISystemIdentityService _systemIdentityService ;
27- private readonly IHttpClientFactory _httpClientFactory ;
21+ private readonly IHttpSignatureVerifier _signatureVerifier ;
22+ private readonly SignedClientProvider _signedClientProvider ;
2823 private readonly AttachmentProcessingService _attachmentProcessingService ;
2924 private readonly ObjectEnrichmentService _enrichmentService ;
3025 private readonly IMemoryCache _cache ;
@@ -37,10 +32,8 @@ public InboxController(
3732 IInboxHandler inboxHandler ,
3833 IActivityRepository activityRepository ,
3934 IActorRepository actorRepository ,
40- HttpSignatureService signatureService ,
41- IActivityPubClient activityPubClient ,
42- ISystemIdentityService systemIdentityService ,
43- IHttpClientFactory httpClientFactory ,
35+ IHttpSignatureVerifier signatureVerifier ,
36+ SignedClientProvider signedClientProvider ,
4437 AttachmentProcessingService attachmentProcessingService ,
4538 ObjectEnrichmentService enrichmentService ,
4639 IMemoryCache cache ,
@@ -50,10 +43,8 @@ public InboxController(
5043 _inboxHandler = inboxHandler ;
5144 _activityRepository = activityRepository ;
5245 _actorRepository = actorRepository ;
53- _signatureService = signatureService ;
54- _activityPubClient = activityPubClient ;
55- _systemIdentityService = systemIdentityService ;
56- _httpClientFactory = httpClientFactory ;
46+ _signatureVerifier = signatureVerifier ;
47+ _signedClientProvider = signedClientProvider ;
5748 _attachmentProcessingService = attachmentProcessingService ;
5849 _enrichmentService = enrichmentService ;
5950 _cache = cache ;
@@ -233,7 +224,6 @@ private async Task<bool> VerifySignatureAsync(string body, CancellationToken can
233224 _logger . LogDebug ( "Starting signature verification. Request headers: {Headers}" ,
234225 string . Join ( ", " , Request . Headers . Keys ) ) ;
235226
236- // Get Signature header
237227 if ( ! Request . Headers . TryGetValue ( "Signature" , out var signatureHeader ) || string . IsNullOrEmpty ( signatureHeader ) )
238228 {
239229 _logger . LogWarning ( "Signature header is missing from request" ) ;
@@ -242,20 +232,11 @@ private async Task<bool> VerifySignatureAsync(string body, CancellationToken can
242232
243233 _logger . LogDebug ( "Signature header found: {SignatureHeader}" , signatureHeader ! ) ;
244234
245- // Parse the signature to see what headers it expects
246- var signatureParts = _signatureService . ParseSignatureParts ( signatureHeader ! ) ;
247- if ( signatureParts . TryGetValue ( "headers" , out var headersInSignature ) )
248- {
249- _logger . LogInformation ( "Signature expects these headers to be signed: {SignedHeaders}" , headersInSignature ) ;
250- }
251-
252- // Extract keyId from signature
253- var keyId = _signatureService . GetSignatureKeyId ( signatureHeader ! ) ;
235+ var keyId = _signatureVerifier . GetSignatureKeyId ( signatureHeader ! ) ;
254236 _logger . LogInformation ( "Extracted keyId from signature: {KeyId}" , keyId ) ;
255237
256238 ValidateRequestClockSkew ( Request ) ;
257239
258- // Fetch the actor's public key
259240 var publicKeyPem = await FetchActorPublicKeyAsync ( keyId , cancellationToken ) ;
260241
261242 if ( string . IsNullOrWhiteSpace ( publicKeyPem ) )
@@ -266,62 +247,39 @@ private async Task<bool> VerifySignatureAsync(string body, CancellationToken can
266247
267248 _logger . LogDebug ( "Successfully fetched public key for keyId: {KeyId}" , keyId ) ;
268249
269- // Build headers dictionary for verification
270250 var headers = new Dictionary < string , string > ( ) ;
271-
272- // Add the Signature header itself (required for verification)
273251 headers [ "signature" ] = signatureHeader ! ;
274-
275- // Add (request-target) pseudo-header
276- var requestTarget = $ "{ Request . Method . ToLower ( ) } { Request . Path } ";
277- headers [ "(request-target)" ] = requestTarget ;
252+ headers [ "(request-target)" ] = $ "{ Request . Method . ToLower ( ) } { Request . Path } ";
278253
279- // Add all headers from the request (lowercase keys)
280- // The verification service will use only the ones that are part of the signature
281254 foreach ( var header in Request . Headers )
282255 {
283256 var headerName = header . Key . ToLower ( ) ;
284- // Don't duplicate the signature header
285257 if ( headerName != "signature" )
286- {
287258 headers [ headerName ] = header . Value . ToString ( ) ;
288- }
289259 }
290260
291261 _logger . LogDebug ( "Headers being verified: {Headers}" ,
292262 string . Join ( ", " , headers . Select ( h => $ "\" { h . Key } \" ") ) ) ;
293263
294- // Validate Digest header for POST requests (required per ActivityPub spec)
295264 if ( Request . Method . Equals ( "POST" , StringComparison . OrdinalIgnoreCase ) )
296265 {
297266 if ( ! Request . Headers . TryGetValue ( "Digest" , out var digestHeader ) )
298267 {
299268 _logger . LogWarning ( "POST request missing Digest header" ) ;
300- // Some implementations may not send Digest, log but don't fail
301269 }
302270 else
303271 {
304- // Verify the digest matches the body
305272 var bodyBytes = System . Text . Encoding . UTF8 . GetBytes ( body ) ;
306- var expectedDigest = _signatureService . ComputeContentDigestHash ( bodyBytes ) ;
307- var digestValue = digestHeader . ToString ( ) ;
308-
309- if ( digestValue . StartsWith ( "SHA-256=" ) )
273+ if ( ! _signatureVerifier . VerifyDigest ( bodyBytes , digestHeader . ToString ( ) ) )
310274 {
311- var providedDigest = digestValue . Substring ( 8 ) ;
312- if ( providedDigest != expectedDigest )
313- {
314- _logger . LogWarning ( "Digest header mismatch. Expected: {Expected}, Got: {Got}" ,
315- expectedDigest , providedDigest ) ;
316- throw new InvalidOperationException ( "Digest header does not match request body" ) ;
317- }
275+ _logger . LogWarning ( "Digest header mismatch for inbox request to keyId: {KeyId}" , keyId ) ;
276+ throw new InvalidOperationException ( "Digest header does not match request body" ) ;
318277 }
319278 }
320279 }
321280
322- // Verify the signature
323- _logger . LogDebug ( "Calling HttpSignatureService.VerifyHttpSignatureAsync with {HeaderCount} headers" , headers . Count ) ;
324- var result = await _signatureService . VerifyHttpSignatureAsync ( headers , publicKeyPem , cancellationToken ) ;
281+ _logger . LogDebug ( "Calling IHttpSignatureVerifier.VerifyAsync with {HeaderCount} headers" , headers . Count ) ;
282+ var result = await _signatureVerifier . VerifyAsync ( headers , publicKeyPem , cancellationToken ) ;
325283 _logger . LogDebug ( "Signature verification result: {Result}" , result ) ;
326284 return result ;
327285 }
@@ -422,21 +380,8 @@ private async Task<bool> VerifySignatureAsync(string body, CancellationToken can
422380 {
423381 try
424382 {
425- var systemActor = await _systemIdentityService . GetSystemActorAsync ( cancellationToken ) ;
426- var privateKey = await _systemIdentityService . GetSystemPrivateKeyAsync ( cancellationToken ) ;
427- var publicKeyId = $ "{ systemActor . Id } #main-key";
428-
429- using var httpClient = _httpClientFactory . CreateClient ( "ActivityPub" ) ;
430- using var response = await _signatureService . SendSignedGetAsync (
431- httpClient , new Uri ( actorUrl ) , publicKeyId , privateKey , cancellationToken ) ;
432-
433- if ( ! response . IsSuccessStatusCode )
434- {
435- _logger . LogWarning ( "Signed GET for actor {ActorUrl} failed with status {StatusCode}" , actorUrl , response . StatusCode ) ;
436- return null ;
437- }
438-
439- return await response . Content . ReadFromJsonAsync < Actor > ( _jsonOptions , cancellationToken ) ;
383+ var client = await _signedClientProvider . CreateForSystemActorAsync ( cancellationToken ) ;
384+ return await client . GetActorAsync ( new Uri ( actorUrl ) , cancellationToken ) ;
440385 }
441386 catch ( Exception ex )
442387 {
0 commit comments