termdock 1.4.168 → 1.4.169
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/ChangeWalkthroughPanel-u9y3e-pI.js +2 -0
- package/dist/client/assets/ChangeWalkthroughPanel-u9y3e-pI.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-u9y3e-pI.js.gz +0 -0
- package/dist/client/assets/DagPlayground-BLUwaOMM.js +1 -0
- package/dist/client/assets/DagPlayground-BLUwaOMM.js.br +0 -0
- package/dist/client/assets/DagPlayground-BLUwaOMM.js.gz +0 -0
- package/dist/client/assets/DiffLab-ThgXydJA.js +370 -0
- package/dist/client/assets/DiffLab-ThgXydJA.js.br +0 -0
- package/dist/client/assets/DiffLab-ThgXydJA.js.gz +0 -0
- package/dist/client/assets/DiffReview-DNkXOQ2y.js +1 -0
- package/dist/client/assets/DiffReview-DNkXOQ2y.js.br +0 -0
- package/dist/client/assets/DiffReview-DNkXOQ2y.js.gz +0 -0
- package/dist/client/assets/DiffReviewLab-CHyV1WMR.js +2 -0
- package/dist/client/assets/DiffReviewLab-CHyV1WMR.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-CHyV1WMR.js.gz +0 -0
- package/dist/client/assets/DiffViewer-CxxOpsVz.js +35 -0
- package/dist/client/assets/DiffViewer-CxxOpsVz.js.br +0 -0
- package/dist/client/assets/DiffViewer-CxxOpsVz.js.gz +0 -0
- package/dist/client/assets/DiffViewer-T3uj2-aP.css +1 -0
- package/dist/client/assets/DiffViewer-T3uj2-aP.css.br +0 -0
- package/dist/client/assets/DiffViewer-T3uj2-aP.css.gz +0 -0
- package/dist/client/assets/ModelPreview-DZzx3Tzo.js +4112 -0
- package/dist/client/assets/ModelPreview-DZzx3Tzo.js.br +0 -0
- package/dist/client/assets/ModelPreview-DZzx3Tzo.js.gz +0 -0
- package/dist/client/assets/RightSidebar-Bv8Y6hqx.js +55 -0
- package/dist/client/assets/RightSidebar-Bv8Y6hqx.js.br +0 -0
- package/dist/client/assets/RightSidebar-Bv8Y6hqx.js.gz +0 -0
- package/dist/client/assets/RightSidebar-DW-JEgm2.css +1 -0
- package/dist/client/assets/{abnfDiagram-VRR7QNED-BPFn9m09.js → abnfDiagram-VCTEODGH-DKmZLRlf.js} +1 -1
- package/dist/client/assets/abnfDiagram-VCTEODGH-DKmZLRlf.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-DKmZLRlf.js.gz +0 -0
- package/dist/client/assets/app-tT08GaCs.js +175 -0
- package/dist/client/assets/app-tT08GaCs.js.br +0 -0
- package/dist/client/assets/app-tT08GaCs.js.gz +0 -0
- package/dist/client/assets/arc-CjmHoRed.js +1 -0
- package/dist/client/assets/arc-CjmHoRed.js.br +0 -0
- package/dist/client/assets/arc-CjmHoRed.js.gz +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-B0EDOwYH.js +36 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-B0EDOwYH.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-B0EDOwYH.js.gz +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-CW-AaouZ.js +129 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-CW-AaouZ.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-CW-AaouZ.js.gz +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-aE7hFKfo.js +38 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-aE7hFKfo.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-aE7hFKfo.js.gz +0 -0
- package/dist/client/assets/channel-DhsPQnwY.js +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-CXqAcWtO.js → chunk-2Q5K7J3B-FAEL5P17.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-B2ewCivF.js → chunk-5VM5RSS4-BQJAvucM.js} +1 -1
- package/dist/client/assets/chunk-F27PBJKO-DEkt187T.js +1 -0
- package/dist/client/assets/chunk-F27PBJKO-DEkt187T.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-DEkt187T.js.gz +0 -0
- package/dist/client/assets/{chunk-EX3LRPZG-DcpNYccw.js → chunk-IMKFNOWR-BfOJ-x_l.js} +5 -5
- package/dist/client/assets/chunk-IMKFNOWR-BfOJ-x_l.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-BfOJ-x_l.js.gz +0 -0
- package/dist/client/assets/{chunk-JWPE2WC7-DJGW22NC.js → chunk-JWPE2WC7-BN6q6jKH.js} +1 -1
- package/dist/client/assets/chunk-POPQ4Y6H-BrhQRNCn.js +1 -0
- package/dist/client/assets/{chunk-MOJQB5TN-CI12TXOM.js → chunk-SVP7TREG-CjZOC5Dj.js} +4 -4
- package/dist/client/assets/chunk-SVP7TREG-CjZOC5Dj.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-CjZOC5Dj.js.gz +0 -0
- package/dist/client/assets/{chunk-V7JOEXUC-D2J88tQk.js → chunk-TICWLB2K-Wshj9ws7.js} +3 -3
- package/dist/client/assets/chunk-TICWLB2K-Wshj9ws7.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-Wshj9ws7.js.gz +0 -0
- package/dist/client/assets/{chunk-XXDRQBXY-DFycwWDp.js → chunk-XXDRQBXY-BPPghuc3.js} +1 -1
- package/dist/client/assets/classDiagram-ZZMXUADV-2OomHNTG.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-2OomHNTG.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-D8eG4PZe.js → cose-bilkent-JH36ORCC-BjxJYQH8.js} +1 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-BjxJYQH8.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-BjxJYQH8.js.gz +0 -0
- package/dist/client/assets/{cynefin-VYW2F7L2-B9Z9SAtQ.js → cynefin-OW5HDTMX-QmUTVmd_.js} +38 -38
- package/dist/client/assets/cynefin-OW5HDTMX-QmUTVmd_.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-QmUTVmd_.js.gz +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CBJtWB9m.js +62 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CBJtWB9m.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CBJtWB9m.js.gz +0 -0
- package/dist/client/assets/cytoscape.esm-D3_iZ_3b.js.br +0 -0
- package/dist/client/assets/cytoscape.esm-D3_iZ_3b.js.gz +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-CJFctjtR.js +4 -0
- package/dist/client/assets/dagre-GXQ25YYZ-CJFctjtR.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-CJFctjtR.js.gz +0 -0
- package/dist/client/assets/defaultLocale-CrowFXzY.js.br +0 -0
- package/dist/client/assets/defaultLocale-CrowFXzY.js.gz +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-e7Jn-RGH.js +30 -0
- package/dist/client/assets/diagram-S7CK7UJ4-e7Jn-RGH.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-e7Jn-RGH.js.gz +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-B1G-uMf2.js +41 -0
- package/dist/client/assets/diagram-UQ7AKVKN-B1G-uMf2.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-B1G-uMf2.js.gz +0 -0
- package/dist/client/assets/{diagram-FQU43EPY-BSU4bMc7.js → diagram-VSXAHHWV-cp7u53yF.js} +3 -3
- package/dist/client/assets/diagram-VSXAHHWV-cp7u53yF.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-cp7u53yF.js.gz +0 -0
- package/dist/client/assets/diagram-VX7I27RA-DJWrVfMd.js +24 -0
- package/dist/client/assets/diagram-VX7I27RA-DJWrVfMd.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-DJWrVfMd.js.gz +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-B-IZbqzJ.js +24 -0
- package/dist/client/assets/diagram-Z3DM3KII-B-IZbqzJ.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-B-IZbqzJ.js.gz +0 -0
- package/dist/client/assets/diffWorker-CAzvFFr7.js +27 -0
- package/dist/client/assets/diffWorker-CAzvFFr7.js.br +0 -0
- package/dist/client/assets/diffWorker-CAzvFFr7.js.gz +0 -0
- package/dist/client/assets/{ebnfDiagram-CCIWWBDH-N_k0E7sQ.js → ebnfDiagram-PWID7BFC-Bt4zDbpn.js} +1 -1
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Bt4zDbpn.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Bt4zDbpn.js.gz +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-DUPOkndO.js +99 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-DUPOkndO.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-DUPOkndO.js.gz +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-CBSvTIxa.js +168 -0
- package/dist/client/assets/flowDiagram-HODETNUW-CBSvTIxa.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-CBSvTIxa.js.gz +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-C7BvkSc8.js +292 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-C7BvkSc8.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-C7BvkSc8.js.gz +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-C4v6Do2L.js +106 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-C4v6Do2L.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-C4v6Do2L.js.gz +0 -0
- package/dist/client/assets/index-BaBARzax.css +1 -0
- package/dist/client/assets/index-BaBARzax.css.br +0 -0
- package/dist/client/assets/index-BaBARzax.css.gz +0 -0
- package/dist/client/assets/{index-Ca-rq7yX.js → index-UqXCGE5m.js} +4 -4
- package/dist/client/assets/index-UqXCGE5m.js.br +0 -0
- package/dist/client/assets/index-UqXCGE5m.js.gz +0 -0
- package/dist/client/assets/infoDiagram-27XIBGKW-CVQtEdgb.js +2 -0
- package/dist/client/assets/{ishikawaDiagram-FXEZZL3T-Ew07ODU5.js → ishikawaDiagram-5VMMS53U-Cf7tUoyW.js} +5 -5
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-Cf7tUoyW.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-Cf7tUoyW.js.gz +0 -0
- package/dist/client/assets/{journeyDiagram-5HDEW3XC-BUjwylu4.js → journeyDiagram-3NMN7TZE-B-9CWrlr.js} +5 -5
- package/dist/client/assets/journeyDiagram-3NMN7TZE-B-9CWrlr.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-B-9CWrlr.js.gz +0 -0
- package/dist/client/assets/{kanban-definition-HUTT4EX6-Cjv8zokk.js → kanban-definition-UXKFOSKX-LDN2IZeo.js} +7 -7
- package/dist/client/assets/kanban-definition-UXKFOSKX-LDN2IZeo.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-LDN2IZeo.js.gz +0 -0
- package/dist/client/assets/katex-55ZPZeOF.css.br +0 -0
- package/dist/client/assets/katex-55ZPZeOF.css.gz +0 -0
- package/dist/client/assets/katex-DnlPpQZa.js.br +0 -0
- package/dist/client/assets/katex-DnlPpQZa.js.gz +0 -0
- package/dist/client/assets/katex-HP8lGamR.js.br +0 -0
- package/dist/client/assets/katex-HP8lGamR.js.gz +0 -0
- package/dist/client/assets/layout-DvqSuFgF.js +1 -0
- package/dist/client/assets/layout-DvqSuFgF.js.br +0 -0
- package/dist/client/assets/layout-DvqSuFgF.js.gz +0 -0
- package/dist/client/assets/{linear-C6Z8ZZfN.js → linear-D43LQnis.js} +1 -1
- package/dist/client/assets/linear-D43LQnis.js.br +0 -0
- package/dist/client/assets/linear-D43LQnis.js.gz +0 -0
- package/dist/client/assets/mermaid.core-DiblHLKe.js +308 -0
- package/dist/client/assets/mermaid.core-DiblHLKe.js.br +0 -0
- package/dist/client/assets/mermaid.core-DiblHLKe.js.gz +0 -0
- package/dist/client/assets/{mindmap-definition-LN4V7U3C-DACHJUhw.js → mindmap-definition-YA3MSWOX-k3f4uWuu.js} +3 -3
- package/dist/client/assets/mindmap-definition-YA3MSWOX-k3f4uWuu.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-k3f4uWuu.js.gz +0 -0
- package/dist/client/assets/ordinal-Cboi1Yqb.js.br +0 -0
- package/dist/client/assets/ordinal-Cboi1Yqb.js.gz +0 -0
- package/dist/client/assets/{pegDiagram-2B236MQR-C6YRG4Sp.js → pegDiagram-XKGWAZYB-Dj32Fl3j.js} +1 -1
- package/dist/client/assets/pegDiagram-XKGWAZYB-Dj32Fl3j.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-Dj32Fl3j.js.gz +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-DWGSixfl.js +39 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-DWGSixfl.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-DWGSixfl.js.gz +0 -0
- package/dist/client/assets/purify.es-4eNOHKSq.js +3 -0
- package/dist/client/assets/purify.es-4eNOHKSq.js.br +0 -0
- package/dist/client/assets/purify.es-4eNOHKSq.js.gz +0 -0
- package/dist/client/assets/{quadrantDiagram-ABIIQ3AL-DugxSPrH.js → quadrantDiagram-AXDQQJYC-BPScfZWR.js} +1 -1
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-BPScfZWR.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-BPScfZWR.js.gz +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-CL00HIC2.js +1 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-CL00HIC2.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-CL00HIC2.js.gz +0 -0
- package/dist/client/assets/react-XDCjal2T.js.br +0 -0
- package/dist/client/assets/react-XDCjal2T.js.gz +0 -0
- package/dist/client/assets/{requirementDiagram-TGXJPOKE-BzaF87gc.js → requirementDiagram-BXWQKSXE-CosES4L6.js} +12 -12
- package/dist/client/assets/requirementDiagram-BXWQKSXE-CosES4L6.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-CosES4L6.js.gz +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CjM8CYFn.js +40 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CjM8CYFn.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CjM8CYFn.js.gz +0 -0
- package/dist/client/assets/{sequenceDiagram-DBY2YBRQ-B1gfbBUX.js → sequenceDiagram-WJ2MYXX4-3RKv_35o.js} +1 -1
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-3RKv_35o.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-3RKv_35o.js.gz +0 -0
- package/dist/client/assets/{sizeCapture-X5ZJPWSS-Cx3c55P-.js → sizeCapture-INFHLROL-BrVkA4VD.js} +1 -1
- package/dist/client/assets/sizeCapture-INFHLROL-BrVkA4VD.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-BrVkA4VD.js.gz +0 -0
- package/dist/client/assets/sparkles-B3pwUd8-.js +1 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-DeWhyAVC.js +1 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-DeWhyAVC.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-DeWhyAVC.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-DvdrGmTm.js +1 -0
- package/dist/client/assets/swimlanes-42K2YHIH-i2m0Wmhn.js +1 -0
- package/dist/client/assets/swimlanes-42K2YHIH-i2m0Wmhn.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-i2m0Wmhn.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-DIzij9pB.js +8 -0
- package/dist/client/assets/terminal-C7X98Amf.js.br +0 -0
- package/dist/client/assets/terminal-C7X98Amf.js.gz +0 -0
- package/dist/client/assets/{timeline-definition-FHXFAJF6-Dmjeiy4n.js → timeline-definition-24CTP7MA-BImN0AS_.js} +1 -1
- package/dist/client/assets/timeline-definition-24CTP7MA-BImN0AS_.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-BImN0AS_.js.gz +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-DVUHKmvC.js +34 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-DVUHKmvC.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-DVUHKmvC.js.gz +0 -0
- package/dist/client/assets/{wardleyDiagram-EHGQE667-C0Qt8nhi.js → wardleyDiagram-VM6X3IG4-B9qi-hc7.js} +4 -4
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-B9qi-hc7.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-B9qi-hc7.js.gz +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-3jgBcYVl.js +7 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-3jgBcYVl.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-3jgBcYVl.js.gz +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-38-022d7c89c800.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-39-63f8fa5b3eba.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3a-2d8d46cc4dca.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3b-e75aed5d3969.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c-ac2534aae681.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c0-8c49a98e75c4.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c1-971c5e7a86ce.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c2-e5c4893acfb9.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c3-156f2560c871.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c4-49f0d18a7492.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c5-33d81ad28c5c.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c6-5c301879d053.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3d-52c90894de44.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-text-9e8d9df2dd02.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-38-7942d3c93afb.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-39-19989a2be535.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3a-7786ff4a4dd9.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3b-a759fd623d7e.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c-2a1178076740.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c0-6f2c7518f354.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c1-4bf64cae9dd2.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c2-7f26d4c7240b.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c3-fc8e5a85d620.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c4-91819b7977d3.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c5-26933eec54e2.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c6-af186404c8af.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3d-b004d85f5642.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-text-da002b4e56d3.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-38-b3e69191d92f.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-39-c4d8d66882cb.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3a-27609324e8a3.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3b-5e73d85d7506.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c-7e535d65bbdb.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c0-6465060a06a1.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c1-9fd72ccd9350.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c2-ea7dd77de270.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c3-12808f88907a.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c4-14b598e5e739.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c5-3d40530ce6c2.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c6-7020aec0d9e1.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3d-19831897003a.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-text-b7a9c776b048.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-38-a637901140d8.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-39-838726e8eeca.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3a-ec149087d0b9.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3b-db8e5a24d580.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c-2290d2ad4621.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c0-3b9edaf85d65.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c1-5e7fb0696bbc.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c2-cfad2884adf5.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c3-d641de88278b.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c4-3b0227356b3b.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c5-9dc67c4d20b4.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c6-c5b444110c62.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3d-2b19b65bb43a.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-text-d7b9316fdf4f.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-4e-46bdca5c323f.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-4f-17200dc0dd0d.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-50-370e36250c30.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-51-66352f738581.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-52-191f4025d2b5.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-53-fb0a637c39bf.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-54-66f2e72c9ca0.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-55-54b538fd4fd8.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-56-88f45aeb2030.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-57-154d4324f0ce.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-58-1660c86b8a05.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-59-31a4c5afa3aa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-5a-fa1d1941710e.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-5b-031a2b2ebeb7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-5c-065b634c07b3.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-5d-71f6cd3ed180.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-5e-f59de7a6e5c5.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-5f-8cbe737b6011.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-60-22913526da09.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-61-c810c1d1a3a3.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-62-9464d5d87d65.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-63-79564d99f5da.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-64-4b7cff1dae6f.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-65-8dd48db5e297.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-66-a808e22a3d14.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-67-ae5f61af3f79.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-68-a46bf47bd9ba.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-69-28210414eafb.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-6a-6bfb1f5e4fb7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-6b-39be890e04e4.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-6c-79a4ff740d98.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-6d-2de5a763980e.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-6e-8e55b339244d.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-6f-a56caf9fc7fc.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-70-d70c6ee8e03c.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-71-ac6f5f86dfef.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-72-db3d346ecc61.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-73-e7371bd71f0b.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-74-43946d9b2f0b.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-75-ea7cf53e31fa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-76-04c7fa4e0ebf.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-77-24d70898f6b8.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-78-c6a5d7135296.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-79-7812cb6432aa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-7a-6e123be5cd36.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-7b-a183ddc6890f.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-7c-0895291ece9c.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-7d-1d44252384cf.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-7e-7be4dc6f056e.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-7f-0d8e987db151.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-80-c0c154bb8be0.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-81-5343baca5ce7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-82-6d89af9614ce.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-83-fa17ef529c5b.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-84-287ecb493fad.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-85-fea695c48165.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-86-8bb35373cb82.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-87-f83e9f70a6cc.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-88-894cd19292c1.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-89-2903a6eaf546.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-8a-3ce275bfcf96.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-8b-3aaeb26309a6.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-8c-719b6608b746.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-8d-a7f1ccd0dfb7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-8e-d503ad5c4958.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-8f-18c6d04746c8.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-90-e9d94d915dfe.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-91-c258b07ec626.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-92-e4833a556b60.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-94-0889f5b84499.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-95-7ef116efe7ee.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-96-afbc0d2cacda.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-97-df3903d86f65.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-98-0f21094931ee.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-99-eb95f4bead58.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-9a-764e8b8723ec.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-9b-33a540b9196a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-9c-60d6040aa049.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-9e-4a64c65bf44d.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-9f-4d84fba11345.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-punctuation-f1b7708e797a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-4e-bb1ec5541ecc.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-4f-d6e8daa67360.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-50-63c2ae7f85e8.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-51-41b6e0624888.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-52-57de15003b8d.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-53-94382657e2bc.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-54-177141086f32.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-55-5ec6fae9813a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-56-720aa493b429.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-57-a8884711a286.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-58-42a3e7e1fe9a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-59-887ee4253daa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-5a-c45806889e3c.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-5b-da142b99dca9.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-5c-2bb495e5b511.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-5d-9da87d6061f2.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-5e-e4010764e593.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-5f-a9c9021f6e01.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-60-306f229a68e0.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-61-6e4546c5f52a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-62-a73e47933059.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-63-e8f49f472799.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-64-37b54957eadc.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-65-2742b20127ad.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-66-239656e7fe56.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-67-5dfa72b26c3f.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-68-fe3d1fc05aae.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-69-22535dbbd090.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-6a-c4117cd520aa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-6b-895d3349f7de.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-6c-56a0c71eb1b4.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-6d-9ec807661604.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-6e-3b633363cd57.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-6f-91a1f1c31b75.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-70-3a904a2a2371.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-71-e8efb60879b0.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-72-591318b99498.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-73-d8f444050aa7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-74-55a832a12d7e.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-75-660977996a4c.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-76-441a04df9fb5.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-77-5915143c4398.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-78-242fbc33c745.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-79-24d13953150a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-7a-41973af74017.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-7b-f9661fdaf003.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-7c-ef5167770bf7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-7d-d84ad5d95f37.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-7e-66841a1c6381.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-7f-5090e017351a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-80-9ad74a67c2b9.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-81-423a60a6dcf1.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-82-aad812217807.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-83-3dc74dbac89c.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-84-68db7802ffe8.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-85-fa235a7160e4.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-86-75a6a33d0db2.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-87-7d98ea8ce063.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-88-363fa8f178aa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-89-f2d185e8721f.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-8a-e372253a07f5.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-8b-0af53db9bdc1.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-8c-6a43d3643480.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-8d-09c4b5345b99.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-8e-122a752954a6.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-8f-c651bbfffeb3.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-90-ab0a5fef3083.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-91-e07b5cbe4792.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-92-cba0a8ee6758.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-94-e7a6bd14e248.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-95-420f721d52ba.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-96-90fd476b83f2.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-97-34036fc287f7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-98-5c3cdd76911e.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-99-73e6090fd7c8.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-9a-673ebaebe683.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-9b-90a5a3ee22d6.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-9c-116d201c978b.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-9e-78db36865caa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-9f-27e8d16243d5.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-punctuation-a4288065ed29.woff2 +0 -0
- package/dist/client/fonts/terminal/manifest.json +1349 -0
- package/dist/client/fonts/terminal/manifest.json.br +0 -0
- package/dist/client/fonts/terminal/manifest.json.gz +0 -0
- package/dist/client/icons/agents/claude.svg.br +0 -0
- package/dist/client/icons/agents/claude.svg.gz +0 -0
- package/dist/client/icons/agents/codex.svg.br +0 -0
- package/dist/client/icons/agents/codex.svg.gz +0 -0
- package/dist/client/icons/agents/copilot.svg.br +0 -0
- package/dist/client/icons/agents/copilot.svg.gz +0 -0
- package/dist/client/icons/agents/droid.svg.br +0 -0
- package/dist/client/icons/agents/droid.svg.gz +0 -0
- package/dist/client/icons/agents/gemini.svg.br +0 -0
- package/dist/client/icons/agents/gemini.svg.gz +0 -0
- package/dist/client/icons/agents/goose.svg.br +0 -0
- package/dist/client/icons/agents/goose.svg.gz +0 -0
- package/dist/client/index.html +7 -52
- package/dist/client/index.html.br +0 -0
- package/dist/client/index.html.gz +0 -0
- package/dist/client/sw-notifications.js.br +0 -0
- package/dist/client/sw-notifications.js.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/client/workbox-9845bf53.js.br +0 -0
- package/dist/client/workbox-9845bf53.js.gz +0 -0
- package/dist/server/agent/installers.js +47 -27
- package/dist/server/cli.js +4 -4
- package/dist/server/entry.js +57 -145
- package/dist/server/routes/auth.js +9 -3
- package/dist/server/routes/filesystem.js +39 -9
- package/dist/server/routes/local.js +3 -2
- package/dist/server/routes/terminal.js +337 -225
- package/dist/server/utils/apiAccess.js +27 -0
- package/dist/server/utils/apiCachePolicy.js +10 -0
- package/dist/server/utils/authProtection.js +140 -38
- package/dist/server/utils/cookieSecurity.js +3 -2
- package/dist/server/utils/csrfProtection.js +2 -6
- package/dist/server/utils/previewValidation.js +16 -0
- package/dist/server/utils/publicSecurity.js +44 -0
- package/dist/server/utils/requestDeadline.js +2 -0
- package/dist/server/utils/requestSecurity.js +23 -28
- package/dist/server/utils/staticAssets.js +97 -0
- package/dist/server/utils/terminalClientAttachment.js +61 -0
- package/dist/server/utils/terminalHandshakeDimensions.js +9 -0
- package/dist/server/utils/terminalOutputDelivery.js +90 -0
- package/dist/server/utils/tmuxClientRedraw.js +16 -0
- package/dist/server/utils/tmuxInitialScreen.js +50 -0
- package/dist/server/utils/tmuxResizeReady.js +56 -0
- package/dist/server/utils/webSocketSecurity.js +28 -0
- package/package.json +7 -4
- package/runtime-manifest.json +4 -4
- package/scripts/generate-font-subsets.py +88 -0
- package/scripts/precompress-client.mjs +28 -0
- package/dist/client/assets/ModelPreview-BVdIA5hh.js +0 -4108
- package/dist/client/assets/app-uayLhfKS.js +0 -632
- package/dist/client/assets/arc-BrdWVufU.js +0 -1
- package/dist/client/assets/architectureDiagram-ZJ3FMSHR-M74Mohos.js +0 -36
- package/dist/client/assets/blockDiagram-677ZJIJ3-D6OG5gyC.js +0 -132
- package/dist/client/assets/c4Diagram-LMCZKHZV-C2w-_Jc4.js +0 -10
- package/dist/client/assets/channel-B3PaW8my.js +0 -1
- package/dist/client/assets/chunk-32BRIVSS-CEtSQTtD.js +0 -1
- package/dist/client/assets/chunk-RYQCIY6F-DS5ufo5c.js +0 -1
- package/dist/client/assets/chunk-VR4S4FIN-0lqTHFzc.js +0 -1
- package/dist/client/assets/classDiagram-OUVF2IWQ-CLK6o5ur.js +0 -1
- package/dist/client/assets/classDiagram-v2-EOCWNBFH-CLK6o5ur.js +0 -1
- package/dist/client/assets/cynefinDiagram-TSTJHNR4-DLfD0XDP.js +0 -62
- package/dist/client/assets/dagre-VKFMJZFB-BVcVxS_K.js +0 -4
- package/dist/client/assets/diagram-G47NLZAW-U4SDLU5l.js +0 -24
- package/dist/client/assets/diagram-NH7WQ7WH-DzUUOLaX.js +0 -24
- package/dist/client/assets/diagram-OA4YK3LP-CkCRYrYh.js +0 -30
- package/dist/client/assets/diagram-WEI45ONY-D5_8zUCk.js +0 -41
- package/dist/client/assets/diffWorker-Bg2YXCD-.js +0 -27
- package/dist/client/assets/erDiagram-Q63AITRT-CaBjWdJp.js +0 -85
- package/dist/client/assets/flowDiagram-23GEKE2U-CVOqw7CA.js +0 -156
- package/dist/client/assets/ganttDiagram-NO4QXBWP-DI8IFeJE.js +0 -292
- package/dist/client/assets/gitGraphDiagram-IHSO6WYX-CnpSm3yq.js +0 -106
- package/dist/client/assets/graph-D2o_JWn5.js +0 -1
- package/dist/client/assets/index-C13NrW5y.css +0 -1
- package/dist/client/assets/infoDiagram-FWYZ7A6U-C-dKF4KW.js +0 -2
- package/dist/client/assets/layout-1eBIAoSl.js +0 -1
- package/dist/client/assets/map-BdqsVdb3.js +0 -1
- package/dist/client/assets/mermaid.core-B13cUj_d.js +0 -306
- package/dist/client/assets/pieDiagram-ENE6RG2P-7cfuhoAx.js +0 -39
- package/dist/client/assets/purify.es-CC4Brkr_.js +0 -3
- package/dist/client/assets/railroadDiagram-RFXS5EU6-BhRp2Kow.js +0 -1
- package/dist/client/assets/sankeyDiagram-HTMAVEWB-4yvODBzh.js +0 -40
- package/dist/client/assets/stateDiagram-2N3HPSRC-CyZ_X_VK.js +0 -1
- package/dist/client/assets/stateDiagram-v2-6OUMAXLB-9hsqTyV0.js +0 -1
- package/dist/client/assets/swimlanes-5IMT3BWC-BZPAGrt1.js +0 -2
- package/dist/client/assets/swimlanesDiagram-G3AALYLV-DYvi0MbZ.js +0 -8
- package/dist/client/assets/vennDiagram-L72KCM5P-BC2FrHDP.js +0 -34
- package/dist/client/assets/xychartDiagram-FW5EYKEG-cQNpjzG4.js +0 -7
- package/dist/client/registerSW.js +0 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
import { requireAuth } from './authProtection.js';
|
|
3
|
+
export function isTrustedLocalRequest(req, token) {
|
|
4
|
+
const supplied = req.header('X-Termdock-Local-Token');
|
|
5
|
+
if (!token || !supplied || req.headers.origin || req.headers['sec-fetch-site'])
|
|
6
|
+
return false;
|
|
7
|
+
const address = req.socket.remoteAddress ?? '';
|
|
8
|
+
if (!['127.0.0.1', '::1', '::ffff:127.0.0.1'].includes(address))
|
|
9
|
+
return false;
|
|
10
|
+
const a = Buffer.from(token);
|
|
11
|
+
const b = Buffer.from(supplied);
|
|
12
|
+
return a.length === b.length && crypto.timingSafeEqual(a, b);
|
|
13
|
+
}
|
|
14
|
+
/** Mounted at /api BEFORE body parsing. New endpoints are private by default. */
|
|
15
|
+
export function apiAccessGate(localToken) {
|
|
16
|
+
return requireAuth({ bypass: (req) => {
|
|
17
|
+
const path = req.path.toLowerCase().replace(/\/$/, '');
|
|
18
|
+
if (['GET', 'HEAD'].includes(req.method) && ['/auth/status', '/meta'].includes(path))
|
|
19
|
+
return true;
|
|
20
|
+
if (req.method === 'POST' && ['/auth/login', '/auth/logout'].includes(path))
|
|
21
|
+
return true;
|
|
22
|
+
// Preview capabilities perform scoped, session-bound authentication themselves.
|
|
23
|
+
if (['GET', 'HEAD'].includes(req.method) && /^\/terminal\/fs\/preview\//.test(path))
|
|
24
|
+
return true;
|
|
25
|
+
return isTrustedLocalRequest(req, localToken) && (/^\/(?:terminal|local)(?:\/|$)/.test(path) || path === '/diagnostics/runtime');
|
|
26
|
+
} });
|
|
27
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const VALIDATED_PREVIEWS = new Set(['/terminal/fs/read', '/terminal/fs/blob', '/terminal/fs/eda-preview']);
|
|
2
|
+
/** Ordinary JSON callers require bodies. Preview callers explicitly handle 304. */
|
|
3
|
+
export const apiCachePolicy = (req, res, next) => {
|
|
4
|
+
if (!VALIDATED_PREVIEWS.has(req.path)) {
|
|
5
|
+
delete req.headers['if-none-match'];
|
|
6
|
+
delete req.headers['if-modified-since'];
|
|
7
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
8
|
+
}
|
|
9
|
+
next();
|
|
10
|
+
};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import crypto from 'crypto';
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
2
3
|
import fs from 'fs';
|
|
3
4
|
import os from 'os';
|
|
4
5
|
import path from 'path';
|
|
5
6
|
import { getCookieSecurityOptions } from './cookieSecurity.js';
|
|
6
7
|
// Auth state lives under ~/.termdock/. We keep two separate files:
|
|
7
8
|
// - auth.json: password hash (mode 0600). Presence enables auth.
|
|
8
|
-
// - auth-sessions.json: active session
|
|
9
|
+
// - auth-sessions.json: active session token hashes (mode 0600). Persisted so
|
|
9
10
|
// clients survive a server restart without re-login.
|
|
10
11
|
const AUTH_DIR = path.join(os.homedir(), '.termdock');
|
|
11
12
|
const AUTH_FILE = path.join(AUTH_DIR, 'auth.json');
|
|
@@ -13,7 +14,7 @@ const SESSIONS_FILE = path.join(AUTH_DIR, 'auth-sessions.json');
|
|
|
13
14
|
// Cookie holding the opaque session token. httpOnly + sameSite=lax. The token
|
|
14
15
|
// itself is 32 random bytes hex; never derived from the password.
|
|
15
16
|
export const AUTH_COOKIE = 'termdock-auth';
|
|
16
|
-
const SESSION_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
17
|
+
const SESSION_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
17
18
|
// scrypt parameters. N=2^15 keeps interactive login latency acceptable on
|
|
18
19
|
// laptops/phones while still being painful for offline brute force on a
|
|
19
20
|
// single secret.
|
|
@@ -22,7 +23,9 @@ const SCRYPT_R = 8;
|
|
|
22
23
|
const SCRYPT_P = 1;
|
|
23
24
|
const SCRYPT_KEY_LEN = 64;
|
|
24
25
|
const SCRYPT_SALT_LEN = 16;
|
|
25
|
-
// In-memory cache of active sessions, keyed by token
|
|
26
|
+
// In-memory cache of active sessions, keyed by SHA-256 token hash.
|
|
27
|
+
export const authEvents = new EventEmitter();
|
|
28
|
+
authEvents.setMaxListeners(0);
|
|
26
29
|
const sessions = new Map();
|
|
27
30
|
let sessionsLoaded = false;
|
|
28
31
|
const loginAttempts = new Map();
|
|
@@ -33,7 +36,14 @@ function ensureAuthDir() {
|
|
|
33
36
|
}
|
|
34
37
|
function writeFileSecure(filePath, content) {
|
|
35
38
|
ensureAuthDir();
|
|
36
|
-
|
|
39
|
+
const temporary = `${filePath}.${crypto.randomBytes(8).toString('hex')}.tmp`;
|
|
40
|
+
try {
|
|
41
|
+
fs.writeFileSync(temporary, content, { encoding: 'utf-8', mode: 0o600, flag: 'wx' });
|
|
42
|
+
fs.renameSync(temporary, filePath);
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
fs.rmSync(temporary, { force: true });
|
|
46
|
+
}
|
|
37
47
|
// Best-effort chmod in case the file already existed with looser perms.
|
|
38
48
|
try {
|
|
39
49
|
fs.chmodSync(filePath, 0o600);
|
|
@@ -105,6 +115,11 @@ function getEnvPasswordHash() {
|
|
|
105
115
|
}
|
|
106
116
|
return cachedEnvHash.hash;
|
|
107
117
|
}
|
|
118
|
+
function credentialFingerprint() {
|
|
119
|
+
const password = getEnvPassword();
|
|
120
|
+
const source = password ? `env:${getEnvPasswordHash()}` : `file:${readAuthFile()?.passwordHash ?? 'disabled'}`;
|
|
121
|
+
return crypto.createHash('sha256').update(source).digest('hex');
|
|
122
|
+
}
|
|
108
123
|
export function isEnvPasswordSet() {
|
|
109
124
|
return getEnvPassword() !== null;
|
|
110
125
|
}
|
|
@@ -112,10 +127,13 @@ export function isAuthEnabled() {
|
|
|
112
127
|
if (getEnvPassword())
|
|
113
128
|
return true;
|
|
114
129
|
try {
|
|
115
|
-
|
|
130
|
+
fs.statSync(AUTH_FILE);
|
|
131
|
+
return true;
|
|
116
132
|
}
|
|
117
|
-
catch {
|
|
118
|
-
|
|
133
|
+
catch (error) {
|
|
134
|
+
// Only a missing file disables auth. I/O and permission failures must not
|
|
135
|
+
// turn an authenticated terminal into an anonymous one.
|
|
136
|
+
return error.code !== 'ENOENT';
|
|
119
137
|
}
|
|
120
138
|
}
|
|
121
139
|
export function readAuthFile() {
|
|
@@ -124,11 +142,13 @@ export function readAuthFile() {
|
|
|
124
142
|
return null;
|
|
125
143
|
const raw = fs.readFileSync(AUTH_FILE, 'utf-8');
|
|
126
144
|
const parsed = JSON.parse(raw);
|
|
127
|
-
if (parsed.version !== 1 || typeof parsed.passwordHash !== 'string'
|
|
145
|
+
if (parsed.version !== 1 || typeof parsed.passwordHash !== 'string' ||
|
|
146
|
+
!/^scrypt\$[0-9a-f]{32}\$[0-9a-f]{128}$/.test(parsed.passwordHash))
|
|
128
147
|
return null;
|
|
129
148
|
return {
|
|
130
149
|
version: 1,
|
|
131
150
|
passwordHash: parsed.passwordHash,
|
|
151
|
+
passwordLength: typeof parsed.passwordLength === 'number' ? parsed.passwordLength : undefined,
|
|
132
152
|
createdAt: typeof parsed.createdAt === 'number' ? parsed.createdAt : Date.now(),
|
|
133
153
|
};
|
|
134
154
|
}
|
|
@@ -136,8 +156,8 @@ export function readAuthFile() {
|
|
|
136
156
|
return null;
|
|
137
157
|
}
|
|
138
158
|
}
|
|
139
|
-
export function writeAuthFile(passwordHash) {
|
|
140
|
-
const payload = { version: 1, passwordHash, createdAt: Date.now() };
|
|
159
|
+
export function writeAuthFile(passwordHash, passwordLength) {
|
|
160
|
+
const payload = { version: 1, passwordHash, createdAt: Date.now(), passwordLength };
|
|
141
161
|
writeFileSecure(AUTH_FILE, JSON.stringify(payload, null, 2));
|
|
142
162
|
}
|
|
143
163
|
export function clearAuthFile() {
|
|
@@ -147,8 +167,10 @@ export function clearAuthFile() {
|
|
|
147
167
|
}
|
|
148
168
|
catch { /* ignore */ }
|
|
149
169
|
// Clearing the password also invalidates all existing sessions.
|
|
170
|
+
sessionsLoaded = true;
|
|
150
171
|
sessions.clear();
|
|
151
172
|
persistSessions();
|
|
173
|
+
authEvents.emit('revoked');
|
|
152
174
|
}
|
|
153
175
|
function loadSessionsIfNeeded() {
|
|
154
176
|
if (sessionsLoaded)
|
|
@@ -159,14 +181,17 @@ function loadSessionsIfNeeded() {
|
|
|
159
181
|
return;
|
|
160
182
|
const raw = fs.readFileSync(SESSIONS_FILE, 'utf-8');
|
|
161
183
|
const parsed = JSON.parse(raw);
|
|
162
|
-
if (parsed.version !==
|
|
184
|
+
if (parsed.version !== 2 || !Array.isArray(parsed.sessions))
|
|
163
185
|
return;
|
|
164
186
|
const now = Date.now();
|
|
165
187
|
for (const record of parsed.sessions) {
|
|
166
188
|
if (record &&
|
|
167
189
|
typeof record.token === 'string' &&
|
|
190
|
+
/^[0-9a-f]{64}$/.test(record.token) &&
|
|
191
|
+
record.credential === credentialFingerprint() &&
|
|
168
192
|
typeof record.expiresAt === 'number' &&
|
|
169
193
|
typeof record.createdAt === 'number' &&
|
|
194
|
+
typeof record.lastUsedAt === 'number' &&
|
|
170
195
|
record.expiresAt > now) {
|
|
171
196
|
sessions.set(record.token, record);
|
|
172
197
|
}
|
|
@@ -174,20 +199,11 @@ function loadSessionsIfNeeded() {
|
|
|
174
199
|
}
|
|
175
200
|
catch { /* ignore */ }
|
|
176
201
|
}
|
|
177
|
-
let persistTimer = null;
|
|
178
202
|
function persistSessions() {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const payload = {
|
|
184
|
-
version: 1,
|
|
185
|
-
sessions: Array.from(sessions.values()),
|
|
186
|
-
};
|
|
187
|
-
writeFileSecure(SESSIONS_FILE, JSON.stringify(payload, null, 2));
|
|
188
|
-
}
|
|
189
|
-
catch { /* ignore */ }
|
|
190
|
-
}, 200);
|
|
203
|
+
// Revocations must reach disk before logout succeeds; a debounce could
|
|
204
|
+
// resurrect the session if the server restarts immediately after logout.
|
|
205
|
+
const payload = { version: 2, sessions: Array.from(sessions.values()) };
|
|
206
|
+
writeFileSecure(SESSIONS_FILE, JSON.stringify(payload, null, 2));
|
|
191
207
|
}
|
|
192
208
|
function pruneExpiredSessions() {
|
|
193
209
|
loadSessionsIfNeeded();
|
|
@@ -203,42 +219,65 @@ function pruneExpiredSessions() {
|
|
|
203
219
|
persistSessions();
|
|
204
220
|
}
|
|
205
221
|
export function createSession() {
|
|
206
|
-
|
|
222
|
+
pruneExpiredSessions();
|
|
223
|
+
if (sessions.size >= 100) {
|
|
224
|
+
sessions.delete(sessions.keys().next().value);
|
|
225
|
+
authEvents.emit('revoked');
|
|
226
|
+
}
|
|
207
227
|
const token = crypto.randomBytes(32).toString('hex');
|
|
208
228
|
const now = Date.now();
|
|
209
229
|
const record = {
|
|
210
230
|
token,
|
|
211
231
|
createdAt: now,
|
|
212
232
|
expiresAt: now + SESSION_TTL_MS,
|
|
233
|
+
lastUsedAt: now,
|
|
234
|
+
credential: credentialFingerprint(),
|
|
213
235
|
};
|
|
214
|
-
|
|
236
|
+
const tokenHash = crypto.createHash('sha256').update(token).digest('hex');
|
|
237
|
+
sessions.set(tokenHash, { ...record, token: tokenHash });
|
|
215
238
|
persistSessions();
|
|
216
239
|
return record;
|
|
217
240
|
}
|
|
218
|
-
export function isSessionValid(token) {
|
|
241
|
+
export function isSessionValid(token, touch = false) {
|
|
219
242
|
if (!token || typeof token !== 'string')
|
|
220
243
|
return false;
|
|
221
244
|
loadSessionsIfNeeded();
|
|
222
|
-
const
|
|
245
|
+
const tokenHash = crypto.createHash('sha256').update(token).digest('hex');
|
|
246
|
+
const record = sessions.get(tokenHash);
|
|
223
247
|
if (!record)
|
|
224
248
|
return false;
|
|
225
|
-
if (record.expiresAt <= Date.now()
|
|
226
|
-
|
|
249
|
+
if (record.expiresAt <= Date.now() ||
|
|
250
|
+
record.credential !== credentialFingerprint()) {
|
|
251
|
+
sessions.delete(tokenHash);
|
|
227
252
|
persistSessions();
|
|
228
253
|
return false;
|
|
229
254
|
}
|
|
255
|
+
if (touch) {
|
|
256
|
+
const now = Date.now();
|
|
257
|
+
// Coalesce subsecond HTTP/input bursts, while persisting every new visit
|
|
258
|
+
// before replying. Also immediately upgrade still-valid shorter sessions.
|
|
259
|
+
if (now - record.lastUsedAt >= 1000 || record.expiresAt - record.lastUsedAt < SESSION_TTL_MS) {
|
|
260
|
+
record.lastUsedAt = now;
|
|
261
|
+
record.expiresAt = now + SESSION_TTL_MS;
|
|
262
|
+
persistSessions();
|
|
263
|
+
}
|
|
264
|
+
}
|
|
230
265
|
return true;
|
|
231
266
|
}
|
|
232
267
|
export function destroySession(token) {
|
|
233
268
|
if (!token)
|
|
234
269
|
return;
|
|
235
270
|
loadSessionsIfNeeded();
|
|
236
|
-
if (sessions.delete(token))
|
|
271
|
+
if (sessions.delete(crypto.createHash('sha256').update(token).digest('hex'))) {
|
|
237
272
|
persistSessions();
|
|
273
|
+
authEvents.emit('revoked');
|
|
274
|
+
}
|
|
238
275
|
}
|
|
239
276
|
export function destroyAllSessions() {
|
|
277
|
+
sessionsLoaded = true;
|
|
240
278
|
sessions.clear();
|
|
241
279
|
persistSessions();
|
|
280
|
+
authEvents.emit('revoked');
|
|
242
281
|
}
|
|
243
282
|
// ── Login rate limiting ──
|
|
244
283
|
// Exponential backoff per source IP: 0, 0, 0, 1s, 4s, 16s, 64s, 256s, capped.
|
|
@@ -248,6 +287,10 @@ const BACKOFF_BASE_MS = 1000;
|
|
|
248
287
|
const BACKOFF_CAP_MS = 15 * 60 * 1000; // 15 min hard cap per attempt window
|
|
249
288
|
export function getLoginBlockMs(ip) {
|
|
250
289
|
const record = loginAttempts.get(ip);
|
|
290
|
+
if (record && Date.now() - record.updatedAt > BACKOFF_CAP_MS * 2) {
|
|
291
|
+
loginAttempts.delete(ip);
|
|
292
|
+
return 0;
|
|
293
|
+
}
|
|
251
294
|
if (!record)
|
|
252
295
|
return 0;
|
|
253
296
|
const remaining = record.blockedUntil - Date.now();
|
|
@@ -255,8 +298,12 @@ export function getLoginBlockMs(ip) {
|
|
|
255
298
|
}
|
|
256
299
|
export function recordLoginFailure(ip) {
|
|
257
300
|
const now = Date.now();
|
|
258
|
-
const record = loginAttempts.get(ip) ?? { failures: 0, blockedUntil: 0 };
|
|
301
|
+
const record = loginAttempts.get(ip) ?? { failures: 0, blockedUntil: 0, updatedAt: now };
|
|
302
|
+
record.updatedAt = now;
|
|
259
303
|
record.failures += 1;
|
|
304
|
+
if (loginAttempts.size >= 4096 && !loginAttempts.has(ip)) {
|
|
305
|
+
loginAttempts.delete(loginAttempts.keys().next().value);
|
|
306
|
+
}
|
|
260
307
|
if (record.failures > BACKOFF_GRACE_FAILURES) {
|
|
261
308
|
const exponent = record.failures - BACKOFF_GRACE_FAILURES - 1;
|
|
262
309
|
const delay = Math.min(BACKOFF_CAP_MS, BACKOFF_BASE_MS * Math.pow(4, exponent));
|
|
@@ -274,6 +321,18 @@ export function isRequestAuthenticated(req) {
|
|
|
274
321
|
const token = req.cookies?.[AUTH_COOKIE];
|
|
275
322
|
return isSessionValid(typeof token === 'string' ? token : undefined);
|
|
276
323
|
}
|
|
324
|
+
// Refresh both sides of the login on HTTP visits. Socket validation alone
|
|
325
|
+
// cannot update a browser cookie, so the UI also checks status on foregrounding.
|
|
326
|
+
export function renewSessionMiddleware(req, res, next) {
|
|
327
|
+
const token = req.cookies?.[AUTH_COOKIE];
|
|
328
|
+
const authMutation = /^\/(?:api\/)?auth\/(?:login|logout)\/?$/i.test(req.path);
|
|
329
|
+
if (!authMutation && isAuthEnabled() && typeof token === 'string' && isSessionValid(token, true)) {
|
|
330
|
+
const key = crypto.createHash('sha256').update(token).digest('hex');
|
|
331
|
+
const record = sessions.get(key);
|
|
332
|
+
setSessionCookie(res, token, record.expiresAt);
|
|
333
|
+
}
|
|
334
|
+
next();
|
|
335
|
+
}
|
|
277
336
|
// Middleware factory: blocks the request with 401 unless either auth is
|
|
278
337
|
// disabled (no auth.json) or the request carries a valid session cookie.
|
|
279
338
|
// Bypass paths are public (login/status/health/static).
|
|
@@ -290,7 +349,7 @@ export function requireAuth(options) {
|
|
|
290
349
|
}
|
|
291
350
|
// Verify the cookie attached to a WebSocket upgrade request. Reads the raw
|
|
292
351
|
// Cookie header and matches AUTH_COOKIE without depending on Express middleware.
|
|
293
|
-
export function isUpgradeRequestAuthenticated(cookieHeader) {
|
|
352
|
+
export function isUpgradeRequestAuthenticated(cookieHeader, touch = false) {
|
|
294
353
|
if (!isAuthEnabled())
|
|
295
354
|
return true;
|
|
296
355
|
if (!cookieHeader)
|
|
@@ -303,9 +362,13 @@ export function isUpgradeRequestAuthenticated(cookieHeader) {
|
|
|
303
362
|
const name = pair.slice(0, idx).trim();
|
|
304
363
|
if (name !== AUTH_COOKIE)
|
|
305
364
|
continue;
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
return
|
|
365
|
+
try {
|
|
366
|
+
const value = decodeURIComponent(pair.slice(idx + 1).trim());
|
|
367
|
+
return isSessionValid(value, touch);
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
309
372
|
}
|
|
310
373
|
return false;
|
|
311
374
|
}
|
|
@@ -315,11 +378,11 @@ export function getClientIp(req) {
|
|
|
315
378
|
// sees the proxy IP — that's an acceptable trade-off here.
|
|
316
379
|
return req.socket.remoteAddress ?? 'unknown';
|
|
317
380
|
}
|
|
318
|
-
export function setSessionCookie(res, token) {
|
|
381
|
+
export function setSessionCookie(res, token, expiresAt = Date.now() + SESSION_TTL_MS) {
|
|
319
382
|
res.cookie(AUTH_COOKIE, token, {
|
|
320
383
|
httpOnly: true,
|
|
321
384
|
...getCookieSecurityOptions(),
|
|
322
|
-
maxAge:
|
|
385
|
+
maxAge: Math.max(0, expiresAt - Date.now()),
|
|
323
386
|
path: '/',
|
|
324
387
|
});
|
|
325
388
|
}
|
|
@@ -338,3 +401,42 @@ export function verifyPassword(password) {
|
|
|
338
401
|
return false;
|
|
339
402
|
return verifyPasswordAgainstHash(password, auth.passwordHash);
|
|
340
403
|
}
|
|
404
|
+
// A bounded asynchronous KDF prevents login traffic from blocking terminal I/O
|
|
405
|
+
// or filling the libuv worker queue. The shared budget also covers rotating IPs.
|
|
406
|
+
let activeVerifications = 0;
|
|
407
|
+
let verificationWindow = 0;
|
|
408
|
+
let verificationCount = 0;
|
|
409
|
+
export async function verifyPasswordAsync(password) {
|
|
410
|
+
const now = Date.now();
|
|
411
|
+
if (now - verificationWindow >= 60_000) {
|
|
412
|
+
verificationWindow = now;
|
|
413
|
+
verificationCount = 0;
|
|
414
|
+
}
|
|
415
|
+
if (activeVerifications >= 2 || verificationCount >= 30)
|
|
416
|
+
return null;
|
|
417
|
+
if (!password || Buffer.byteLength(password) > 1024)
|
|
418
|
+
return false;
|
|
419
|
+
verificationCount++;
|
|
420
|
+
const stored = getEnvPasswordHash() ?? readAuthFile()?.passwordHash;
|
|
421
|
+
if (!stored)
|
|
422
|
+
return false;
|
|
423
|
+
const [algorithm, salt, hash] = stored.split('$');
|
|
424
|
+
if (algorithm !== 'scrypt' || !/^[0-9a-f]{32}$/.test(salt ?? '') || !/^[0-9a-f]{128}$/.test(hash ?? ''))
|
|
425
|
+
return false;
|
|
426
|
+
const credential = credentialFingerprint();
|
|
427
|
+
activeVerifications++;
|
|
428
|
+
try {
|
|
429
|
+
const derived = await new Promise((resolve, reject) => {
|
|
430
|
+
crypto.scrypt(password, Buffer.from(salt, 'hex'), SCRYPT_KEY_LEN, {
|
|
431
|
+
N: SCRYPT_N, r: SCRYPT_R, p: SCRYPT_P, maxmem: 128 * SCRYPT_N * SCRYPT_R * 2,
|
|
432
|
+
}, (error, key) => error ? reject(error) : resolve(key));
|
|
433
|
+
});
|
|
434
|
+
return credential === credentialFingerprint() && crypto.timingSafeEqual(derived, Buffer.from(hash, 'hex'));
|
|
435
|
+
}
|
|
436
|
+
catch {
|
|
437
|
+
return false;
|
|
438
|
+
}
|
|
439
|
+
finally {
|
|
440
|
+
activeVerifications--;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import { getPublicOrigin } from './publicSecurity.js';
|
|
1
2
|
let secureCookies = false;
|
|
2
3
|
export function setSecureCookieMode(enabled) {
|
|
3
4
|
secureCookies = enabled;
|
|
4
5
|
}
|
|
5
6
|
export function shouldUseSecureCookies() {
|
|
6
|
-
return secureCookies;
|
|
7
|
+
return secureCookies || Boolean(getPublicOrigin());
|
|
7
8
|
}
|
|
8
9
|
export function getCookieSecurityOptions() {
|
|
9
10
|
return {
|
|
10
|
-
secure:
|
|
11
|
+
secure: shouldUseSecureCookies(),
|
|
11
12
|
sameSite: 'lax',
|
|
12
13
|
};
|
|
13
14
|
}
|
|
@@ -29,7 +29,8 @@ export class CsrfProtection {
|
|
|
29
29
|
* 验证CSRF令牌
|
|
30
30
|
*/
|
|
31
31
|
verifyToken(cookieToken, headerToken) {
|
|
32
|
-
if (typeof cookieToken !== 'string' || typeof headerToken !== 'string'
|
|
32
|
+
if (typeof cookieToken !== 'string' || typeof headerToken !== 'string' ||
|
|
33
|
+
!new RegExp(`^[0-9a-f]{${this.config.tokenLength * 2}}$`).test(cookieToken) || cookieToken.length !== headerToken.length) {
|
|
33
34
|
return false;
|
|
34
35
|
}
|
|
35
36
|
const cookieBuffer = Buffer.from(cookieToken);
|
|
@@ -72,11 +73,6 @@ export class CsrfProtection {
|
|
|
72
73
|
if (safeMethods.includes(req.method)) {
|
|
73
74
|
return next();
|
|
74
75
|
}
|
|
75
|
-
// 跳过某些端点(如果需要)
|
|
76
|
-
const skipPaths = ['/api/csrf-token'];
|
|
77
|
-
if (skipPaths.some(path => req.path.startsWith(path))) {
|
|
78
|
-
return next();
|
|
79
|
-
}
|
|
80
76
|
// 获取令牌
|
|
81
77
|
const cookieToken = req.cookies?.[this.config.cookieName];
|
|
82
78
|
const headerToken = req.headers[this.config.headerName.toLowerCase()];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import { requestAcceptsEtag } from './edaPreviewCache.js';
|
|
3
|
+
/** Call only after authentication, path validation and file-type/size checks. */
|
|
4
|
+
export function validatePreview(req, res, file, stat, representation) {
|
|
5
|
+
const revision = crypto.createHash('sha256')
|
|
6
|
+
.update(JSON.stringify([file, stat.size, stat.mtimeMs, stat.ctimeMs, representation]))
|
|
7
|
+
.digest('base64url').slice(0, 24);
|
|
8
|
+
const etag = `W/"preview-${revision}"`;
|
|
9
|
+
res.setHeader('ETag', etag);
|
|
10
|
+
res.setHeader('Last-Modified', stat.mtime.toUTCString());
|
|
11
|
+
res.setHeader('Cache-Control', 'private, no-cache');
|
|
12
|
+
if (!requestAcceptsEtag(req.headers['if-none-match'], etag))
|
|
13
|
+
return false;
|
|
14
|
+
res.status(304).end();
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { isAuthEnabled, readAuthFile } from './authProtection.js';
|
|
2
|
+
/** Explicit external origin; never infer TLS or trust from forwarded headers. */
|
|
3
|
+
export function getPublicOrigin() {
|
|
4
|
+
const raw = process.env.TERMDOCK_PUBLIC_ORIGIN;
|
|
5
|
+
if (!raw)
|
|
6
|
+
return null;
|
|
7
|
+
const url = new URL(raw);
|
|
8
|
+
if (url.protocol !== 'https:' || url.username || url.password || url.pathname !== '/' || url.search || url.hash) {
|
|
9
|
+
throw new Error('TERMDOCK_PUBLIC_ORIGIN must be an HTTPS origin, e.g. https://term.example.com');
|
|
10
|
+
}
|
|
11
|
+
return url.origin;
|
|
12
|
+
}
|
|
13
|
+
export function assertPublicSecurity() {
|
|
14
|
+
if (!getPublicOrigin())
|
|
15
|
+
return;
|
|
16
|
+
if (!isAuthEnabled() || (!process.env.TERMDOCK_PASSWORD && !readAuthFile())) {
|
|
17
|
+
throw new Error('Public access requires authentication. Run td --set-password before starting.');
|
|
18
|
+
}
|
|
19
|
+
if (!process.env.TERMDOCK_PASSWORD && (readAuthFile()?.passwordLength ?? 0) < 16) {
|
|
20
|
+
throw new Error('Public access requires a verified 16-character password. Run td --set-password again.');
|
|
21
|
+
}
|
|
22
|
+
if (process.env.TERMDOCK_PASSWORD && process.env.TERMDOCK_PASSWORD.length < 16) {
|
|
23
|
+
throw new Error('Public access requires TERMDOCK_PASSWORD to contain at least 16 characters.');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export const securityHeaders = (req, res, next) => {
|
|
27
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
28
|
+
res.setHeader('Referrer-Policy', 'no-referrer');
|
|
29
|
+
res.setHeader('X-Frame-Options', 'SAMEORIGIN');
|
|
30
|
+
// Enforce sandbox even for top-level navigation to user-controlled HTML/SVG.
|
|
31
|
+
// allow-same-origin must NEVER be added: that would expose the terminal API.
|
|
32
|
+
const preview = /^\/api\/terminal\/fs(?:\/|$)/i.test(req.path);
|
|
33
|
+
res.setHeader('Content-Security-Policy', preview
|
|
34
|
+
? "sandbox allow-scripts; frame-ancestors 'self'; object-src 'none'; base-uri 'self'"
|
|
35
|
+
: "script-src 'self' 'wasm-unsafe-eval'; script-src-attr 'none'; worker-src 'self' blob:; frame-ancestors 'self'; object-src 'none'; base-uri 'self'");
|
|
36
|
+
if (getPublicOrigin()) {
|
|
37
|
+
res.setHeader('Strict-Transport-Security', 'max-age=31536000');
|
|
38
|
+
if (!isAuthEnabled()) {
|
|
39
|
+
res.status(503).json({ error: 'Public access requires authentication', code: 'PUBLIC_AUTH_REQUIRED' });
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
next();
|
|
44
|
+
};
|
|
@@ -20,6 +20,8 @@ const DEADLINE_RULES = [
|
|
|
20
20
|
// 有限但可能很久:大目录搜索(有 done 事件的进度流)、大文件下载。
|
|
21
21
|
{ method: 'GET', pattern: /^\/api\/terminal\/fs\/search$/, deadlineMs: 120_000 },
|
|
22
22
|
{ method: 'GET', pattern: /^\/api\/terminal\/fs\/download$/, deadlineMs: 300_000 },
|
|
23
|
+
// KiCad GLB responses can take longer than rendering to transfer to a phone.
|
|
24
|
+
{ method: 'GET', pattern: /^\/api\/terminal\/fs\/eda-preview$/, deadlineMs: 120_000 },
|
|
23
25
|
// 上传最多 100MB×50 文件,弱网下接收请求体可能要几分钟。注意 Node 内置
|
|
24
26
|
// requestTimeout(默认 300s,本项目未改)管「请求体接收」阶段并在超时后
|
|
25
27
|
// 回 408,所以这里必须低于 300s——让我们的 503+日志先出手,而不是被
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { shouldUseSecureCookies } from './cookieSecurity.js';
|
|
2
|
+
import { getPublicOrigin } from './publicSecurity.js';
|
|
1
3
|
import { getLanIPv4Addresses, localAccessManager } from './localAccess.js';
|
|
2
4
|
const LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '::1']);
|
|
3
5
|
function stripPort(hostHeader) {
|
|
@@ -39,6 +41,9 @@ export function getAllowedHosts() {
|
|
|
39
41
|
for (const host of getEnvExtraHosts()) {
|
|
40
42
|
hosts.add(host);
|
|
41
43
|
}
|
|
44
|
+
const publicOrigin = getPublicOrigin();
|
|
45
|
+
if (publicOrigin)
|
|
46
|
+
hosts.add(new URL(publicOrigin).hostname);
|
|
42
47
|
return hosts;
|
|
43
48
|
}
|
|
44
49
|
export function isAllowedHost(hostHeader) {
|
|
@@ -55,20 +60,25 @@ export function validateHostMiddleware(req, res, next) {
|
|
|
55
60
|
next();
|
|
56
61
|
}
|
|
57
62
|
export function isAllowedOrigin(originHeader, _hostHeader) {
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
// `http://192.168.x.x:9833`,强制 Origin === Host 会让 LAN 访问的所有 POST
|
|
61
|
-
// (包括登录)全部 403。Origin 头由浏览器控制、无法被网页攻击者伪造,所以只
|
|
62
|
-
// 要求 origin host 落在 allowedHosts 白名单内即可,防 CSRF 的强度不变。
|
|
63
|
-
// 注意:反向代理场景下 Host 头可能是内部地址,不用它来 gate Origin 检查,
|
|
64
|
-
// 否则 TERMDOCK_ALLOWED_HOSTS 只包含公网域名时会误杀正常登录请求。
|
|
63
|
+
// Non-browser API clients may omit Origin; cookie-authenticated mutations
|
|
64
|
+
// additionally require CSRF tokens. Browsers cannot forge this header.
|
|
65
65
|
if (!originHeader)
|
|
66
66
|
return true;
|
|
67
67
|
try {
|
|
68
|
-
const
|
|
69
|
-
if (!
|
|
68
|
+
const origin = new URL(originHeader);
|
|
69
|
+
if (!['http:', 'https:'].includes(origin.protocol) || origin.origin !== originHeader)
|
|
70
70
|
return false;
|
|
71
|
-
|
|
71
|
+
const publicOrigin = getPublicOrigin();
|
|
72
|
+
if (publicOrigin)
|
|
73
|
+
return origin.origin === publicOrigin;
|
|
74
|
+
if (!getAllowedHosts().has(stripPort(origin.host)))
|
|
75
|
+
return false;
|
|
76
|
+
// Only the development proxy intentionally changes Host/port. On normal
|
|
77
|
+
// listeners, another service on the same LAN host is a different origin.
|
|
78
|
+
if (process.env.NODE_ENV === 'development')
|
|
79
|
+
return true;
|
|
80
|
+
return origin.host.toLowerCase() === (_hostHeader ?? '').toLowerCase() &&
|
|
81
|
+
origin.protocol === (shouldUseSecureCookies() ? 'https:' : 'http:');
|
|
72
82
|
}
|
|
73
83
|
catch {
|
|
74
84
|
return false;
|
|
@@ -81,23 +91,8 @@ export function validateOriginMiddleware(req, res, next) {
|
|
|
81
91
|
}
|
|
82
92
|
next();
|
|
83
93
|
}
|
|
84
|
-
export function isUpgradeOriginAllowed(originHeader,
|
|
85
|
-
|
|
86
|
-
// 在 dev 模式下 Vite proxy (9833 → 9835) 用 changeOrigin: true 会把 Host 改写成
|
|
87
|
-
// `localhost:9835`,但 Origin 仍是 `http://192.168.x.x:9833`。这种 mismatch
|
|
88
|
-
// 会让正常 LAN 访问全部 403、WS 退化为持续 reconnecting。
|
|
89
|
-
// 这里只要求 origin host 落在 allowedHosts 里(loopback + LAN IPv4 + mDNS 域名),
|
|
90
|
-
// 不强制等于 request.headers.host。Origin 校验保持原强度(必须能解析出 host、
|
|
91
|
-
// 且 host 在白名单内),所以攻击者把 Origin 改成任意地址仍然过不了。
|
|
92
|
-
if (!originHeader)
|
|
93
|
-
return true;
|
|
94
|
-
try {
|
|
95
|
-
const originHost = stripPort(new URL(originHeader).host);
|
|
96
|
-
if (!originHost)
|
|
97
|
-
return false;
|
|
98
|
-
return getAllowedHosts().has(originHost);
|
|
99
|
-
}
|
|
100
|
-
catch {
|
|
94
|
+
export function isUpgradeOriginAllowed(originHeader, hostHeader) {
|
|
95
|
+
if (getPublicOrigin() && !originHeader)
|
|
101
96
|
return false;
|
|
102
|
-
|
|
97
|
+
return isAllowedOrigin(originHeader, hostHeader);
|
|
103
98
|
}
|