@saluzi/saluzi-edu 0.2.9 → 0.2.11
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/cli.js +336 -333
- package/dist/rcs-web/assets/Dashboard-BwotBWlJ.js +1 -0
- package/dist/rcs-web/assets/Join-4yrksbdX.js +1 -0
- package/dist/rcs-web/assets/Login-Cxm_yEeE.js +1 -0
- package/dist/rcs-web/assets/SessionDetail-DNdfPOYy.js +50 -0
- package/dist/rcs-web/assets/Setup-BiAAxugt.js +1 -0
- package/dist/rcs-web/assets/ShareLanding-CP3Z6ckr.js +1 -0
- package/dist/rcs-web/assets/TeamCreate-DgdCwRSb.js +1 -0
- package/dist/rcs-web/assets/TeamDetail-CkNTFoMB.js +11 -0
- package/dist/rcs-web/assets/TeamList-Bf0sQ5RQ.js +1 -0
- package/dist/rcs-web/assets/TeamSettings-BaNAfXU3.js +1 -0
- package/dist/rcs-web/assets/UserSettings-CsutQjxG.js +1 -0
- package/{packages/remote-control-server/web/dist/assets/arc-D90597o-.js → dist/rcs-web/assets/arc-BxxmNQO6.js} +1 -1
- package/dist/rcs-web/assets/architectureDiagram-3BPJPVTR-DBjkRdbd.js +36 -0
- package/dist/rcs-web/assets/{blockDiagram-GPEHLZMM-DHd8IbOs.js → blockDiagram-GPEHLZMM-BF6COWlM.js} +2 -2
- package/dist/rcs-web/assets/{c4Diagram-AAUBKEIU-CjFkQJ9h.js → c4Diagram-AAUBKEIU-DHOf390v.js} +2 -2
- package/dist/rcs-web/assets/channel-JsvbMQjW.js +1 -0
- package/dist/rcs-web/assets/{chunk-2J33WTMH-C21XWnGZ.js → chunk-2J33WTMH-CeJN8yjM.js} +1 -1
- package/dist/rcs-web/assets/{chunk-4BX2VUAB-B3SXiJlt.js → chunk-4BX2VUAB-jP76_P2A.js} +1 -1
- package/dist/rcs-web/assets/{chunk-55IACEB6-DjImv45F.js → chunk-55IACEB6-BsFA6emB.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/chunk-727SXJPM-DtnaqsyD.js → dist/rcs-web/assets/chunk-727SXJPM-BF4HrQjZ.js} +1 -1
- package/dist/rcs-web/assets/{chunk-AQP2D5EJ-BVFgH5mS.js → chunk-AQP2D5EJ-DToJ74Kc.js} +1 -1
- package/dist/rcs-web/assets/{chunk-FMBD7UC4-Bl8jgb57.js → chunk-FMBD7UC4-DVTARgsa.js} +1 -1
- package/dist/rcs-web/assets/{chunk-ND2GUHAM-BpK111zh.js → chunk-ND2GUHAM-C50Gqv9c.js} +1 -1
- package/dist/rcs-web/assets/{chunk-QZHKN3VN-ruhIHBim.js → chunk-QZHKN3VN-EsIIh6zV.js} +1 -1
- package/dist/rcs-web/assets/classDiagram-4FO5ZUOK-BXn8Uc4c.js +1 -0
- package/dist/rcs-web/assets/classDiagram-v2-Q7XG4LA2-BXn8Uc4c.js +1 -0
- package/dist/rcs-web/assets/code-block-IT6T5CEO-BnufHNTT.js +2 -0
- package/dist/rcs-web/assets/cose-bilkent-S5V4N54A-M6tNt14I.js +1 -0
- package/dist/rcs-web/assets/dagre-BM42HDAG-DaTm29qG.js +4 -0
- package/dist/rcs-web/assets/diagram-2AECGRRQ-fqoeOvq2.js +43 -0
- package/dist/rcs-web/assets/diagram-5GNKFQAL-6s2CiaGG.js +10 -0
- package/dist/rcs-web/assets/{diagram-KO2AKTUF-Uy3PDP5S.js → diagram-KO2AKTUF-C0aw_N95.js} +2 -2
- package/dist/rcs-web/assets/diagram-LMA3HP47-C8_Rv3rB.js +24 -0
- package/dist/rcs-web/assets/diagram-OG6HWLK6-Dae4u8Uc.js +24 -0
- package/{packages/remote-control-server/web/dist/assets/erDiagram-TEJ5UH35-sre_MTeK.js → dist/rcs-web/assets/erDiagram-TEJ5UH35-CosS5VWr.js} +13 -13
- package/dist/rcs-web/assets/{flowDiagram-I6XJVG4X-DwrWaLoe.js → flowDiagram-I6XJVG4X-D_Mxs46-.js} +2 -2
- package/dist/rcs-web/assets/ganttDiagram-6RSMTGT7-B0jy8Am_.js +292 -0
- package/dist/rcs-web/assets/gitGraphDiagram-PVQCEYII-CSdu2HVI.js +106 -0
- package/dist/rcs-web/assets/i18n-Dbt-vEQ3.js +1 -0
- package/dist/rcs-web/assets/infoDiagram-5YYISTIA-Dcbc9L1S.js +2 -0
- package/{packages/remote-control-server/web/dist/assets/ishikawaDiagram-YF4QCWOH-SO0nn3--.js → dist/rcs-web/assets/ishikawaDiagram-YF4QCWOH-BLMjFE4t.js} +2 -2
- package/dist/rcs-web/assets/{journeyDiagram-JHISSGLW-D4igFUd4.js → journeyDiagram-JHISSGLW-Dw4nh1xI.js} +2 -2
- package/dist/rcs-web/assets/{kanban-definition-UN3LZRKU-Cm_yKsZC.js → kanban-definition-UN3LZRKU-DkU3j_ly.js} +2 -2
- package/dist/rcs-web/assets/{linear-4IMGll_E.js → linear-N5Cify7M.js} +1 -1
- package/dist/rcs-web/assets/main-30YqUvTd.js +238 -0
- package/dist/rcs-web/assets/main-EP6Lac2m.css +1 -0
- package/{packages/remote-control-server/web/dist/assets/mermaid-VLURNSYL-D_yQ7nAd.js → dist/rcs-web/assets/mermaid-VLURNSYL-gfiJUpl_.js} +5 -5
- package/dist/rcs-web/assets/{mermaid.core-B1qOUdiU.js → mermaid.core-B_Xc65Bf.js} +5 -5
- package/dist/rcs-web/assets/{mindmap-definition-RKZ34NQL-yETom5qt.js → mindmap-definition-RKZ34NQL-DUavHfNu.js} +2 -2
- package/{packages/remote-control-server/web/dist/assets/pieDiagram-4H26LBE5-KIhqXGT6.js → dist/rcs-web/assets/pieDiagram-4H26LBE5-DSJaToTU.js} +2 -2
- package/{packages/remote-control-server/web/dist/assets/quadrantDiagram-W4KKPZXB-DISqmoA6.js → dist/rcs-web/assets/quadrantDiagram-W4KKPZXB-BFp6TnHj.js} +2 -2
- package/dist/rcs-web/assets/{requirementDiagram-4Y6WPE33-DsgT4ptk.js → requirementDiagram-4Y6WPE33-eil6F3-O.js} +2 -2
- package/{packages/remote-control-server/web/dist/assets/sankeyDiagram-5OEKKPKP-Dn67kbn0.js → dist/rcs-web/assets/sankeyDiagram-5OEKKPKP-DbGhoepK.js} +2 -2
- package/{packages/remote-control-server/web/dist/assets/sequenceDiagram-3UESZ5HK-CtWaXZHl.js → dist/rcs-web/assets/sequenceDiagram-3UESZ5HK-B0YrN1ud.js} +14 -14
- package/dist/rcs-web/assets/stateDiagram-AJRCARHV-CofFPj3N.js +1 -0
- package/dist/rcs-web/assets/stateDiagram-v2-BHNVJYJU-DPlcvPn1.js +1 -0
- package/{packages/remote-control-server/web/dist/assets/timeline-definition-PNZ67QCA-Dk5WUenC.js → dist/rcs-web/assets/timeline-definition-PNZ67QCA-Bx4dusy8.js} +2 -2
- package/dist/rcs-web/assets/useTeams-MDI4djXg.js +1 -0
- package/{packages/remote-control-server/web/dist/assets/vennDiagram-CIIHVFJN-TY8EiRrC.js → dist/rcs-web/assets/vennDiagram-CIIHVFJN-B_-3l-MF.js} +2 -2
- package/dist/rcs-web/assets/{wardleyDiagram-YWT4CUSO-BK3oi47X.js → wardleyDiagram-YWT4CUSO-DNSn-pGp.js} +2 -2
- package/dist/rcs-web/assets/workerType-OM09y7Lk.js +1 -0
- package/{packages/remote-control-server/web/dist/assets/xychartDiagram-2RQKCTM6-DhsxqX67.js → dist/rcs-web/assets/xychartDiagram-2RQKCTM6-TqUbNp0j.js} +2 -2
- package/dist/rcs-web/index.html +2 -3
- package/package.json +2 -1
- package/packages/remote-control-server/src/__tests__/acp-ws-handler.test.ts +7 -19
- package/packages/remote-control-server/src/__tests__/auth-login.test.ts +561 -0
- package/packages/remote-control-server/src/__tests__/auth-security.test.ts +547 -0
- package/packages/remote-control-server/src/__tests__/auth.test.ts +7 -18
- package/packages/remote-control-server/src/__tests__/bind-replacement.test.ts +251 -0
- package/packages/remote-control-server/src/__tests__/cookie.test.ts +155 -0
- package/packages/remote-control-server/src/__tests__/data-layer-fixes.test.ts +147 -0
- package/packages/remote-control-server/src/__tests__/db.test.ts +582 -0
- package/packages/remote-control-server/src/__tests__/design-gaps.test.ts +440 -0
- package/packages/remote-control-server/src/__tests__/disconnect-monitor.test.ts +2 -18
- package/packages/remote-control-server/src/__tests__/helpers/db.ts +43 -0
- package/packages/remote-control-server/src/__tests__/helpers/fixtures.ts +94 -0
- package/packages/remote-control-server/src/__tests__/helpers/mock-config.ts +31 -0
- package/packages/remote-control-server/src/__tests__/middleware.test.ts +4 -112
- package/packages/remote-control-server/src/__tests__/password.test.ts +76 -0
- package/packages/remote-control-server/src/__tests__/phase4-cleanup.test.ts +290 -0
- package/packages/remote-control-server/src/__tests__/phase4-integration.test.ts +224 -0
- package/packages/remote-control-server/src/__tests__/routes.test.ts +292 -207
- package/packages/remote-control-server/src/__tests__/services.test.ts +2 -18
- package/packages/remote-control-server/src/__tests__/session-visibility.test.ts +452 -0
- package/packages/remote-control-server/src/__tests__/session.test.ts +216 -0
- package/packages/remote-control-server/src/__tests__/shares.test.ts +1419 -0
- package/packages/remote-control-server/src/__tests__/sse-writer.test.ts +2 -18
- package/packages/remote-control-server/src/__tests__/teams.test.ts +2089 -0
- package/packages/remote-control-server/src/__tests__/work-dispatch.test.ts +2 -18
- package/packages/remote-control-server/src/__tests__/worker-token-removal.test.ts +487 -0
- package/packages/remote-control-server/src/__tests__/ws-handler.test.ts +2 -18
- package/packages/remote-control-server/src/auth/constants.ts +13 -0
- package/packages/remote-control-server/src/auth/cookie.ts +75 -0
- package/packages/remote-control-server/src/auth/middleware.ts +75 -165
- package/packages/remote-control-server/src/auth/password.ts +116 -0
- package/packages/remote-control-server/src/auth/session.ts +130 -0
- package/packages/remote-control-server/src/db/schema.sql +116 -0
- package/packages/remote-control-server/src/db/sqlite.ts +99 -0
- package/packages/remote-control-server/src/routes/acp/index.ts +6 -11
- package/packages/remote-control-server/src/routes/v1/environments.ts +111 -8
- package/packages/remote-control-server/src/routes/web/auth-routes.ts +634 -0
- package/packages/remote-control-server/src/routes/web/control.ts +5 -5
- package/packages/remote-control-server/src/routes/web/environments.ts +5 -27
- package/packages/remote-control-server/src/routes/web/sessions.ts +19 -41
- package/packages/remote-control-server/src/routes/web/shares.ts +371 -0
- package/packages/remote-control-server/src/routes/web/teams.ts +850 -0
- package/packages/remote-control-server/src/services/environment.ts +1 -4
- package/packages/remote-control-server/src/services/session-visibility.ts +79 -0
- package/packages/remote-control-server/src/services/session.ts +0 -13
- package/packages/remote-control-server/src/store.ts +150 -56
- package/packages/remote-control-server/src/types/api.ts +2 -8
- package/packages/remote-control-server/web/dist/assets/Dashboard-BwotBWlJ.js +1 -0
- package/packages/remote-control-server/web/dist/assets/Join-4yrksbdX.js +1 -0
- package/packages/remote-control-server/web/dist/assets/Login-Cxm_yEeE.js +1 -0
- package/packages/remote-control-server/web/dist/assets/SessionDetail-DNdfPOYy.js +50 -0
- package/packages/remote-control-server/web/dist/assets/Setup-BiAAxugt.js +1 -0
- package/packages/remote-control-server/web/dist/assets/ShareLanding-CP3Z6ckr.js +1 -0
- package/packages/remote-control-server/web/dist/assets/TeamCreate-DgdCwRSb.js +1 -0
- package/packages/remote-control-server/web/dist/assets/TeamDetail-CkNTFoMB.js +11 -0
- package/packages/remote-control-server/web/dist/assets/TeamList-Bf0sQ5RQ.js +1 -0
- package/packages/remote-control-server/web/dist/assets/TeamSettings-BaNAfXU3.js +1 -0
- package/packages/remote-control-server/web/dist/assets/UserSettings-CsutQjxG.js +1 -0
- package/{dist/rcs-web/assets/arc-D90597o-.js → packages/remote-control-server/web/dist/assets/arc-BxxmNQO6.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/architectureDiagram-3BPJPVTR-DBjkRdbd.js +36 -0
- package/packages/remote-control-server/web/dist/assets/{blockDiagram-GPEHLZMM-DHd8IbOs.js → blockDiagram-GPEHLZMM-BF6COWlM.js} +2 -2
- package/packages/remote-control-server/web/dist/assets/{c4Diagram-AAUBKEIU-CjFkQJ9h.js → c4Diagram-AAUBKEIU-DHOf390v.js} +2 -2
- package/packages/remote-control-server/web/dist/assets/channel-JsvbMQjW.js +1 -0
- package/packages/remote-control-server/web/dist/assets/{chunk-2J33WTMH-C21XWnGZ.js → chunk-2J33WTMH-CeJN8yjM.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{chunk-4BX2VUAB-B3SXiJlt.js → chunk-4BX2VUAB-jP76_P2A.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{chunk-55IACEB6-DjImv45F.js → chunk-55IACEB6-BsFA6emB.js} +1 -1
- package/{dist/rcs-web/assets/chunk-727SXJPM-DtnaqsyD.js → packages/remote-control-server/web/dist/assets/chunk-727SXJPM-BF4HrQjZ.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{chunk-AQP2D5EJ-BVFgH5mS.js → chunk-AQP2D5EJ-DToJ74Kc.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{chunk-FMBD7UC4-Bl8jgb57.js → chunk-FMBD7UC4-DVTARgsa.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{chunk-ND2GUHAM-BpK111zh.js → chunk-ND2GUHAM-C50Gqv9c.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{chunk-QZHKN3VN-ruhIHBim.js → chunk-QZHKN3VN-EsIIh6zV.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/classDiagram-4FO5ZUOK-BXn8Uc4c.js +1 -0
- package/packages/remote-control-server/web/dist/assets/classDiagram-v2-Q7XG4LA2-BXn8Uc4c.js +1 -0
- package/packages/remote-control-server/web/dist/assets/code-block-IT6T5CEO-BnufHNTT.js +2 -0
- package/packages/remote-control-server/web/dist/assets/cose-bilkent-S5V4N54A-M6tNt14I.js +1 -0
- package/packages/remote-control-server/web/dist/assets/dagre-BM42HDAG-DaTm29qG.js +4 -0
- package/packages/remote-control-server/web/dist/assets/diagram-2AECGRRQ-fqoeOvq2.js +43 -0
- package/packages/remote-control-server/web/dist/assets/diagram-5GNKFQAL-6s2CiaGG.js +10 -0
- package/packages/remote-control-server/web/dist/assets/{diagram-KO2AKTUF-Uy3PDP5S.js → diagram-KO2AKTUF-C0aw_N95.js} +2 -2
- package/packages/remote-control-server/web/dist/assets/diagram-LMA3HP47-C8_Rv3rB.js +24 -0
- package/packages/remote-control-server/web/dist/assets/diagram-OG6HWLK6-Dae4u8Uc.js +24 -0
- package/{dist/rcs-web/assets/erDiagram-TEJ5UH35-sre_MTeK.js → packages/remote-control-server/web/dist/assets/erDiagram-TEJ5UH35-CosS5VWr.js} +13 -13
- package/packages/remote-control-server/web/dist/assets/{flowDiagram-I6XJVG4X-DwrWaLoe.js → flowDiagram-I6XJVG4X-D_Mxs46-.js} +2 -2
- package/packages/remote-control-server/web/dist/assets/ganttDiagram-6RSMTGT7-B0jy8Am_.js +292 -0
- package/packages/remote-control-server/web/dist/assets/gitGraphDiagram-PVQCEYII-CSdu2HVI.js +106 -0
- package/packages/remote-control-server/web/dist/assets/i18n-Dbt-vEQ3.js +1 -0
- package/packages/remote-control-server/web/dist/assets/infoDiagram-5YYISTIA-Dcbc9L1S.js +2 -0
- package/{dist/rcs-web/assets/ishikawaDiagram-YF4QCWOH-SO0nn3--.js → packages/remote-control-server/web/dist/assets/ishikawaDiagram-YF4QCWOH-BLMjFE4t.js} +2 -2
- package/packages/remote-control-server/web/dist/assets/{journeyDiagram-JHISSGLW-D4igFUd4.js → journeyDiagram-JHISSGLW-Dw4nh1xI.js} +2 -2
- package/packages/remote-control-server/web/dist/assets/{kanban-definition-UN3LZRKU-Cm_yKsZC.js → kanban-definition-UN3LZRKU-DkU3j_ly.js} +2 -2
- package/packages/remote-control-server/web/dist/assets/{linear-4IMGll_E.js → linear-N5Cify7M.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/main-30YqUvTd.js +238 -0
- package/packages/remote-control-server/web/dist/assets/main-EP6Lac2m.css +1 -0
- package/{dist/rcs-web/assets/mermaid-VLURNSYL-D_yQ7nAd.js → packages/remote-control-server/web/dist/assets/mermaid-VLURNSYL-gfiJUpl_.js} +5 -5
- package/packages/remote-control-server/web/dist/assets/{mermaid.core-B1qOUdiU.js → mermaid.core-B_Xc65Bf.js} +5 -5
- package/packages/remote-control-server/web/dist/assets/{mindmap-definition-RKZ34NQL-yETom5qt.js → mindmap-definition-RKZ34NQL-DUavHfNu.js} +2 -2
- package/{dist/rcs-web/assets/pieDiagram-4H26LBE5-KIhqXGT6.js → packages/remote-control-server/web/dist/assets/pieDiagram-4H26LBE5-DSJaToTU.js} +2 -2
- package/{dist/rcs-web/assets/quadrantDiagram-W4KKPZXB-DISqmoA6.js → packages/remote-control-server/web/dist/assets/quadrantDiagram-W4KKPZXB-BFp6TnHj.js} +2 -2
- package/packages/remote-control-server/web/dist/assets/{requirementDiagram-4Y6WPE33-DsgT4ptk.js → requirementDiagram-4Y6WPE33-eil6F3-O.js} +2 -2
- package/{dist/rcs-web/assets/sankeyDiagram-5OEKKPKP-Dn67kbn0.js → packages/remote-control-server/web/dist/assets/sankeyDiagram-5OEKKPKP-DbGhoepK.js} +2 -2
- package/{dist/rcs-web/assets/sequenceDiagram-3UESZ5HK-CtWaXZHl.js → packages/remote-control-server/web/dist/assets/sequenceDiagram-3UESZ5HK-B0YrN1ud.js} +14 -14
- package/packages/remote-control-server/web/dist/assets/stateDiagram-AJRCARHV-CofFPj3N.js +1 -0
- package/packages/remote-control-server/web/dist/assets/stateDiagram-v2-BHNVJYJU-DPlcvPn1.js +1 -0
- package/{dist/rcs-web/assets/timeline-definition-PNZ67QCA-Dk5WUenC.js → packages/remote-control-server/web/dist/assets/timeline-definition-PNZ67QCA-Bx4dusy8.js} +2 -2
- package/packages/remote-control-server/web/dist/assets/useTeams-MDI4djXg.js +1 -0
- package/{dist/rcs-web/assets/vennDiagram-CIIHVFJN-TY8EiRrC.js → packages/remote-control-server/web/dist/assets/vennDiagram-CIIHVFJN-B_-3l-MF.js} +2 -2
- package/packages/remote-control-server/web/dist/assets/{wardleyDiagram-YWT4CUSO-BK3oi47X.js → wardleyDiagram-YWT4CUSO-DNSn-pGp.js} +2 -2
- package/packages/remote-control-server/web/dist/assets/workerType-OM09y7Lk.js +1 -0
- package/{dist/rcs-web/assets/xychartDiagram-2RQKCTM6-DhsxqX67.js → packages/remote-control-server/web/dist/assets/xychartDiagram-2RQKCTM6-TqUbNp0j.js} +2 -2
- package/packages/remote-control-server/web/dist/index.html +2 -3
- package/dist/rcs-web/assets/Dashboard-Cyj-Bb86.js +0 -2
- package/dist/rcs-web/assets/SessionDetail-SA9QBkyj.js +0 -51
- package/dist/rcs-web/assets/architectureDiagram-3BPJPVTR-CG9q9_bk.js +0 -36
- package/dist/rcs-web/assets/channel-CQFGglg-.js +0 -1
- package/dist/rcs-web/assets/classDiagram-4FO5ZUOK-C5rBdShD.js +0 -1
- package/dist/rcs-web/assets/classDiagram-v2-Q7XG4LA2-C5rBdShD.js +0 -1
- package/dist/rcs-web/assets/code-block-IT6T5CEO-BLGFrBw3.js +0 -2
- package/dist/rcs-web/assets/cose-bilkent-S5V4N54A-DBKEXjqM.js +0 -1
- package/dist/rcs-web/assets/dagre-BM42HDAG-DB_SWlAe.js +0 -4
- package/dist/rcs-web/assets/diagram-2AECGRRQ-Gbm8G3Xz.js +0 -43
- package/dist/rcs-web/assets/diagram-5GNKFQAL-BBuWqfDc.js +0 -10
- package/dist/rcs-web/assets/diagram-LMA3HP47-DyUwNrlg.js +0 -24
- package/dist/rcs-web/assets/diagram-OG6HWLK6-BXpvRwkJ.js +0 -24
- package/dist/rcs-web/assets/ganttDiagram-6RSMTGT7-ByDYviDl.js +0 -292
- package/dist/rcs-web/assets/gitGraphDiagram-PVQCEYII-BUnOPw74.js +0 -106
- package/dist/rcs-web/assets/infoDiagram-5YYISTIA-B1RpwJHG.js +0 -2
- package/dist/rcs-web/assets/main-0A4a3FDU.css +0 -1
- package/dist/rcs-web/assets/main-Dom16YJk.js +0 -283
- package/dist/rcs-web/assets/qr-C0jP9HcD.js +0 -8
- package/dist/rcs-web/assets/qr-scanner-worker.min-D85Z9gVD.js +0 -98
- package/dist/rcs-web/assets/stateDiagram-AJRCARHV-D6xp64f3.js +0 -1
- package/dist/rcs-web/assets/stateDiagram-v2-BHNVJYJU-D76vZCyQ.js +0 -1
- package/packages/remote-control-server/web/dist/assets/Dashboard-Cyj-Bb86.js +0 -2
- package/packages/remote-control-server/web/dist/assets/SessionDetail-SA9QBkyj.js +0 -51
- package/packages/remote-control-server/web/dist/assets/architectureDiagram-3BPJPVTR-CG9q9_bk.js +0 -36
- package/packages/remote-control-server/web/dist/assets/channel-CQFGglg-.js +0 -1
- package/packages/remote-control-server/web/dist/assets/classDiagram-4FO5ZUOK-C5rBdShD.js +0 -1
- package/packages/remote-control-server/web/dist/assets/classDiagram-v2-Q7XG4LA2-C5rBdShD.js +0 -1
- package/packages/remote-control-server/web/dist/assets/code-block-IT6T5CEO-BLGFrBw3.js +0 -2
- package/packages/remote-control-server/web/dist/assets/cose-bilkent-S5V4N54A-DBKEXjqM.js +0 -1
- package/packages/remote-control-server/web/dist/assets/dagre-BM42HDAG-DB_SWlAe.js +0 -4
- package/packages/remote-control-server/web/dist/assets/diagram-2AECGRRQ-Gbm8G3Xz.js +0 -43
- package/packages/remote-control-server/web/dist/assets/diagram-5GNKFQAL-BBuWqfDc.js +0 -10
- package/packages/remote-control-server/web/dist/assets/diagram-LMA3HP47-DyUwNrlg.js +0 -24
- package/packages/remote-control-server/web/dist/assets/diagram-OG6HWLK6-BXpvRwkJ.js +0 -24
- package/packages/remote-control-server/web/dist/assets/ganttDiagram-6RSMTGT7-ByDYviDl.js +0 -292
- package/packages/remote-control-server/web/dist/assets/gitGraphDiagram-PVQCEYII-BUnOPw74.js +0 -106
- package/packages/remote-control-server/web/dist/assets/infoDiagram-5YYISTIA-B1RpwJHG.js +0 -2
- package/packages/remote-control-server/web/dist/assets/main-0A4a3FDU.css +0 -1
- package/packages/remote-control-server/web/dist/assets/main-Dom16YJk.js +0 -283
- package/packages/remote-control-server/web/dist/assets/qr-C0jP9HcD.js +0 -8
- package/packages/remote-control-server/web/dist/assets/qr-scanner-worker.min-D85Z9gVD.js +0 -98
- package/packages/remote-control-server/web/dist/assets/stateDiagram-AJRCARHV-D6xp64f3.js +0 -1
- package/packages/remote-control-server/web/dist/assets/stateDiagram-v2-BHNVJYJU-D76vZCyQ.js +0 -1
|
@@ -1,24 +1,10 @@
|
|
|
1
1
|
import { describe, test, expect, beforeEach, afterAll, mock } from 'bun:test'
|
|
2
|
+
import { mockConfigModule } from './helpers/mock-config'
|
|
2
3
|
|
|
3
4
|
// Mock config before imports
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
apiKeys: ['test-api-key'],
|
|
8
|
-
baseUrl: 'http://localhost:3000',
|
|
9
|
-
pollTimeout: 8,
|
|
10
|
-
heartbeatInterval: 20,
|
|
11
|
-
jwtExpiresIn: 3600,
|
|
12
|
-
disconnectTimeout: 300,
|
|
13
|
-
webCorsOrigins: ['https://dashboard.example'],
|
|
14
|
-
wsIdleTimeout: 30,
|
|
15
|
-
wsKeepaliveInterval: 20,
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
mock.module('../config', () => ({
|
|
19
|
-
config: mockConfig,
|
|
20
|
-
getBaseUrl: () => 'http://localhost:3000',
|
|
21
|
-
}))
|
|
5
|
+
mock.module('../config', () =>
|
|
6
|
+
mockConfigModule({ webCorsOrigins: ['https://dashboard.example'] }),
|
|
7
|
+
)
|
|
22
8
|
|
|
23
9
|
import { Hono } from 'hono'
|
|
24
10
|
import { cors } from 'hono/cors'
|
|
@@ -27,10 +13,7 @@ import {
|
|
|
27
13
|
apiKeyAuth,
|
|
28
14
|
encodeWebSocketAuthProtocol,
|
|
29
15
|
extractWebSocketAuthToken,
|
|
30
|
-
requireWorkerToken,
|
|
31
16
|
sessionIngressAuth,
|
|
32
|
-
uuidAuth,
|
|
33
|
-
getUuidFromRequest,
|
|
34
17
|
} from '../auth/middleware'
|
|
35
18
|
import { issueToken } from '../auth/token'
|
|
36
19
|
import { generateWorkerJwt } from '../auth/jwt'
|
|
@@ -54,25 +37,10 @@ function createTestApp() {
|
|
|
54
37
|
return c.json({ ok: true, jwtPayload: c.get('jwtPayload') || null })
|
|
55
38
|
})
|
|
56
39
|
|
|
57
|
-
// Test route for uuidAuth
|
|
58
|
-
app.get('/uuid-test', uuidAuth, c => {
|
|
59
|
-
return c.json({ uuid: c.get('uuid') })
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
// Test route for getUuidFromRequest
|
|
63
|
-
app.get('/uuid-extract', c => {
|
|
64
|
-
return c.json({ uuid: getUuidFromRequest(c) })
|
|
65
|
-
})
|
|
66
|
-
|
|
67
40
|
app.get('/ws-auth-token', c => {
|
|
68
41
|
return c.json({ token: extractWebSocketAuthToken(c) ?? null })
|
|
69
42
|
})
|
|
70
43
|
|
|
71
|
-
// Test route for requireWorkerToken
|
|
72
|
-
app.get('/worker-token-test/:id', requireWorkerToken, c => {
|
|
73
|
-
return c.json({ ok: true })
|
|
74
|
-
})
|
|
75
|
-
|
|
76
44
|
return app
|
|
77
45
|
}
|
|
78
46
|
|
|
@@ -194,37 +162,6 @@ describe('Auth Middleware', () => {
|
|
|
194
162
|
})
|
|
195
163
|
})
|
|
196
164
|
|
|
197
|
-
describe('requireWorkerToken', () => {
|
|
198
|
-
const originalKeys = process.env.RCS_API_KEYS
|
|
199
|
-
beforeEach(() => {
|
|
200
|
-
process.env.RCS_API_KEYS = 'test-api-key'
|
|
201
|
-
})
|
|
202
|
-
afterAll(() => {
|
|
203
|
-
process.env.RCS_API_KEYS = originalKeys
|
|
204
|
-
})
|
|
205
|
-
|
|
206
|
-
test('admin API key via Authorization Bearer bypasses worker token', async () => {
|
|
207
|
-
const res = await app.request('/worker-token-test/ses_123', {
|
|
208
|
-
headers: { Authorization: 'Bearer test-api-key' },
|
|
209
|
-
})
|
|
210
|
-
expect(res.status).toBe(200)
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
test('admin API key via X-Worker-Token header bypasses worker token', async () => {
|
|
214
|
-
const res = await app.request('/worker-token-test/ses_123', {
|
|
215
|
-
headers: { 'X-Worker-Token': 'test-api-key' },
|
|
216
|
-
})
|
|
217
|
-
expect(res.status).toBe(200)
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
test('admin API key via worker_token query param bypasses worker token', async () => {
|
|
221
|
-
const res = await app.request(
|
|
222
|
-
'/worker-token-test/ses_123?worker_token=test-api-key',
|
|
223
|
-
)
|
|
224
|
-
expect(res.status).toBe(200)
|
|
225
|
-
})
|
|
226
|
-
})
|
|
227
|
-
|
|
228
165
|
describe('extractWebSocketAuthToken', () => {
|
|
229
166
|
test('does not read tokens from query params', async () => {
|
|
230
167
|
const res = await app.request('/ws-auth-token?token=test-api-key')
|
|
@@ -242,51 +179,6 @@ describe('Auth Middleware', () => {
|
|
|
242
179
|
expect(body.token).toBe('test-api-key')
|
|
243
180
|
})
|
|
244
181
|
})
|
|
245
|
-
|
|
246
|
-
describe('uuidAuth', () => {
|
|
247
|
-
test('accepts UUID from query param', async () => {
|
|
248
|
-
const res = await app.request('/uuid-test?uuid=test-uuid-1')
|
|
249
|
-
expect(res.status).toBe(200)
|
|
250
|
-
const body = await res.json()
|
|
251
|
-
expect(body.uuid).toBe('test-uuid-1')
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
test('accepts UUID from header', async () => {
|
|
255
|
-
const res = await app.request('/uuid-test', {
|
|
256
|
-
headers: { 'X-UUID': 'test-uuid-2' },
|
|
257
|
-
})
|
|
258
|
-
expect(res.status).toBe(200)
|
|
259
|
-
const body = await res.json()
|
|
260
|
-
expect(body.uuid).toBe('test-uuid-2')
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
test('rejects missing UUID', async () => {
|
|
264
|
-
const res = await app.request('/uuid-test')
|
|
265
|
-
expect(res.status).toBe(401)
|
|
266
|
-
})
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
describe('getUuidFromRequest', () => {
|
|
270
|
-
test('extracts from query param', async () => {
|
|
271
|
-
const res = await app.request('/uuid-extract?uuid=from-query')
|
|
272
|
-
const body = await res.json()
|
|
273
|
-
expect(body.uuid).toBe('from-query')
|
|
274
|
-
})
|
|
275
|
-
|
|
276
|
-
test('extracts from header', async () => {
|
|
277
|
-
const res = await app.request('/uuid-extract', {
|
|
278
|
-
headers: { 'X-UUID': 'from-header' },
|
|
279
|
-
})
|
|
280
|
-
const body = await res.json()
|
|
281
|
-
expect(body.uuid).toBe('from-header')
|
|
282
|
-
})
|
|
283
|
-
|
|
284
|
-
test('returns undefined when no UUID', async () => {
|
|
285
|
-
const res = await app.request('/uuid-extract')
|
|
286
|
-
const body = await res.json()
|
|
287
|
-
expect(body.uuid).toBeUndefined()
|
|
288
|
-
})
|
|
289
|
-
})
|
|
290
182
|
})
|
|
291
183
|
|
|
292
184
|
describe('Web CORS', () => {
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { describe, test, expect } from 'bun:test'
|
|
2
|
+
|
|
3
|
+
// Dynamic import — module may not exist yet (TDD)
|
|
4
|
+
let hashPassword: ((password: string) => string) | undefined
|
|
5
|
+
let verifyPassword: ((password: string, hash: string) => boolean) | undefined
|
|
6
|
+
|
|
7
|
+
try {
|
|
8
|
+
const mod = await import('../auth/password')
|
|
9
|
+
hashPassword = mod.hashPassword
|
|
10
|
+
verifyPassword = mod.verifyPassword
|
|
11
|
+
} catch {
|
|
12
|
+
// Module not implemented yet — tests will fail on assertions
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe('hashPassword', () => {
|
|
16
|
+
test('returns a string containing argon2id identifier', () => {
|
|
17
|
+
expect(hashPassword).toBeDefined()
|
|
18
|
+
const hash = hashPassword!('my-secure-password')
|
|
19
|
+
expect(typeof hash).toBe('string')
|
|
20
|
+
expect(hash).toContain('argon2id')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('same password hashed twice produces different results (different salt)', () => {
|
|
24
|
+
expect(hashPassword).toBeDefined()
|
|
25
|
+
const hash1 = hashPassword!('same-password')
|
|
26
|
+
const hash2 = hashPassword!('same-password')
|
|
27
|
+
expect(hash1).not.toBe(hash2)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('hash length is reasonable (between 50 and 200 chars)', () => {
|
|
31
|
+
expect(hashPassword).toBeDefined()
|
|
32
|
+
const hash = hashPassword!('test-password-123')
|
|
33
|
+
expect(hash.length).toBeGreaterThan(50)
|
|
34
|
+
expect(hash.length).toBeLessThan(200)
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
describe('verifyPassword', () => {
|
|
39
|
+
test('returns true for correct password', () => {
|
|
40
|
+
expect(hashPassword).toBeDefined()
|
|
41
|
+
expect(verifyPassword).toBeDefined()
|
|
42
|
+
const password = 'correct-horse-battery-staple'
|
|
43
|
+
const hash = hashPassword!(password)
|
|
44
|
+
expect(verifyPassword!(password, hash)).toBe(true)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test('returns false for wrong password', () => {
|
|
48
|
+
expect(hashPassword).toBeDefined()
|
|
49
|
+
expect(verifyPassword).toBeDefined()
|
|
50
|
+
const hash = hashPassword!('correct-password')
|
|
51
|
+
expect(verifyPassword!('wrong-password', hash)).toBe(false)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('returns false for empty token', () => {
|
|
55
|
+
expect(hashPassword).toBeDefined()
|
|
56
|
+
expect(verifyPassword).toBeDefined()
|
|
57
|
+
const hash = hashPassword!('some-password')
|
|
58
|
+
expect(verifyPassword!('', hash)).toBe(false)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
test('returns false for tampered hash', () => {
|
|
62
|
+
expect(hashPassword).toBeDefined()
|
|
63
|
+
expect(verifyPassword).toBeDefined()
|
|
64
|
+
const hash = hashPassword!('my-password')
|
|
65
|
+
// Tamper with the hash by changing a character in the encoded part
|
|
66
|
+
const parts = hash.split('$')
|
|
67
|
+
// Argon2id format: $argon2id$v=19$m=...,t=...,p=...$<salt>$<hash>
|
|
68
|
+
// Tamper with the last segment (the actual hash)
|
|
69
|
+
const lastPart = parts[parts.length - 1]
|
|
70
|
+
const tampered =
|
|
71
|
+
lastPart.length > 4
|
|
72
|
+
? parts.slice(0, -1).join('$') + '$' + 'XXXX' + lastPart.slice(4)
|
|
73
|
+
: hash + 'x'
|
|
74
|
+
expect(verifyPassword!('my-password', tampered)).toBe(false)
|
|
75
|
+
})
|
|
76
|
+
})
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { describe, test, expect, beforeEach, mock } from 'bun:test'
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
3
|
+
import { resolve } from 'node:path'
|
|
4
|
+
import { mockConfigModule } from './helpers/mock-config'
|
|
5
|
+
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Mock config before any other imports
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
mock.module('../config', () => mockConfigModule({ pollTimeout: 1 }))
|
|
10
|
+
|
|
11
|
+
import { Hono } from 'hono'
|
|
12
|
+
import { storeReset } from '../store'
|
|
13
|
+
import { issueToken } from '../auth/token'
|
|
14
|
+
import { hasAcpRelayAuth } from '../routes/acp'
|
|
15
|
+
import { sessionAuth } from '../auth/middleware'
|
|
16
|
+
|
|
17
|
+
// Source file paths for static analysis
|
|
18
|
+
const STORE_PATH = resolve(import.meta.dir, '../store.ts')
|
|
19
|
+
const ACP_INDEX_PATH = resolve(import.meta.dir, '../routes/acp/index.ts')
|
|
20
|
+
const MIDDLEWARE_PATH = resolve(import.meta.dir, '../auth/middleware.ts')
|
|
21
|
+
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Test app for sessionAuth behavior
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
function createTestApp() {
|
|
26
|
+
const app = new Hono()
|
|
27
|
+
|
|
28
|
+
app.get('/protected', async (c, next) => {
|
|
29
|
+
const result = await sessionAuth(c, next)
|
|
30
|
+
if (result) return result
|
|
31
|
+
return c.json({ userId: c.get('userId'), isAdmin: c.get('isAdmin') })
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
return app
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// 1. sessionOwners Map removed
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
describe('sessionOwners Map removed', () => {
|
|
41
|
+
const storeSource = readFileSync(STORE_PATH, 'utf8')
|
|
42
|
+
|
|
43
|
+
test('store.ts does not declare a sessionOwners Map variable', () => {
|
|
44
|
+
// Match `const sessionOwners = new Map` or similar declarations
|
|
45
|
+
const hasMapDecl = /(?:const|let|var)\s+sessionOwners\s*=\s*new\s+Map/.test(
|
|
46
|
+
storeSource,
|
|
47
|
+
)
|
|
48
|
+
expect(hasMapDecl).toBe(false)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test('storeBindSession uses SQLite instead of in-memory Map', () => {
|
|
52
|
+
// The function should reference db/sqlite or a SQL INSERT statement,
|
|
53
|
+
// NOT sessionOwners.set or sessionOwners.get
|
|
54
|
+
const bindFnMatch = storeSource.match(
|
|
55
|
+
/export\s+function\s+storeBindSession[\s\S]*?^}/m,
|
|
56
|
+
)
|
|
57
|
+
if (!bindFnMatch) {
|
|
58
|
+
// If function was removed entirely, that's also acceptable
|
|
59
|
+
expect(true).toBe(true)
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
const fnBody = bindFnMatch[0]
|
|
63
|
+
// Should NOT use sessionOwners Map
|
|
64
|
+
expect(/sessionOwners\.(set|get)/.test(fnBody)).toBe(false)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
test('storeListSessionsByOwnerUuid is removed or migrated to SQLite', () => {
|
|
68
|
+
// If the function still exists, it must NOT iterate over sessionOwners Map
|
|
69
|
+
const fnMatch = storeSource.match(
|
|
70
|
+
/export\s+function\s+storeListSessionsByOwnerUuid[\s\S]*?^}/m,
|
|
71
|
+
)
|
|
72
|
+
if (!fnMatch) {
|
|
73
|
+
// Function removed entirely — acceptable
|
|
74
|
+
expect(true).toBe(true)
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
const fnBody = fnMatch[0]
|
|
78
|
+
// Should NOT reference sessionOwners Map
|
|
79
|
+
expect(/sessionOwners\.(get|has|entries|forEach)/.test(fnBody)).toBe(false)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
test('storeIsSessionOwner uses SQLite instead of in-memory Map', () => {
|
|
83
|
+
const fnMatch = storeSource.match(
|
|
84
|
+
/export\s+function\s+storeIsSessionOwner[\s\S]*?^}/m,
|
|
85
|
+
)
|
|
86
|
+
if (!fnMatch) {
|
|
87
|
+
expect(true).toBe(true)
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
const fnBody = fnMatch[0]
|
|
91
|
+
expect(/sessionOwners\.(get|has)/.test(fnBody)).toBe(false)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
test('storeGetSessionOwners uses SQLite instead of in-memory Map', () => {
|
|
95
|
+
const fnMatch = storeSource.match(
|
|
96
|
+
/export\s+function\s+storeGetSessionOwners[\s\S]*?^}/m,
|
|
97
|
+
)
|
|
98
|
+
if (!fnMatch) {
|
|
99
|
+
expect(true).toBe(true)
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
const fnBody = fnMatch[0]
|
|
103
|
+
expect(/sessionOwners\.(get|has)/.test(fnBody)).toBe(false)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
test('storeReset does not reference sessionOwners.clear()', () => {
|
|
107
|
+
const resetMatch = storeSource.match(
|
|
108
|
+
/export\s+function\s+storeReset[\s\S]*?^}/m,
|
|
109
|
+
)
|
|
110
|
+
if (!resetMatch) {
|
|
111
|
+
expect(true).toBe(true)
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
expect(/sessionOwners\.clear\(\)/.test(resetMatch[0])).toBe(false)
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// 2. ACP relay WS UUID bypass removed
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
describe('ACP relay WS UUID bypass removed', () => {
|
|
122
|
+
const acpSource = readFileSync(ACP_INDEX_PATH, 'utf8')
|
|
123
|
+
|
|
124
|
+
test('hasAcpRelayAuth does not accept any non-empty token as UUID', () => {
|
|
125
|
+
// The current implementation has a comment "Treat any other non-empty token
|
|
126
|
+
// as a web UI UUID" and returns true unconditionally after validateApiKey.
|
|
127
|
+
// After cleanup, it should NOT have this pattern.
|
|
128
|
+
const fnMatch = acpSource.match(
|
|
129
|
+
/export\s+function\s+hasAcpRelayAuth[\s\S]*?^}/m,
|
|
130
|
+
)
|
|
131
|
+
expect(fnMatch).not.toBeNull()
|
|
132
|
+
const fnBody = fnMatch![0]
|
|
133
|
+
|
|
134
|
+
// Should NOT contain the UUID bypass comment or unconditional return true
|
|
135
|
+
const hasUuidBypass =
|
|
136
|
+
/Treat any other non-empty token as a.*UUID/i.test(fnBody) ||
|
|
137
|
+
/web UI UUID/i.test(fnBody)
|
|
138
|
+
expect(hasUuidBypass).toBe(false)
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
test('hasAcpRelayAuth rejects when no token is provided', () => {
|
|
142
|
+
// Create a mock context with no auth
|
|
143
|
+
const c = {
|
|
144
|
+
req: {
|
|
145
|
+
header: (name: string) => undefined,
|
|
146
|
+
},
|
|
147
|
+
} as any
|
|
148
|
+
|
|
149
|
+
const result = hasAcpRelayAuth(c)
|
|
150
|
+
expect(result).toBe(false)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
test('hasAcpRelayAuth accepts valid admin API key', () => {
|
|
154
|
+
const c = {
|
|
155
|
+
req: {
|
|
156
|
+
header: (name: string) => {
|
|
157
|
+
if (name === 'Authorization') return 'Bearer test-api-key'
|
|
158
|
+
return undefined
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
} as any
|
|
162
|
+
|
|
163
|
+
const result = hasAcpRelayAuth(c)
|
|
164
|
+
expect(result).toBe(true)
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
test('hasAcpRelayAuth rejects invalid non-empty token that is not an API key or session token', () => {
|
|
168
|
+
// After cleanup, an arbitrary string like a UUID should NOT be accepted
|
|
169
|
+
const c = {
|
|
170
|
+
req: {
|
|
171
|
+
header: (name: string) => {
|
|
172
|
+
if (name === 'Authorization')
|
|
173
|
+
return 'Bearer some-random-uuid-not-an-api-key'
|
|
174
|
+
return undefined
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
} as any
|
|
178
|
+
|
|
179
|
+
// This test verifies the function no longer blindly accepts non-empty tokens.
|
|
180
|
+
// After cleanup: only admin API key or valid session token should pass.
|
|
181
|
+
const result = hasAcpRelayAuth(c)
|
|
182
|
+
expect(result).toBe(false)
|
|
183
|
+
})
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
// 3. uuidAuth middleware removed / sessionAuth UUID fallback removed
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
189
|
+
describe('uuidAuth middleware removed', () => {
|
|
190
|
+
const middlewareSource = readFileSync(MIDDLEWARE_PATH, 'utf8')
|
|
191
|
+
|
|
192
|
+
test('uuidAuth function does not exist in middleware.ts', () => {
|
|
193
|
+
const hasUuidAuthExport = /export\s+(?:async\s+)?function\s+uuidAuth/.test(
|
|
194
|
+
middlewareSource,
|
|
195
|
+
)
|
|
196
|
+
expect(hasUuidAuthExport).toBe(false)
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
test('sessionAuth does not have UUID fallback', () => {
|
|
200
|
+
const sessionAuthMatch = middlewareSource.match(
|
|
201
|
+
/export\s+async\s+function\s+sessionAuth[\s\S]*?^}/m,
|
|
202
|
+
)
|
|
203
|
+
if (!sessionAuthMatch) {
|
|
204
|
+
// If sessionAuth doesn't exist, something is very wrong
|
|
205
|
+
expect(true).toBe(false)
|
|
206
|
+
return
|
|
207
|
+
}
|
|
208
|
+
const fnBody = sessionAuthMatch[0]
|
|
209
|
+
|
|
210
|
+
// Should NOT contain UUID backward compatibility code
|
|
211
|
+
const hasUuidFallback =
|
|
212
|
+
/Phase 1 backward compatibility.*UUID/i.test(fnBody) ||
|
|
213
|
+
/getUuidFromRequest/.test(fnBody)
|
|
214
|
+
expect(hasUuidFallback).toBe(false)
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
test('getUuidFromRequest function does not exist in middleware.ts', () => {
|
|
218
|
+
const hasGetUuid =
|
|
219
|
+
/export\s+(?:async\s+)?function\s+getUuidFromRequest/.test(
|
|
220
|
+
middlewareSource,
|
|
221
|
+
)
|
|
222
|
+
expect(hasGetUuid).toBe(false)
|
|
223
|
+
})
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
// ---------------------------------------------------------------------------
|
|
227
|
+
// 3b. sessionAuth behavioral tests (anonymous / UUID → 401)
|
|
228
|
+
// ---------------------------------------------------------------------------
|
|
229
|
+
describe('sessionAuth blocks anonymous and UUID-only access', () => {
|
|
230
|
+
let app: Hono
|
|
231
|
+
|
|
232
|
+
beforeEach(() => {
|
|
233
|
+
storeReset()
|
|
234
|
+
app = createTestApp()
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
test('anonymous request (no cookie, no Bearer, no UUID) returns 401', async () => {
|
|
238
|
+
const res = await app.request('/protected')
|
|
239
|
+
expect(res.status).toBe(401)
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
test('request with ?uuid=xxx but no token returns 401', async () => {
|
|
243
|
+
const res = await app.request('/protected?uuid=some-uuid-value')
|
|
244
|
+
expect(res.status).toBe(401)
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
test('request with X-UUID header but no token returns 401', async () => {
|
|
248
|
+
const res = await app.request('/protected', {
|
|
249
|
+
headers: { 'X-UUID': 'some-uuid-value' },
|
|
250
|
+
})
|
|
251
|
+
expect(res.status).toBe(401)
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
test('valid admin API key Bearer returns 200', async () => {
|
|
255
|
+
const res = await app.request('/protected', {
|
|
256
|
+
headers: { Authorization: 'Bearer test-api-key' },
|
|
257
|
+
})
|
|
258
|
+
expect(res.status).toBe(200)
|
|
259
|
+
const body = await res.json()
|
|
260
|
+
expect(body.userId).toBe('__system__')
|
|
261
|
+
expect(body.isAdmin).toBe(true)
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
test('valid session token via Bearer returns 200', async () => {
|
|
265
|
+
const { token } = issueToken('testuser')
|
|
266
|
+
const res = await app.request('/protected', {
|
|
267
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
268
|
+
})
|
|
269
|
+
expect(res.status).toBe(200)
|
|
270
|
+
const body = await res.json()
|
|
271
|
+
expect(body.userId).toBe('testuser')
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
test('valid session token via cookie returns 200', async () => {
|
|
275
|
+
const { token } = issueToken('cookieuser')
|
|
276
|
+
const res = await app.request('/protected', {
|
|
277
|
+
headers: { Cookie: `rcs_access=${token}` },
|
|
278
|
+
})
|
|
279
|
+
expect(res.status).toBe(200)
|
|
280
|
+
const body = await res.json()
|
|
281
|
+
expect(body.userId).toBe('cookieuser')
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
test('invalid Bearer token returns 401', async () => {
|
|
285
|
+
const res = await app.request('/protected', {
|
|
286
|
+
headers: { Authorization: 'Bearer invalid-token-xyz' },
|
|
287
|
+
})
|
|
288
|
+
expect(res.status).toBe(401)
|
|
289
|
+
})
|
|
290
|
+
})
|