diff --git a/CHANGES.md b/CHANGES.md index d3d89eb01..aecea796d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,16 @@ Version 2.0.21 To be released. +### @fedify/fedify + + - Fixed outbound activity delivery aborting when Linked Data Signature + creation fails during JSON-LD canonicalization. Fedify now logs the + signing failure and continues delivery without the Linked Data Signature + for JSON-LD processing failures, while still surfacing key, configuration, + and programming errors from signing. [[#824]] + +[#824]: https://github.com/fedify-dev/fedify/issues/824 + Version 2.0.20 -------------- diff --git a/packages/fedify/src/federation/middleware.ts b/packages/fedify/src/federation/middleware.ts index 845bff1d9..00c113fd0 100644 --- a/packages/fedify/src/federation/middleware.ts +++ b/packages/fedify/src/federation/middleware.ts @@ -180,6 +180,41 @@ function isPermanentInboxParseError(error: unknown): error is Error { isInvalidUrlTypeError(error))); } +type LinkedDataSignatureJsonLdProcessingError = Error & { + details?: { code?: unknown; cause?: unknown }; + cause?: unknown; +}; + +function hasLinkedDataSignatureJsonLdProcessingError( + error: LinkedDataSignatureJsonLdProcessingError, +): boolean { + if ( + error.message.startsWith("Maximum deep iterations exceeded") + ) { + return true; + } + const cause = error.cause instanceof Error + ? error.cause + : error.details?.cause; + if ( + error.name === "jsonld.InvalidUrl" && + error.details?.code === "loading remote context failed" && + cause instanceof Error + ) { + return ( + cause.message.startsWith("Maximum deep iterations exceeded") + ) || cause.name.startsWith("jsonld."); + } + return error.name !== "jsonld.InvalidUrl" && error.name.startsWith("jsonld."); +} + +function isLinkedDataSignatureJsonLdProcessingError( + error: unknown, +): error is LinkedDataSignatureJsonLdProcessingError { + return error instanceof Error && + hasLinkedDataSignatureJsonLdProcessingError(error); +} + /** * Options for {@link createFederation} function. * @template TContextData The type of the context data. @@ -1325,10 +1360,20 @@ export class FederationImpl }, ); } else { - jsonLd = await signJsonLd(jsonLd, rsaKey.privateKey, rsaKey.keyId, { - contextLoader, - tracerProvider: this.tracerProvider, - }); + try { + jsonLd = await signJsonLd(jsonLd, rsaKey.privateKey, rsaKey.keyId, { + contextLoader, + tracerProvider: this.tracerProvider, + }); + } catch (error) { + if (!isLinkedDataSignatureJsonLdProcessingError(error)) throw error; + logger.warn( + "Failed to create a Linked Data signature for the activity " + + "{activityId}. The activity will be sent without a Linked " + + "Data signature.", + { activityId, error }, + ); + } } if (!proofCreated) { logger.warn(