Is your feature request related to a problem? Please describe...
Summary
SignedXml has a natural template-method shape — computeSignature calls createSignedInfo, which calls createReferences, which calls getCanonReferenceXml, which calls the (public) getCanonXml; separately computeSignature calls getKeyInfo and createSignature. In v6 every one of those intermediate methods is declared private, which makes the class impossible to subclass cleanly in strict TypeScript: any override triggers TS4114 (must have 'override' modifier) and adding override triggers TS2415 (private in base class). The only way to keep the subclass compiling is @ts-expect-error or an intersection-type cast — both of which sidestep type safety rather than express the design.
The proposed change is a one-line-per-method visibility change from private to protected on the methods that participate in the template. No behavior change; consumers who don't subclass see no difference. Consumers who do subclass can now express legitimate customizations in typed code.
Motivating cases
-
Pretty-printing / spec-mandated formatting of SignedInfo and its children. Post-processing the emitted signature to reformat <SignedInfo> isn't safe — non-exclusive C14N preserves inter-element whitespace as text nodes, so any post-hoc reformat changes the canonical form and invalidates the already-computed SignatureValue. The only correct place to intervene is inside the same chain that produces the pre-canonicalization string, which today means overriding createSignedInfo (private) or createReferences (private).
-
Reference-emission customization. Some SMPTE standards require that Reference elements not contain a <Transforms> child at all. The digest still has to be computed under C14N; only the emission changes. Doing this cleanly needs a createReferences override, which is currently blocked.
-
Custom getKeyInfo output (e.g. emitting a full X.509 certificate chain rather than a single cert) — the getKeyInfoContent callback covers the content, but a subclass that wants to alter attribute ordering, whitespace, or attach Id attributes to the outer <KeyInfo> element needs the wrapping method.
-
Repro-friendly algorithm lookups in tests. The findSignatureAlgorithm / findCanonicalizationAlgorithm / findHashAlgorithm helpers are the natural stub points for deterministic tests of subclass logic; keeping them private forces test subclasses into the same visibility gymnastics.
Describe teh solution you'd like...
Concrete ask
Change visibility from private to protected on the following methods in src/signed-xml.ts (line numbers from v6.1.2):
| Method |
Line |
Role |
getCanonSignedInfoXml |
383 |
Called by calculateSignatureValue; entry point for SignedInfo C14N |
getCanonReferenceXml |
425 |
Per-reference C14N; entry point for reference digest computation |
calculateSignatureValue |
441 |
Signature computation; useful for algorithm-injection subclasses |
findSignatureAlgorithm |
454 |
Algorithm lookup |
findCanonicalizationAlgorithm |
466 |
Algorithm lookup |
findHashAlgorithm |
477 |
Algorithm lookup |
loadReference |
699 |
Per-reference load during verify; parallel to createReferences |
getKeyInfo |
1055 |
Emits the <KeyInfo> wrapper |
createReferences |
1077 |
Emits <Reference> elements |
ensureHasId |
1163 |
Id-attribute placement |
createSignedInfo |
1208 |
Emits <SignedInfo> |
createSignature |
1243 |
Emits the wrapping <Signature> element |
The state fields those methods touch (this.signatureNode, this.references, this.signatureValue, etc.) can stay private — subclasses that need them can be added incrementally.
Compatibility
private → protected is a source-compatible widening. Existing consumers that don't subclass are unaffected. Existing subclasses (if any) that were already relying on TypeScript workarounds can drop those workarounds. The compiled JavaScript is byte-identical.
Related
Describe the alternatives you've considered...
Forking the type declarations -- ugh.
Is your feature request related to a problem? Please describe...
Summary
SignedXmlhas a natural template-method shape —computeSignaturecallscreateSignedInfo, which callscreateReferences, which callsgetCanonReferenceXml, which calls the (public)getCanonXml; separatelycomputeSignaturecallsgetKeyInfoandcreateSignature. In v6 every one of those intermediate methods is declaredprivate, which makes the class impossible to subclass cleanly in strict TypeScript: any override triggers TS4114 (must have 'override' modifier) and addingoverridetriggers TS2415 (private in base class). The only way to keep the subclass compiling is@ts-expect-erroror an intersection-type cast — both of which sidestep type safety rather than express the design.The proposed change is a one-line-per-method visibility change from
privatetoprotectedon the methods that participate in the template. No behavior change; consumers who don't subclass see no difference. Consumers who do subclass can now express legitimate customizations in typed code.Motivating cases
Pretty-printing / spec-mandated formatting of
SignedInfoand its children. Post-processing the emitted signature to reformat<SignedInfo>isn't safe — non-exclusive C14N preserves inter-element whitespace as text nodes, so any post-hoc reformat changes the canonical form and invalidates the already-computedSignatureValue. The only correct place to intervene is inside the same chain that produces the pre-canonicalization string, which today means overridingcreateSignedInfo(private) orcreateReferences(private).Reference-emission customization. Some SMPTE standards require that Reference elements not contain a
<Transforms>child at all. The digest still has to be computed under C14N; only the emission changes. Doing this cleanly needs acreateReferencesoverride, which is currently blocked.Custom
getKeyInfooutput (e.g. emitting a full X.509 certificate chain rather than a single cert) — thegetKeyInfoContentcallback covers the content, but a subclass that wants to alter attribute ordering, whitespace, or attachIdattributes to the outer<KeyInfo>element needs the wrapping method.Repro-friendly algorithm lookups in tests. The
findSignatureAlgorithm/findCanonicalizationAlgorithm/findHashAlgorithmhelpers are the natural stub points for deterministic tests of subclass logic; keeping themprivateforces test subclasses into the same visibility gymnastics.Describe teh solution you'd like...
Concrete ask
Change visibility from
privatetoprotectedon the following methods insrc/signed-xml.ts(line numbers from v6.1.2):getCanonSignedInfoXmlcalculateSignatureValue; entry point for SignedInfo C14NgetCanonReferenceXmlcalculateSignatureValuefindSignatureAlgorithmfindCanonicalizationAlgorithmfindHashAlgorithmloadReferencecreateReferencesgetKeyInfo<KeyInfo>wrappercreateReferences<Reference>elementsensureHasIdcreateSignedInfo<SignedInfo>createSignature<Signature>elementThe state fields those methods touch (
this.signatureNode,this.references,this.signatureValue, etc.) can stayprivate— subclasses that need them can be added incrementally.Compatibility
private → protectedis a source-compatible widening. Existing consumers that don't subclass are unaffected. Existing subclasses (if any) that were already relying on TypeScript workarounds can drop those workarounds. The compiled JavaScript is byte-identical.Related
findNSPrefixreturns only the first xmlns declaration → duplicate default xmlns in non-exclusive C14N when subset declares anyxmlns:*#538 (findNSPrefixreturns only the firstxmlns[:*]attribute).Describe the alternatives you've considered...
Forking the type declarations -- ugh.