@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.
Files changed (219) hide show
  1. package/dist/cli.js +336 -333
  2. package/dist/rcs-web/assets/Dashboard-BwotBWlJ.js +1 -0
  3. package/dist/rcs-web/assets/Join-4yrksbdX.js +1 -0
  4. package/dist/rcs-web/assets/Login-Cxm_yEeE.js +1 -0
  5. package/dist/rcs-web/assets/SessionDetail-DNdfPOYy.js +50 -0
  6. package/dist/rcs-web/assets/Setup-BiAAxugt.js +1 -0
  7. package/dist/rcs-web/assets/ShareLanding-CP3Z6ckr.js +1 -0
  8. package/dist/rcs-web/assets/TeamCreate-DgdCwRSb.js +1 -0
  9. package/dist/rcs-web/assets/TeamDetail-CkNTFoMB.js +11 -0
  10. package/dist/rcs-web/assets/TeamList-Bf0sQ5RQ.js +1 -0
  11. package/dist/rcs-web/assets/TeamSettings-BaNAfXU3.js +1 -0
  12. package/dist/rcs-web/assets/UserSettings-CsutQjxG.js +1 -0
  13. package/{packages/remote-control-server/web/dist/assets/arc-D90597o-.js → dist/rcs-web/assets/arc-BxxmNQO6.js} +1 -1
  14. package/dist/rcs-web/assets/architectureDiagram-3BPJPVTR-DBjkRdbd.js +36 -0
  15. package/dist/rcs-web/assets/{blockDiagram-GPEHLZMM-DHd8IbOs.js → blockDiagram-GPEHLZMM-BF6COWlM.js} +2 -2
  16. package/dist/rcs-web/assets/{c4Diagram-AAUBKEIU-CjFkQJ9h.js → c4Diagram-AAUBKEIU-DHOf390v.js} +2 -2
  17. package/dist/rcs-web/assets/channel-JsvbMQjW.js +1 -0
  18. package/dist/rcs-web/assets/{chunk-2J33WTMH-C21XWnGZ.js → chunk-2J33WTMH-CeJN8yjM.js} +1 -1
  19. package/dist/rcs-web/assets/{chunk-4BX2VUAB-B3SXiJlt.js → chunk-4BX2VUAB-jP76_P2A.js} +1 -1
  20. package/dist/rcs-web/assets/{chunk-55IACEB6-DjImv45F.js → chunk-55IACEB6-BsFA6emB.js} +1 -1
  21. package/{packages/remote-control-server/web/dist/assets/chunk-727SXJPM-DtnaqsyD.js → dist/rcs-web/assets/chunk-727SXJPM-BF4HrQjZ.js} +1 -1
  22. package/dist/rcs-web/assets/{chunk-AQP2D5EJ-BVFgH5mS.js → chunk-AQP2D5EJ-DToJ74Kc.js} +1 -1
  23. package/dist/rcs-web/assets/{chunk-FMBD7UC4-Bl8jgb57.js → chunk-FMBD7UC4-DVTARgsa.js} +1 -1
  24. package/dist/rcs-web/assets/{chunk-ND2GUHAM-BpK111zh.js → chunk-ND2GUHAM-C50Gqv9c.js} +1 -1
  25. package/dist/rcs-web/assets/{chunk-QZHKN3VN-ruhIHBim.js → chunk-QZHKN3VN-EsIIh6zV.js} +1 -1
  26. package/dist/rcs-web/assets/classDiagram-4FO5ZUOK-BXn8Uc4c.js +1 -0
  27. package/dist/rcs-web/assets/classDiagram-v2-Q7XG4LA2-BXn8Uc4c.js +1 -0
  28. package/dist/rcs-web/assets/code-block-IT6T5CEO-BnufHNTT.js +2 -0
  29. package/dist/rcs-web/assets/cose-bilkent-S5V4N54A-M6tNt14I.js +1 -0
  30. package/dist/rcs-web/assets/dagre-BM42HDAG-DaTm29qG.js +4 -0
  31. package/dist/rcs-web/assets/diagram-2AECGRRQ-fqoeOvq2.js +43 -0
  32. package/dist/rcs-web/assets/diagram-5GNKFQAL-6s2CiaGG.js +10 -0
  33. package/dist/rcs-web/assets/{diagram-KO2AKTUF-Uy3PDP5S.js → diagram-KO2AKTUF-C0aw_N95.js} +2 -2
  34. package/dist/rcs-web/assets/diagram-LMA3HP47-C8_Rv3rB.js +24 -0
  35. package/dist/rcs-web/assets/diagram-OG6HWLK6-Dae4u8Uc.js +24 -0
  36. package/{packages/remote-control-server/web/dist/assets/erDiagram-TEJ5UH35-sre_MTeK.js → dist/rcs-web/assets/erDiagram-TEJ5UH35-CosS5VWr.js} +13 -13
  37. package/dist/rcs-web/assets/{flowDiagram-I6XJVG4X-DwrWaLoe.js → flowDiagram-I6XJVG4X-D_Mxs46-.js} +2 -2
  38. package/dist/rcs-web/assets/ganttDiagram-6RSMTGT7-B0jy8Am_.js +292 -0
  39. package/dist/rcs-web/assets/gitGraphDiagram-PVQCEYII-CSdu2HVI.js +106 -0
  40. package/dist/rcs-web/assets/i18n-Dbt-vEQ3.js +1 -0
  41. package/dist/rcs-web/assets/infoDiagram-5YYISTIA-Dcbc9L1S.js +2 -0
  42. package/{packages/remote-control-server/web/dist/assets/ishikawaDiagram-YF4QCWOH-SO0nn3--.js → dist/rcs-web/assets/ishikawaDiagram-YF4QCWOH-BLMjFE4t.js} +2 -2
  43. package/dist/rcs-web/assets/{journeyDiagram-JHISSGLW-D4igFUd4.js → journeyDiagram-JHISSGLW-Dw4nh1xI.js} +2 -2
  44. package/dist/rcs-web/assets/{kanban-definition-UN3LZRKU-Cm_yKsZC.js → kanban-definition-UN3LZRKU-DkU3j_ly.js} +2 -2
  45. package/dist/rcs-web/assets/{linear-4IMGll_E.js → linear-N5Cify7M.js} +1 -1
  46. package/dist/rcs-web/assets/main-30YqUvTd.js +238 -0
  47. package/dist/rcs-web/assets/main-EP6Lac2m.css +1 -0
  48. package/{packages/remote-control-server/web/dist/assets/mermaid-VLURNSYL-D_yQ7nAd.js → dist/rcs-web/assets/mermaid-VLURNSYL-gfiJUpl_.js} +5 -5
  49. package/dist/rcs-web/assets/{mermaid.core-B1qOUdiU.js → mermaid.core-B_Xc65Bf.js} +5 -5
  50. package/dist/rcs-web/assets/{mindmap-definition-RKZ34NQL-yETom5qt.js → mindmap-definition-RKZ34NQL-DUavHfNu.js} +2 -2
  51. package/{packages/remote-control-server/web/dist/assets/pieDiagram-4H26LBE5-KIhqXGT6.js → dist/rcs-web/assets/pieDiagram-4H26LBE5-DSJaToTU.js} +2 -2
  52. package/{packages/remote-control-server/web/dist/assets/quadrantDiagram-W4KKPZXB-DISqmoA6.js → dist/rcs-web/assets/quadrantDiagram-W4KKPZXB-BFp6TnHj.js} +2 -2
  53. package/dist/rcs-web/assets/{requirementDiagram-4Y6WPE33-DsgT4ptk.js → requirementDiagram-4Y6WPE33-eil6F3-O.js} +2 -2
  54. package/{packages/remote-control-server/web/dist/assets/sankeyDiagram-5OEKKPKP-Dn67kbn0.js → dist/rcs-web/assets/sankeyDiagram-5OEKKPKP-DbGhoepK.js} +2 -2
  55. package/{packages/remote-control-server/web/dist/assets/sequenceDiagram-3UESZ5HK-CtWaXZHl.js → dist/rcs-web/assets/sequenceDiagram-3UESZ5HK-B0YrN1ud.js} +14 -14
  56. package/dist/rcs-web/assets/stateDiagram-AJRCARHV-CofFPj3N.js +1 -0
  57. package/dist/rcs-web/assets/stateDiagram-v2-BHNVJYJU-DPlcvPn1.js +1 -0
  58. package/{packages/remote-control-server/web/dist/assets/timeline-definition-PNZ67QCA-Dk5WUenC.js → dist/rcs-web/assets/timeline-definition-PNZ67QCA-Bx4dusy8.js} +2 -2
  59. package/dist/rcs-web/assets/useTeams-MDI4djXg.js +1 -0
  60. package/{packages/remote-control-server/web/dist/assets/vennDiagram-CIIHVFJN-TY8EiRrC.js → dist/rcs-web/assets/vennDiagram-CIIHVFJN-B_-3l-MF.js} +2 -2
  61. package/dist/rcs-web/assets/{wardleyDiagram-YWT4CUSO-BK3oi47X.js → wardleyDiagram-YWT4CUSO-DNSn-pGp.js} +2 -2
  62. package/dist/rcs-web/assets/workerType-OM09y7Lk.js +1 -0
  63. package/{packages/remote-control-server/web/dist/assets/xychartDiagram-2RQKCTM6-DhsxqX67.js → dist/rcs-web/assets/xychartDiagram-2RQKCTM6-TqUbNp0j.js} +2 -2
  64. package/dist/rcs-web/index.html +2 -3
  65. package/package.json +2 -1
  66. package/packages/remote-control-server/src/__tests__/acp-ws-handler.test.ts +7 -19
  67. package/packages/remote-control-server/src/__tests__/auth-login.test.ts +561 -0
  68. package/packages/remote-control-server/src/__tests__/auth-security.test.ts +547 -0
  69. package/packages/remote-control-server/src/__tests__/auth.test.ts +7 -18
  70. package/packages/remote-control-server/src/__tests__/bind-replacement.test.ts +251 -0
  71. package/packages/remote-control-server/src/__tests__/cookie.test.ts +155 -0
  72. package/packages/remote-control-server/src/__tests__/data-layer-fixes.test.ts +147 -0
  73. package/packages/remote-control-server/src/__tests__/db.test.ts +582 -0
  74. package/packages/remote-control-server/src/__tests__/design-gaps.test.ts +440 -0
  75. package/packages/remote-control-server/src/__tests__/disconnect-monitor.test.ts +2 -18
  76. package/packages/remote-control-server/src/__tests__/helpers/db.ts +43 -0
  77. package/packages/remote-control-server/src/__tests__/helpers/fixtures.ts +94 -0
  78. package/packages/remote-control-server/src/__tests__/helpers/mock-config.ts +31 -0
  79. package/packages/remote-control-server/src/__tests__/middleware.test.ts +4 -112
  80. package/packages/remote-control-server/src/__tests__/password.test.ts +76 -0
  81. package/packages/remote-control-server/src/__tests__/phase4-cleanup.test.ts +290 -0
  82. package/packages/remote-control-server/src/__tests__/phase4-integration.test.ts +224 -0
  83. package/packages/remote-control-server/src/__tests__/routes.test.ts +292 -207
  84. package/packages/remote-control-server/src/__tests__/services.test.ts +2 -18
  85. package/packages/remote-control-server/src/__tests__/session-visibility.test.ts +452 -0
  86. package/packages/remote-control-server/src/__tests__/session.test.ts +216 -0
  87. package/packages/remote-control-server/src/__tests__/shares.test.ts +1419 -0
  88. package/packages/remote-control-server/src/__tests__/sse-writer.test.ts +2 -18
  89. package/packages/remote-control-server/src/__tests__/teams.test.ts +2089 -0
  90. package/packages/remote-control-server/src/__tests__/work-dispatch.test.ts +2 -18
  91. package/packages/remote-control-server/src/__tests__/worker-token-removal.test.ts +487 -0
  92. package/packages/remote-control-server/src/__tests__/ws-handler.test.ts +2 -18
  93. package/packages/remote-control-server/src/auth/constants.ts +13 -0
  94. package/packages/remote-control-server/src/auth/cookie.ts +75 -0
  95. package/packages/remote-control-server/src/auth/middleware.ts +75 -165
  96. package/packages/remote-control-server/src/auth/password.ts +116 -0
  97. package/packages/remote-control-server/src/auth/session.ts +130 -0
  98. package/packages/remote-control-server/src/db/schema.sql +116 -0
  99. package/packages/remote-control-server/src/db/sqlite.ts +99 -0
  100. package/packages/remote-control-server/src/routes/acp/index.ts +6 -11
  101. package/packages/remote-control-server/src/routes/v1/environments.ts +111 -8
  102. package/packages/remote-control-server/src/routes/web/auth-routes.ts +634 -0
  103. package/packages/remote-control-server/src/routes/web/control.ts +5 -5
  104. package/packages/remote-control-server/src/routes/web/environments.ts +5 -27
  105. package/packages/remote-control-server/src/routes/web/sessions.ts +19 -41
  106. package/packages/remote-control-server/src/routes/web/shares.ts +371 -0
  107. package/packages/remote-control-server/src/routes/web/teams.ts +850 -0
  108. package/packages/remote-control-server/src/services/environment.ts +1 -4
  109. package/packages/remote-control-server/src/services/session-visibility.ts +79 -0
  110. package/packages/remote-control-server/src/services/session.ts +0 -13
  111. package/packages/remote-control-server/src/store.ts +150 -56
  112. package/packages/remote-control-server/src/types/api.ts +2 -8
  113. package/packages/remote-control-server/web/dist/assets/Dashboard-BwotBWlJ.js +1 -0
  114. package/packages/remote-control-server/web/dist/assets/Join-4yrksbdX.js +1 -0
  115. package/packages/remote-control-server/web/dist/assets/Login-Cxm_yEeE.js +1 -0
  116. package/packages/remote-control-server/web/dist/assets/SessionDetail-DNdfPOYy.js +50 -0
  117. package/packages/remote-control-server/web/dist/assets/Setup-BiAAxugt.js +1 -0
  118. package/packages/remote-control-server/web/dist/assets/ShareLanding-CP3Z6ckr.js +1 -0
  119. package/packages/remote-control-server/web/dist/assets/TeamCreate-DgdCwRSb.js +1 -0
  120. package/packages/remote-control-server/web/dist/assets/TeamDetail-CkNTFoMB.js +11 -0
  121. package/packages/remote-control-server/web/dist/assets/TeamList-Bf0sQ5RQ.js +1 -0
  122. package/packages/remote-control-server/web/dist/assets/TeamSettings-BaNAfXU3.js +1 -0
  123. package/packages/remote-control-server/web/dist/assets/UserSettings-CsutQjxG.js +1 -0
  124. package/{dist/rcs-web/assets/arc-D90597o-.js → packages/remote-control-server/web/dist/assets/arc-BxxmNQO6.js} +1 -1
  125. package/packages/remote-control-server/web/dist/assets/architectureDiagram-3BPJPVTR-DBjkRdbd.js +36 -0
  126. package/packages/remote-control-server/web/dist/assets/{blockDiagram-GPEHLZMM-DHd8IbOs.js → blockDiagram-GPEHLZMM-BF6COWlM.js} +2 -2
  127. package/packages/remote-control-server/web/dist/assets/{c4Diagram-AAUBKEIU-CjFkQJ9h.js → c4Diagram-AAUBKEIU-DHOf390v.js} +2 -2
  128. package/packages/remote-control-server/web/dist/assets/channel-JsvbMQjW.js +1 -0
  129. package/packages/remote-control-server/web/dist/assets/{chunk-2J33WTMH-C21XWnGZ.js → chunk-2J33WTMH-CeJN8yjM.js} +1 -1
  130. package/packages/remote-control-server/web/dist/assets/{chunk-4BX2VUAB-B3SXiJlt.js → chunk-4BX2VUAB-jP76_P2A.js} +1 -1
  131. package/packages/remote-control-server/web/dist/assets/{chunk-55IACEB6-DjImv45F.js → chunk-55IACEB6-BsFA6emB.js} +1 -1
  132. package/{dist/rcs-web/assets/chunk-727SXJPM-DtnaqsyD.js → packages/remote-control-server/web/dist/assets/chunk-727SXJPM-BF4HrQjZ.js} +1 -1
  133. package/packages/remote-control-server/web/dist/assets/{chunk-AQP2D5EJ-BVFgH5mS.js → chunk-AQP2D5EJ-DToJ74Kc.js} +1 -1
  134. package/packages/remote-control-server/web/dist/assets/{chunk-FMBD7UC4-Bl8jgb57.js → chunk-FMBD7UC4-DVTARgsa.js} +1 -1
  135. package/packages/remote-control-server/web/dist/assets/{chunk-ND2GUHAM-BpK111zh.js → chunk-ND2GUHAM-C50Gqv9c.js} +1 -1
  136. package/packages/remote-control-server/web/dist/assets/{chunk-QZHKN3VN-ruhIHBim.js → chunk-QZHKN3VN-EsIIh6zV.js} +1 -1
  137. package/packages/remote-control-server/web/dist/assets/classDiagram-4FO5ZUOK-BXn8Uc4c.js +1 -0
  138. package/packages/remote-control-server/web/dist/assets/classDiagram-v2-Q7XG4LA2-BXn8Uc4c.js +1 -0
  139. package/packages/remote-control-server/web/dist/assets/code-block-IT6T5CEO-BnufHNTT.js +2 -0
  140. package/packages/remote-control-server/web/dist/assets/cose-bilkent-S5V4N54A-M6tNt14I.js +1 -0
  141. package/packages/remote-control-server/web/dist/assets/dagre-BM42HDAG-DaTm29qG.js +4 -0
  142. package/packages/remote-control-server/web/dist/assets/diagram-2AECGRRQ-fqoeOvq2.js +43 -0
  143. package/packages/remote-control-server/web/dist/assets/diagram-5GNKFQAL-6s2CiaGG.js +10 -0
  144. package/packages/remote-control-server/web/dist/assets/{diagram-KO2AKTUF-Uy3PDP5S.js → diagram-KO2AKTUF-C0aw_N95.js} +2 -2
  145. package/packages/remote-control-server/web/dist/assets/diagram-LMA3HP47-C8_Rv3rB.js +24 -0
  146. package/packages/remote-control-server/web/dist/assets/diagram-OG6HWLK6-Dae4u8Uc.js +24 -0
  147. package/{dist/rcs-web/assets/erDiagram-TEJ5UH35-sre_MTeK.js → packages/remote-control-server/web/dist/assets/erDiagram-TEJ5UH35-CosS5VWr.js} +13 -13
  148. package/packages/remote-control-server/web/dist/assets/{flowDiagram-I6XJVG4X-DwrWaLoe.js → flowDiagram-I6XJVG4X-D_Mxs46-.js} +2 -2
  149. package/packages/remote-control-server/web/dist/assets/ganttDiagram-6RSMTGT7-B0jy8Am_.js +292 -0
  150. package/packages/remote-control-server/web/dist/assets/gitGraphDiagram-PVQCEYII-CSdu2HVI.js +106 -0
  151. package/packages/remote-control-server/web/dist/assets/i18n-Dbt-vEQ3.js +1 -0
  152. package/packages/remote-control-server/web/dist/assets/infoDiagram-5YYISTIA-Dcbc9L1S.js +2 -0
  153. package/{dist/rcs-web/assets/ishikawaDiagram-YF4QCWOH-SO0nn3--.js → packages/remote-control-server/web/dist/assets/ishikawaDiagram-YF4QCWOH-BLMjFE4t.js} +2 -2
  154. package/packages/remote-control-server/web/dist/assets/{journeyDiagram-JHISSGLW-D4igFUd4.js → journeyDiagram-JHISSGLW-Dw4nh1xI.js} +2 -2
  155. package/packages/remote-control-server/web/dist/assets/{kanban-definition-UN3LZRKU-Cm_yKsZC.js → kanban-definition-UN3LZRKU-DkU3j_ly.js} +2 -2
  156. package/packages/remote-control-server/web/dist/assets/{linear-4IMGll_E.js → linear-N5Cify7M.js} +1 -1
  157. package/packages/remote-control-server/web/dist/assets/main-30YqUvTd.js +238 -0
  158. package/packages/remote-control-server/web/dist/assets/main-EP6Lac2m.css +1 -0
  159. package/{dist/rcs-web/assets/mermaid-VLURNSYL-D_yQ7nAd.js → packages/remote-control-server/web/dist/assets/mermaid-VLURNSYL-gfiJUpl_.js} +5 -5
  160. package/packages/remote-control-server/web/dist/assets/{mermaid.core-B1qOUdiU.js → mermaid.core-B_Xc65Bf.js} +5 -5
  161. package/packages/remote-control-server/web/dist/assets/{mindmap-definition-RKZ34NQL-yETom5qt.js → mindmap-definition-RKZ34NQL-DUavHfNu.js} +2 -2
  162. package/{dist/rcs-web/assets/pieDiagram-4H26LBE5-KIhqXGT6.js → packages/remote-control-server/web/dist/assets/pieDiagram-4H26LBE5-DSJaToTU.js} +2 -2
  163. package/{dist/rcs-web/assets/quadrantDiagram-W4KKPZXB-DISqmoA6.js → packages/remote-control-server/web/dist/assets/quadrantDiagram-W4KKPZXB-BFp6TnHj.js} +2 -2
  164. package/packages/remote-control-server/web/dist/assets/{requirementDiagram-4Y6WPE33-DsgT4ptk.js → requirementDiagram-4Y6WPE33-eil6F3-O.js} +2 -2
  165. package/{dist/rcs-web/assets/sankeyDiagram-5OEKKPKP-Dn67kbn0.js → packages/remote-control-server/web/dist/assets/sankeyDiagram-5OEKKPKP-DbGhoepK.js} +2 -2
  166. package/{dist/rcs-web/assets/sequenceDiagram-3UESZ5HK-CtWaXZHl.js → packages/remote-control-server/web/dist/assets/sequenceDiagram-3UESZ5HK-B0YrN1ud.js} +14 -14
  167. package/packages/remote-control-server/web/dist/assets/stateDiagram-AJRCARHV-CofFPj3N.js +1 -0
  168. package/packages/remote-control-server/web/dist/assets/stateDiagram-v2-BHNVJYJU-DPlcvPn1.js +1 -0
  169. package/{dist/rcs-web/assets/timeline-definition-PNZ67QCA-Dk5WUenC.js → packages/remote-control-server/web/dist/assets/timeline-definition-PNZ67QCA-Bx4dusy8.js} +2 -2
  170. package/packages/remote-control-server/web/dist/assets/useTeams-MDI4djXg.js +1 -0
  171. package/{dist/rcs-web/assets/vennDiagram-CIIHVFJN-TY8EiRrC.js → packages/remote-control-server/web/dist/assets/vennDiagram-CIIHVFJN-B_-3l-MF.js} +2 -2
  172. package/packages/remote-control-server/web/dist/assets/{wardleyDiagram-YWT4CUSO-BK3oi47X.js → wardleyDiagram-YWT4CUSO-DNSn-pGp.js} +2 -2
  173. package/packages/remote-control-server/web/dist/assets/workerType-OM09y7Lk.js +1 -0
  174. package/{dist/rcs-web/assets/xychartDiagram-2RQKCTM6-DhsxqX67.js → packages/remote-control-server/web/dist/assets/xychartDiagram-2RQKCTM6-TqUbNp0j.js} +2 -2
  175. package/packages/remote-control-server/web/dist/index.html +2 -3
  176. package/dist/rcs-web/assets/Dashboard-Cyj-Bb86.js +0 -2
  177. package/dist/rcs-web/assets/SessionDetail-SA9QBkyj.js +0 -51
  178. package/dist/rcs-web/assets/architectureDiagram-3BPJPVTR-CG9q9_bk.js +0 -36
  179. package/dist/rcs-web/assets/channel-CQFGglg-.js +0 -1
  180. package/dist/rcs-web/assets/classDiagram-4FO5ZUOK-C5rBdShD.js +0 -1
  181. package/dist/rcs-web/assets/classDiagram-v2-Q7XG4LA2-C5rBdShD.js +0 -1
  182. package/dist/rcs-web/assets/code-block-IT6T5CEO-BLGFrBw3.js +0 -2
  183. package/dist/rcs-web/assets/cose-bilkent-S5V4N54A-DBKEXjqM.js +0 -1
  184. package/dist/rcs-web/assets/dagre-BM42HDAG-DB_SWlAe.js +0 -4
  185. package/dist/rcs-web/assets/diagram-2AECGRRQ-Gbm8G3Xz.js +0 -43
  186. package/dist/rcs-web/assets/diagram-5GNKFQAL-BBuWqfDc.js +0 -10
  187. package/dist/rcs-web/assets/diagram-LMA3HP47-DyUwNrlg.js +0 -24
  188. package/dist/rcs-web/assets/diagram-OG6HWLK6-BXpvRwkJ.js +0 -24
  189. package/dist/rcs-web/assets/ganttDiagram-6RSMTGT7-ByDYviDl.js +0 -292
  190. package/dist/rcs-web/assets/gitGraphDiagram-PVQCEYII-BUnOPw74.js +0 -106
  191. package/dist/rcs-web/assets/infoDiagram-5YYISTIA-B1RpwJHG.js +0 -2
  192. package/dist/rcs-web/assets/main-0A4a3FDU.css +0 -1
  193. package/dist/rcs-web/assets/main-Dom16YJk.js +0 -283
  194. package/dist/rcs-web/assets/qr-C0jP9HcD.js +0 -8
  195. package/dist/rcs-web/assets/qr-scanner-worker.min-D85Z9gVD.js +0 -98
  196. package/dist/rcs-web/assets/stateDiagram-AJRCARHV-D6xp64f3.js +0 -1
  197. package/dist/rcs-web/assets/stateDiagram-v2-BHNVJYJU-D76vZCyQ.js +0 -1
  198. package/packages/remote-control-server/web/dist/assets/Dashboard-Cyj-Bb86.js +0 -2
  199. package/packages/remote-control-server/web/dist/assets/SessionDetail-SA9QBkyj.js +0 -51
  200. package/packages/remote-control-server/web/dist/assets/architectureDiagram-3BPJPVTR-CG9q9_bk.js +0 -36
  201. package/packages/remote-control-server/web/dist/assets/channel-CQFGglg-.js +0 -1
  202. package/packages/remote-control-server/web/dist/assets/classDiagram-4FO5ZUOK-C5rBdShD.js +0 -1
  203. package/packages/remote-control-server/web/dist/assets/classDiagram-v2-Q7XG4LA2-C5rBdShD.js +0 -1
  204. package/packages/remote-control-server/web/dist/assets/code-block-IT6T5CEO-BLGFrBw3.js +0 -2
  205. package/packages/remote-control-server/web/dist/assets/cose-bilkent-S5V4N54A-DBKEXjqM.js +0 -1
  206. package/packages/remote-control-server/web/dist/assets/dagre-BM42HDAG-DB_SWlAe.js +0 -4
  207. package/packages/remote-control-server/web/dist/assets/diagram-2AECGRRQ-Gbm8G3Xz.js +0 -43
  208. package/packages/remote-control-server/web/dist/assets/diagram-5GNKFQAL-BBuWqfDc.js +0 -10
  209. package/packages/remote-control-server/web/dist/assets/diagram-LMA3HP47-DyUwNrlg.js +0 -24
  210. package/packages/remote-control-server/web/dist/assets/diagram-OG6HWLK6-BXpvRwkJ.js +0 -24
  211. package/packages/remote-control-server/web/dist/assets/ganttDiagram-6RSMTGT7-ByDYviDl.js +0 -292
  212. package/packages/remote-control-server/web/dist/assets/gitGraphDiagram-PVQCEYII-BUnOPw74.js +0 -106
  213. package/packages/remote-control-server/web/dist/assets/infoDiagram-5YYISTIA-B1RpwJHG.js +0 -2
  214. package/packages/remote-control-server/web/dist/assets/main-0A4a3FDU.css +0 -1
  215. package/packages/remote-control-server/web/dist/assets/main-Dom16YJk.js +0 -283
  216. package/packages/remote-control-server/web/dist/assets/qr-C0jP9HcD.js +0 -8
  217. package/packages/remote-control-server/web/dist/assets/qr-scanner-worker.min-D85Z9gVD.js +0 -98
  218. package/packages/remote-control-server/web/dist/assets/stateDiagram-AJRCARHV-D6xp64f3.js +0 -1
  219. package/packages/remote-control-server/web/dist/assets/stateDiagram-v2-BHNVJYJU-D76vZCyQ.js +0 -1
@@ -0,0 +1,547 @@
1
+ import { describe, test, expect, beforeEach, mock } from 'bun:test'
2
+ import { randomUUID, createHash } from 'node:crypto'
3
+
4
+ // Mock config before any module imports
5
+ const mockConfig = {
6
+ port: 3000,
7
+ host: '0.0.0.0',
8
+ apiKeys: ['test-api-key'],
9
+ baseUrl: 'http://localhost:3000',
10
+ pollTimeout: 8,
11
+ heartbeatInterval: 20,
12
+ jwtExpiresIn: 3600,
13
+ disconnectTimeout: 300,
14
+ webCorsOrigins: [],
15
+ wsIdleTimeout: 30,
16
+ wsKeepaliveInterval: 20,
17
+ }
18
+
19
+ mock.module('../config', () => ({
20
+ config: mockConfig,
21
+ getBaseUrl: () => 'http://localhost:3000',
22
+ }))
23
+
24
+ import { Hono } from 'hono'
25
+ import { Database } from 'bun:sqlite'
26
+
27
+ let authRoutes: Hono | undefined
28
+ let shareRoutes: Hono | undefined
29
+ let migrateDatabase: ((db: Database) => void) | undefined
30
+ let initDatabase: ((path?: string) => Database) | undefined
31
+ let resetDbSingleton: (() => void) | undefined
32
+ let getDb: (() => Database) | undefined
33
+ let resetRateLimits: (() => void) | undefined
34
+
35
+ try {
36
+ const dbMod = await import('../db/sqlite')
37
+ migrateDatabase = dbMod.migrateDatabase
38
+ getDb = dbMod.getDb
39
+ initDatabase = dbMod.initDatabase
40
+ resetDbSingleton = dbMod.resetDbSingleton
41
+ } catch {
42
+ // Module may not exist yet
43
+ }
44
+
45
+ try {
46
+ const mod = await import('../routes/web/auth-routes')
47
+ authRoutes = mod.default
48
+ resetRateLimits = mod._resetRateLimits
49
+ } catch {
50
+ // Module may not exist yet
51
+ }
52
+
53
+ try {
54
+ const mod = await import('../routes/web/shares')
55
+ shareRoutes = mod.default
56
+ } catch {
57
+ // Module may not exist yet
58
+ }
59
+
60
+ function freshDb(): Database {
61
+ if (resetDbSingleton) {
62
+ try {
63
+ resetDbSingleton()
64
+ } catch {
65
+ // ignore
66
+ }
67
+ }
68
+ // Use the same pattern as auth-login.test.ts: just reset and let
69
+ // getDb() lazily initialize at the default temp path.
70
+ // This ensures route handlers that call getDb() get the same instance.
71
+ if (getDb) {
72
+ return getDb()
73
+ }
74
+ throw new Error('getDb not available')
75
+ }
76
+
77
+ function createApp(): Hono {
78
+ const app = new Hono()
79
+ if (authRoutes) app.route('/web/auth', authRoutes)
80
+ if (shareRoutes) app.route('/web', shareRoutes)
81
+ return app
82
+ }
83
+
84
+ // ===========================================================================
85
+ // Task 1: /setup concurrent protection
86
+ // ===========================================================================
87
+ describe('Security: /setup concurrent protection', () => {
88
+ let app: Hono
89
+
90
+ beforeEach(() => {
91
+ freshDb()
92
+ app = createApp()
93
+ })
94
+
95
+ test('concurrent setup requests only create one admin', async () => {
96
+ // Fire two setup requests concurrently
97
+ const [res1, res2] = await Promise.all([
98
+ app.request('/web/auth/setup', {
99
+ method: 'POST',
100
+ headers: { 'Content-Type': 'application/json' },
101
+ body: JSON.stringify({
102
+ apiKey: 'test-api-key',
103
+ username: 'admin1',
104
+ password: 'secure-password-1',
105
+ }),
106
+ }),
107
+ app.request('/web/auth/setup', {
108
+ method: 'POST',
109
+ headers: { 'Content-Type': 'application/json' },
110
+ body: JSON.stringify({
111
+ apiKey: 'test-api-key',
112
+ username: 'admin2',
113
+ password: 'secure-password-2',
114
+ }),
115
+ }),
116
+ ])
117
+
118
+ // Exactly one should succeed (200) and one should fail (409)
119
+ const statuses = [res1.status, res2.status].sort()
120
+ expect(statuses).toEqual([200, 409])
121
+
122
+ // Verify only one admin user exists in DB
123
+ const db = getDb!()
124
+ const count = db.query('SELECT COUNT(*) as count FROM users').get() as {
125
+ count: number
126
+ }
127
+ expect(count.count).toBe(1)
128
+ })
129
+ })
130
+
131
+ // ===========================================================================
132
+ // Task 2: /login rate limiting
133
+ // ===========================================================================
134
+ describe('Security: /login rate limiting', () => {
135
+ let app: Hono
136
+
137
+ beforeEach(async () => {
138
+ freshDb()
139
+ if (resetRateLimits) resetRateLimits()
140
+ app = createApp()
141
+ // Create admin via setup
142
+ await app.request('/web/auth/setup', {
143
+ method: 'POST',
144
+ headers: { 'Content-Type': 'application/json' },
145
+ body: JSON.stringify({
146
+ apiKey: 'test-api-key',
147
+ username: 'admin',
148
+ password: 'admin-password-123',
149
+ }),
150
+ })
151
+ })
152
+
153
+ test(
154
+ 'returns 429 after 5 consecutive failed login attempts',
155
+ async () => {
156
+ // 5 failed attempts
157
+ for (let i = 0; i < 5; i++) {
158
+ const res = await app.request('/web/auth/login', {
159
+ method: 'POST',
160
+ headers: {
161
+ 'Content-Type': 'application/json',
162
+ 'X-Forwarded-For': '10.0.0.1',
163
+ },
164
+ body: JSON.stringify({
165
+ username: 'admin',
166
+ password: 'wrong-password',
167
+ }),
168
+ })
169
+ // Should be 401 for the first 4, may become 429 on the 5th
170
+ expect([401, 429]).toContain(res.status)
171
+ }
172
+
173
+ // 6th attempt should be rate-limited
174
+ const res6 = await app.request('/web/auth/login', {
175
+ method: 'POST',
176
+ headers: {
177
+ 'Content-Type': 'application/json',
178
+ 'X-Forwarded-For': '10.0.0.1',
179
+ },
180
+ body: JSON.stringify({
181
+ username: 'admin',
182
+ password: 'wrong-password',
183
+ }),
184
+ })
185
+ expect(res6.status).toBe(429)
186
+ },
187
+ { timeout: 30000 },
188
+ )
189
+
190
+ test(
191
+ 'rate limit does not affect different IPs',
192
+ async () => {
193
+ // 5 failed attempts from IP A
194
+ for (let i = 0; i < 5; i++) {
195
+ await app.request('/web/auth/login', {
196
+ method: 'POST',
197
+ headers: {
198
+ 'Content-Type': 'application/json',
199
+ 'X-Forwarded-For': '10.0.0.1',
200
+ },
201
+ body: JSON.stringify({
202
+ username: 'admin',
203
+ password: 'wrong-password',
204
+ }),
205
+ })
206
+ }
207
+
208
+ // Attempt from IP B should not be rate-limited
209
+ const res = await app.request('/web/auth/login', {
210
+ method: 'POST',
211
+ headers: {
212
+ 'Content-Type': 'application/json',
213
+ 'X-Forwarded-For': '10.0.0.2',
214
+ },
215
+ body: JSON.stringify({
216
+ username: 'admin',
217
+ password: 'wrong-password',
218
+ }),
219
+ })
220
+ expect(res.status).toBe(401)
221
+ },
222
+ { timeout: 30000 },
223
+ )
224
+
225
+ test(
226
+ 'successful login clears rate limit counter',
227
+ async () => {
228
+ // 4 failed attempts (one below threshold)
229
+ for (let i = 0; i < 4; i++) {
230
+ await app.request('/web/auth/login', {
231
+ method: 'POST',
232
+ headers: {
233
+ 'Content-Type': 'application/json',
234
+ 'X-Forwarded-For': '10.0.0.3',
235
+ },
236
+ body: JSON.stringify({
237
+ username: 'admin',
238
+ password: 'wrong-password',
239
+ }),
240
+ })
241
+ }
242
+
243
+ // Successful login
244
+ const successRes = await app.request('/web/auth/login', {
245
+ method: 'POST',
246
+ headers: {
247
+ 'Content-Type': 'application/json',
248
+ 'X-Forwarded-For': '10.0.0.3',
249
+ },
250
+ body: JSON.stringify({
251
+ username: 'admin',
252
+ password: 'admin-password-123',
253
+ }),
254
+ })
255
+ expect(successRes.status).toBe(200)
256
+
257
+ // After success, 4 more failed attempts should not trigger rate limit
258
+ for (let i = 0; i < 4; i++) {
259
+ const res = await app.request('/web/auth/login', {
260
+ method: 'POST',
261
+ headers: {
262
+ 'Content-Type': 'application/json',
263
+ 'X-Forwarded-For': '10.0.0.3',
264
+ },
265
+ body: JSON.stringify({
266
+ username: 'admin',
267
+ password: 'wrong-password',
268
+ }),
269
+ })
270
+ expect(res.status).toBe(401)
271
+ }
272
+ },
273
+ { timeout: 30000 },
274
+ )
275
+ })
276
+
277
+ // ===========================================================================
278
+ // Task 3: Invitation max_uses atomic
279
+ // ===========================================================================
280
+ describe('Security: invitation max_uses atomic', () => {
281
+ let app: Hono
282
+ let inviteToken: string
283
+
284
+ beforeEach(async () => {
285
+ freshDb()
286
+ app = createApp()
287
+ // Setup admin
288
+ await app.request('/web/auth/setup', {
289
+ method: 'POST',
290
+ headers: { 'Content-Type': 'application/json' },
291
+ body: JSON.stringify({
292
+ apiKey: 'test-api-key',
293
+ username: 'admin',
294
+ password: 'admin-password-123',
295
+ }),
296
+ })
297
+
298
+ // Create a max_uses=1 invitation
299
+ const db = getDb!()
300
+ inviteToken = `inv_race_${randomUUID().slice(0, 8)}`
301
+ const tokenHash = createHash('sha256').update(inviteToken).digest('hex')
302
+ const futureExpiry = new Date(Date.now() + 86400000).toISOString()
303
+ const adminRow = db
304
+ .query("SELECT id FROM users WHERE username = 'admin'")
305
+ .get() as { id: string }
306
+ db.exec(
307
+ `INSERT INTO invitations (token_hash, role, expires_at, max_uses, uses, created_by)
308
+ VALUES ('${tokenHash}', 'member', '${futureExpiry}', 1, 0, '${adminRow.id}')`,
309
+ )
310
+ })
311
+
312
+ test('concurrent joins with max_uses=1 only succeed once', async () => {
313
+ // Fire two join requests concurrently with the same invitation
314
+ const [res1, res2] = await Promise.all([
315
+ app.request('/web/auth/join', {
316
+ method: 'POST',
317
+ headers: { 'Content-Type': 'application/json' },
318
+ body: JSON.stringify({
319
+ inviteToken,
320
+ username: 'user_a',
321
+ password: 'user-a-password-123',
322
+ }),
323
+ }),
324
+ app.request('/web/auth/join', {
325
+ method: 'POST',
326
+ headers: { 'Content-Type': 'application/json' },
327
+ body: JSON.stringify({
328
+ inviteToken,
329
+ username: 'user_b',
330
+ password: 'user-b-password-123',
331
+ }),
332
+ }),
333
+ ])
334
+
335
+ const statuses = [res1.status, res2.status].sort()
336
+ // Exactly one 200 and one 400 (due to atomic check or username race)
337
+ expect(statuses).toEqual([200, 400])
338
+
339
+ // Verify only one new user was created (in addition to admin)
340
+ const db = getDb!()
341
+ const count = db.query('SELECT COUNT(*) as count FROM users').get() as {
342
+ count: number
343
+ }
344
+ expect(count.count).toBe(2) // admin + 1 new user
345
+ })
346
+ })
347
+
348
+ // ===========================================================================
349
+ // Task 4: Refresh token rotation
350
+ // ===========================================================================
351
+ describe('Security: refresh token rotation', () => {
352
+ let app: Hono
353
+ let refreshToken: string
354
+
355
+ beforeEach(async () => {
356
+ freshDb()
357
+ app = createApp()
358
+ // Setup admin
359
+ await app.request('/web/auth/setup', {
360
+ method: 'POST',
361
+ headers: { 'Content-Type': 'application/json' },
362
+ body: JSON.stringify({
363
+ apiKey: 'test-api-key',
364
+ username: 'admin',
365
+ password: 'admin-password-123',
366
+ }),
367
+ })
368
+ const loginRes = await app.request('/web/auth/login', {
369
+ method: 'POST',
370
+ headers: { 'Content-Type': 'application/json' },
371
+ body: JSON.stringify({
372
+ username: 'admin',
373
+ password: 'admin-password-123',
374
+ }),
375
+ })
376
+ const loginBody = await loginRes.json()
377
+ refreshToken = loginBody.refreshToken || loginBody.refresh_token || ''
378
+ })
379
+
380
+ test('refresh returns new access and refresh tokens', async () => {
381
+ const res = await app.request('/web/auth/refresh', {
382
+ method: 'POST',
383
+ headers: { 'Content-Type': 'application/json' },
384
+ body: JSON.stringify({ refreshToken }),
385
+ })
386
+ expect(res.status).toBe(200)
387
+ const body = await res.json()
388
+ expect(body.accessToken).toBeDefined()
389
+ expect(body.refreshToken).toBeDefined()
390
+ // New refresh token should be different from old one
391
+ expect(body.refreshToken).not.toBe(refreshToken)
392
+ })
393
+
394
+ test('old refresh token is invalid after rotation', async () => {
395
+ // Use refresh token once
396
+ const res1 = await app.request('/web/auth/refresh', {
397
+ method: 'POST',
398
+ headers: { 'Content-Type': 'application/json' },
399
+ body: JSON.stringify({ refreshToken }),
400
+ })
401
+ expect(res1.status).toBe(200)
402
+
403
+ // Try to use the OLD refresh token again — should fail
404
+ const res2 = await app.request('/web/auth/refresh', {
405
+ method: 'POST',
406
+ headers: { 'Content-Type': 'application/json' },
407
+ body: JSON.stringify({ refreshToken }),
408
+ })
409
+ expect(res2.status).toBe(401)
410
+ })
411
+
412
+ test('new refresh token can be used for subsequent refresh', async () => {
413
+ const res1 = await app.request('/web/auth/refresh', {
414
+ method: 'POST',
415
+ headers: { 'Content-Type': 'application/json' },
416
+ body: JSON.stringify({ refreshToken }),
417
+ })
418
+ const body1 = await res1.json()
419
+ const newRefreshToken = body1.refreshToken
420
+
421
+ // Use the new refresh token
422
+ const res2 = await app.request('/web/auth/refresh', {
423
+ method: 'POST',
424
+ headers: { 'Content-Type': 'application/json' },
425
+ body: JSON.stringify({ refreshToken: newRefreshToken }),
426
+ })
427
+ expect(res2.status).toBe(200)
428
+ const body2 = await res2.json()
429
+ expect(body2.accessToken).toBeDefined()
430
+ })
431
+ })
432
+
433
+ // ===========================================================================
434
+ // Task 5: API key bypass uses __system__ identity
435
+ // ===========================================================================
436
+ describe('Security: API key bypass identity', () => {
437
+ let app: Hono
438
+
439
+ beforeEach(() => {
440
+ freshDb()
441
+ app = new Hono()
442
+
443
+ // Protected route using sessionAuth
444
+ const { sessionAuth } = require('../auth/middleware')
445
+ app.get('/protected', async (c, next) => {
446
+ const result = await sessionAuth(c, next)
447
+ if (result) return result
448
+ return c.json({ userId: c.get('userId'), isAdmin: c.get('isAdmin') })
449
+ })
450
+ })
451
+
452
+ test('API key bypass sets userId to __system__ not __admin__', async () => {
453
+ const res = await app.request('/protected', {
454
+ headers: { Authorization: 'Bearer test-api-key' },
455
+ })
456
+ expect(res.status).toBe(200)
457
+ const body = await res.json()
458
+ expect(body.userId).toBe('__system__')
459
+ expect(body.isAdmin).toBe(true)
460
+ })
461
+ })
462
+
463
+ // ===========================================================================
464
+ // Task 8: Share endpoint SELECT * fix
465
+ // ===========================================================================
466
+ describe('Security: share endpoint does not leak internal fields', () => {
467
+ let app: Hono
468
+ let shareToken: string
469
+ let accessToken: string
470
+
471
+ beforeEach(async () => {
472
+ freshDb()
473
+ app = createApp()
474
+
475
+ // Setup admin
476
+ await app.request('/web/auth/setup', {
477
+ method: 'POST',
478
+ headers: { 'Content-Type': 'application/json' },
479
+ body: JSON.stringify({
480
+ apiKey: 'test-api-key',
481
+ username: 'admin',
482
+ password: 'admin-password-123',
483
+ }),
484
+ })
485
+
486
+ const loginRes = await app.request('/web/auth/login', {
487
+ method: 'POST',
488
+ headers: { 'Content-Type': 'application/json' },
489
+ body: JSON.stringify({
490
+ username: 'admin',
491
+ password: 'admin-password-123',
492
+ }),
493
+ })
494
+ const loginBody = await loginRes.json()
495
+ accessToken = loginBody.accessToken || loginBody.access_token || ''
496
+
497
+ // Create a session in the DB
498
+ const db = getDb!()
499
+ const sessionId = `ses_${randomUUID().replace(/-/g, '').slice(0, 16)}`
500
+ const now = new Date().toISOString()
501
+ db.query(
502
+ `INSERT INTO sessions (id, title, status, source, created_at, updated_at)
503
+ VALUES ($id, $title, $status, $source, $now, $now)`,
504
+ ).run({
505
+ $id: sessionId,
506
+ $title: 'Test session',
507
+ $status: 'idle',
508
+ $source: 'web',
509
+ $now: now,
510
+ })
511
+
512
+ // Create a share for the session
513
+ const adminRow = db
514
+ .query("SELECT id FROM users WHERE username = 'admin'")
515
+ .get() as { id: string }
516
+ shareToken = `shr_${randomUUID().replace(/-/g, '')}`
517
+ db.query(
518
+ `INSERT INTO session_shares (id, session_id, permission, granted_at, granted_by)
519
+ VALUES ($id, $sid, 'read', $now, $by)`,
520
+ ).run({
521
+ $id: shareToken,
522
+ $sid: sessionId,
523
+ $now: now,
524
+ $by: adminRow.id,
525
+ })
526
+ })
527
+
528
+ test('GET /web/sessions/s/:shareToken does not return environment_id', async () => {
529
+ const res = await app.request(`/web/sessions/s/${shareToken}`, {
530
+ headers: {
531
+ Authorization: `Bearer ${accessToken}`,
532
+ },
533
+ })
534
+ expect(res.status).toBe(200)
535
+ const body = await res.json()
536
+
537
+ // Must have expected safe fields
538
+ expect(body.id).toBeDefined()
539
+ expect(body.title).toBe('Test session')
540
+ expect(body.status).toBe('idle')
541
+
542
+ // Must NOT have internal/sensitive fields
543
+ expect(body.environment_id).toBeUndefined()
544
+ expect(body.permission_mode).toBeUndefined()
545
+ expect(body.visibility).toBeUndefined()
546
+ })
547
+ })
@@ -7,26 +7,15 @@ import {
7
7
  mock,
8
8
  spyOn,
9
9
  } from 'bun:test'
10
+ import { mockConfigModule } from './helpers/mock-config'
10
11
 
11
12
  // Mock config before importing modules that depend on it
12
- const mockConfig = {
13
- port: 3000,
14
- host: '0.0.0.0',
15
- apiKeys: ['test-key-1', 'test-key-2'],
16
- baseUrl: '',
17
- pollTimeout: 8,
18
- heartbeatInterval: 20,
19
- jwtExpiresIn: 3600,
20
- disconnectTimeout: 300,
21
- webCorsOrigins: [],
22
- wsIdleTimeout: 30,
23
- wsKeepaliveInterval: 20,
24
- }
25
-
26
- mock.module('../config', () => ({
27
- config: mockConfig,
28
- getBaseUrl: () => 'http://localhost:3000',
29
- }))
13
+ mock.module('../config', () =>
14
+ mockConfigModule({
15
+ apiKeys: ['test-key-1', 'test-key-2'],
16
+ baseUrl: '',
17
+ }),
18
+ )
30
19
 
31
20
  import { validateApiKey, hashApiKey } from '../auth/api-key'
32
21
  import { generateWorkerJwt, verifyWorkerJwt } from '../auth/jwt'