@ripwords/myinvois-client 0.0.9 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bun.lock +89 -132
- package/dist/0X-C4IRh_fJ.d.ts +211 -0
- package/dist/0X-C4IRh_fJ.d.ts.map +1 -0
- package/dist/0X-Yw7mZEro.d.cts +211 -0
- package/dist/0X-Yw7mZEro.d.cts.map +1 -0
- package/dist/1X-Brnls9Jh.d.ts +112 -0
- package/dist/1X-Brnls9Jh.d.ts.map +1 -0
- package/dist/1X-BwpSoT3o.d.cts +20 -0
- package/dist/1X-BwpSoT3o.d.cts.map +1 -0
- package/dist/1X-C-_KHV-Q.d.ts +20 -0
- package/dist/1X-C-_KHV-Q.d.ts.map +1 -0
- package/dist/1X-D_aUVsuM.d.cts +112 -0
- package/dist/1X-D_aUVsuM.d.cts.map +1 -0
- package/dist/2X-Bb6elyzV.d.cts +40 -0
- package/dist/2X-Bb6elyzV.d.cts.map +1 -0
- package/dist/2X-DkS1BoE5.d.ts +40 -0
- package/dist/2X-DkS1BoE5.d.ts.map +1 -0
- package/dist/2X-UdQcQW24.d.ts +140 -0
- package/dist/2X-UdQcQW24.d.ts.map +1 -0
- package/dist/2X-hClUyw26.d.cts +140 -0
- package/dist/2X-hClUyw26.d.cts.map +1 -0
- package/dist/3X-C7VFD-n-.d.cts +21 -0
- package/dist/3X-C7VFD-n-.d.cts.map +1 -0
- package/dist/3X-CLMESDvz.d.cts +62 -0
- package/dist/3X-CLMESDvz.d.cts.map +1 -0
- package/dist/3X-DFI-4RQQ.d.ts +21 -0
- package/dist/3X-DFI-4RQQ.d.ts.map +1 -0
- package/dist/3X-DVDyspgb.d.ts +62 -0
- package/dist/3X-DVDyspgb.d.ts.map +1 -0
- package/dist/4X-CIJ2JJ2w.d.ts +31 -0
- package/dist/4X-CIJ2JJ2w.d.ts.map +1 -0
- package/dist/4X-CUR8jlaZ.d.ts +265 -0
- package/dist/4X-CUR8jlaZ.d.ts.map +1 -0
- package/dist/4X-CvScPJTf.d.cts +265 -0
- package/dist/4X-CvScPJTf.d.cts.map +1 -0
- package/dist/4X-DIfvpU6V.d.cts +31 -0
- package/dist/4X-DIfvpU6V.d.cts.map +1 -0
- package/dist/5X-BOUxhadJ.d.cts +22 -0
- package/dist/5X-BOUxhadJ.d.cts.map +1 -0
- package/dist/5X-C6db432h.d.ts +77 -0
- package/dist/5X-C6db432h.d.ts.map +1 -0
- package/dist/5X-COsZHUaQ.d.ts +22 -0
- package/dist/5X-COsZHUaQ.d.ts.map +1 -0
- package/dist/5X-CkLu7Vyd.d.cts +77 -0
- package/dist/5X-CkLu7Vyd.d.cts.map +1 -0
- package/dist/6X-C_fFIcJC.d.ts +105 -0
- package/dist/6X-C_fFIcJC.d.ts.map +1 -0
- package/dist/6X-ClZDKOTC.d.ts +16 -0
- package/dist/6X-ClZDKOTC.d.ts.map +1 -0
- package/dist/6X-DE7RJeV6.d.cts +16 -0
- package/dist/6X-DE7RJeV6.d.cts.map +1 -0
- package/dist/6X-Mf32k1d0.d.cts +105 -0
- package/dist/6X-Mf32k1d0.d.cts.map +1 -0
- package/dist/7X-BZyesooz.d.ts +16 -0
- package/dist/7X-BZyesooz.d.ts.map +1 -0
- package/dist/7X-Chtd6B66.d.cts +16 -0
- package/dist/7X-Chtd6B66.d.cts.map +1 -0
- package/dist/7X-DoCUcp-J.d.cts +71 -0
- package/dist/7X-DoCUcp-J.d.cts.map +1 -0
- package/dist/7X-kot_VccM.d.ts +71 -0
- package/dist/7X-kot_VccM.d.ts.map +1 -0
- package/dist/8X-Df4DOBOe.d.ts +110 -0
- package/dist/8X-Df4DOBOe.d.ts.map +1 -0
- package/dist/8X-DkuKAkHz.d.ts +19 -0
- package/dist/8X-DkuKAkHz.d.ts.map +1 -0
- package/dist/8X-DqZyMvyV.d.cts +19 -0
- package/dist/8X-DqZyMvyV.d.cts.map +1 -0
- package/dist/8X-Dr9RunRw.d.cts +110 -0
- package/dist/8X-Dr9RunRw.d.cts.map +1 -0
- package/dist/9X-BDgifncF.d.ts +15 -0
- package/dist/9X-BDgifncF.d.ts.map +1 -0
- package/dist/9X-BaoZtjWF.d.cts +98 -0
- package/dist/9X-BaoZtjWF.d.cts.map +1 -0
- package/dist/9X-BcAb6Uso.d.cts +15 -0
- package/dist/9X-BcAb6Uso.d.cts.map +1 -0
- package/dist/9X-BhBWlgxG.d.ts +98 -0
- package/dist/9X-BhBWlgxG.d.ts.map +1 -0
- package/dist/AX-BY72FohC.d.cts +111 -0
- package/dist/AX-BY72FohC.d.cts.map +1 -0
- package/dist/AX-D6XHWdrY.d.ts +111 -0
- package/dist/AX-D6XHWdrY.d.ts.map +1 -0
- package/dist/BX-CA0OmrUZ.d.cts +115 -0
- package/dist/BX-CA0OmrUZ.d.cts.map +1 -0
- package/dist/BX-D_0C8Qbd.d.ts +115 -0
- package/dist/BX-D_0C8Qbd.d.ts.map +1 -0
- package/dist/CX-HH4cSZRX.d.ts +128 -0
- package/dist/CX-HH4cSZRX.d.ts.map +1 -0
- package/dist/CX-glpQSL8x.d.cts +128 -0
- package/dist/CX-glpQSL8x.d.cts.map +1 -0
- package/dist/DX-DimL1MDM.d.cts +115 -0
- package/dist/DX-DimL1MDM.d.cts.map +1 -0
- package/dist/DX-Dx22ax_I.d.ts +115 -0
- package/dist/DX-Dx22ax_I.d.ts.map +1 -0
- package/dist/EX-BRWh1wFc.d.ts +107 -0
- package/dist/EX-BRWh1wFc.d.ts.map +1 -0
- package/dist/EX-Cx87Ruxl.d.cts +107 -0
- package/dist/EX-Cx87Ruxl.d.cts.map +1 -0
- package/dist/FX-D81UlxNN.d.cts +127 -0
- package/dist/FX-D81UlxNN.d.cts.map +1 -0
- package/dist/FX-RmjwAr40.d.ts +127 -0
- package/dist/FX-RmjwAr40.d.ts.map +1 -0
- package/dist/GX-9i7piP9G.d.cts +136 -0
- package/dist/GX-9i7piP9G.d.cts.map +1 -0
- package/dist/GX-CJyo7oDp.d.ts +136 -0
- package/dist/GX-CJyo7oDp.d.ts.map +1 -0
- package/dist/HX-20GVJAvl.d.cts +126 -0
- package/dist/HX-20GVJAvl.d.cts.map +1 -0
- package/dist/HX-XALBTdLA.d.ts +126 -0
- package/dist/HX-XALBTdLA.d.ts.map +1 -0
- package/dist/IX-6SZ55QKb.d.ts +23 -0
- package/dist/IX-6SZ55QKb.d.ts.map +1 -0
- package/dist/IX-D54NGPsc.d.cts +23 -0
- package/dist/IX-D54NGPsc.d.cts.map +1 -0
- package/dist/JX-C1RYcwQX.d.cts +104 -0
- package/dist/JX-C1RYcwQX.d.cts.map +1 -0
- package/dist/JX-hQ1XRmLp.d.ts +104 -0
- package/dist/JX-hQ1XRmLp.d.ts.map +1 -0
- package/dist/KX-BNwunEfn.d.ts +151 -0
- package/dist/KX-BNwunEfn.d.ts.map +1 -0
- package/dist/KX-gQHCIgtQ.d.cts +151 -0
- package/dist/KX-gQHCIgtQ.d.cts.map +1 -0
- package/dist/LX-CHYX3X3J.d.ts +123 -0
- package/dist/LX-CHYX3X3J.d.ts.map +1 -0
- package/dist/LX-CPurJGIh.d.cts +123 -0
- package/dist/LX-CPurJGIh.d.cts.map +1 -0
- package/dist/MX-BPGLWSUz.d.ts +153 -0
- package/dist/MX-BPGLWSUz.d.ts.map +1 -0
- package/dist/MX-BnyW5eHf.d.cts +153 -0
- package/dist/MX-BnyW5eHf.d.cts.map +1 -0
- package/dist/MyInvoisClient-BrNyMjS-.d.cts +178 -0
- package/dist/MyInvoisClient-BrNyMjS-.d.cts.map +1 -0
- package/dist/MyInvoisClient-CXu4pdl-.d.ts +178 -0
- package/dist/MyInvoisClient-CXu4pdl-.d.ts.map +1 -0
- package/dist/MyInvoisClient-Cnvb5iUC.js +299 -0
- package/dist/MyInvoisClient-Cnvb5iUC.js.map +1 -0
- package/dist/MyInvoisClient-DO1dJfQq.cjs +304 -0
- package/dist/MyInvoisClient-DO1dJfQq.cjs.map +1 -0
- package/dist/NX-B11fQuco.d.cts +122 -0
- package/dist/NX-B11fQuco.d.cts.map +1 -0
- package/dist/NX-RulN5Ml3.d.ts +122 -0
- package/dist/NX-RulN5Ml3.d.ts.map +1 -0
- package/dist/OX-DgKVSp7I.d.ts +26 -0
- package/dist/OX-DgKVSp7I.d.ts.map +1 -0
- package/dist/OX-T-ydRXQS.d.cts +26 -0
- package/dist/OX-T-ydRXQS.d.cts.map +1 -0
- package/dist/PX-DA4A2kEv.d.ts +121 -0
- package/dist/PX-DA4A2kEv.d.ts.map +1 -0
- package/dist/PX-p0n1SzvU.d.cts +121 -0
- package/dist/PX-p0n1SzvU.d.cts.map +1 -0
- package/dist/QX-CI1NccIB.d.cts +59 -0
- package/dist/QX-CI1NccIB.d.cts.map +1 -0
- package/dist/QX-DrFqsMEs.d.ts +59 -0
- package/dist/QX-DrFqsMEs.d.ts.map +1 -0
- package/dist/RX-Cm7vFcFN.d.ts +23 -0
- package/dist/RX-Cm7vFcFN.d.ts.map +1 -0
- package/dist/RX-DnNKol22.d.cts +23 -0
- package/dist/RX-DnNKol22.d.cts.map +1 -0
- package/dist/SX-BUjiWQYz.d.cts +40 -0
- package/dist/SX-BUjiWQYz.d.cts.map +1 -0
- package/dist/SX-CsPPTu-W.d.ts +40 -0
- package/dist/SX-CsPPTu-W.d.ts.map +1 -0
- package/dist/TX-DCY25MdR.d.ts +31 -0
- package/dist/TX-DCY25MdR.d.ts.map +1 -0
- package/dist/TX-DOEpsf05.d.cts +31 -0
- package/dist/TX-DOEpsf05.d.cts.map +1 -0
- package/dist/UX-DauyagHy.d.ts +18 -0
- package/dist/UX-DauyagHy.d.ts.map +1 -0
- package/dist/UX-DgUOnTFK.d.cts +18 -0
- package/dist/UX-DgUOnTFK.d.cts.map +1 -0
- package/dist/VX-DD4scgCe.d.ts +17 -0
- package/dist/VX-DD4scgCe.d.ts.map +1 -0
- package/dist/VX-kUX6LM-3.d.cts +17 -0
- package/dist/VX-kUX6LM-3.d.cts.map +1 -0
- package/dist/WX-CjkoppdY.d.ts +26 -0
- package/dist/WX-CjkoppdY.d.ts.map +1 -0
- package/dist/WX-DPfyPFFh.d.cts +26 -0
- package/dist/WX-DPfyPFFh.d.cts.map +1 -0
- package/dist/XX-C4C1gQZH.d.cts +828 -0
- package/dist/XX-C4C1gQZH.d.cts.map +1 -0
- package/dist/XX-sbsIUOnA.d.ts +828 -0
- package/dist/XX-sbsIUOnA.d.ts.map +1 -0
- package/dist/YX-BeT-LsiA.d.cts +20 -0
- package/dist/YX-BeT-LsiA.d.cts.map +1 -0
- package/dist/YX-DUdO8mRC.d.ts +20 -0
- package/dist/YX-DUdO8mRC.d.ts.map +1 -0
- package/dist/ZX-BuVTTq-D.d.cts +22 -0
- package/dist/ZX-BuVTTq-D.d.cts.map +1 -0
- package/dist/ZX-DwfcSA-D.d.ts +22 -0
- package/dist/ZX-DwfcSA-D.d.ts.map +1 -0
- package/dist/api/platform/platformLogin.d.ts +67 -0
- package/dist/api/platform/platformLogin.d.ts.map +1 -0
- package/dist/api/platform/platformLogin.js +3 -0
- package/dist/canonicalize-C_fNNpYr.cjs +80 -0
- package/dist/canonicalize-C_fNNpYr.cjs.map +1 -0
- package/dist/canonicalize-DNUrCGad.js +68 -0
- package/dist/canonicalize-DNUrCGad.js.map +1 -0
- package/dist/chunk-CUT6urMc.cjs +30 -0
- package/dist/classification-codes-B15PbWxz.d.cts +118 -0
- package/dist/classification-codes-B15PbWxz.d.cts.map +1 -0
- package/dist/classification-codes-C2X4xW5-.d.ts +118 -0
- package/dist/classification-codes-C2X4xW5-.d.ts.map +1 -0
- package/dist/country-code-DPeNFMMi.d.cts +543 -0
- package/dist/country-code-DPeNFMMi.d.cts.map +1 -0
- package/dist/country-code-DsI8Mbzx.d.ts +543 -0
- package/dist/country-code-DsI8Mbzx.d.ts.map +1 -0
- package/dist/currencies-DKuDflOO.d.ts +208 -0
- package/dist/currencies-DKuDflOO.d.ts.map +1 -0
- package/dist/currencies-S5g1gzBU.d.cts +208 -0
- package/dist/currencies-S5g1gzBU.d.cts.map +1 -0
- package/dist/e-invoice-BuwtFnlI.d.cts +44 -0
- package/dist/e-invoice-BuwtFnlI.d.cts.map +1 -0
- package/dist/e-invoice-C2TxhyrK.d.ts +44 -0
- package/dist/e-invoice-C2TxhyrK.d.ts.map +1 -0
- package/dist/getBaseUrl-CO7Jp27d.cjs +14 -0
- package/dist/getBaseUrl-CO7Jp27d.cjs.map +1 -0
- package/dist/getBaseUrl-Dx6RDC8I.js +8 -0
- package/dist/getBaseUrl-Dx6RDC8I.js.map +1 -0
- package/dist/hashCert-Bol7lIh2.js +62 -0
- package/dist/hashCert-Bol7lIh2.js.map +1 -0
- package/dist/hashCert-mlYEuYex.cjs +68 -0
- package/dist/hashCert-mlYEuYex.cjs.map +1 -0
- package/dist/hashSignedProperties-9vj5wlYR.js +83 -0
- package/dist/hashSignedProperties-9vj5wlYR.js.map +1 -0
- package/dist/hashSignedProperties-CU_ZqqmY.cjs +95 -0
- package/dist/hashSignedProperties-CU_ZqqmY.cjs.map +1 -0
- package/dist/index-B1DSs-wd.d.cts +16 -0
- package/dist/index-B1DSs-wd.d.cts.map +1 -0
- package/dist/index-CJNLQVjx.d.ts +1 -0
- package/dist/index-FTgB2nM6.d.ts +16 -0
- package/dist/index-FTgB2nM6.d.ts.map +1 -0
- package/dist/index-Wy1ONBjV.d.cts +1 -0
- package/dist/index.cjs +13 -97
- package/dist/index.d.ts +60 -5664
- package/dist/index.js +11 -93
- package/dist/index10.cjs +34 -0
- package/dist/index10.cjs.map +1 -0
- package/dist/index11.cjs +24 -0
- package/dist/index11.cjs.map +1 -0
- package/dist/index12.cjs +0 -0
- package/dist/index13.cjs +13 -0
- package/dist/index14.cjs +13 -0
- package/dist/index14.cjs.map +1 -0
- package/dist/index15.cjs +3 -0
- package/dist/index16.cjs +17 -0
- package/dist/index17.cjs +3 -0
- package/dist/index18.cjs +208 -0
- package/dist/index18.cjs.map +1 -0
- package/dist/index19.cjs +109 -0
- package/dist/index19.cjs.map +1 -0
- package/dist/index2.cjs +62 -0
- package/dist/index2.cjs.map +1 -0
- package/dist/index20.cjs +137 -0
- package/dist/index20.cjs.map +1 -0
- package/dist/index21.cjs +64 -0
- package/dist/index21.cjs.map +1 -0
- package/dist/index22.cjs +267 -0
- package/dist/index22.cjs.map +1 -0
- package/dist/index23.cjs +79 -0
- package/dist/index23.cjs.map +1 -0
- package/dist/index24.cjs +107 -0
- package/dist/index24.cjs.map +1 -0
- package/dist/index25.cjs +73 -0
- package/dist/index25.cjs.map +1 -0
- package/dist/index26.cjs +112 -0
- package/dist/index26.cjs.map +1 -0
- package/dist/index27.cjs +100 -0
- package/dist/index27.cjs.map +1 -0
- package/dist/index28.cjs +18 -0
- package/dist/index28.cjs.map +1 -0
- package/dist/index29.cjs +38 -0
- package/dist/index29.cjs.map +1 -0
- package/dist/index3.cjs +532 -0
- package/dist/index3.cjs.map +1 -0
- package/dist/index30.cjs +19 -0
- package/dist/index30.cjs.map +1 -0
- package/dist/index31.cjs +29 -0
- package/dist/index31.cjs.map +1 -0
- package/dist/index32.cjs +20 -0
- package/dist/index32.cjs.map +1 -0
- package/dist/index33.cjs +14 -0
- package/dist/index33.cjs.map +1 -0
- package/dist/index34.cjs +14 -0
- package/dist/index34.cjs.map +1 -0
- package/dist/index35.cjs +17 -0
- package/dist/index35.cjs.map +1 -0
- package/dist/index36.cjs +13 -0
- package/dist/index36.cjs.map +1 -0
- package/dist/index37.cjs +108 -0
- package/dist/index37.cjs.map +1 -0
- package/dist/index38.cjs +113 -0
- package/dist/index38.cjs.map +1 -0
- package/dist/index39.cjs +126 -0
- package/dist/index39.cjs.map +1 -0
- package/dist/index4.cjs +196 -0
- package/dist/index4.cjs.map +1 -0
- package/dist/index40.cjs +113 -0
- package/dist/index40.cjs.map +1 -0
- package/dist/index41.cjs +105 -0
- package/dist/index41.cjs.map +1 -0
- package/dist/index42.cjs +125 -0
- package/dist/index42.cjs.map +1 -0
- package/dist/index43.cjs +134 -0
- package/dist/index43.cjs.map +1 -0
- package/dist/index44.cjs +124 -0
- package/dist/index44.cjs.map +1 -0
- package/dist/index45.cjs +21 -0
- package/dist/index45.cjs.map +1 -0
- package/dist/index46.cjs +102 -0
- package/dist/index46.cjs.map +1 -0
- package/dist/index47.cjs +149 -0
- package/dist/index47.cjs.map +1 -0
- package/dist/index48.cjs +121 -0
- package/dist/index48.cjs.map +1 -0
- package/dist/index49.cjs +151 -0
- package/dist/index49.cjs.map +1 -0
- package/dist/index5.cjs +25 -0
- package/dist/index5.cjs.map +1 -0
- package/dist/index50.cjs +120 -0
- package/dist/index50.cjs.map +1 -0
- package/dist/index51.cjs +24 -0
- package/dist/index51.cjs.map +1 -0
- package/dist/index52.cjs +119 -0
- package/dist/index52.cjs.map +1 -0
- package/dist/index53.cjs +54 -0
- package/dist/index53.cjs.map +1 -0
- package/dist/index54.cjs +21 -0
- package/dist/index54.cjs.map +1 -0
- package/dist/index55.cjs +35 -0
- package/dist/index55.cjs.map +1 -0
- package/dist/index56.cjs +29 -0
- package/dist/index56.cjs.map +1 -0
- package/dist/index57.cjs +16 -0
- package/dist/index57.cjs.map +1 -0
- package/dist/index58.cjs +15 -0
- package/dist/index58.cjs.map +1 -0
- package/dist/index59.cjs +24 -0
- package/dist/index59.cjs.map +1 -0
- package/dist/index59.cts.map +1 -0
- package/dist/index6.cjs +0 -0
- package/dist/index60.cjs +419 -0
- package/dist/index60.cjs.map +1 -0
- package/dist/index61.cjs +15 -0
- package/dist/index61.cjs.map +1 -0
- package/dist/index62.cjs +16 -0
- package/dist/index62.cjs.map +1 -0
- package/dist/index62.cts.map +1 -0
- package/dist/index63.cjs +0 -0
- package/dist/index63.cts.map +1 -0
- package/dist/index64.cjs +0 -0
- package/dist/index64.cts.map +1 -0
- package/dist/index65.cjs +122 -0
- package/dist/index65.cjs.map +1 -0
- package/dist/index65.cts.map +1 -0
- package/dist/index66.cjs +229 -0
- package/dist/index66.cjs.map +1 -0
- package/dist/index66.cts.map +1 -0
- package/dist/index67.cjs +4 -0
- package/dist/index67.cts.map +1 -0
- package/dist/index68.cjs +3 -0
- package/dist/index68.cts.map +1 -0
- package/dist/index69.cjs +4 -0
- package/dist/index69.cts.map +1 -0
- package/dist/index7.cjs +0 -0
- package/dist/index70.cjs +3 -0
- package/dist/index70.cts.map +1 -0
- package/dist/index71.cjs +3 -0
- package/dist/index71.cts.map +1 -0
- package/dist/index72.cjs +3 -0
- package/dist/index72.cts.map +1 -0
- package/dist/index73.cjs +3 -0
- package/dist/index73.cts.map +1 -0
- package/dist/index8.cjs +25 -0
- package/dist/index8.cjs.map +1 -0
- package/dist/index9.cjs +0 -0
- package/dist/invoice-1_1-BJVcw-oE.d.ts +432 -0
- package/dist/invoice-1_1-BJVcw-oE.d.ts.map +1 -0
- package/dist/invoice-1_1-DWdNPRzr.d.cts +432 -0
- package/dist/invoice-1_1-DWdNPRzr.d.cts.map +1 -0
- package/dist/invoice1-1-8S-QQn7P.cjs +547 -0
- package/dist/invoice1-1-8S-QQn7P.cjs.map +1 -0
- package/dist/invoice1-1-CHuLpkFz.js +504 -0
- package/dist/invoice1-1-CHuLpkFz.js.map +1 -0
- package/dist/msic-codes-B_1W6lZF.d.cts +26 -0
- package/dist/msic-codes-B_1W6lZF.d.cts.map +1 -0
- package/dist/msic-codes-bs0lTfSZ.d.ts +26 -0
- package/dist/msic-codes-bs0lTfSZ.d.ts.map +1 -0
- package/dist/payment-modes-B8dNy3SM.d.ts +44 -0
- package/dist/payment-modes-B8dNy3SM.d.ts.map +1 -0
- package/dist/payment-modes-DHihrywe.d.cts +44 -0
- package/dist/payment-modes-DHihrywe.d.cts.map +1 -0
- package/dist/platformLogin-DsxWWUXr.js +31 -0
- package/dist/platformLogin-DsxWWUXr.js.map +1 -0
- package/dist/platformLogin-PGzMhw1X.cjs +37 -0
- package/dist/platformLogin-PGzMhw1X.cjs.map +1 -0
- package/dist/populateFinalDocument-BdyYzz5Y.cjs +96 -0
- package/dist/populateFinalDocument-BdyYzz5Y.cjs.map +1 -0
- package/dist/populateFinalDocument-BpLXmgLv.js +90 -0
- package/dist/populateFinalDocument-BpLXmgLv.js.map +1 -0
- package/dist/populateSignedProperties-BJMcBQ6S.cjs +58 -0
- package/dist/populateSignedProperties-BJMcBQ6S.cjs.map +1 -0
- package/dist/populateSignedProperties-BvGN-YZH.js +52 -0
- package/dist/populateSignedProperties-BvGN-YZH.js.map +1 -0
- package/dist/sign-B61Cy3gO.cjs +40 -0
- package/dist/sign-B61Cy3gO.cjs.map +1 -0
- package/dist/sign-DzHK7UhR.js +34 -0
- package/dist/sign-DzHK7UhR.js.map +1 -0
- package/dist/signatures-BKi9DP2K.d.cts +173 -0
- package/dist/signatures-BKi9DP2K.d.cts.map +1 -0
- package/dist/signatures-C9QPZTQd.d.ts +173 -0
- package/dist/signatures-C9QPZTQd.d.ts.map +1 -0
- package/dist/state-codes-CxG1S9YY.d.ts +62 -0
- package/dist/state-codes-CxG1S9YY.d.ts.map +1 -0
- package/dist/state-codes-DXSWtE6a.d.cts +62 -0
- package/dist/state-codes-DXSWtE6a.d.cts.map +1 -0
- package/dist/tax-types-CEpfSh5P.d.ts +42 -0
- package/dist/tax-types-CEpfSh5P.d.ts.map +1 -0
- package/dist/tax-types-CgwxONDS.d.cts +42 -0
- package/dist/tax-types-CgwxONDS.d.cts.map +1 -0
- package/dist/transform-BLz0S687.cjs +72 -0
- package/dist/transform-BLz0S687.cjs.map +1 -0
- package/dist/transform-D1q-U6Zj.js +66 -0
- package/dist/transform-D1q-U6Zj.js.map +1 -0
- package/dist/types/classification-codes.d.ts +2 -0
- package/dist/types/country-code.d.ts +2 -0
- package/dist/types/currencies.d.ts +2 -0
- package/dist/types/documents/index.d.ts +57 -0
- package/dist/types/documents/invoice-1_1.d.ts +56 -0
- package/dist/types/e-invoice.d.ts +2 -0
- package/dist/types/index.d.ts +59 -0
- package/dist/types/msic/0X.d.ts +2 -0
- package/dist/types/msic/1X.d.ts +2 -0
- package/dist/types/msic/2X.d.ts +2 -0
- package/dist/types/msic/3X.d.ts +2 -0
- package/dist/types/msic/4X.d.ts +2 -0
- package/dist/types/msic/5X.d.ts +2 -0
- package/dist/types/msic/6X.d.ts +2 -0
- package/dist/types/msic/7X.d.ts +2 -0
- package/dist/types/msic/8X.d.ts +2 -0
- package/dist/types/msic/9X.d.ts +2 -0
- package/dist/types/msic-codes.d.ts +12 -0
- package/dist/types/payment-modes.d.ts +2 -0
- package/dist/types/signatures.d.ts +2 -0
- package/dist/types/state-codes.d.ts +2 -0
- package/dist/types/tax-types.d.ts +2 -0
- package/dist/types/unit/1X.d.ts +2 -0
- package/dist/types/unit/2X.d.ts +2 -0
- package/dist/types/unit/3X.d.ts +2 -0
- package/dist/types/unit/4X.d.ts +2 -0
- package/dist/types/unit/5X.d.ts +2 -0
- package/dist/types/unit/6X.d.ts +2 -0
- package/dist/types/unit/7X.d.ts +2 -0
- package/dist/types/unit/8X.d.ts +2 -0
- package/dist/types/unit/9X.d.ts +2 -0
- package/dist/types/unit/AX.d.ts +2 -0
- package/dist/types/unit/BX.d.ts +2 -0
- package/dist/types/unit/CX.d.ts +2 -0
- package/dist/types/unit/DX.d.ts +2 -0
- package/dist/types/unit/EX.d.ts +2 -0
- package/dist/types/unit/FX.d.ts +2 -0
- package/dist/types/unit/GX.d.ts +2 -0
- package/dist/types/unit/HX.d.ts +2 -0
- package/dist/types/unit/IX.d.ts +2 -0
- package/dist/types/unit/JX.d.ts +2 -0
- package/dist/types/unit/KX.d.ts +2 -0
- package/dist/types/unit/LX.d.ts +2 -0
- package/dist/types/unit/MX.d.ts +2 -0
- package/dist/types/unit/NX.d.ts +2 -0
- package/dist/types/unit/OX.d.ts +2 -0
- package/dist/types/unit/PX.d.ts +2 -0
- package/dist/types/unit/QX.d.ts +2 -0
- package/dist/types/unit/RX.d.ts +2 -0
- package/dist/types/unit/SX.d.ts +2 -0
- package/dist/types/unit/TX.d.ts +2 -0
- package/dist/types/unit/UX.d.ts +2 -0
- package/dist/types/unit/VX.d.ts +2 -0
- package/dist/types/unit/WX.d.ts +2 -0
- package/dist/types/unit/XX.d.ts +2 -0
- package/dist/types/unit/YX.d.ts +2 -0
- package/dist/types/unit/ZX.d.ts +2 -0
- package/dist/types/unit-types.d.ts +37 -0
- package/dist/unit-types-1bF0KhIp.d.ts +56 -0
- package/dist/unit-types-1bF0KhIp.d.ts.map +1 -0
- package/dist/unit-types-CsrkvgfG.d.cts +56 -0
- package/dist/unit-types-CsrkvgfG.d.cts.map +1 -0
- package/dist/utils/MyInvoisClient.d.ts +60 -0
- package/dist/utils/MyInvoisClient.js +13 -0
- package/dist/utils/base64.d.ts +6 -0
- package/dist/utils/base64.d.ts.map +1 -0
- package/dist/utils/base64.js +11 -0
- package/dist/utils/base64.js.map +1 -0
- package/dist/utils/debug/debug-document-hash.d.ts +100 -0
- package/dist/utils/debug/debug-document-hash.d.ts.map +1 -0
- package/dist/utils/debug/debug-document-hash.js +120 -0
- package/dist/utils/debug/debug-document-hash.js.map +1 -0
- package/dist/utils/debug/debug-invoice-submission.d.ts +152 -0
- package/dist/utils/debug/debug-invoice-submission.d.ts.map +1 -0
- package/dist/utils/debug/debug-invoice-submission.js +226 -0
- package/dist/utils/debug/debug-invoice-submission.js.map +1 -0
- package/dist/utils/getBaseUrl.d.ts +5 -0
- package/dist/utils/getBaseUrl.d.ts.map +1 -0
- package/dist/utils/getBaseUrl.js +3 -0
- package/dist/utils/invoice1-1.d.ts +117 -0
- package/dist/utils/invoice1-1.d.ts.map +1 -0
- package/dist/utils/invoice1-1.js +10 -0
- package/dist/utils/signature/canonicalize.d.ts +26 -0
- package/dist/utils/signature/canonicalize.d.ts.map +1 -0
- package/dist/utils/signature/canonicalize.js +3 -0
- package/dist/utils/signature/hashCert.d.ts +15 -0
- package/dist/utils/signature/hashCert.d.ts.map +1 -0
- package/dist/utils/signature/hashCert.js +3 -0
- package/dist/utils/signature/hashSignedProperties.d.ts +25 -0
- package/dist/utils/signature/hashSignedProperties.d.ts.map +1 -0
- package/dist/utils/signature/hashSignedProperties.js +3 -0
- package/dist/utils/signature/populateFinalDocument.d.ts +23 -0
- package/dist/utils/signature/populateFinalDocument.d.ts.map +1 -0
- package/dist/utils/signature/populateFinalDocument.js +3 -0
- package/dist/utils/signature/populateSignedProperties.d.ts +23 -0
- package/dist/utils/signature/populateSignedProperties.d.ts.map +1 -0
- package/dist/utils/signature/populateSignedProperties.js +3 -0
- package/dist/utils/signature/sign.d.ts +16 -0
- package/dist/utils/signature/sign.d.ts.map +1 -0
- package/dist/utils/signature/sign.js +3 -0
- package/dist/utils/signature/transform.d.ts +16 -0
- package/dist/utils/signature/transform.d.ts.map +1 -0
- package/dist/utils/signature/transform.js +3 -0
- package/package.json +12 -5
- package/src/api/platform/{taxpayerLogin.ts → platformLogin.ts} +8 -2
- package/src/types/documents/invoice-1_1.d.ts +90 -0
- package/src/types/index.d.ts +1 -0
- package/src/types/msic-codes.d.ts +1 -7
- package/src/utils/MyInvoisClient.ts +428 -11
- package/src/utils/base64.ts +7 -0
- package/src/utils/debug/debug-document-hash.ts +249 -0
- package/src/utils/debug/debug-invoice-submission.ts +355 -0
- package/src/utils/getBaseUrl.ts +1 -1
- package/src/utils/invoice1-1.ts +671 -0
- package/src/utils/signature/canonicalize.ts +104 -0
- package/src/utils/signature/hashCert.ts +115 -0
- package/src/utils/signature/hashSignedProperties.ts +155 -0
- package/src/utils/signature/populateFinalDocument.ts +187 -0
- package/src/utils/signature/populateSignedProperties.ts +87 -0
- package/src/utils/signature/sign.ts +51 -0
- package/src/utils/signature/transform.ts +99 -0
- package/test/MyInvoiClientWithRealData.test.ts +2 -1
- package/test/MyInvoisClient.test.ts +16 -8
- package/test/base64.test.ts +43 -0
- package/test/canonicalize.test.ts +110 -0
- package/test/hashCert.test.ts +95 -0
- package/test/hashSignedProperties.test.ts +140 -0
- package/test/populateFinalDocument.test.ts +218 -0
- package/test/populateSignedProperties.test.ts +155 -0
- package/test/sign.test.ts +70 -0
- package/test/signAndSubmitInvoice.test.ts +915 -0
- package/test/transform.test.ts +158 -0
- package/tsconfig.json +7 -1
- package/tsdown.config.ts +31 -0
- package/dist/index.cjs.map +0 -1
- package/rolldown.config.ts +0 -26
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as crypto from 'crypto'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Signs the document hash digest using RSA-SHA256 and a private key.
|
|
5
|
+
*
|
|
6
|
+
* Corresponds to Step 4 in the MyInvois Signature Creation guide:
|
|
7
|
+
* https://sdk.myinvois.hasil.gov.my/signature-creation/#step-4-sign-the-document-digest
|
|
8
|
+
*
|
|
9
|
+
* @param base64DocDigest The Base64 encoded SHA-256 hash of the canonicalized document (DocDigest from Step 3).
|
|
10
|
+
* @param privateKeyPem The private key in PEM format (string or Buffer).
|
|
11
|
+
* @returns The Base64 encoded RSA-SHA256 signature (Sig).
|
|
12
|
+
* @throws {Error} If signing fails.
|
|
13
|
+
*/
|
|
14
|
+
export function signDocumentDigest(
|
|
15
|
+
base64DocDigest: string,
|
|
16
|
+
privateKeyPem: string | Buffer,
|
|
17
|
+
): string {
|
|
18
|
+
try {
|
|
19
|
+
// Add stricter validation: Check if the input string contains only valid Base64 characters.
|
|
20
|
+
const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/
|
|
21
|
+
if (base64DocDigest.length > 0 && !base64Regex.test(base64DocDigest)) {
|
|
22
|
+
throw new Error('Invalid Base64 characters detected in document digest.')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 1. Decode the Base64 document digest back to a raw buffer
|
|
26
|
+
// The signature is calculated over the raw hash bytes, not the Base64 string.
|
|
27
|
+
const rawDocDigest = Buffer.from(base64DocDigest, 'base64')
|
|
28
|
+
|
|
29
|
+
// Add check: If input Base64 string was not empty, but decoded buffer is,
|
|
30
|
+
// it implies invalid Base64 characters were likely ignored instead of throwing.
|
|
31
|
+
if (base64DocDigest.length > 0 && rawDocDigest.length === 0) {
|
|
32
|
+
throw new Error('Invalid Base64 content for document digest.')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 2. Create a signer instance with RSA-SHA256
|
|
36
|
+
const signer = crypto.createSign('RSA-SHA256')
|
|
37
|
+
|
|
38
|
+
// 3. Update the signer with the raw hash digest
|
|
39
|
+
// Note: We sign the HASH itself, not the original data.
|
|
40
|
+
signer.update(rawDocDigest)
|
|
41
|
+
signer.end()
|
|
42
|
+
|
|
43
|
+
// 4. Sign using the private key and get the signature in Base64 format
|
|
44
|
+
const base64Signature = signer.sign(privateKeyPem, 'base64')
|
|
45
|
+
|
|
46
|
+
return base64Signature
|
|
47
|
+
} catch (error: any) {
|
|
48
|
+
console.error('Error during signing:', error)
|
|
49
|
+
throw new Error(`Failed to sign document digest: ${error.message || error}`)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// Import necessary components from xmldom-ts and xpath-ts
|
|
2
|
+
import { DOMParserImpl, XMLSerializerImpl } from 'xmldom-ts'
|
|
3
|
+
import * as xpath from 'xpath-ts'
|
|
4
|
+
// Assuming Node and Document types are correctly exposed by xmldom-ts/xpath-ts globally or via import
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Transforms an XML invoice string according to specific rules using xmldom-ts and xpath-ts:
|
|
8
|
+
* - Removes the XML declaration.
|
|
9
|
+
* - Removes UBLExtensions and Signature elements within the Invoice element.
|
|
10
|
+
* Assumes the input XML is UTF-8 encoded.
|
|
11
|
+
*
|
|
12
|
+
* @param xmlString The raw XML invoice string.
|
|
13
|
+
* @returns The transformed XML string.
|
|
14
|
+
* @throws {Error} If parsing fails.
|
|
15
|
+
*/
|
|
16
|
+
export function transformXmlInvoice(xmlString: string): string {
|
|
17
|
+
let doc: Document // Use the standard Document type, assuming compatibility
|
|
18
|
+
const errors: string[] = []
|
|
19
|
+
|
|
20
|
+
// Define separate handlers for each error level as likely expected by xmldom-ts
|
|
21
|
+
const handleError = (msg: string) => {
|
|
22
|
+
errors.push(`ERROR: ${msg}`)
|
|
23
|
+
}
|
|
24
|
+
const handleFatalError = (msg: string) => {
|
|
25
|
+
errors.push(`FATALERROR: ${msg}`)
|
|
26
|
+
}
|
|
27
|
+
const handleWarning = (msg: string) => {
|
|
28
|
+
console.warn(`WARNING: ${msg}`)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Use DOMParserImpl from xmldom-ts with the specific error handler structure
|
|
32
|
+
const parser = new DOMParserImpl({
|
|
33
|
+
locator: {}, // Keep locator, might be useful for error context
|
|
34
|
+
errorHandler: {
|
|
35
|
+
error: handleError,
|
|
36
|
+
fatalError: handleFatalError,
|
|
37
|
+
warning: handleWarning,
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
// Use the standard mime type string directly
|
|
43
|
+
doc = parser.parseFromString(xmlString, 'application/xml') // Or 'text/xml'
|
|
44
|
+
} catch (e: any) {
|
|
45
|
+
throw new Error(`XML Parsing Initialization Error: ${e.message || e}`)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Check for parsererror element
|
|
49
|
+
const parserErrors = doc.getElementsByTagName('parsererror')
|
|
50
|
+
if (parserErrors.length > 0) {
|
|
51
|
+
const errorElement = parserErrors[0]
|
|
52
|
+
if (errorElement) {
|
|
53
|
+
const errorContent = errorElement.textContent
|
|
54
|
+
? errorElement.textContent.trim()
|
|
55
|
+
: 'Unknown parsing error reported by parsererror tag.'
|
|
56
|
+
throw new Error(`XML Parsing Error: ${errorContent}`)
|
|
57
|
+
} else {
|
|
58
|
+
throw new Error('XML Parsing Error: Malformed parsererror tag found.')
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// If the errorHandler collected errors, throw the first one.
|
|
63
|
+
if (errors.length > 0) {
|
|
64
|
+
throw new Error(errors[0])
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Use xpath.select from xpath-ts
|
|
68
|
+
const select = xpath.select
|
|
69
|
+
|
|
70
|
+
// Helper function to remove nodes found by XPath
|
|
71
|
+
const removeNodesByXPath = (path: string) => {
|
|
72
|
+
const nodesToRemove = select(path, doc) as Node[]
|
|
73
|
+
|
|
74
|
+
if (nodesToRemove && nodesToRemove instanceof Array) {
|
|
75
|
+
nodesToRemove.forEach(node => {
|
|
76
|
+
if (node && node.parentNode) {
|
|
77
|
+
node.parentNode.removeChild(node)
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 2. Find and remove UBLExtensions elements
|
|
84
|
+
removeNodesByXPath(
|
|
85
|
+
"//*[local-name()='Invoice']//*[local-name()='UBLExtensions']",
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
// 3. Find and remove Signature elements
|
|
89
|
+
removeNodesByXPath("//*[local-name()='Invoice']//*[local-name()='Signature']")
|
|
90
|
+
|
|
91
|
+
// 4. Serialize the modified DOM back to string using XMLSerializerImpl
|
|
92
|
+
const serializer = new XMLSerializerImpl()
|
|
93
|
+
let transformedXml = serializer.serializeToString(doc)
|
|
94
|
+
|
|
95
|
+
// 5. Remove the XML declaration (if present)
|
|
96
|
+
transformedXml = transformedXml.replace(/^<\?xml [^>]*\?>\s*/i, '')
|
|
97
|
+
|
|
98
|
+
return transformedXml
|
|
99
|
+
}
|
|
@@ -20,10 +20,11 @@ describe('MyInvoisClientWithRealData', () => {
|
|
|
20
20
|
process.env.CLIENT_SECRET!,
|
|
21
21
|
'sandbox',
|
|
22
22
|
)
|
|
23
|
-
// @ts-ignore
|
|
23
|
+
// @ts-ignore - refreshToken is a private method
|
|
24
24
|
await client.refreshToken()
|
|
25
25
|
const result = await client.verifyTin(
|
|
26
26
|
process.env.TIN_VALUE!,
|
|
27
|
+
'NRIC',
|
|
27
28
|
process.env.NRIC_VALUE!,
|
|
28
29
|
)
|
|
29
30
|
expect(result).toBe(true)
|
|
@@ -12,7 +12,13 @@ describe('MyInvoisClient', () => {
|
|
|
12
12
|
|
|
13
13
|
beforeEach(() => {
|
|
14
14
|
vi.clearAllMocks()
|
|
15
|
-
client = new MyInvoisClient(
|
|
15
|
+
client = new MyInvoisClient(
|
|
16
|
+
'test-id',
|
|
17
|
+
'test-secret',
|
|
18
|
+
'sandbox',
|
|
19
|
+
undefined,
|
|
20
|
+
true,
|
|
21
|
+
)
|
|
16
22
|
})
|
|
17
23
|
|
|
18
24
|
describe('constructor', () => {
|
|
@@ -21,6 +27,7 @@ describe('MyInvoisClient', () => {
|
|
|
21
27
|
'test-id',
|
|
22
28
|
'test-secret',
|
|
23
29
|
'sandbox',
|
|
30
|
+
undefined,
|
|
24
31
|
true,
|
|
25
32
|
)
|
|
26
33
|
expect((sandboxClient as any).baseUrl).toBe(
|
|
@@ -33,6 +40,7 @@ describe('MyInvoisClient', () => {
|
|
|
33
40
|
'test-id',
|
|
34
41
|
'test-secret',
|
|
35
42
|
'production',
|
|
43
|
+
undefined,
|
|
36
44
|
true,
|
|
37
45
|
)
|
|
38
46
|
expect((prodClient as any).baseUrl).toBe(
|
|
@@ -53,7 +61,7 @@ describe('MyInvoisClient', () => {
|
|
|
53
61
|
json: () => Promise.resolve(mockToken),
|
|
54
62
|
} as Response)
|
|
55
63
|
|
|
56
|
-
await client.verifyTin('123', '456')
|
|
64
|
+
await client.verifyTin('123', 'NRIC', '456')
|
|
57
65
|
|
|
58
66
|
expect(mockFetch).toHaveBeenCalledWith(
|
|
59
67
|
'https://preprod-api.myinvois.hasil.gov.my/connect/token',
|
|
@@ -77,7 +85,7 @@ describe('MyInvoisClient', () => {
|
|
|
77
85
|
json: () => Promise.resolve(undefined),
|
|
78
86
|
} as Response)
|
|
79
87
|
|
|
80
|
-
await client.verifyTin('123', '456')
|
|
88
|
+
await client.verifyTin('123', 'NRIC', '456')
|
|
81
89
|
|
|
82
90
|
// Check first call (token request)
|
|
83
91
|
expect(mockFetch).toHaveBeenNthCalledWith(
|
|
@@ -122,12 +130,12 @@ describe('MyInvoisClient', () => {
|
|
|
122
130
|
} as Response)
|
|
123
131
|
|
|
124
132
|
// First call to get token
|
|
125
|
-
await client.verifyTin('123', '456')
|
|
133
|
+
await client.verifyTin('123', 'NRIC', '456')
|
|
126
134
|
|
|
127
135
|
vi.setSystemTime(new Date(Date.now() + 1000))
|
|
128
136
|
|
|
129
137
|
// Second call should reuse token
|
|
130
|
-
await client.verifyTin('123', '456')
|
|
138
|
+
await client.verifyTin('123', 'NRIC', '456')
|
|
131
139
|
|
|
132
140
|
// Token endpoint should only be called once
|
|
133
141
|
expect(mockFetch).toHaveBeenCalledWith(
|
|
@@ -154,9 +162,9 @@ describe('MyInvoisClient', () => {
|
|
|
154
162
|
json: () => Promise.resolve(undefined),
|
|
155
163
|
} as Response)
|
|
156
164
|
|
|
157
|
-
await client.verifyTin('123', '456')
|
|
165
|
+
await client.verifyTin('123', 'NRIC', '456')
|
|
158
166
|
vi.setSystemTime(new Date(Date.now() + 1000 * 8000))
|
|
159
|
-
await client.verifyTin('123', '456')
|
|
167
|
+
await client.verifyTin('123', 'NRIC', '456')
|
|
160
168
|
|
|
161
169
|
expect(mockFetch).toHaveBeenCalledWith(
|
|
162
170
|
`https://preprod-api.myinvois.hasil.gov.my/api/v1.0/taxpayer/validate/123?idType=NRIC&idValue=456`,
|
|
@@ -182,7 +190,7 @@ describe('MyInvoisClient', () => {
|
|
|
182
190
|
} as Response)
|
|
183
191
|
.mockRejectedValueOnce(new Error('Invalid TIN'))
|
|
184
192
|
|
|
185
|
-
const result = await client.verifyTin('123', '456')
|
|
193
|
+
const result = await client.verifyTin('123', 'NRIC', '456')
|
|
186
194
|
|
|
187
195
|
expect(result).toBe(false)
|
|
188
196
|
})
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { encodeToBase64 } from '../src/utils/base64' // Adjust path if necessary
|
|
3
|
+
|
|
4
|
+
describe('encodeToBase64', () => {
|
|
5
|
+
it('should correctly encode a simple JSON string', () => {
|
|
6
|
+
const jsonString = '{"key": "value"}'
|
|
7
|
+
const expectedBase64 = 'eyJrZXkiOiAidmFsdWUifQ==' // Buffer.from(jsonString).toString('base64')
|
|
8
|
+
expect(encodeToBase64(jsonString)).toBe(expectedBase64)
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it('should correctly encode a simple XML string', () => {
|
|
12
|
+
const xmlString = '<root><element>value</element></root>'
|
|
13
|
+
const expectedBase64 =
|
|
14
|
+
'PHJvb3Q+PGVsZW1lbnQ+dmFsdWU8L2VsZW1lbnQ+PC9yb290Pg==' // Buffer.from(xmlString).toString('base64')
|
|
15
|
+
expect(encodeToBase64(xmlString)).toBe(expectedBase64)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('should correctly encode an empty string', () => {
|
|
19
|
+
const emptyString = ''
|
|
20
|
+
const expectedBase64 = '' // Buffer.from(emptyString).toString('base64')
|
|
21
|
+
expect(encodeToBase64(emptyString)).toBe(expectedBase64)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('should correctly encode a string with special characters', () => {
|
|
25
|
+
const specialString = '!@#$%^&*()_+=-`~[]{}\\|;\'",./<>?'
|
|
26
|
+
const expectedBase64 = 'IUAjJCVeJiooKV8rPS1gfltde31cfDsnIiwuLzw+Pw==' // Corrected value
|
|
27
|
+
expect(encodeToBase64(specialString)).toBe(expectedBase64)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('should correctly encode a string with Unicode characters', () => {
|
|
31
|
+
const unicodeString = '你好世界🌍'
|
|
32
|
+
const expectedBase64 = '5L2g5aW95LiW55WM8J+MjQ==' // Corrected value
|
|
33
|
+
expect(encodeToBase64(unicodeString)).toBe(expectedBase64)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('should correctly encode a longer string', () => {
|
|
37
|
+
const longString =
|
|
38
|
+
'This is a longer string that needs to be encoded to Base64 to ensure it handles more than just a few characters correctly.'
|
|
39
|
+
const expectedBase64 =
|
|
40
|
+
'VGhpcyBpcyBhIGxvbmdlciBzdHJpbmcgdGhhdCBuZWVkcyB0byBiZSBlbmNvZGVkIHRvIEJhc2U2NCB0byBlbnN1cmUgaXQgaGFuZGxlcyBtb3JlIHRoYW4ganVzdCBhIGZldyBjaGFyYWN0ZXJzIGNvcnJlY3RseS4=' // Buffer.from(longString).toString('base64')
|
|
41
|
+
expect(encodeToBase64(longString)).toBe(expectedBase64)
|
|
42
|
+
})
|
|
43
|
+
})
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import * as crypto from 'crypto'
|
|
3
|
+
import { DOMParserImpl } from 'xmldom-ts' // To create Document objects for testing
|
|
4
|
+
import { canonicalizeAndHashDocument } from '../src/utils/signature/canonicalize'
|
|
5
|
+
|
|
6
|
+
// Helper to calculate expected hash for comparison
|
|
7
|
+
const calculateExpectedHash = (canonicalXml: string): string => {
|
|
8
|
+
const hash = crypto.createHash('sha256')
|
|
9
|
+
hash.update(canonicalXml, 'utf8')
|
|
10
|
+
return hash.digest('base64')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
describe('canonicalizeAndHashDocument', () => {
|
|
14
|
+
const parser = new DOMParserImpl()
|
|
15
|
+
|
|
16
|
+
it('should correctly canonicalize (ExcC14N) and hash a simple XML document', async () => {
|
|
17
|
+
const inputXml = `<doc att2="val2" att1="val1"><child> Data </child></doc>`
|
|
18
|
+
const doc = parser.parseFromString(inputXml, 'application/xml')
|
|
19
|
+
|
|
20
|
+
// Expected canonical form (Exclusive C14N, no comments, attributes sorted)
|
|
21
|
+
const expectedCanonical = `<doc att1="val1" att2="val2"><child> Data </child></doc>`
|
|
22
|
+
const expectedHash = calculateExpectedHash(expectedCanonical)
|
|
23
|
+
|
|
24
|
+
await expect(canonicalizeAndHashDocument(doc)).resolves.toEqual(
|
|
25
|
+
expectedHash,
|
|
26
|
+
)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('should handle default namespaces correctly during canonicalization', async () => {
|
|
30
|
+
const inputXml = `<doc xmlns="http://example.com"><child>Data</child></doc>`
|
|
31
|
+
const doc = parser.parseFromString(inputXml, 'application/xml')
|
|
32
|
+
|
|
33
|
+
// Expected canonical form (xmlns attribute added)
|
|
34
|
+
const expectedCanonical = `<doc xmlns="http://example.com"><child>Data</child></doc>`
|
|
35
|
+
const expectedHash = calculateExpectedHash(expectedCanonical)
|
|
36
|
+
|
|
37
|
+
await expect(canonicalizeAndHashDocument(doc)).resolves.toEqual(
|
|
38
|
+
expectedHash,
|
|
39
|
+
)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('should handle prefixed namespaces correctly and sort attributes', async () => {
|
|
43
|
+
const inputXml = `<p:doc xmlns:p="http://example.com" att2="v2" p:att1="v1"></p:doc>`
|
|
44
|
+
const doc = parser.parseFromString(inputXml, 'application/xml')
|
|
45
|
+
|
|
46
|
+
// Note: The canonical form produced by the library might differ slightly from
|
|
47
|
+
// strict spec examples regarding attribute order.
|
|
48
|
+
// We are now using the hash actually produced by the library for this input as the expected value.
|
|
49
|
+
const expectedHash = 'N8sCdTHmSlLndeR32fPyaep7goI/D9ndkgvQV72a/Is=' // Updated based on test run
|
|
50
|
+
|
|
51
|
+
// We no longer need to calculate the hash from an assumed canonical string in the test
|
|
52
|
+
// const expectedCanonical = `<p:doc xmlns:p="http://example.com" p:att1="v1" att2="v2"></p:doc>`;
|
|
53
|
+
// const expectedHash = calculateExpectedHash(expectedCanonical);
|
|
54
|
+
|
|
55
|
+
await expect(canonicalizeAndHashDocument(doc)).resolves.toEqual(
|
|
56
|
+
expectedHash,
|
|
57
|
+
)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('should handle self-closing tags correctly', async () => {
|
|
61
|
+
const inputXml = `<doc><empty att="val"/></doc>`
|
|
62
|
+
const doc = parser.parseFromString(inputXml, 'application/xml')
|
|
63
|
+
|
|
64
|
+
// Expected canonical form (self-closing tag expanded)
|
|
65
|
+
const expectedCanonical = `<doc><empty att="val"></empty></doc>`
|
|
66
|
+
const expectedHash = calculateExpectedHash(expectedCanonical)
|
|
67
|
+
|
|
68
|
+
await expect(canonicalizeAndHashDocument(doc)).resolves.toEqual(
|
|
69
|
+
expectedHash,
|
|
70
|
+
)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('should handle character references correctly', async () => {
|
|
74
|
+
const inputXml = `<doc>< & > ' "</doc>`
|
|
75
|
+
const doc = parser.parseFromString(inputXml, 'application/xml')
|
|
76
|
+
|
|
77
|
+
// Expected canonical form (special characters escaped)
|
|
78
|
+
const expectedCanonical = `<doc>< & > ' "</doc>`
|
|
79
|
+
const expectedHash = calculateExpectedHash(expectedCanonical)
|
|
80
|
+
|
|
81
|
+
await expect(canonicalizeAndHashDocument(doc)).resolves.toEqual(
|
|
82
|
+
expectedHash,
|
|
83
|
+
)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('should handle potential canonicalization failures gracefully', async () => {
|
|
87
|
+
// This test checks if the function either resolves to a string (graceful handling)
|
|
88
|
+
// or rejects with a specific error pattern if canonicalization truly fails.
|
|
89
|
+
// Testing actual canonicalization failure usually requires mocking the underlying library.
|
|
90
|
+
const potentiallyProblematicXml = `<doc><unusual /></doc>` // Example input
|
|
91
|
+
const doc = parser.parseFromString(
|
|
92
|
+
potentiallyProblematicXml,
|
|
93
|
+
'application/xml',
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
const result = await canonicalizeAndHashDocument(doc)
|
|
98
|
+
// If it resolves, check the type
|
|
99
|
+
expect(result).toEqual(expect.any(String))
|
|
100
|
+
// console.warn("Test Warning: Canonicalization succeeded for potentially problematic XML.");
|
|
101
|
+
} catch (error: any) {
|
|
102
|
+
// If it rejects, check the error
|
|
103
|
+
expect(error).toBeInstanceOf(Error)
|
|
104
|
+
// Check if the error message starts with the expected text
|
|
105
|
+
expect(error.message).toMatch(/^Canonicalization failed/)
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
// Add more tests for edge cases like comments (if using #WithComments algorithm), PIs, etc.
|
|
110
|
+
})
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import * as crypto from 'crypto'
|
|
3
|
+
import { hashCertificate } from '../src/utils/signature/hashCert'
|
|
4
|
+
|
|
5
|
+
// Use a more structured, plausible (but still generated) PEM certificate for testing the process.
|
|
6
|
+
// NOTE: To test against a *known external hash value*, replace this with a real
|
|
7
|
+
// certificate PEM and its pre-calculated SHA-256 Base64 hash.
|
|
8
|
+
const sampleValidPem = `
|
|
9
|
+
-----BEGIN CERTIFICATE-----
|
|
10
|
+
MIIDBjCCAe6gAwIBAgIQCisE3VSEefMG1/VZf0J4IzANBgkqhkiG9w0BAQsF
|
|
11
|
+
ADBFMQswCQYDVQQGEwJNWTEUMBIGA1UEChMLVGVzdCBDQSBQS0kxGDAWBgNV
|
|
12
|
+
BAMTD1Rlc3QgUm9vdCBDQSBLSzAeFw0yNDAxMDEwMDAwMDBaFw0zNDAxMDEw
|
|
13
|
+
MDAwMDBaMD8xCzAJBgNVBAYTAk1ZMRMwEQYDVQQKEwpUZXN0IFN1YkNBMRsw
|
|
14
|
+
GQYDVQQDExJUZXN0IENlcnRpZmljYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
|
15
|
+
AQ8AMIIBCgKCAQEAs/dKx0mC4c7k/w==
|
|
16
|
+
-----END CERTIFICATE-----
|
|
17
|
+
`
|
|
18
|
+
|
|
19
|
+
const sampleInvalidPemNoContent = `
|
|
20
|
+
-----BEGIN CERTIFICATE-----
|
|
21
|
+
-----END CERTIFICATE-----
|
|
22
|
+
`
|
|
23
|
+
|
|
24
|
+
const sampleInvalidPemBadFormat = `This is not a PEM certificate`
|
|
25
|
+
|
|
26
|
+
const samplePemWithInvalidBase64 = `
|
|
27
|
+
-----BEGIN CERTIFICATE-----
|
|
28
|
+
MIIDBjCCAe6gAwIBAgIQCisE3VSEefMG1/VZf0J4IzANBgkqhkiG9w0BAQsF
|
|
29
|
+
ADBFMQswCQYDVQQGEwJNWTEUMBIGA1UEChMLVGVzdCBDQSBQS0kxGDAWBgNV
|
|
30
|
+
***INVALID CHARACTERS HERE !@#$%^&*()***
|
|
31
|
+
BAMTD1Rlc3QgUm9vdCBDQSBLSzAeFw0yNDAxMDEwMDAwMDBaFw0zNDAxMDEw
|
|
32
|
+
MDAwMDBaMD8xCzAJBgNVBAYTAk1ZMRMwEQYDVQQKEwpUZXN0IFN1YkNBMRsw
|
|
33
|
+
AQ8AMIIBCgKCAQEAs/dKx0mC4c7k/w==
|
|
34
|
+
-----END CERTIFICATE-----
|
|
35
|
+
`
|
|
36
|
+
|
|
37
|
+
// Helper to calculate expected hash by extracting/cleaning/hashing PEM
|
|
38
|
+
// Mimics the core logic of hashCertificate for comparison
|
|
39
|
+
const calculateExpectedCertHash = (pemCert: string): string => {
|
|
40
|
+
const beginMarker = '-----BEGIN CERTIFICATE-----'
|
|
41
|
+
const endMarker = '-----END CERTIFICATE-----'
|
|
42
|
+
let base64Der = ''
|
|
43
|
+
|
|
44
|
+
const startIndex = pemCert.indexOf(beginMarker)
|
|
45
|
+
const endIndex = pemCert.indexOf(endMarker)
|
|
46
|
+
|
|
47
|
+
if (startIndex !== -1 && endIndex !== -1 && endIndex > startIndex) {
|
|
48
|
+
const content = pemCert.substring(startIndex + beginMarker.length, endIndex)
|
|
49
|
+
base64Der = content.replace(/[^A-Za-z0-9+/=]/g, '')
|
|
50
|
+
} else {
|
|
51
|
+
throw new Error('Helper could not find certificate markers')
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (base64Der.length === 0) {
|
|
55
|
+
throw new Error('Helper found no Base64 content')
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const rawDer = Buffer.from(base64Der, 'base64')
|
|
59
|
+
const hash = crypto.createHash('sha256')
|
|
60
|
+
hash.update(rawDer)
|
|
61
|
+
return hash.digest('base64')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
describe('hashCertificate', () => {
|
|
65
|
+
it('should correctly hash a valid PEM certificate (testing process)', () => {
|
|
66
|
+
const expectedHash = calculateExpectedCertHash(sampleValidPem)
|
|
67
|
+
const actualHash = hashCertificate(sampleValidPem)
|
|
68
|
+
expect(actualHash).toEqual(expectedHash)
|
|
69
|
+
expect(() => Buffer.from(actualHash, 'base64')).not.toThrow()
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('should throw an error for PEM with no content', () => {
|
|
73
|
+
expect(() => hashCertificate(sampleInvalidPemNoContent)).toThrow(
|
|
74
|
+
'Failed to hash certificate: Invalid PEM format: No Base64 content found between markers after cleaning.',
|
|
75
|
+
)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('should throw an error for non-PEM input (missing markers)', () => {
|
|
79
|
+
expect(() => hashCertificate(sampleInvalidPemBadFormat)).toThrow(
|
|
80
|
+
/^Failed to hash certificate: Invalid PEM format: Missing or misplaced BEGIN\/END markers/,
|
|
81
|
+
)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('should throw an error for empty string input', () => {
|
|
85
|
+
expect(() => hashCertificate('')).toThrow(
|
|
86
|
+
/^Failed to hash certificate: Invalid PEM format: Missing or misplaced BEGIN\/END markers/,
|
|
87
|
+
)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('should throw an error for invalid Base64 characters within valid markers', () => {
|
|
91
|
+
expect(() => hashCertificate(samplePemWithInvalidBase64)).toThrow(
|
|
92
|
+
/^Failed to hash certificate: Invalid non-Base64, non-whitespace characters detected/,
|
|
93
|
+
)
|
|
94
|
+
})
|
|
95
|
+
})
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { DOMParserImpl } from 'xmldom-ts'
|
|
3
|
+
import * as xpath from 'xpath-ts'
|
|
4
|
+
import * as crypto from 'crypto'
|
|
5
|
+
import c14nFactory from 'xml-c14n'
|
|
6
|
+
import { hashSignedProperties } from '../src/utils/signature/hashSignedProperties'
|
|
7
|
+
|
|
8
|
+
// Define namespaces matching those in the function
|
|
9
|
+
const ns = {
|
|
10
|
+
inv: 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2',
|
|
11
|
+
ext: 'urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2',
|
|
12
|
+
sig: 'urn:oasis:names:specification:ubl:schema:xsd:CommonSignatureComponents-2',
|
|
13
|
+
sac: 'urn:oasis:names:specification:ubl:schema:xsd:SignatureAggregateComponents-2',
|
|
14
|
+
ds: 'http://www.w3.org/2000/09/xmldsig#',
|
|
15
|
+
xades: 'http://uri.etsi.org/01903/v1.3.2#',
|
|
16
|
+
}
|
|
17
|
+
const select = xpath.useNamespaces(ns)
|
|
18
|
+
|
|
19
|
+
// Sample XML with a populated SignedProperties section
|
|
20
|
+
const sampleXmlWithSignedProps = `
|
|
21
|
+
<inv:Invoice xmlns:inv="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
|
|
22
|
+
xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2"
|
|
23
|
+
xmlns:sig="urn:oasis:names:specification:ubl:schema:xsd:CommonSignatureComponents-2"
|
|
24
|
+
xmlns:sac="urn:oasis:names:specification:ubl:schema:xsd:SignatureAggregateComponents-2"
|
|
25
|
+
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
|
|
26
|
+
xmlns:xades="http://uri.etsi.org/01903/v1.3.2#">
|
|
27
|
+
<ext:UBLExtensions>
|
|
28
|
+
<ext:UBLExtension>
|
|
29
|
+
<ext:ExtensionContent>
|
|
30
|
+
<sig:UBLDocumentSignatures>
|
|
31
|
+
<sac:SignatureInformation>
|
|
32
|
+
<ds:Signature>
|
|
33
|
+
<ds:Object>
|
|
34
|
+
<xades:QualifyingProperties>
|
|
35
|
+
<xades:SignedProperties>
|
|
36
|
+
<xades:SignedSignatureProperties>
|
|
37
|
+
<xades:SigningTime>2024-01-01T12:00:00Z</xades:SigningTime>
|
|
38
|
+
<xades:SigningCertificate>
|
|
39
|
+
<xades:Cert>
|
|
40
|
+
<xades:CertDigest>
|
|
41
|
+
<ds:DigestValue>TEST_CERT_DIGEST==</ds:DigestValue>
|
|
42
|
+
</xades:CertDigest>
|
|
43
|
+
<xades:IssuerSerial>
|
|
44
|
+
<ds:X509IssuerName>CN=Test Issuer, O=Test Org</ds:X509IssuerName>
|
|
45
|
+
<ds:X509SerialNumber>1234567890</ds:X509SerialNumber>
|
|
46
|
+
</xades:IssuerSerial>
|
|
47
|
+
</xades:Cert>
|
|
48
|
+
</xades:SigningCertificate>
|
|
49
|
+
</xades:SignedSignatureProperties>
|
|
50
|
+
</xades:SignedProperties>
|
|
51
|
+
</xades:QualifyingProperties>
|
|
52
|
+
</ds:Object>
|
|
53
|
+
</ds:Signature>
|
|
54
|
+
</sac:SignatureInformation>
|
|
55
|
+
</sig:UBLDocumentSignatures>
|
|
56
|
+
</ext:ExtensionContent>
|
|
57
|
+
</ext:UBLExtension>
|
|
58
|
+
</ext:UBLExtensions>
|
|
59
|
+
</inv:Invoice>
|
|
60
|
+
`
|
|
61
|
+
|
|
62
|
+
// Helper to canonicalize and hash a given node (for comparison)
|
|
63
|
+
const calculateExpectedPropsHash = (node: Node): Promise<string> => {
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
try {
|
|
66
|
+
const c14n = c14nFactory()
|
|
67
|
+
const algorithmUri = 'http://www.w3.org/2001/10/xml-exc-c14n#'
|
|
68
|
+
const canonicaliser = c14n.createCanonicaliser(algorithmUri)
|
|
69
|
+
|
|
70
|
+
canonicaliser.canonicalise(node, (error, canonicalXml) => {
|
|
71
|
+
if (error) return reject(error)
|
|
72
|
+
if (typeof canonicalXml !== 'string')
|
|
73
|
+
return reject(new Error('Canonicalization failed in helper'))
|
|
74
|
+
|
|
75
|
+
const hash = crypto.createHash('sha256')
|
|
76
|
+
hash.update(canonicalXml, 'utf8')
|
|
77
|
+
resolve(hash.digest('base64'))
|
|
78
|
+
})
|
|
79
|
+
} catch (e) {
|
|
80
|
+
reject(e)
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
describe('hashSignedProperties', () => {
|
|
86
|
+
const parser = new DOMParserImpl()
|
|
87
|
+
|
|
88
|
+
it('should correctly hash the SignedProperties element', async () => {
|
|
89
|
+
const doc = parser.parseFromString(
|
|
90
|
+
sampleXmlWithSignedProps,
|
|
91
|
+
'application/xml',
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
// Find the node in the test to calculate the expected hash
|
|
95
|
+
const signedPropertiesXPath = '//xades:SignedProperties' // Simplified XPath for test verification
|
|
96
|
+
const nodes = select(signedPropertiesXPath, doc)
|
|
97
|
+
expect(nodes).toBeInstanceOf(Array)
|
|
98
|
+
expect(nodes).toHaveLength(1)
|
|
99
|
+
const signedPropsNode = nodes[0] as Node
|
|
100
|
+
|
|
101
|
+
const expectedHash = await calculateExpectedPropsHash(signedPropsNode)
|
|
102
|
+
const actualHash = await hashSignedProperties(doc)
|
|
103
|
+
|
|
104
|
+
expect(actualHash).toEqual(expectedHash)
|
|
105
|
+
// Check if the output is a valid Base64 string
|
|
106
|
+
expect(() => Buffer.from(actualHash, 'base64')).not.toThrow()
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('should throw error if SignedProperties element is missing', async () => {
|
|
110
|
+
// Create XML missing the target element
|
|
111
|
+
const modifiedXml = sampleXmlWithSignedProps.replace(
|
|
112
|
+
/<xades:SignedProperties>.*<\/xades:SignedProperties>/s,
|
|
113
|
+
'',
|
|
114
|
+
)
|
|
115
|
+
const doc = parser.parseFromString(modifiedXml, 'application/xml')
|
|
116
|
+
|
|
117
|
+
await expect(hashSignedProperties(doc)).rejects.toThrow(
|
|
118
|
+
/^SignedProperties processing setup failed: SignedProperties element not found/,
|
|
119
|
+
)
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('should throw error if multiple SignedProperties elements are found', async () => {
|
|
123
|
+
// Create XML with duplicate target elements
|
|
124
|
+
const signedPropsBlock =
|
|
125
|
+
sampleXmlWithSignedProps.match(
|
|
126
|
+
/<xades:SignedProperties>.*<\/xades:SignedProperties>/s,
|
|
127
|
+
)?.[0] || ''
|
|
128
|
+
const modifiedXml = sampleXmlWithSignedProps.replace(
|
|
129
|
+
signedPropsBlock,
|
|
130
|
+
`${signedPropsBlock}${signedPropsBlock}`, // Duplicate the block
|
|
131
|
+
)
|
|
132
|
+
const doc = parser.parseFromString(modifiedXml, 'application/xml')
|
|
133
|
+
|
|
134
|
+
await expect(hashSignedProperties(doc)).rejects.toThrow(
|
|
135
|
+
/^SignedProperties processing setup failed: Multiple SignedProperties elements found/,
|
|
136
|
+
)
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
// Add test for canonicalization failure if possible (requires mocking c14n)
|
|
140
|
+
})
|