termdock 1.4.239 → 1.4.241
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/dist/client/assets/{App-CmlGDKDj.js → App-Dk1zwrS6.js} +3 -3
- package/dist/client/assets/App-Dk1zwrS6.js.br +0 -0
- package/dist/client/assets/App-Dk1zwrS6.js.gz +0 -0
- package/dist/client/assets/{ChangeWalkthroughPanel-9whVVXTr.js → ChangeWalkthroughPanel-C8tldKLn.js} +1 -1
- package/dist/client/assets/ChangeWalkthroughPanel-C8tldKLn.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-C8tldKLn.js.gz +0 -0
- package/dist/client/assets/{DagPlayground-y80OTTQj.js → DagPlayground-_8xFwzoy.js} +1 -1
- package/dist/client/assets/DagPlayground-_8xFwzoy.js.br +0 -0
- package/dist/client/assets/DagPlayground-_8xFwzoy.js.gz +0 -0
- package/dist/client/assets/{DiffLab-BY2wbRtg.js → DiffLab-Bm27LDoY.js} +1 -1
- package/dist/client/assets/DiffLab-Bm27LDoY.js.br +0 -0
- package/dist/client/assets/DiffLab-Bm27LDoY.js.gz +0 -0
- package/dist/client/assets/{DiffReview-DLlDJbK1.js → DiffReview-B_gl5KEk.js} +1 -1
- package/dist/client/assets/DiffReview-B_gl5KEk.js.br +0 -0
- package/dist/client/assets/DiffReview-B_gl5KEk.js.gz +0 -0
- package/dist/client/assets/{DiffReviewLab-CEpa_B8I.js → DiffReviewLab-Dgu955Xn.js} +1 -1
- package/dist/client/assets/DiffReviewLab-Dgu955Xn.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-Dgu955Xn.js.gz +0 -0
- package/dist/client/assets/{DiffViewer-GLkd1zMQ.js → DiffViewer-3tHakIDI.js} +1 -1
- package/dist/client/assets/DiffViewer-3tHakIDI.js.br +0 -0
- package/dist/client/assets/DiffViewer-3tHakIDI.js.gz +0 -0
- package/dist/client/assets/{ModelPreview-DB8tw45f.js → ModelPreview-D8rlVB76.js} +1 -1
- package/dist/client/assets/ModelPreview-D8rlVB76.js.br +0 -0
- package/dist/client/assets/ModelPreview-D8rlVB76.js.gz +0 -0
- package/dist/client/assets/{RightSidebar-aoJjOQGX.js → RightSidebar-Cd6fVuZ6.js} +4 -4
- package/dist/client/assets/RightSidebar-Cd6fVuZ6.js.br +0 -0
- package/dist/client/assets/RightSidebar-Cd6fVuZ6.js.gz +0 -0
- package/dist/client/assets/{abnfDiagram-VCTEODGH-RBGYciHa.js → abnfDiagram-VCTEODGH-Dt72PWoy.js} +1 -1
- package/dist/client/assets/abnfDiagram-VCTEODGH-Dt72PWoy.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-Dt72PWoy.js.gz +0 -0
- package/dist/client/assets/{app-Ctrh4Bku.js → app-DuOQ5oY3.js} +9 -9
- package/dist/client/assets/app-DuOQ5oY3.js.br +0 -0
- package/dist/client/assets/app-DuOQ5oY3.js.gz +0 -0
- package/dist/client/assets/{arc-CzQsNCup.js → arc-CKvN_JkE.js} +1 -1
- package/dist/client/assets/arc-CKvN_JkE.js.br +0 -0
- package/dist/client/assets/arc-CKvN_JkE.js.gz +0 -0
- package/dist/client/assets/{architectureDiagram-5GKGNRK7-sDp6hSiy.js → architectureDiagram-5GKGNRK7-CX7Gjex9.js} +1 -1
- package/dist/client/assets/{architectureDiagram-5GKGNRK7-sDp6hSiy.js.br → architectureDiagram-5GKGNRK7-CX7Gjex9.js.br} +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-CX7Gjex9.js.gz +0 -0
- package/dist/client/assets/{blockDiagram-I7D4REHJ-C-AHqZPo.js → blockDiagram-I7D4REHJ-BMaBqkw8.js} +1 -1
- package/dist/client/assets/blockDiagram-I7D4REHJ-BMaBqkw8.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-BMaBqkw8.js.gz +0 -0
- package/dist/client/assets/{c4Diagram-7LVT6UL2-B8VGhLwN.js → c4Diagram-7LVT6UL2-Bm7U73rl.js} +1 -1
- package/dist/client/assets/c4Diagram-7LVT6UL2-Bm7U73rl.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-Bm7U73rl.js.gz +0 -0
- package/dist/client/assets/channel-BukD64h5.js +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-D56jCJTr.js → chunk-2Q5K7J3B-B1NuLwpJ.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-cga3WKIM.js → chunk-5VM5RSS4-CjfAUVix.js} +1 -1
- package/dist/client/assets/{chunk-F27PBJKO-BNOR_7WA.js → chunk-F27PBJKO-KLmJjuc2.js} +1 -1
- package/dist/client/assets/chunk-F27PBJKO-KLmJjuc2.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-KLmJjuc2.js.gz +0 -0
- package/dist/client/assets/{chunk-IMKFNOWR-Dk12DKtC.js → chunk-IMKFNOWR-D1b50_xa.js} +1 -1
- package/dist/client/assets/chunk-IMKFNOWR-D1b50_xa.js.br +0 -0
- package/dist/client/assets/{chunk-IMKFNOWR-Dk12DKtC.js.gz → chunk-IMKFNOWR-D1b50_xa.js.gz} +0 -0
- package/dist/client/assets/{chunk-JWPE2WC7-CVqdLg0d.js → chunk-JWPE2WC7-CrjqhBX6.js} +1 -1
- package/dist/client/assets/{chunk-POPQ4Y6H-Y6gEzK15.js → chunk-POPQ4Y6H-Izugq_I1.js} +1 -1
- package/dist/client/assets/{chunk-SVP7TREG-BIJtdFBL.js → chunk-SVP7TREG-sL_467mK.js} +1 -1
- package/dist/client/assets/chunk-SVP7TREG-sL_467mK.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-sL_467mK.js.gz +0 -0
- package/dist/client/assets/{chunk-TICWLB2K-CS3jsxv7.js → chunk-TICWLB2K-BQWSilD2.js} +1 -1
- package/dist/client/assets/chunk-TICWLB2K-BQWSilD2.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-BQWSilD2.js.gz +0 -0
- package/dist/client/assets/{chunk-XXDRQBXY-BYgvxPrj.js → chunk-XXDRQBXY-C10F0akw.js} +1 -1
- package/dist/client/assets/classDiagram-ZZMXUADV-DA86AYYB.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-DA86AYYB.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-9udJiW7h.js → cose-bilkent-JH36ORCC-CrPAUlRG.js} +1 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-CrPAUlRG.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-CrPAUlRG.js.gz +0 -0
- package/dist/client/assets/{cynefin-OW5HDTMX-D-6q-6N2.js → cynefin-OW5HDTMX-Bx2REbom.js} +1 -1
- package/dist/client/assets/cynefin-OW5HDTMX-Bx2REbom.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-Bx2REbom.js.gz +0 -0
- package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-B5c37uFA.js → cynefinDiagram-5FMLGOSQ-DIdCmQka.js} +1 -1
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-DIdCmQka.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-DIdCmQka.js.gz +0 -0
- package/dist/client/assets/{dagre-GXQ25YYZ-DoFMIka4.js → dagre-GXQ25YYZ-6T64o8VI.js} +1 -1
- package/dist/client/assets/dagre-GXQ25YYZ-6T64o8VI.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-6T64o8VI.js.gz +0 -0
- package/dist/client/assets/{diagram-S7CK7UJ4-DrAwxGx7.js → diagram-S7CK7UJ4-BenkfLAl.js} +1 -1
- package/dist/client/assets/diagram-S7CK7UJ4-BenkfLAl.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-BenkfLAl.js.gz +0 -0
- package/dist/client/assets/{diagram-UQ7AKVKN-DbWfEzKd.js → diagram-UQ7AKVKN-BHobFcQF.js} +1 -1
- package/dist/client/assets/diagram-UQ7AKVKN-BHobFcQF.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-BHobFcQF.js.gz +0 -0
- package/dist/client/assets/{diagram-VSXAHHWV-zKcVacRq.js → diagram-VSXAHHWV-dhk5gov4.js} +1 -1
- package/dist/client/assets/diagram-VSXAHHWV-dhk5gov4.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-dhk5gov4.js.gz +0 -0
- package/dist/client/assets/{diagram-VX7I27RA-BNAI-5sG.js → diagram-VX7I27RA-98uipYMt.js} +1 -1
- package/dist/client/assets/diagram-VX7I27RA-98uipYMt.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-98uipYMt.js.gz +0 -0
- package/dist/client/assets/{diagram-Z3DM3KII-ChB9ZeuK.js → diagram-Z3DM3KII-Bi8PFZ27.js} +1 -1
- package/dist/client/assets/diagram-Z3DM3KII-Bi8PFZ27.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-Bi8PFZ27.js.gz +0 -0
- package/dist/client/assets/{ebnfDiagram-PWID7BFC-Fe8VFmWJ.js → ebnfDiagram-PWID7BFC-7NoB0jrU.js} +1 -1
- package/dist/client/assets/ebnfDiagram-PWID7BFC-7NoB0jrU.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-7NoB0jrU.js.gz +0 -0
- package/dist/client/assets/{erDiagram-RLTQ6QDP-CC7DagoX.js → erDiagram-RLTQ6QDP-C7Z9m9Nf.js} +1 -1
- package/dist/client/assets/erDiagram-RLTQ6QDP-C7Z9m9Nf.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-C7Z9m9Nf.js.gz +0 -0
- package/dist/client/assets/{flowDiagram-HODETNUW-BBIgixMV.js → flowDiagram-HODETNUW-BY1yTBdY.js} +1 -1
- package/dist/client/assets/flowDiagram-HODETNUW-BY1yTBdY.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-BY1yTBdY.js.gz +0 -0
- package/dist/client/assets/{ganttDiagram-EL5Y4UJY-CHRaIQ9P.js → ganttDiagram-EL5Y4UJY-BExP528m.js} +1 -1
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-BExP528m.js.br +0 -0
- package/dist/client/assets/{ganttDiagram-EL5Y4UJY-CHRaIQ9P.js.gz → ganttDiagram-EL5Y4UJY-BExP528m.js.gz} +0 -0
- package/dist/client/assets/{gestureArbiter-5c1oGojb.js → gestureArbiter-BX1L2PZl.js} +1 -1
- package/dist/client/assets/{gestureArbiter-5c1oGojb.js.br → gestureArbiter-BX1L2PZl.js.br} +0 -0
- package/dist/client/assets/gestureArbiter-BX1L2PZl.js.gz +0 -0
- package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-iJPivC9C.js → gitGraphDiagram-WWUBYQGX-Dgw8DcAZ.js} +1 -1
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-Dgw8DcAZ.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-Dgw8DcAZ.js.gz +0 -0
- package/dist/client/assets/{infoDiagram-27XIBGKW-CWjxPUb1.js → infoDiagram-27XIBGKW-BtyGlLCl.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-2dN_H6WK.js → ishikawaDiagram-5VMMS53U-DHor3FxJ.js} +1 -1
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-DHor3FxJ.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-DHor3FxJ.js.gz +0 -0
- package/dist/client/assets/{journeyDiagram-3NMN7TZE-BqY-OLE2.js → journeyDiagram-3NMN7TZE-zIpSOGqw.js} +1 -1
- package/dist/client/assets/journeyDiagram-3NMN7TZE-zIpSOGqw.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-zIpSOGqw.js.gz +0 -0
- package/dist/client/assets/{kanban-definition-UXKFOSKX-CSOXhjNh.js → kanban-definition-UXKFOSKX-Db-J_3Ke.js} +1 -1
- package/dist/client/assets/kanban-definition-UXKFOSKX-Db-J_3Ke.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-Db-J_3Ke.js.gz +0 -0
- package/dist/client/assets/{layout-BxIcRRf7.js → layout-fhC50xhx.js} +1 -1
- package/dist/client/assets/layout-fhC50xhx.js.br +0 -0
- package/dist/client/assets/layout-fhC50xhx.js.gz +0 -0
- package/dist/client/assets/{linear-BYWiw-Yd.js → linear-cRh-kitO.js} +1 -1
- package/dist/client/assets/linear-cRh-kitO.js.br +0 -0
- package/dist/client/assets/linear-cRh-kitO.js.gz +0 -0
- package/dist/client/assets/{mermaid.core-DhRpdkKn.js → mermaid.core-BJ-BnV2O.js} +5 -5
- package/dist/client/assets/mermaid.core-BJ-BnV2O.js.br +0 -0
- package/dist/client/assets/mermaid.core-BJ-BnV2O.js.gz +0 -0
- package/dist/client/assets/{mindmap-definition-YA3MSWOX-DwBcGwTF.js → mindmap-definition-YA3MSWOX-CASwnewq.js} +1 -1
- package/dist/client/assets/mindmap-definition-YA3MSWOX-CASwnewq.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-CASwnewq.js.gz +0 -0
- package/dist/client/assets/{passwordBootstrap-BkAa-DO2.js → passwordBootstrap-BUCqUzVV.js} +1 -1
- package/dist/client/assets/passwordBootstrap-BUCqUzVV.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-BUCqUzVV.js.gz +0 -0
- package/dist/client/assets/{pegDiagram-XKGWAZYB-D_04AQMs.js → pegDiagram-XKGWAZYB-DvxIsNki.js} +1 -1
- package/dist/client/assets/pegDiagram-XKGWAZYB-DvxIsNki.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-DvxIsNki.js.gz +0 -0
- package/dist/client/assets/{pieDiagram-E7YTZNPT-DgHIGdDc.js → pieDiagram-E7YTZNPT-Cd5KTCKr.js} +1 -1
- package/dist/client/assets/pieDiagram-E7YTZNPT-Cd5KTCKr.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-Cd5KTCKr.js.gz +0 -0
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-BrxP_uCp.js → quadrantDiagram-AXDQQJYC-B2Dzl9r4.js} +1 -1
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-B2Dzl9r4.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-B2Dzl9r4.js.gz +0 -0
- package/dist/client/assets/{railroadDiagram-O6MQD6OU-Bj8aV8et.js → railroadDiagram-O6MQD6OU-0k2P5vxC.js} +1 -1
- package/dist/client/assets/railroadDiagram-O6MQD6OU-0k2P5vxC.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-0k2P5vxC.js.gz +0 -0
- package/dist/client/assets/{referenceLongPress-CG4k8F2W.js → referenceLongPress-DiAiVNRD.js} +1 -1
- package/dist/client/assets/referenceLongPress-DiAiVNRD.js.br +0 -0
- package/dist/client/assets/referenceLongPress-DiAiVNRD.js.gz +0 -0
- package/dist/client/assets/{requirementDiagram-BXWQKSXE-DHOBnmaH.js → requirementDiagram-BXWQKSXE-q7DHcUvb.js} +1 -1
- package/dist/client/assets/requirementDiagram-BXWQKSXE-q7DHcUvb.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-q7DHcUvb.js.gz +0 -0
- package/dist/client/assets/{sankeyDiagram-P5KCCOFB-B46rNwzQ.js → sankeyDiagram-P5KCCOFB-Bl1JWXJq.js} +1 -1
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-Bl1JWXJq.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-Bl1JWXJq.js.gz +0 -0
- package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-D8PnDgC6.js → sequenceDiagram-WJ2MYXX4-BrEcjCaW.js} +1 -1
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BrEcjCaW.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BrEcjCaW.js.gz +0 -0
- package/dist/client/assets/{sizeCapture-INFHLROL-CjofpSnZ.js → sizeCapture-INFHLROL-JIXpO6YT.js} +1 -1
- package/dist/client/assets/sizeCapture-INFHLROL-JIXpO6YT.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-JIXpO6YT.js.gz +0 -0
- package/dist/client/assets/{sparkles-Zi8g0TMb.js → sparkles-Cr5Ep9Lu.js} +1 -1
- package/dist/client/assets/{stateDiagram-D77RDMKH-BX_StFJV.js → stateDiagram-D77RDMKH-uz_XpHV7.js} +1 -1
- package/dist/client/assets/stateDiagram-D77RDMKH-uz_XpHV7.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-uz_XpHV7.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-DLePl8jh.js +1 -0
- package/dist/client/assets/{swimlanes-42K2YHIH-bxGulCYh.js → swimlanes-42K2YHIH-BYE9uO28.js} +1 -1
- package/dist/client/assets/swimlanes-42K2YHIH-BYE9uO28.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-BYE9uO28.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-4NCunUpJ.js +8 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-DcHYPI0d.js → timeline-definition-24CTP7MA-46Pz3ht4.js} +1 -1
- package/dist/client/assets/timeline-definition-24CTP7MA-46Pz3ht4.js.br +0 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-DcHYPI0d.js.gz → timeline-definition-24CTP7MA-46Pz3ht4.js.gz} +0 -0
- package/dist/client/assets/{triangle-alert-BXXcxTk8.js → triangle-alert-CD2hoUd0.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-CjIGwkZf.js → vennDiagram-4TSXK5OY-K0fm406P.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-CjIGwkZf.js.br → vennDiagram-4TSXK5OY-K0fm406P.js.br} +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-K0fm406P.js.gz +0 -0
- package/dist/client/assets/{wardleyDiagram-VM6X3IG4-B-WK3Fil.js → wardleyDiagram-VM6X3IG4-Defom9Go.js} +1 -1
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-Defom9Go.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-Defom9Go.js.gz +0 -0
- package/dist/client/assets/{xychartDiagram-S5SC5T6Z-4RzKQfNK.js → xychartDiagram-S5SC5T6Z-DjylOW-i.js} +1 -1
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-DjylOW-i.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-DjylOW-i.js.gz +0 -0
- package/dist/client/index.html +1 -1
- package/dist/client/index.html.br +0 -0
- package/dist/client/index.html.gz +0 -0
- package/dist/client/sw.js +1 -1
- package/dist/client/sw.js.br +0 -0
- package/dist/client/sw.js.gz +0 -0
- package/dist/server/certificateWatcher.js +7 -29
- package/dist/server/cli.js +58 -83
- package/dist/server/entry.js +24 -2
- package/dist/server/federation/relay.js +3 -0
- package/dist/server/federation/routeAccess.js +39 -2
- package/dist/server/federation/runtime.js +5 -0
- package/dist/server/federation/selfRelay.js +182 -0
- package/dist/server/utils/certificateNames.js +12 -0
- package/package.json +1 -1
- package/runtime-manifest.json +3 -3
- package/dist/client/assets/App-CmlGDKDj.js.br +0 -0
- package/dist/client/assets/App-CmlGDKDj.js.gz +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-9whVVXTr.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-9whVVXTr.js.gz +0 -0
- package/dist/client/assets/DagPlayground-y80OTTQj.js.br +0 -0
- package/dist/client/assets/DagPlayground-y80OTTQj.js.gz +0 -0
- package/dist/client/assets/DiffLab-BY2wbRtg.js.br +0 -0
- package/dist/client/assets/DiffLab-BY2wbRtg.js.gz +0 -0
- package/dist/client/assets/DiffReview-DLlDJbK1.js.br +0 -0
- package/dist/client/assets/DiffReview-DLlDJbK1.js.gz +0 -0
- package/dist/client/assets/DiffReviewLab-CEpa_B8I.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-CEpa_B8I.js.gz +0 -0
- package/dist/client/assets/DiffViewer-GLkd1zMQ.js.br +0 -0
- package/dist/client/assets/DiffViewer-GLkd1zMQ.js.gz +0 -0
- package/dist/client/assets/ModelPreview-DB8tw45f.js.br +0 -0
- package/dist/client/assets/ModelPreview-DB8tw45f.js.gz +0 -0
- package/dist/client/assets/RightSidebar-aoJjOQGX.js.br +0 -0
- package/dist/client/assets/RightSidebar-aoJjOQGX.js.gz +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-RBGYciHa.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-RBGYciHa.js.gz +0 -0
- package/dist/client/assets/app-Ctrh4Bku.js.br +0 -0
- package/dist/client/assets/app-Ctrh4Bku.js.gz +0 -0
- package/dist/client/assets/arc-CzQsNCup.js.br +0 -0
- package/dist/client/assets/arc-CzQsNCup.js.gz +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-sDp6hSiy.js.gz +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-C-AHqZPo.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-C-AHqZPo.js.gz +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-B8VGhLwN.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-B8VGhLwN.js.gz +0 -0
- package/dist/client/assets/channel-zK78er-R.js +0 -1
- package/dist/client/assets/chunk-F27PBJKO-BNOR_7WA.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-BNOR_7WA.js.gz +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-Dk12DKtC.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-BIJtdFBL.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-BIJtdFBL.js.gz +0 -0
- package/dist/client/assets/chunk-TICWLB2K-CS3jsxv7.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-CS3jsxv7.js.gz +0 -0
- package/dist/client/assets/classDiagram-ZZMXUADV-BMh5Sak3.js +0 -1
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-BMh5Sak3.js +0 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-9udJiW7h.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-9udJiW7h.js.gz +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-D-6q-6N2.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-D-6q-6N2.js.gz +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-B5c37uFA.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-B5c37uFA.js.gz +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-DoFMIka4.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-DoFMIka4.js.gz +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-DrAwxGx7.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-DrAwxGx7.js.gz +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-DbWfEzKd.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-DbWfEzKd.js.gz +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-zKcVacRq.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-zKcVacRq.js.gz +0 -0
- package/dist/client/assets/diagram-VX7I27RA-BNAI-5sG.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-BNAI-5sG.js.gz +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-ChB9ZeuK.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-ChB9ZeuK.js.gz +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Fe8VFmWJ.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Fe8VFmWJ.js.gz +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-CC7DagoX.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-CC7DagoX.js.gz +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-BBIgixMV.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-BBIgixMV.js.gz +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-CHRaIQ9P.js.br +0 -0
- package/dist/client/assets/gestureArbiter-5c1oGojb.js.gz +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-iJPivC9C.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-iJPivC9C.js.gz +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-2dN_H6WK.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-2dN_H6WK.js.gz +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-BqY-OLE2.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-BqY-OLE2.js.gz +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-CSOXhjNh.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-CSOXhjNh.js.gz +0 -0
- package/dist/client/assets/layout-BxIcRRf7.js.br +0 -0
- package/dist/client/assets/layout-BxIcRRf7.js.gz +0 -0
- package/dist/client/assets/linear-BYWiw-Yd.js.br +0 -0
- package/dist/client/assets/linear-BYWiw-Yd.js.gz +0 -0
- package/dist/client/assets/mermaid.core-DhRpdkKn.js.br +0 -0
- package/dist/client/assets/mermaid.core-DhRpdkKn.js.gz +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-DwBcGwTF.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-DwBcGwTF.js.gz +0 -0
- package/dist/client/assets/passwordBootstrap-BkAa-DO2.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-BkAa-DO2.js.gz +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-D_04AQMs.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-D_04AQMs.js.gz +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-DgHIGdDc.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-DgHIGdDc.js.gz +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-BrxP_uCp.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-BrxP_uCp.js.gz +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-Bj8aV8et.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-Bj8aV8et.js.gz +0 -0
- package/dist/client/assets/referenceLongPress-CG4k8F2W.js.br +0 -0
- package/dist/client/assets/referenceLongPress-CG4k8F2W.js.gz +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-DHOBnmaH.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-DHOBnmaH.js.gz +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-B46rNwzQ.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-B46rNwzQ.js.gz +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-D8PnDgC6.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-D8PnDgC6.js.gz +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-CjofpSnZ.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-CjofpSnZ.js.gz +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-BX_StFJV.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-BX_StFJV.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-CMG96YGj.js +0 -1
- package/dist/client/assets/swimlanes-42K2YHIH-bxGulCYh.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-bxGulCYh.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-sPKOywKp.js +0 -8
- package/dist/client/assets/timeline-definition-24CTP7MA-DcHYPI0d.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-CjIGwkZf.js.gz +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-B-WK3Fil.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-B-WK3Fil.js.gz +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-4RzKQfNK.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-4RzKQfNK.js.gz +0 -0
package/dist/server/cli.js
CHANGED
|
@@ -20,6 +20,7 @@ import { detectLocalSessionContext, resolveLocalCollaborationContext } from './a
|
|
|
20
20
|
import { parseAutomationCommand, executeAutomationCommand, AUTOMATION_HELP } from './agent/automationCli.js';
|
|
21
21
|
import { parseCollaborationCommand, executeCollaborationCommand, COLLAB_HELP } from './agent/collaborationCli.js';
|
|
22
22
|
import fs from 'fs';
|
|
23
|
+
import { getMissingCertificateNames } from './utils/certificateNames.js';
|
|
23
24
|
import http from 'http';
|
|
24
25
|
import https from 'https';
|
|
25
26
|
import path from 'path';
|
|
@@ -323,19 +324,6 @@ function getOrCreateLocalApiToken() {
|
|
|
323
324
|
fs.writeFileSync(localApiTokenPath, `${token}\n`, { mode: 0o600 });
|
|
324
325
|
return token;
|
|
325
326
|
}
|
|
326
|
-
function buildServerState(params) {
|
|
327
|
-
return {
|
|
328
|
-
pid: params.pid,
|
|
329
|
-
host: params.host,
|
|
330
|
-
port: params.port,
|
|
331
|
-
scheme: params.scheme,
|
|
332
|
-
localUrl: `${params.scheme}://${params.host === '0.0.0.0' ? 'localhost' : params.host}:${params.port}`,
|
|
333
|
-
localAccessReason: params.localAccessReason,
|
|
334
|
-
logFile: logFilePath,
|
|
335
|
-
startedAt: new Date().toISOString(),
|
|
336
|
-
localApiToken: params.localApiToken,
|
|
337
|
-
};
|
|
338
|
-
}
|
|
339
327
|
function fileExists(filePath) {
|
|
340
328
|
return typeof filePath === 'string' && filePath.length > 0 && fs.existsSync(filePath);
|
|
341
329
|
}
|
|
@@ -417,50 +405,10 @@ function getRequiredLocalHttpsNames() {
|
|
|
417
405
|
'::1',
|
|
418
406
|
];
|
|
419
407
|
}
|
|
420
|
-
async function readCertificateSans(certPath) {
|
|
421
|
-
try {
|
|
422
|
-
const { stdout } = await execFileAsync('openssl', ['x509', '-in', certPath, '-noout', '-ext', 'subjectAltName'], {
|
|
423
|
-
timeout: 5000,
|
|
424
|
-
maxBuffer: 256 * 1024,
|
|
425
|
-
});
|
|
426
|
-
return stdout
|
|
427
|
-
.split(/[\n,]/)
|
|
428
|
-
.map((part) => part.trim())
|
|
429
|
-
.filter(Boolean);
|
|
430
|
-
}
|
|
431
|
-
catch {
|
|
432
|
-
return [];
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
function sanMatches(required, sans) {
|
|
436
|
-
if (/^\d+\.\d+\.\d+\.\d+$/.test(required)) {
|
|
437
|
-
return sans.some((san) => san === `IP Address:${required}` || san === `IP:${required}`);
|
|
438
|
-
}
|
|
439
|
-
if (required.includes(':')) {
|
|
440
|
-
const normalizeIpv6 = (value) => {
|
|
441
|
-
const [left = '', right = ''] = value.toLowerCase().split('::');
|
|
442
|
-
const leftGroups = left ? left.split(':') : [];
|
|
443
|
-
const rightGroups = right ? right.split(':') : [];
|
|
444
|
-
const missing = Math.max(0, 8 - leftGroups.length - rightGroups.length);
|
|
445
|
-
return [...leftGroups, ...Array(missing).fill('0'), ...rightGroups]
|
|
446
|
-
.map((group) => Number.parseInt(group || '0', 16).toString(16))
|
|
447
|
-
.join(':');
|
|
448
|
-
};
|
|
449
|
-
const normalizedRequired = normalizeIpv6(required);
|
|
450
|
-
return sans.some((san) => {
|
|
451
|
-
const match = /^(?:IP Address|IP):(.+)$/.exec(san);
|
|
452
|
-
return match ? normalizeIpv6(match[1]) === normalizedRequired : false;
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
return sans.some((san) => san === `DNS:${required}`);
|
|
456
|
-
}
|
|
457
408
|
async function defaultCertificateNeedsRefresh() {
|
|
458
409
|
if (!fileExists(defaultHttpsCertPath) || !fileExists(defaultHttpsKeyPath))
|
|
459
410
|
return true;
|
|
460
|
-
|
|
461
|
-
if (sans.length === 0)
|
|
462
|
-
return true;
|
|
463
|
-
return getRequiredLocalHttpsNames().some((name) => !sanMatches(name, sans));
|
|
411
|
+
return (await getMissingCertificateNames(defaultHttpsCertPath, getRequiredLocalHttpsNames())).length > 0;
|
|
464
412
|
}
|
|
465
413
|
async function ensureDefaultHttpsCertificateFresh() {
|
|
466
414
|
if (!(await defaultCertificateNeedsRefresh()))
|
|
@@ -1443,12 +1391,19 @@ const STOP_GRACE_MS = 5000;
|
|
|
1443
1391
|
/** Max time to wait for the daemon child to respond to /health after spawn. */
|
|
1444
1392
|
const DAEMON_START_TIMEOUT_MS = 10000;
|
|
1445
1393
|
/** Poll the health endpoint until it responds or timeout expires. */
|
|
1446
|
-
async function waitForHealth(healthUrl, caPath, timeoutMs) {
|
|
1394
|
+
async function waitForHealth(healthUrl, caPath, timeoutMs, isReady, isAlive) {
|
|
1447
1395
|
const deadline = Date.now() + timeoutMs;
|
|
1448
1396
|
while (Date.now() < deadline) {
|
|
1397
|
+
if (!isAlive())
|
|
1398
|
+
return false;
|
|
1399
|
+
if (!isReady()) {
|
|
1400
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
1401
|
+
continue;
|
|
1402
|
+
}
|
|
1449
1403
|
try {
|
|
1450
1404
|
const ok = await new Promise((resolve) => {
|
|
1451
|
-
const
|
|
1405
|
+
const transport = healthUrl.startsWith('https:') ? https : http;
|
|
1406
|
+
const req = transport.get(healthUrl, {
|
|
1452
1407
|
ca: caPath ? fs.readFileSync(caPath) : undefined,
|
|
1453
1408
|
rejectUnauthorized: Boolean(caPath),
|
|
1454
1409
|
timeout: 2000,
|
|
@@ -1460,7 +1415,7 @@ async function waitForHealth(healthUrl, caPath, timeoutMs) {
|
|
|
1460
1415
|
req.on('error', () => resolve(false));
|
|
1461
1416
|
req.on('timeout', () => { req.destroy(); resolve(false); });
|
|
1462
1417
|
});
|
|
1463
|
-
if (ok)
|
|
1418
|
+
if (ok && isAlive())
|
|
1464
1419
|
return true;
|
|
1465
1420
|
}
|
|
1466
1421
|
catch {
|
|
@@ -3473,10 +3428,6 @@ async function main() {
|
|
|
3473
3428
|
await runPluginRemove(options.pluginRemove);
|
|
3474
3429
|
process.exit(0);
|
|
3475
3430
|
}
|
|
3476
|
-
const localApiToken = getOrCreateLocalApiToken();
|
|
3477
|
-
await refreshDefaultHttpsCertificateSafely();
|
|
3478
|
-
const https = resolveHttpsOptions(options);
|
|
3479
|
-
const isManagedDefaultHttps = Boolean(https.cert === defaultHttpsCertPath && https.key === defaultHttpsKeyPath);
|
|
3480
3431
|
if (options.status) {
|
|
3481
3432
|
const runningState = getRunningState();
|
|
3482
3433
|
if (!runningState) {
|
|
@@ -3513,6 +3464,10 @@ async function main() {
|
|
|
3513
3464
|
}
|
|
3514
3465
|
process.exit(0);
|
|
3515
3466
|
}
|
|
3467
|
+
const localApiToken = getOrCreateLocalApiToken();
|
|
3468
|
+
await refreshDefaultHttpsCertificateSafely();
|
|
3469
|
+
const https = resolveHttpsOptions(options);
|
|
3470
|
+
const isManagedDefaultHttps = Boolean(https.cert === defaultHttpsCertPath && https.key === defaultHttpsKeyPath);
|
|
3516
3471
|
if (options.foreground) {
|
|
3517
3472
|
// Boot check (marker prevents re-run if parent already completed)
|
|
3518
3473
|
runBootChecks();
|
|
@@ -3582,6 +3537,20 @@ async function main() {
|
|
|
3582
3537
|
startedAt: new Date().toISOString(),
|
|
3583
3538
|
localApiToken,
|
|
3584
3539
|
});
|
|
3540
|
+
// Only this child can acknowledge startup; an existing listener on the
|
|
3541
|
+
// same port must not make the parent report a successful launch.
|
|
3542
|
+
const acknowledgeStartup = () => {
|
|
3543
|
+
if (process.connected) {
|
|
3544
|
+
process.send?.({ type: 'termdock-ready' }, () => {
|
|
3545
|
+
if (process.connected)
|
|
3546
|
+
process.disconnect();
|
|
3547
|
+
});
|
|
3548
|
+
}
|
|
3549
|
+
};
|
|
3550
|
+
if (result.server.listening)
|
|
3551
|
+
acknowledgeStartup();
|
|
3552
|
+
else
|
|
3553
|
+
result.server.once('listening', acknowledgeStartup);
|
|
3585
3554
|
return;
|
|
3586
3555
|
}
|
|
3587
3556
|
const runningState = getRunningState();
|
|
@@ -3622,24 +3591,40 @@ async function main() {
|
|
|
3622
3591
|
childArgs.push('--https-ca', activeHttps.ca);
|
|
3623
3592
|
}
|
|
3624
3593
|
const scheme = activeHttps.cert && activeHttps.key ? 'https' : 'http';
|
|
3625
|
-
const localAccessReason = activeHttps.source === 'default'
|
|
3626
|
-
? 'Using local HTTPS certificates from ~/.termdock/certs.'
|
|
3627
|
-
: null;
|
|
3628
3594
|
const logFileFd = fs.openSync(logFilePath, 'a');
|
|
3629
3595
|
const child = spawn(process.execPath, childArgs, {
|
|
3630
3596
|
detached: true,
|
|
3631
|
-
stdio: ['ignore', logFileFd, logFileFd],
|
|
3597
|
+
stdio: ['ignore', logFileFd, logFileFd, 'ipc'],
|
|
3632
3598
|
});
|
|
3633
3599
|
fs.closeSync(logFileFd);
|
|
3600
|
+
let ready = false;
|
|
3601
|
+
let startupError;
|
|
3602
|
+
child.on('error', (error) => { startupError = error; });
|
|
3603
|
+
child.on('message', (message) => {
|
|
3604
|
+
if (message && typeof message === 'object' && 'type' in message
|
|
3605
|
+
&& message.type === 'termdock-ready')
|
|
3606
|
+
ready = true;
|
|
3607
|
+
});
|
|
3608
|
+
const isAlive = () => !startupError && child.pid !== undefined
|
|
3609
|
+
&& child.exitCode === null && child.signalCode === null && isProcessRunning(child.pid);
|
|
3610
|
+
const displayHost = childHost === '0.0.0.0' ? 'localhost' : childHost;
|
|
3611
|
+
const healthOk = await waitForHealth(`${scheme}://${displayHost}:${childPort}/health`, activeHttps.ca, DAEMON_START_TIMEOUT_MS, () => ready, isAlive);
|
|
3612
|
+
if (child.connected)
|
|
3613
|
+
child.disconnect();
|
|
3634
3614
|
child.unref();
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3615
|
+
if (!healthOk) {
|
|
3616
|
+
const alive = isAlive();
|
|
3617
|
+
if (!alive && child.pid !== undefined && readState()?.pid === child.pid)
|
|
3618
|
+
removeStateFile();
|
|
3619
|
+
const detail = startupError?.message ?? (alive
|
|
3620
|
+
? 'Startup timed out; the process is still running but readiness could not be confirmed.'
|
|
3621
|
+
: `Background process exited (code: ${child.exitCode ?? 'unknown'}, signal: ${child.signalCode ?? 'none'}).`);
|
|
3622
|
+
console.error(`${ICON.err} ${c.red('Termdock startup could not be confirmed.')} ${detail}`);
|
|
3623
|
+
console.error(` ${c.dim('Log:')} ${logFilePath}`);
|
|
3624
|
+
console.error(` Read the startup error with: tail -n 80 ${shellQuote(logFilePath)}`);
|
|
3625
|
+
process.exitCode = 1;
|
|
3626
|
+
return;
|
|
3627
|
+
}
|
|
3643
3628
|
console.log(`${ICON.ok} ${c.green('Termdock started in background.')}`);
|
|
3644
3629
|
console.log(` ${c.dim('URL:')} ${c.cyan(`${scheme}://${childHost === '0.0.0.0' ? 'localhost' : childHost}:${childPort}`)}`);
|
|
3645
3630
|
if (scheme === 'https') {
|
|
@@ -3651,16 +3636,6 @@ async function main() {
|
|
|
3651
3636
|
console.log(` ${c.dim('PID:')} ${child.pid}`);
|
|
3652
3637
|
console.log(` ${c.dim('Log:')} ${logFilePath}`);
|
|
3653
3638
|
warnIfAuthDisabled(childHost);
|
|
3654
|
-
// Wait for the daemon child to become healthy before returning — a
|
|
3655
|
-
// subsequent deploy step that curls the server won't race startup.
|
|
3656
|
-
{
|
|
3657
|
-
const displayHost = childHost === '0.0.0.0' ? 'localhost' : childHost;
|
|
3658
|
-
const healthUrl = `${scheme}://${displayHost}:${childPort}/health`;
|
|
3659
|
-
const healthOk = await waitForHealth(healthUrl, activeHttps.ca, DAEMON_START_TIMEOUT_MS);
|
|
3660
|
-
if (!healthOk) {
|
|
3661
|
-
console.log(`${ICON.warn} ${c.yellow('Server started but health check did not respond in time — it may still be initializing.')}`);
|
|
3662
|
-
}
|
|
3663
|
-
}
|
|
3664
3639
|
process.exit(0);
|
|
3665
3640
|
}
|
|
3666
3641
|
main().catch((err) => {
|
package/dist/server/entry.js
CHANGED
|
@@ -14,6 +14,7 @@ import { RouteInvitationStore } from './federation/routeInvitations.js';
|
|
|
14
14
|
import { attachRegisteredDirectTargets, verifyDirectTarget } from './federation/directRoutes.js';
|
|
15
15
|
import { secureChannelOriginAllowed } from './federation/originPolicy.js';
|
|
16
16
|
import { RelayRouter } from './federation/relay.js';
|
|
17
|
+
import { DesktopSelfRelay } from './federation/selfRelay.js';
|
|
17
18
|
import { assertPublicSecurity, securityHeaders } from './utils/publicSecurity.js';
|
|
18
19
|
import { apiCachePolicy } from './utils/apiCachePolicy.js';
|
|
19
20
|
import 'dotenv/config';
|
|
@@ -415,13 +416,15 @@ export function startServer(options = {}) {
|
|
|
415
416
|
let entrySubjectAllowed = (_subjectId) => false;
|
|
416
417
|
let routeInvitations;
|
|
417
418
|
let federationServiceId = '';
|
|
419
|
+
let activeRouteIds = () => [];
|
|
418
420
|
const desktopTargets = () => desktopDirectTargets(path.join(homedir(), '.termdock', 'desktop.json'), federationServiceId);
|
|
419
|
-
const routeAccess = new RouteAccess(path.join(homedir(), '.termdock', 'federation', 'routes.json'), Date.now, (subjectId, targetServiceId) => routeInvitations?.allows(subjectId, targetServiceId) === true || collaborationTransport?.canRoute(subjectId, targetServiceId) === true, desktopTargets);
|
|
421
|
+
const routeAccess = new RouteAccess(path.join(homedir(), '.termdock', 'federation', 'routes.json'), Date.now, (subjectId, targetServiceId) => routeInvitations?.allows(subjectId, targetServiceId) === true || collaborationTransport?.canRoute(subjectId, targetServiceId) === true, desktopTargets, () => activeRouteIds());
|
|
420
422
|
const relayRouter = new RelayRouter({
|
|
421
423
|
authenticate: context => context,
|
|
422
424
|
allowRegister: (principal, serviceId) => routeAccess.allowRegister(principal, serviceId),
|
|
423
425
|
allowRoute: (principal, serviceId) => routeAccess.allowRoute(principal, serviceId),
|
|
424
426
|
});
|
|
427
|
+
activeRouteIds = () => relayRouter.activeRouteIds();
|
|
425
428
|
const dynamicDirectTargets = new Map();
|
|
426
429
|
const refreshDirectTargets = () => {
|
|
427
430
|
const desired = new Map(routeAccess.configuredDirectTargets().filter(target => target.serviceId !== federationServiceId).map(target => [target.serviceId, target]));
|
|
@@ -493,6 +496,7 @@ export function startServer(options = {}) {
|
|
|
493
496
|
},
|
|
494
497
|
revokeRouteAccess: id => routeInvitations?.revoke(id) || false,
|
|
495
498
|
issueRouteTicket: (subjectId, serviceId) => routeAccess.issueRouteTicket(subjectId, serviceId),
|
|
499
|
+
issueSelfRelayTicket: (serviceId) => routeAccess.issueSelfRelayTicket(serviceId),
|
|
496
500
|
hasRouteGrant: (subjectId, serviceId) => routeInvitations?.allows(subjectId, serviceId) === true || collaborationTransport?.canRoute(subjectId, serviceId) === true,
|
|
497
501
|
createRouteInvitation: (issuerId, serviceId) => {
|
|
498
502
|
if (!routeInvitations)
|
|
@@ -567,6 +571,20 @@ export function startServer(options = {}) {
|
|
|
567
571
|
issuerAllowed: subjectId => entrySubjectAllowed(subjectId),
|
|
568
572
|
targetAvailable: serviceId => routeAccess.hasConfiguredTarget(serviceId) && relayRouter.hasRoute(serviceId),
|
|
569
573
|
});
|
|
574
|
+
let localCa;
|
|
575
|
+
if (scheme === 'https' && options.httpsCaPath)
|
|
576
|
+
try {
|
|
577
|
+
localCa = fs.readFileSync(options.httpsCaPath);
|
|
578
|
+
}
|
|
579
|
+
catch { /* System trust may still validate the local certificate. */ }
|
|
580
|
+
const localHostname = ['0.0.0.0', '::'].includes(host) ? 'localhost' : host;
|
|
581
|
+
const localAuthority = localHostname.includes(':') && !localHostname.startsWith('[') ? `[${localHostname}]` : localHostname;
|
|
582
|
+
const selfRelay = new DesktopSelfRelay({
|
|
583
|
+
desktopFile: path.join(homedir(), '.termdock', 'desktop.json'), identity: runtime.identity, serviceId: runtime.serviceId,
|
|
584
|
+
localOrigin: `${scheme}://${localAuthority}:${port}`, ...(localCa ? { localCa } : {}),
|
|
585
|
+
});
|
|
586
|
+
selfRelay.start();
|
|
587
|
+
server.once('close', () => selfRelay.close());
|
|
570
588
|
}).catch(() => console.error('Route invitations unavailable; uninitialized route grants remain denied.'));
|
|
571
589
|
void federation.catch(() => console.error('Encrypted access initialization failed; business access remains closed.'));
|
|
572
590
|
server.once('close', () => { void federation.then(runtime => runtime.close()).catch(() => { }); });
|
|
@@ -661,7 +679,11 @@ export function startServer(options = {}) {
|
|
|
661
679
|
socket.end('HTTP/1.1 403 Forbidden\r\nConnection: close\r\n\r\n');
|
|
662
680
|
return;
|
|
663
681
|
}
|
|
664
|
-
const
|
|
682
|
+
const routeToken = url.searchParams.get('routeToken');
|
|
683
|
+
const selfRelayToken = url.searchParams.get('selfRelayToken');
|
|
684
|
+
const principal = selfRelayToken && !request.headers.authorization && !routeToken
|
|
685
|
+
? routeAccess.authenticateSelfRelay(selfRelayToken)
|
|
686
|
+
: !selfRelayToken ? routeAccess.authenticate(request.headers.authorization, routeToken) : null;
|
|
665
687
|
if (!principal) {
|
|
666
688
|
socket.end('HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n');
|
|
667
689
|
return;
|
|
@@ -111,6 +111,9 @@ export class RelayRouter {
|
|
|
111
111
|
const route = this.routes.get(serviceId);
|
|
112
112
|
return !this.stopped && !!route && route.expires > Date.now() && route.peer.ws.readyState === 1 && this.canRegister(route.peer, serviceId);
|
|
113
113
|
}
|
|
114
|
+
activeRouteIds() {
|
|
115
|
+
return [...this.routes.keys()].filter(serviceId => this.hasRoute(serviceId));
|
|
116
|
+
}
|
|
114
117
|
/** Trusted local configuration only. Clients never supply a target URL or factory. */
|
|
115
118
|
registerDirect(serviceId, connect) {
|
|
116
119
|
if (this.stopped || !identifier(serviceId) || typeof connect !== 'function' || this.hasRoute(serviceId))
|
|
@@ -9,12 +9,15 @@ export class RouteAccess {
|
|
|
9
9
|
now;
|
|
10
10
|
canRouteSubject;
|
|
11
11
|
additionalTargets;
|
|
12
|
+
additionalTargetIds;
|
|
12
13
|
tickets = new Map();
|
|
13
|
-
|
|
14
|
+
selfRelayTickets = new Map();
|
|
15
|
+
constructor(filePath, now = Date.now, canRouteSubject = () => false, additionalTargets = () => [], additionalTargetIds = () => []) {
|
|
14
16
|
this.filePath = filePath;
|
|
15
17
|
this.now = now;
|
|
16
18
|
this.canRouteSubject = canRouteSubject;
|
|
17
19
|
this.additionalTargets = additionalTargets;
|
|
20
|
+
this.additionalTargetIds = additionalTargetIds;
|
|
18
21
|
}
|
|
19
22
|
registry() {
|
|
20
23
|
const empty = { relays: [], directTargets: [] };
|
|
@@ -62,6 +65,34 @@ export class RouteAccess {
|
|
|
62
65
|
this.tickets.set(digest(routeToken).toString('hex'), { subjectId, serviceId, expiresAt });
|
|
63
66
|
return { routeToken, expiresAt };
|
|
64
67
|
}
|
|
68
|
+
/** A Noise-authenticated service can advertise only its own identity. The
|
|
69
|
+
* short-lived token merely transfers that identity onto the relay socket; it
|
|
70
|
+
* grants neither route use nor target-service access. */
|
|
71
|
+
issueSelfRelayTicket(serviceId) {
|
|
72
|
+
if (!validId(serviceId))
|
|
73
|
+
throw new Error('INVALID_SELF_RELAY_IDENTITY');
|
|
74
|
+
for (const [key, value] of this.selfRelayTickets)
|
|
75
|
+
if (value.expiresAt <= this.now())
|
|
76
|
+
this.selfRelayTickets.delete(key);
|
|
77
|
+
if (this.selfRelayTickets.size >= 1024)
|
|
78
|
+
throw new Error('SELF_RELAY_TICKET_LIMIT');
|
|
79
|
+
const selfRelayToken = randomBytes(32).toString('base64url');
|
|
80
|
+
const expiresAt = this.now() + 30_000;
|
|
81
|
+
this.selfRelayTickets.set(digest(selfRelayToken).toString('hex'), { serviceId, expiresAt });
|
|
82
|
+
return { selfRelayToken, expiresAt };
|
|
83
|
+
}
|
|
84
|
+
/** Single-use, fail-closed transfer from the authenticated Noise channel to
|
|
85
|
+
* the opaque relay transport. */
|
|
86
|
+
authenticateSelfRelay(selfRelayToken) {
|
|
87
|
+
if (!selfRelayToken || selfRelayToken.length > 512)
|
|
88
|
+
return null;
|
|
89
|
+
const key = digest(selfRelayToken).toString('hex');
|
|
90
|
+
const ticket = this.selfRelayTickets.get(key);
|
|
91
|
+
this.selfRelayTickets.delete(key);
|
|
92
|
+
if (!ticket || ticket.expiresAt <= this.now())
|
|
93
|
+
return null;
|
|
94
|
+
return { kind: 'self-relay', serviceId: ticket.serviceId };
|
|
95
|
+
}
|
|
65
96
|
/** Called once before upgrading. A route ticket is consumed even if expired. */
|
|
66
97
|
authenticate(authorization, routeToken) {
|
|
67
98
|
if (authorization && routeToken)
|
|
@@ -83,6 +114,8 @@ export class RouteAccess {
|
|
|
83
114
|
return { kind: 'client', subjectId: ticket.subjectId, serviceId: ticket.serviceId };
|
|
84
115
|
}
|
|
85
116
|
allowRegister(principal, serviceId) {
|
|
117
|
+
if (principal.kind === 'self-relay')
|
|
118
|
+
return principal.serviceId === serviceId;
|
|
86
119
|
return principal.kind === 'relay' && this.relays().some(r => r.id === principal.id && digest(r.token).toString('hex') === principal.tokenHash && r.targets.includes(serviceId));
|
|
87
120
|
}
|
|
88
121
|
allowRoute(principal, serviceId) {
|
|
@@ -92,7 +125,8 @@ export class RouteAccess {
|
|
|
92
125
|
if (!validId(serviceId))
|
|
93
126
|
return false;
|
|
94
127
|
const registry = this.registry();
|
|
95
|
-
return registry.relays.some(relay => relay.targets.includes(serviceId)) || registry.directTargets.some(target => target.serviceId === serviceId)
|
|
128
|
+
return registry.relays.some(relay => relay.targets.includes(serviceId)) || registry.directTargets.some(target => target.serviceId === serviceId)
|
|
129
|
+
|| this.additionalTargets().some(target => target.serviceId === serviceId) || this.additionalTargetIds().includes(serviceId);
|
|
96
130
|
}
|
|
97
131
|
addDirectTarget(target) {
|
|
98
132
|
const url = new URL(target.url);
|
|
@@ -139,6 +173,9 @@ export class RouteAccess {
|
|
|
139
173
|
url.protocol = 'https:';
|
|
140
174
|
targets.set(target.serviceId, { serviceId: target.serviceId, url: url.origin, ...(target.label ? { label: target.label } : {}) });
|
|
141
175
|
}
|
|
176
|
+
for (const serviceId of this.additionalTargetIds())
|
|
177
|
+
if (validId(serviceId) && !targets.has(serviceId))
|
|
178
|
+
targets.set(serviceId, { serviceId });
|
|
142
179
|
return [...targets.values()];
|
|
143
180
|
}
|
|
144
181
|
}
|
|
@@ -356,6 +356,11 @@ export async function createFederationRuntime(app, directory, handlers, options
|
|
|
356
356
|
});
|
|
357
357
|
send({ type: 'result', id: packet.id, items });
|
|
358
358
|
}
|
|
359
|
+
else if (packet.type === 'self-relay-ticket') {
|
|
360
|
+
if (!options.issueSelfRelayTicket)
|
|
361
|
+
throw new Error('SELF_RELAY_UNAVAILABLE');
|
|
362
|
+
send({ type: 'result', id: packet.id, serviceId: subjectId, ...options.issueSelfRelayTicket(subjectId) });
|
|
363
|
+
}
|
|
359
364
|
else if (packet.type === 'route-invite-create') {
|
|
360
365
|
check('authorization.manage');
|
|
361
366
|
if (!options.createRouteInvitation || typeof packet.serviceId !== 'string' || !packet.serviceId || packet.serviceId.length > 512)
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import WebSocket from 'ws';
|
|
2
|
+
import { desktopDirectTargets } from './desktopTargets.js';
|
|
3
|
+
import { RelayClient } from './relay.js';
|
|
4
|
+
import { readPinnedCertificateAuthority } from './trustedCa.js';
|
|
5
|
+
import { connectCollaborationRpc } from '../agent/collaborationPeerTransport.js';
|
|
6
|
+
function relayEndpoint(origin, selfRelayToken) {
|
|
7
|
+
const url = new URL('/api/federation/relay', origin);
|
|
8
|
+
url.protocol = 'wss:';
|
|
9
|
+
url.searchParams.set('selfRelayToken', selfRelayToken);
|
|
10
|
+
return url.href;
|
|
11
|
+
}
|
|
12
|
+
function secureEndpoint(origin) {
|
|
13
|
+
const url = new URL('/api/federation/secure', origin);
|
|
14
|
+
url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
15
|
+
return url.href;
|
|
16
|
+
}
|
|
17
|
+
function openSocket(url, ca, maxPayload = 256 * 1024) {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
const secure = new URL(url).protocol === 'wss:';
|
|
20
|
+
const socket = new WebSocket(url, {
|
|
21
|
+
...(secure ? { ...(ca ? { ca } : {}), rejectUnauthorized: true } : {}),
|
|
22
|
+
followRedirects: false,
|
|
23
|
+
handshakeTimeout: 10_000,
|
|
24
|
+
maxPayload,
|
|
25
|
+
});
|
|
26
|
+
const failed = () => { cleanup(); socket.terminate(); reject(new Error('SELF_RELAY_CONNECTION_FAILED')); };
|
|
27
|
+
const opened = () => { cleanup(); socket.on('error', () => socket.terminate()); resolve(socket); };
|
|
28
|
+
const cleanup = () => { socket.off('open', opened); socket.off('error', failed); socket.off('close', failed); };
|
|
29
|
+
socket.once('open', opened);
|
|
30
|
+
socket.once('error', failed);
|
|
31
|
+
socket.once('close', failed);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function waitForReady(socket) {
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
const timer = setTimeout(() => fail(), 10_000);
|
|
37
|
+
timer.unref?.();
|
|
38
|
+
const cleanup = () => { clearTimeout(timer); socket.off('message', ready); socket.off('close', fail); };
|
|
39
|
+
const fail = () => { cleanup(); socket.terminate(); reject(new Error('SELF_RELAY_AUTHENTICATION_FAILED')); };
|
|
40
|
+
const ready = (raw, binary) => {
|
|
41
|
+
try {
|
|
42
|
+
const frame = binary ? null : JSON.parse(raw.toString());
|
|
43
|
+
if (frame?.type !== 'ready') {
|
|
44
|
+
fail();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
cleanup();
|
|
48
|
+
resolve();
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
fail();
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
socket.once('message', ready);
|
|
55
|
+
socket.once('close', fail);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A local Termdock service may publish only its own stable identity to other
|
|
60
|
+
* services pinned by the same Desktop installation. Desktop supplies addresses
|
|
61
|
+
* and CA pins only; the service proves itself with its own Noise identity and
|
|
62
|
+
* no browser/device authorization is copied into this process.
|
|
63
|
+
*/
|
|
64
|
+
export class DesktopSelfRelay {
|
|
65
|
+
options;
|
|
66
|
+
states = new Map();
|
|
67
|
+
timer;
|
|
68
|
+
stopped = false;
|
|
69
|
+
constructor(options) {
|
|
70
|
+
this.options = options;
|
|
71
|
+
}
|
|
72
|
+
start() {
|
|
73
|
+
if (this.timer || this.stopped)
|
|
74
|
+
return;
|
|
75
|
+
this.refresh();
|
|
76
|
+
this.timer = setInterval(() => this.refresh(), 2_000);
|
|
77
|
+
this.timer.unref?.();
|
|
78
|
+
}
|
|
79
|
+
close() {
|
|
80
|
+
if (this.stopped)
|
|
81
|
+
return;
|
|
82
|
+
this.stopped = true;
|
|
83
|
+
clearInterval(this.timer);
|
|
84
|
+
this.timer = undefined;
|
|
85
|
+
for (const state of this.states.values())
|
|
86
|
+
this.stopState(state);
|
|
87
|
+
this.states.clear();
|
|
88
|
+
}
|
|
89
|
+
refresh() {
|
|
90
|
+
if (this.stopped)
|
|
91
|
+
return;
|
|
92
|
+
const desired = new Map(desktopDirectTargets(this.options.desktopFile, this.options.serviceId)
|
|
93
|
+
.map(target => [target.serviceId, target]));
|
|
94
|
+
for (const [serviceId, state] of this.states) {
|
|
95
|
+
const target = desired.get(serviceId);
|
|
96
|
+
const signature = target && JSON.stringify([target.url, target.caFingerprint256]);
|
|
97
|
+
if (!target || signature !== state.signature) {
|
|
98
|
+
this.stopState(state);
|
|
99
|
+
this.states.delete(serviceId);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
for (const [serviceId, target] of desired)
|
|
103
|
+
if (!this.states.has(serviceId)) {
|
|
104
|
+
const state = { signature: JSON.stringify([target.url, target.caFingerprint256]), stopped: false };
|
|
105
|
+
this.states.set(serviceId, state);
|
|
106
|
+
void this.run(state, target);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
stopState(state) {
|
|
110
|
+
if (state.stopped)
|
|
111
|
+
return;
|
|
112
|
+
state.stopped = true;
|
|
113
|
+
state.wake?.();
|
|
114
|
+
state.wake = undefined;
|
|
115
|
+
state.client?.close();
|
|
116
|
+
state.client = undefined;
|
|
117
|
+
state.upstream?.terminate();
|
|
118
|
+
state.upstream = undefined;
|
|
119
|
+
}
|
|
120
|
+
async run(state, target) {
|
|
121
|
+
let delay = 1_000;
|
|
122
|
+
while (!this.stopped && !state.stopped) {
|
|
123
|
+
try {
|
|
124
|
+
await this.connect(state, target);
|
|
125
|
+
delay = 1_000;
|
|
126
|
+
}
|
|
127
|
+
catch { /* Offline and older entries remain dormant and retry with backoff. */ }
|
|
128
|
+
if (this.stopped || state.stopped)
|
|
129
|
+
break;
|
|
130
|
+
await new Promise(resolve => {
|
|
131
|
+
const timer = setTimeout(() => { state.wake = undefined; resolve(); }, delay);
|
|
132
|
+
timer.unref?.();
|
|
133
|
+
state.wake = () => { clearTimeout(timer); state.wake = undefined; resolve(); };
|
|
134
|
+
});
|
|
135
|
+
delay = Math.min(delay * 2, 30_000);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async connect(state, target) {
|
|
139
|
+
const peer = { serviceId: target.serviceId, origin: target.url, ...(target.caFingerprint256 ? { caFingerprint256: target.caFingerprint256 } : {}) };
|
|
140
|
+
const rpc = await connectCollaborationRpc(this.options.identity, peer);
|
|
141
|
+
let selfRelayToken;
|
|
142
|
+
try {
|
|
143
|
+
const result = await rpc.request({ type: 'self-relay-ticket' });
|
|
144
|
+
if (result.serviceId !== this.options.serviceId || typeof result.selfRelayToken !== 'string'
|
|
145
|
+
|| !/^[A-Za-z0-9_-]{43}$/.test(result.selfRelayToken))
|
|
146
|
+
throw new Error('INVALID_SELF_RELAY_TICKET');
|
|
147
|
+
selfRelayToken = result.selfRelayToken;
|
|
148
|
+
}
|
|
149
|
+
finally {
|
|
150
|
+
rpc.close();
|
|
151
|
+
}
|
|
152
|
+
if (this.stopped || state.stopped)
|
|
153
|
+
return;
|
|
154
|
+
const ca = target.caFingerprint256 ? await readPinnedCertificateAuthority(target.url, target.caFingerprint256) : undefined;
|
|
155
|
+
const upstream = await openSocket(relayEndpoint(target.url, selfRelayToken), ca);
|
|
156
|
+
state.upstream = upstream;
|
|
157
|
+
try {
|
|
158
|
+
if (this.stopped || state.stopped)
|
|
159
|
+
return;
|
|
160
|
+
await waitForReady(upstream);
|
|
161
|
+
if (this.stopped || state.stopped)
|
|
162
|
+
return;
|
|
163
|
+
const client = new RelayClient(upstream, { targets: new Map([[this.options.serviceId,
|
|
164
|
+
() => openSocket(secureEndpoint(this.options.localOrigin), this.options.localCa, 1024 * 1024)]]) });
|
|
165
|
+
state.client = client;
|
|
166
|
+
await new Promise(resolve => {
|
|
167
|
+
if (upstream.readyState !== WebSocket.OPEN)
|
|
168
|
+
resolve();
|
|
169
|
+
else
|
|
170
|
+
upstream.once('close', () => resolve());
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
finally {
|
|
174
|
+
state.client?.close();
|
|
175
|
+
state.client = undefined;
|
|
176
|
+
if (upstream.readyState !== WebSocket.CLOSED)
|
|
177
|
+
upstream.terminate();
|
|
178
|
+
if (state.upstream === upstream)
|
|
179
|
+
state.upstream = undefined;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { X509Certificate } from 'node:crypto';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { isIP } from 'node:net';
|
|
4
|
+
// Use Node's certificate parser: the system openssl (notably LibreSSL on
|
|
5
|
+
// macOS) may not support `x509 -ext`. Propagate read/parse errors so callers
|
|
6
|
+
// cannot mistake an inspection failure for an empty SAN extension.
|
|
7
|
+
export async function getMissingCertificateNames(certPath, required) {
|
|
8
|
+
const cert = new X509Certificate(await readFile(certPath));
|
|
9
|
+
return required.filter((name) => isIP(name)
|
|
10
|
+
? cert.checkIP(name) === undefined
|
|
11
|
+
: cert.checkHost(name, { subject: 'never', wildcards: false }) === undefined);
|
|
12
|
+
}
|
package/package.json
CHANGED
package/runtime-manifest.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"packageName": "termdock",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.241",
|
|
5
5
|
"runtimeProtocolVersion": 1,
|
|
6
6
|
"minimumDesktopVersion": "1.4.46",
|
|
7
7
|
"nodeMajor": 22,
|
|
8
8
|
"dependencyHash": "sha256-K4KyYJuVoQDpZsBM8ZX1Rw3MddOxAzVdp/cPm0iGZz0=",
|
|
9
|
-
"serverBundleHash": "sha256-
|
|
10
|
-
"clientBundleHash": "sha256-
|
|
9
|
+
"serverBundleHash": "sha256-pd6lxkGXO9l4hUWug+Q8/kxaLYDXfSgODkoynCdwgBI=",
|
|
10
|
+
"clientBundleHash": "sha256-zyDixEKnPdU8PZdH7+xvwW32LWLFTq5o2zdqqOr3AJM=",
|
|
11
11
|
"entrypoint": "dist/server/cli.js",
|
|
12
12
|
"clientEntrypoint": "dist/client/index.html"
|
|
13
13
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|