@saluzi/saluzi-edu 0.2.12 → 0.2.13

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 (167) hide show
  1. package/dist/cli.js +212 -140
  2. package/dist/rcs-web/assets/Dashboard-YYwDrKTN.js +1 -0
  3. package/dist/rcs-web/assets/Join-DKCP5X6X.js +1 -0
  4. package/dist/rcs-web/assets/Login-0VGZs85I.js +1 -0
  5. package/{packages/remote-control-server/web/dist/assets/SessionDetail-DSoMXZJb.js → dist/rcs-web/assets/SessionDetail-DmK-DfBQ.js} +11 -11
  6. package/dist/rcs-web/assets/Setup-C0cjxXMt.js +1 -0
  7. package/dist/rcs-web/assets/{ShareLanding-C06U9Nrr.js → ShareLanding-DUZrreJ7.js} +1 -1
  8. package/dist/rcs-web/assets/TeamCreate-B8ZV6EdY.js +1 -0
  9. package/dist/rcs-web/assets/{TeamDetail-d_GwIRHd.js → TeamDetail-DBAsJ__i.js} +2 -2
  10. package/dist/rcs-web/assets/{TeamList-BlNGdKci.js → TeamList-C-Hte4nV.js} +1 -1
  11. package/dist/rcs-web/assets/{TeamSettings-CPraC9uS.js → TeamSettings-CNVwYwcp.js} +1 -1
  12. package/dist/rcs-web/assets/UserSettings-DRdz9kYE.js +1 -0
  13. package/dist/rcs-web/assets/{arc-BmYza-0n.js → arc-CJxirXEQ.js} +1 -1
  14. package/dist/rcs-web/assets/{architectureDiagram-3BPJPVTR-CYBtlgdO.js → architectureDiagram-3BPJPVTR-BZvIHrLA.js} +1 -1
  15. package/dist/rcs-web/assets/{blockDiagram-GPEHLZMM-RJAfHk_a.js → blockDiagram-GPEHLZMM-3p0y3Ija.js} +1 -1
  16. package/{packages/remote-control-server/web/dist/assets/c4Diagram-AAUBKEIU-CJ-qJA6w.js → dist/rcs-web/assets/c4Diagram-AAUBKEIU-Bmz9A1wn.js} +1 -1
  17. package/dist/rcs-web/assets/channel-DaI_n8dp.js +1 -0
  18. package/dist/rcs-web/assets/{chunk-2J33WTMH-n5I6Q1zJ.js → chunk-2J33WTMH-B8gQz22j.js} +1 -1
  19. package/dist/rcs-web/assets/{chunk-4BX2VUAB-CSOBh7qY.js → chunk-4BX2VUAB-CgLEZsTU.js} +1 -1
  20. package/dist/rcs-web/assets/{chunk-55IACEB6-C0euQVm_.js → chunk-55IACEB6-0mdE_-IS.js} +1 -1
  21. package/{packages/remote-control-server/web/dist/assets/chunk-727SXJPM-Ch7yD8cR.js → dist/rcs-web/assets/chunk-727SXJPM-DdtjnIHR.js} +1 -1
  22. package/{packages/remote-control-server/web/dist/assets/chunk-AQP2D5EJ-Ms2Q7r6u.js → dist/rcs-web/assets/chunk-AQP2D5EJ-BtwFPk50.js} +1 -1
  23. package/dist/rcs-web/assets/{chunk-FMBD7UC4-bszHUkpx.js → chunk-FMBD7UC4-BcO9mQ0P.js} +1 -1
  24. package/dist/rcs-web/assets/{chunk-ND2GUHAM-BVQIhq6J.js → chunk-ND2GUHAM-BvRq13S_.js} +1 -1
  25. package/dist/rcs-web/assets/{chunk-QZHKN3VN-BVEDe5qc.js → chunk-QZHKN3VN-D7GHkPpq.js} +1 -1
  26. package/dist/rcs-web/assets/classDiagram-4FO5ZUOK-pYllpkOq.js +1 -0
  27. package/dist/rcs-web/assets/classDiagram-v2-Q7XG4LA2-pYllpkOq.js +1 -0
  28. package/dist/rcs-web/assets/{code-block-IT6T5CEO-B26n-rFC.js → code-block-IT6T5CEO-B1p-vO-3.js} +1 -1
  29. package/{packages/remote-control-server/web/dist/assets/cose-bilkent-S5V4N54A-DXc7GE8W.js → dist/rcs-web/assets/cose-bilkent-S5V4N54A-L0rUZuH5.js} +1 -1
  30. package/dist/rcs-web/assets/{dagre-BM42HDAG-DAXofHt_.js → dagre-BM42HDAG-CHGuio22.js} +1 -1
  31. package/dist/rcs-web/assets/{diagram-2AECGRRQ-DK0TBUQA.js → diagram-2AECGRRQ-DIDRyQk8.js} +1 -1
  32. package/dist/rcs-web/assets/{diagram-5GNKFQAL-DMsq-Grp.js → diagram-5GNKFQAL-CNubKb6P.js} +1 -1
  33. package/dist/rcs-web/assets/{diagram-KO2AKTUF-B3FMhmUc.js → diagram-KO2AKTUF-CzQh664-.js} +1 -1
  34. package/dist/rcs-web/assets/{diagram-LMA3HP47-BjO3BHFl.js → diagram-LMA3HP47-CWBR7-VG.js} +1 -1
  35. package/dist/rcs-web/assets/{diagram-OG6HWLK6-CNg4B2L3.js → diagram-OG6HWLK6-BMHdlbcZ.js} +1 -1
  36. package/{packages/remote-control-server/web/dist/assets/erDiagram-TEJ5UH35-BDxz8NRK.js → dist/rcs-web/assets/erDiagram-TEJ5UH35-OgT8dC-K.js} +1 -1
  37. package/{packages/remote-control-server/web/dist/assets/flowDiagram-I6XJVG4X-VIgM13sK.js → dist/rcs-web/assets/flowDiagram-I6XJVG4X-DRrCY2oB.js} +1 -1
  38. package/dist/rcs-web/assets/{ganttDiagram-6RSMTGT7-Ba2QuJU0.js → ganttDiagram-6RSMTGT7-DctpzEKN.js} +1 -1
  39. package/dist/rcs-web/assets/{gitGraphDiagram-PVQCEYII-B-gV-lAg.js → gitGraphDiagram-PVQCEYII-5KpLszm9.js} +1 -1
  40. package/dist/rcs-web/assets/{infoDiagram-5YYISTIA-DothwgD4.js → infoDiagram-5YYISTIA-BAKD_Tt7.js} +1 -1
  41. package/{packages/remote-control-server/web/dist/assets/ishikawaDiagram-YF4QCWOH-DhpjM1Vc.js → dist/rcs-web/assets/ishikawaDiagram-YF4QCWOH-VHOPG4Nc.js} +1 -1
  42. package/dist/rcs-web/assets/{journeyDiagram-JHISSGLW-PbQTouMJ.js → journeyDiagram-JHISSGLW-BtGih-ik.js} +1 -1
  43. package/dist/rcs-web/assets/{kanban-definition-UN3LZRKU-63WdwG-X.js → kanban-definition-UN3LZRKU-BsEGZsD1.js} +1 -1
  44. package/dist/rcs-web/assets/{linear-CeRljV9s.js → linear-Dj636PNG.js} +1 -1
  45. package/dist/rcs-web/assets/main-CkqtCllF.js +238 -0
  46. package/dist/rcs-web/assets/{mermaid-VLURNSYL-CG6yNR7g.js → mermaid-VLURNSYL-DutpHHm9.js} +4 -4
  47. package/dist/rcs-web/assets/{mermaid.core-CAuNNATY.js → mermaid.core-XHHf0pen.js} +5 -5
  48. package/dist/rcs-web/assets/{mindmap-definition-RKZ34NQL-9hDL1CUV.js → mindmap-definition-RKZ34NQL-BBa8V_3g.js} +1 -1
  49. package/dist/rcs-web/assets/{pieDiagram-4H26LBE5-BS_P2t04.js → pieDiagram-4H26LBE5-BuNEdo9H.js} +1 -1
  50. package/dist/rcs-web/assets/{quadrantDiagram-W4KKPZXB-Cp9QQkHV.js → quadrantDiagram-W4KKPZXB-CsJgyQIN.js} +1 -1
  51. package/dist/rcs-web/assets/{requirementDiagram-4Y6WPE33-C_XSzOKE.js → requirementDiagram-4Y6WPE33-DqMJZ914.js} +1 -1
  52. package/{packages/remote-control-server/web/dist/assets/sankeyDiagram-5OEKKPKP-BhuVqzZd.js → dist/rcs-web/assets/sankeyDiagram-5OEKKPKP-CVsz09q2.js} +1 -1
  53. package/{packages/remote-control-server/web/dist/assets/sequenceDiagram-3UESZ5HK-C3IPZrcW.js → dist/rcs-web/assets/sequenceDiagram-3UESZ5HK-BRp4Wddn.js} +1 -1
  54. package/dist/rcs-web/assets/{stateDiagram-AJRCARHV-CN4iNPRl.js → stateDiagram-AJRCARHV-S-QqQr-D.js} +1 -1
  55. package/dist/rcs-web/assets/{stateDiagram-v2-BHNVJYJU-CICBlDSJ.js → stateDiagram-v2-BHNVJYJU-D77KfDr-.js} +1 -1
  56. package/{packages/remote-control-server/web/dist/assets/timeline-definition-PNZ67QCA-Be7t_3rC.js → dist/rcs-web/assets/timeline-definition-PNZ67QCA-De8bFWnE.js} +1 -1
  57. package/dist/rcs-web/assets/{useTeams-DPHGnBHL.js → useTeams-CqJOqEy1.js} +1 -1
  58. package/dist/rcs-web/assets/{vennDiagram-CIIHVFJN-CSaUc2Xv.js → vennDiagram-CIIHVFJN-Dikwrn1L.js} +1 -1
  59. package/dist/rcs-web/assets/{wardleyDiagram-YWT4CUSO-DTuJrl9P.js → wardleyDiagram-YWT4CUSO-DUzpiV6H.js} +1 -1
  60. package/dist/rcs-web/assets/{workerType-CSqeySYe.js → workerType-DOQ0AHrq.js} +1 -1
  61. package/dist/rcs-web/assets/{xychartDiagram-2RQKCTM6-BQ0oU3Qi.js → xychartDiagram-2RQKCTM6-OZNbB32D.js} +1 -1
  62. package/dist/rcs-web/index.html +1 -1
  63. package/package.json +2 -2
  64. package/packages/remote-control-server/src/__tests__/cookie.test.ts +0 -71
  65. package/packages/remote-control-server/src/__tests__/data-layer-round2.test.ts +556 -0
  66. package/packages/remote-control-server/src/__tests__/route-mounting.test.ts +212 -0
  67. package/packages/remote-control-server/src/__tests__/routes.test.ts +5 -44
  68. package/packages/remote-control-server/src/__tests__/security-fixes.test.ts +526 -0
  69. package/packages/remote-control-server/src/__tests__/security-round3.test.ts +780 -0
  70. package/packages/remote-control-server/src/__tests__/shares.test.ts +5 -2
  71. package/packages/remote-control-server/src/auth/constants.ts +0 -6
  72. package/packages/remote-control-server/src/auth/cookie.ts +0 -43
  73. package/packages/remote-control-server/src/auth/csrf.ts +58 -0
  74. package/packages/remote-control-server/src/auth/middleware.ts +7 -4
  75. package/packages/remote-control-server/src/index.ts +26 -0
  76. package/packages/remote-control-server/src/registerRoutes.ts +17 -1
  77. package/packages/remote-control-server/src/routes/web/auth-routes.ts +93 -54
  78. package/packages/remote-control-server/src/routes/web/auth.ts +16 -23
  79. package/packages/remote-control-server/src/routes/web/sessions.ts +30 -5
  80. package/packages/remote-control-server/src/routes/web/shares.ts +38 -1
  81. package/packages/remote-control-server/src/routes/web/teams.ts +22 -4
  82. package/packages/remote-control-server/src/services/session.ts +143 -9
  83. package/packages/remote-control-server/src/store.ts +34 -1
  84. package/packages/remote-control-server/src/types/api.ts +0 -1
  85. package/packages/remote-control-server/web/dist/assets/Dashboard-YYwDrKTN.js +1 -0
  86. package/packages/remote-control-server/web/dist/assets/Join-DKCP5X6X.js +1 -0
  87. package/packages/remote-control-server/web/dist/assets/Login-0VGZs85I.js +1 -0
  88. package/{dist/rcs-web/assets/SessionDetail-DSoMXZJb.js → packages/remote-control-server/web/dist/assets/SessionDetail-DmK-DfBQ.js} +11 -11
  89. package/packages/remote-control-server/web/dist/assets/Setup-C0cjxXMt.js +1 -0
  90. package/packages/remote-control-server/web/dist/assets/{ShareLanding-C06U9Nrr.js → ShareLanding-DUZrreJ7.js} +1 -1
  91. package/packages/remote-control-server/web/dist/assets/TeamCreate-B8ZV6EdY.js +1 -0
  92. package/packages/remote-control-server/web/dist/assets/{TeamDetail-d_GwIRHd.js → TeamDetail-DBAsJ__i.js} +2 -2
  93. package/packages/remote-control-server/web/dist/assets/{TeamList-BlNGdKci.js → TeamList-C-Hte4nV.js} +1 -1
  94. package/packages/remote-control-server/web/dist/assets/{TeamSettings-CPraC9uS.js → TeamSettings-CNVwYwcp.js} +1 -1
  95. package/packages/remote-control-server/web/dist/assets/UserSettings-DRdz9kYE.js +1 -0
  96. package/packages/remote-control-server/web/dist/assets/{arc-BmYza-0n.js → arc-CJxirXEQ.js} +1 -1
  97. package/packages/remote-control-server/web/dist/assets/{architectureDiagram-3BPJPVTR-CYBtlgdO.js → architectureDiagram-3BPJPVTR-BZvIHrLA.js} +1 -1
  98. package/packages/remote-control-server/web/dist/assets/{blockDiagram-GPEHLZMM-RJAfHk_a.js → blockDiagram-GPEHLZMM-3p0y3Ija.js} +1 -1
  99. package/{dist/rcs-web/assets/c4Diagram-AAUBKEIU-CJ-qJA6w.js → packages/remote-control-server/web/dist/assets/c4Diagram-AAUBKEIU-Bmz9A1wn.js} +1 -1
  100. package/packages/remote-control-server/web/dist/assets/channel-DaI_n8dp.js +1 -0
  101. package/packages/remote-control-server/web/dist/assets/{chunk-2J33WTMH-n5I6Q1zJ.js → chunk-2J33WTMH-B8gQz22j.js} +1 -1
  102. package/packages/remote-control-server/web/dist/assets/{chunk-4BX2VUAB-CSOBh7qY.js → chunk-4BX2VUAB-CgLEZsTU.js} +1 -1
  103. package/packages/remote-control-server/web/dist/assets/{chunk-55IACEB6-C0euQVm_.js → chunk-55IACEB6-0mdE_-IS.js} +1 -1
  104. package/{dist/rcs-web/assets/chunk-727SXJPM-Ch7yD8cR.js → packages/remote-control-server/web/dist/assets/chunk-727SXJPM-DdtjnIHR.js} +1 -1
  105. package/{dist/rcs-web/assets/chunk-AQP2D5EJ-Ms2Q7r6u.js → packages/remote-control-server/web/dist/assets/chunk-AQP2D5EJ-BtwFPk50.js} +1 -1
  106. package/packages/remote-control-server/web/dist/assets/{chunk-FMBD7UC4-bszHUkpx.js → chunk-FMBD7UC4-BcO9mQ0P.js} +1 -1
  107. package/packages/remote-control-server/web/dist/assets/{chunk-ND2GUHAM-BVQIhq6J.js → chunk-ND2GUHAM-BvRq13S_.js} +1 -1
  108. package/packages/remote-control-server/web/dist/assets/{chunk-QZHKN3VN-BVEDe5qc.js → chunk-QZHKN3VN-D7GHkPpq.js} +1 -1
  109. package/packages/remote-control-server/web/dist/assets/classDiagram-4FO5ZUOK-pYllpkOq.js +1 -0
  110. package/packages/remote-control-server/web/dist/assets/classDiagram-v2-Q7XG4LA2-pYllpkOq.js +1 -0
  111. package/packages/remote-control-server/web/dist/assets/{code-block-IT6T5CEO-B26n-rFC.js → code-block-IT6T5CEO-B1p-vO-3.js} +1 -1
  112. package/{dist/rcs-web/assets/cose-bilkent-S5V4N54A-DXc7GE8W.js → packages/remote-control-server/web/dist/assets/cose-bilkent-S5V4N54A-L0rUZuH5.js} +1 -1
  113. package/packages/remote-control-server/web/dist/assets/{dagre-BM42HDAG-DAXofHt_.js → dagre-BM42HDAG-CHGuio22.js} +1 -1
  114. package/packages/remote-control-server/web/dist/assets/{diagram-2AECGRRQ-DK0TBUQA.js → diagram-2AECGRRQ-DIDRyQk8.js} +1 -1
  115. package/packages/remote-control-server/web/dist/assets/{diagram-5GNKFQAL-DMsq-Grp.js → diagram-5GNKFQAL-CNubKb6P.js} +1 -1
  116. package/packages/remote-control-server/web/dist/assets/{diagram-KO2AKTUF-B3FMhmUc.js → diagram-KO2AKTUF-CzQh664-.js} +1 -1
  117. package/packages/remote-control-server/web/dist/assets/{diagram-LMA3HP47-BjO3BHFl.js → diagram-LMA3HP47-CWBR7-VG.js} +1 -1
  118. package/packages/remote-control-server/web/dist/assets/{diagram-OG6HWLK6-CNg4B2L3.js → diagram-OG6HWLK6-BMHdlbcZ.js} +1 -1
  119. package/{dist/rcs-web/assets/erDiagram-TEJ5UH35-BDxz8NRK.js → packages/remote-control-server/web/dist/assets/erDiagram-TEJ5UH35-OgT8dC-K.js} +1 -1
  120. package/{dist/rcs-web/assets/flowDiagram-I6XJVG4X-VIgM13sK.js → packages/remote-control-server/web/dist/assets/flowDiagram-I6XJVG4X-DRrCY2oB.js} +1 -1
  121. package/packages/remote-control-server/web/dist/assets/{ganttDiagram-6RSMTGT7-Ba2QuJU0.js → ganttDiagram-6RSMTGT7-DctpzEKN.js} +1 -1
  122. package/packages/remote-control-server/web/dist/assets/{gitGraphDiagram-PVQCEYII-B-gV-lAg.js → gitGraphDiagram-PVQCEYII-5KpLszm9.js} +1 -1
  123. package/packages/remote-control-server/web/dist/assets/{infoDiagram-5YYISTIA-DothwgD4.js → infoDiagram-5YYISTIA-BAKD_Tt7.js} +1 -1
  124. package/{dist/rcs-web/assets/ishikawaDiagram-YF4QCWOH-DhpjM1Vc.js → packages/remote-control-server/web/dist/assets/ishikawaDiagram-YF4QCWOH-VHOPG4Nc.js} +1 -1
  125. package/packages/remote-control-server/web/dist/assets/{journeyDiagram-JHISSGLW-PbQTouMJ.js → journeyDiagram-JHISSGLW-BtGih-ik.js} +1 -1
  126. package/packages/remote-control-server/web/dist/assets/{kanban-definition-UN3LZRKU-63WdwG-X.js → kanban-definition-UN3LZRKU-BsEGZsD1.js} +1 -1
  127. package/packages/remote-control-server/web/dist/assets/{linear-CeRljV9s.js → linear-Dj636PNG.js} +1 -1
  128. package/packages/remote-control-server/web/dist/assets/main-CkqtCllF.js +238 -0
  129. package/packages/remote-control-server/web/dist/assets/{mermaid-VLURNSYL-CG6yNR7g.js → mermaid-VLURNSYL-DutpHHm9.js} +4 -4
  130. package/packages/remote-control-server/web/dist/assets/{mermaid.core-CAuNNATY.js → mermaid.core-XHHf0pen.js} +5 -5
  131. package/packages/remote-control-server/web/dist/assets/{mindmap-definition-RKZ34NQL-9hDL1CUV.js → mindmap-definition-RKZ34NQL-BBa8V_3g.js} +1 -1
  132. package/packages/remote-control-server/web/dist/assets/{pieDiagram-4H26LBE5-BS_P2t04.js → pieDiagram-4H26LBE5-BuNEdo9H.js} +1 -1
  133. package/packages/remote-control-server/web/dist/assets/{quadrantDiagram-W4KKPZXB-Cp9QQkHV.js → quadrantDiagram-W4KKPZXB-CsJgyQIN.js} +1 -1
  134. package/packages/remote-control-server/web/dist/assets/{requirementDiagram-4Y6WPE33-C_XSzOKE.js → requirementDiagram-4Y6WPE33-DqMJZ914.js} +1 -1
  135. package/{dist/rcs-web/assets/sankeyDiagram-5OEKKPKP-BhuVqzZd.js → packages/remote-control-server/web/dist/assets/sankeyDiagram-5OEKKPKP-CVsz09q2.js} +1 -1
  136. package/{dist/rcs-web/assets/sequenceDiagram-3UESZ5HK-C3IPZrcW.js → packages/remote-control-server/web/dist/assets/sequenceDiagram-3UESZ5HK-BRp4Wddn.js} +1 -1
  137. package/packages/remote-control-server/web/dist/assets/{stateDiagram-AJRCARHV-CN4iNPRl.js → stateDiagram-AJRCARHV-S-QqQr-D.js} +1 -1
  138. package/packages/remote-control-server/web/dist/assets/{stateDiagram-v2-BHNVJYJU-CICBlDSJ.js → stateDiagram-v2-BHNVJYJU-D77KfDr-.js} +1 -1
  139. package/{dist/rcs-web/assets/timeline-definition-PNZ67QCA-Be7t_3rC.js → packages/remote-control-server/web/dist/assets/timeline-definition-PNZ67QCA-De8bFWnE.js} +1 -1
  140. package/packages/remote-control-server/web/dist/assets/{useTeams-DPHGnBHL.js → useTeams-CqJOqEy1.js} +1 -1
  141. package/packages/remote-control-server/web/dist/assets/{vennDiagram-CIIHVFJN-CSaUc2Xv.js → vennDiagram-CIIHVFJN-Dikwrn1L.js} +1 -1
  142. package/packages/remote-control-server/web/dist/assets/{wardleyDiagram-YWT4CUSO-DTuJrl9P.js → wardleyDiagram-YWT4CUSO-DUzpiV6H.js} +1 -1
  143. package/packages/remote-control-server/web/dist/assets/{workerType-CSqeySYe.js → workerType-DOQ0AHrq.js} +1 -1
  144. package/packages/remote-control-server/web/dist/assets/{xychartDiagram-2RQKCTM6-BQ0oU3Qi.js → xychartDiagram-2RQKCTM6-OZNbB32D.js} +1 -1
  145. package/packages/remote-control-server/web/dist/index.html +1 -1
  146. package/dist/rcs-web/assets/Dashboard-D_Im4UId.js +0 -1
  147. package/dist/rcs-web/assets/Join-BTnvMsB9.js +0 -1
  148. package/dist/rcs-web/assets/Login-ClT7RckC.js +0 -1
  149. package/dist/rcs-web/assets/Setup-PaDA6Et-.js +0 -1
  150. package/dist/rcs-web/assets/TeamCreate-249rK3U3.js +0 -1
  151. package/dist/rcs-web/assets/UserSettings-X627Fdni.js +0 -1
  152. package/dist/rcs-web/assets/channel-BUwWbT6U.js +0 -1
  153. package/dist/rcs-web/assets/classDiagram-4FO5ZUOK-DYtx22zv.js +0 -1
  154. package/dist/rcs-web/assets/classDiagram-v2-Q7XG4LA2-DYtx22zv.js +0 -1
  155. package/dist/rcs-web/assets/i18n-Dbt-vEQ3.js +0 -1
  156. package/dist/rcs-web/assets/main-DvfxciBy.js +0 -238
  157. package/packages/remote-control-server/web/dist/assets/Dashboard-D_Im4UId.js +0 -1
  158. package/packages/remote-control-server/web/dist/assets/Join-BTnvMsB9.js +0 -1
  159. package/packages/remote-control-server/web/dist/assets/Login-ClT7RckC.js +0 -1
  160. package/packages/remote-control-server/web/dist/assets/Setup-PaDA6Et-.js +0 -1
  161. package/packages/remote-control-server/web/dist/assets/TeamCreate-249rK3U3.js +0 -1
  162. package/packages/remote-control-server/web/dist/assets/UserSettings-X627Fdni.js +0 -1
  163. package/packages/remote-control-server/web/dist/assets/channel-BUwWbT6U.js +0 -1
  164. package/packages/remote-control-server/web/dist/assets/classDiagram-4FO5ZUOK-DYtx22zv.js +0 -1
  165. package/packages/remote-control-server/web/dist/assets/classDiagram-v2-Q7XG4LA2-DYtx22zv.js +0 -1
  166. package/packages/remote-control-server/web/dist/assets/i18n-Dbt-vEQ3.js +0 -1
  167. package/packages/remote-control-server/web/dist/assets/main-DvfxciBy.js +0 -238
@@ -0,0 +1,556 @@
1
+ import { describe, test, expect, beforeEach, mock } from 'bun:test'
2
+ import { randomUUID, createHash } from 'node:crypto'
3
+ import { tmpdir } from 'node:os'
4
+ import { resolve } from 'node:path'
5
+ import { Database } from 'bun:sqlite'
6
+ import { mockConfigModule } from './helpers/mock-config'
7
+
8
+ // Mock config before module imports
9
+ mock.module('../config', () => mockConfigModule())
10
+
11
+ import { migrateDatabase, initDatabase, resetDbSingleton, getDb } from '../db/sqlite'
12
+ import {
13
+ storeReset,
14
+ storeCreateSession,
15
+ storeCreateEnvironment,
16
+ storeUpdateSession,
17
+ storeDeleteSession,
18
+ storeUpdateEnvironment,
19
+ storeGetSession,
20
+ storeGetEnvironment,
21
+ storeBindSession,
22
+ storeIsSessionOwner,
23
+ } from '../store'
24
+ import {
25
+ isSessionVisibleToUser,
26
+ resolveOwnedWebSessionId,
27
+ } from '../services/session'
28
+
29
+ // ---------------------------------------------------------------------------
30
+ // Database helpers
31
+ // ---------------------------------------------------------------------------
32
+
33
+ function freshDb(): Database {
34
+ try {
35
+ resetDbSingleton()
36
+ } catch {
37
+ // ignore
38
+ }
39
+ const path = resolve(
40
+ tmpdir(),
41
+ `rcs-r2-${randomUUID().replace(/-/g, '').slice(0, 8)}.db`,
42
+ )
43
+ return initDatabase(path)
44
+ }
45
+
46
+ function seedUser(
47
+ db: Database,
48
+ opts: { id?: string; username?: string; role?: string },
49
+ ): string {
50
+ const id = opts.id || `usr_${randomUUID().replace(/-/g, '')}`
51
+ const now = new Date().toISOString()
52
+ db.query(
53
+ `INSERT INTO users (id, username, password_hash, role, created_at)
54
+ VALUES ($id, $username, 'hash', $role, $now)`,
55
+ ).run({
56
+ $id: id,
57
+ $username: opts.username || `user_${id.slice(0, 8)}`,
58
+ $role: opts.role || 'member',
59
+ $now: now,
60
+ })
61
+ return id
62
+ }
63
+
64
+ // ===========================================================================
65
+ // Task 1: Store dual-write consistency
66
+ // ===========================================================================
67
+
68
+ describe('Task 1: store dual-write consistency', () => {
69
+ let db: Database
70
+
71
+ beforeEach(() => {
72
+ storeReset()
73
+ db = freshDb()
74
+ })
75
+
76
+ describe('storeUpdateSession throws on DB failure', () => {
77
+ test('throws when DB write fails', () => {
78
+ const session = storeCreateSession({})
79
+ // Close DB to force a write failure
80
+ db.close()
81
+
82
+ expect(() => {
83
+ storeUpdateSession(session.id, { title: 'Updated' })
84
+ }).toThrow()
85
+ })
86
+
87
+ test('succeeds when DB is available', () => {
88
+ const session = storeCreateSession({})
89
+ const result = storeUpdateSession(session.id, { title: 'Updated' })
90
+ expect(result).toBe(true)
91
+ expect(storeGetSession(session.id)?.title).toBe('Updated')
92
+ })
93
+ })
94
+
95
+ describe('storeDeleteSession throws on DB failure', () => {
96
+ test('throws when DB write fails', () => {
97
+ const session = storeCreateSession({})
98
+ // Close DB to force a write failure
99
+ db.close()
100
+
101
+ expect(() => {
102
+ storeDeleteSession(session.id)
103
+ }).toThrow()
104
+ })
105
+
106
+ test('succeeds when DB is available', () => {
107
+ const session = storeCreateSession({})
108
+ const result = storeDeleteSession(session.id)
109
+ expect(result).toBe(true)
110
+ })
111
+ })
112
+
113
+ describe('storeUpdateEnvironment writes to DB', () => {
114
+ test('persists status change to DB', () => {
115
+ const env = storeCreateEnvironment({ secret: 'test-secret' })
116
+ storeUpdateEnvironment(env.id, { status: 'offline' })
117
+
118
+ // Verify DB was updated
119
+ const row = db
120
+ .query('SELECT status FROM environments WHERE id = $id')
121
+ .get({ $id: env.id }) as { status: string } | null
122
+ expect(row).not.toBeNull()
123
+ expect(row!.status).toBe('offline')
124
+ })
125
+
126
+ test('persists machineName to DB', () => {
127
+ const env = storeCreateEnvironment({ secret: 'test-secret' })
128
+ storeUpdateEnvironment(env.id, { machineName: 'my-machine' })
129
+
130
+ const row = db
131
+ .query('SELECT machine_name FROM environments WHERE id = $id')
132
+ .get({ $id: env.id }) as { machine_name: string } | null
133
+ expect(row).not.toBeNull()
134
+ expect(row!.machine_name).toBe('my-machine')
135
+ })
136
+
137
+ test('persists lastPollAt to DB', () => {
138
+ const env = storeCreateEnvironment({ secret: 'test-secret' })
139
+ const newDate = new Date('2026-06-15T12:00:00Z')
140
+ storeUpdateEnvironment(env.id, { lastPollAt: newDate })
141
+
142
+ const row = db
143
+ .query('SELECT last_poll_at FROM environments WHERE id = $id')
144
+ .get({ $id: env.id }) as { last_poll_at: string } | null
145
+ expect(row).not.toBeNull()
146
+ expect(row!.last_poll_at).toBe(newDate.toISOString())
147
+ })
148
+
149
+ test('persists multiple fields at once', () => {
150
+ const env = storeCreateEnvironment({ secret: 'test-secret' })
151
+ storeUpdateEnvironment(env.id, {
152
+ status: 'offline',
153
+ machineName: 'mac1',
154
+ })
155
+
156
+ const row = db
157
+ .query(
158
+ 'SELECT status, machine_name FROM environments WHERE id = $id',
159
+ )
160
+ .get({ $id: env.id }) as {
161
+ status: string
162
+ machine_name: string
163
+ } | null
164
+ expect(row).not.toBeNull()
165
+ expect(row!.status).toBe('offline')
166
+ expect(row!.machine_name).toBe('mac1')
167
+ })
168
+
169
+ test('returns false for non-existent environment', () => {
170
+ expect(storeUpdateEnvironment('env_no', { status: 'active' })).toBe(
171
+ false,
172
+ )
173
+ })
174
+
175
+ test('throws on DB failure', () => {
176
+ const env = storeCreateEnvironment({ secret: 'test-secret' })
177
+ db.close()
178
+
179
+ expect(() => {
180
+ storeUpdateEnvironment(env.id, { status: 'offline' })
181
+ }).toThrow()
182
+ })
183
+ })
184
+ })
185
+
186
+ // ===========================================================================
187
+ // Task 2: isSessionVisibleToUser + resolveOwnedWebSessionId with shares/teams
188
+ // ===========================================================================
189
+
190
+ describe('Task 2: session visibility with shares and teams', () => {
191
+ let db: Database
192
+
193
+ beforeEach(() => {
194
+ storeReset()
195
+ db = freshDb()
196
+ })
197
+
198
+ describe('isSessionVisibleToUser', () => {
199
+ test('returns owner for direct session owner', () => {
200
+ const userId = seedUser(db, { role: 'member' })
201
+ const session = storeCreateSession({})
202
+ storeBindSession(session.id, userId)
203
+
204
+ const result = isSessionVisibleToUser(session.id, userId, db)
205
+ expect(result).toBe('owner')
206
+ })
207
+
208
+ test('returns write for user with write share', () => {
209
+ const ownerId = seedUser(db, { role: 'member' })
210
+ const shareUserId = seedUser(db, {
211
+ username: 'shareuser',
212
+ role: 'member',
213
+ })
214
+ const session = storeCreateSession({})
215
+ storeBindSession(session.id, ownerId)
216
+
217
+ // Create a write share
218
+ const shareId = `share_${randomUUID().replace(/-/g, '')}`
219
+ const now = new Date().toISOString()
220
+ db.query(
221
+ `INSERT INTO session_shares (id, session_id, granted_to_user, permission, granted_by, granted_at)
222
+ VALUES ($id, $sessionId, $userId, 'write', $grantedBy, $now)`,
223
+ ).run({
224
+ $id: shareId,
225
+ $sessionId: session.id,
226
+ $userId: shareUserId,
227
+ $grantedBy: ownerId,
228
+ $now: now,
229
+ })
230
+
231
+ const result = isSessionVisibleToUser(session.id, shareUserId, db)
232
+ expect(result).toBe('write')
233
+ })
234
+
235
+ test('returns read for user with read share', () => {
236
+ const ownerId = seedUser(db, { role: 'member' })
237
+ const shareUserId = seedUser(db, {
238
+ username: 'reader',
239
+ role: 'member',
240
+ })
241
+ const session = storeCreateSession({})
242
+ storeBindSession(session.id, ownerId)
243
+
244
+ const shareId = `share_${randomUUID().replace(/-/g, '')}`
245
+ const now = new Date().toISOString()
246
+ db.query(
247
+ `INSERT INTO session_shares (id, session_id, granted_to_user, permission, granted_by, granted_at)
248
+ VALUES ($id, $sessionId, $userId, 'read', $grantedBy, $now)`,
249
+ ).run({
250
+ $id: shareId,
251
+ $sessionId: session.id,
252
+ $userId: shareUserId,
253
+ $grantedBy: ownerId,
254
+ $now: now,
255
+ })
256
+
257
+ const result = isSessionVisibleToUser(session.id, shareUserId, db)
258
+ expect(result).toBe('read')
259
+ })
260
+
261
+ test('returns null for expired share', () => {
262
+ const ownerId = seedUser(db, { role: 'member' })
263
+ const shareUserId = seedUser(db, {
264
+ username: 'expired',
265
+ role: 'member',
266
+ })
267
+ const session = storeCreateSession({})
268
+ storeBindSession(session.id, ownerId)
269
+
270
+ const shareId = `share_${randomUUID().replace(/-/g, '')}`
271
+ const pastDate = new Date('2020-01-01T00:00:00Z').toISOString()
272
+ const now = new Date().toISOString()
273
+ db.query(
274
+ `INSERT INTO session_shares (id, session_id, granted_to_user, permission, expires_at, granted_by, granted_at)
275
+ VALUES ($id, $sessionId, $userId, 'write', $exp, $grantedBy, $now)`,
276
+ ).run({
277
+ $id: shareId,
278
+ $sessionId: session.id,
279
+ $userId: shareUserId,
280
+ $exp: pastDate,
281
+ $grantedBy: ownerId,
282
+ $now: now,
283
+ })
284
+
285
+ const result = isSessionVisibleToUser(session.id, shareUserId, db)
286
+ expect(result).toBeNull()
287
+ })
288
+
289
+ test('returns owner for team owner when session owned by team', () => {
290
+ const userId = seedUser(db, { role: 'member' })
291
+ const teamId = `team_${randomUUID().replace(/-/g, '')}`
292
+ const now = new Date().toISOString()
293
+
294
+ // Create team and add user as owner
295
+ db.query(
296
+ `INSERT INTO teams (id, name, slug, created_by, created_at, updated_at)
297
+ VALUES ($id, 'Test Team', 'test-team-r2', $userId, $now, $now)`,
298
+ ).run({ $id: teamId, $userId: userId, $now: now })
299
+ db.query(
300
+ `INSERT INTO team_members (team_id, user_id, role, added_at, added_by)
301
+ VALUES ($teamId, $userId, 'owner', $now, $userId)`,
302
+ ).run({ $teamId: teamId, $userId: userId, $now: now })
303
+
304
+ // Create session owned by team
305
+ const session = storeCreateSession({})
306
+ storeBindSession(session.id, teamId, 'team')
307
+
308
+ const result = isSessionVisibleToUser(session.id, userId, db)
309
+ expect(result).toBe('owner')
310
+ })
311
+
312
+ test('returns read for team share', () => {
313
+ const ownerId = seedUser(db, { role: 'member' })
314
+ const userId = seedUser(db, {
315
+ username: 'teammember',
316
+ role: 'member',
317
+ })
318
+ const teamId = `team_${randomUUID().replace(/-/g, '')}`
319
+ const now = new Date().toISOString()
320
+
321
+ // Create team and add user as member
322
+ db.query(
323
+ `INSERT INTO teams (id, name, slug, created_by, created_at, updated_at)
324
+ VALUES ($id, 'Share Team', 'share-team-r2', $ownerId, $now, $now)`,
325
+ ).run({ $id: teamId, $ownerId: ownerId, $now: now })
326
+ db.query(
327
+ `INSERT INTO team_members (team_id, user_id, role, added_at, added_by)
328
+ VALUES ($teamId, $userId, 'member', $now, $ownerId)`,
329
+ ).run({ $teamId: teamId, $userId: userId, $now: now, $ownerId: ownerId })
330
+
331
+ // Create session and share to team
332
+ const session = storeCreateSession({})
333
+ storeBindSession(session.id, ownerId)
334
+
335
+ const shareId = `share_${randomUUID().replace(/-/g, '')}`
336
+ db.query(
337
+ `INSERT INTO session_shares (id, session_id, granted_to_team, permission, granted_by, granted_at)
338
+ VALUES ($id, $sessionId, $teamId, 'read', $grantedBy, $now)`,
339
+ ).run({
340
+ $id: shareId,
341
+ $sessionId: session.id,
342
+ $teamId: teamId,
343
+ $grantedBy: ownerId,
344
+ $now: now,
345
+ })
346
+
347
+ const result = isSessionVisibleToUser(session.id, userId, db)
348
+ expect(result).toBe('read')
349
+ })
350
+
351
+ test('returns null for user with no access', () => {
352
+ const ownerId = seedUser(db, { role: 'member' })
353
+ const otherUserId = seedUser(db, {
354
+ username: 'outsider',
355
+ role: 'member',
356
+ })
357
+ const session = storeCreateSession({})
358
+ storeBindSession(session.id, ownerId)
359
+
360
+ const result = isSessionVisibleToUser(session.id, otherUserId, db)
361
+ expect(result).toBeNull()
362
+ })
363
+ })
364
+
365
+ describe('resolveOwnedWebSessionId with shares', () => {
366
+ test('resolves session for user with write share', () => {
367
+ const ownerId = seedUser(db, { role: 'member' })
368
+ const shareUserId = seedUser(db, {
369
+ username: 'writer',
370
+ role: 'member',
371
+ })
372
+ const session = storeCreateSession({})
373
+ storeBindSession(session.id, ownerId)
374
+
375
+ const shareId = `share_${randomUUID().replace(/-/g, '')}`
376
+ const now = new Date().toISOString()
377
+ db.query(
378
+ `INSERT INTO session_shares (id, session_id, granted_to_user, permission, granted_by, granted_at)
379
+ VALUES ($id, $sessionId, $userId, 'write', $grantedBy, $now)`,
380
+ ).run({
381
+ $id: shareId,
382
+ $sessionId: session.id,
383
+ $userId: shareUserId,
384
+ $grantedBy: ownerId,
385
+ $now: now,
386
+ })
387
+
388
+ // Write-level check: should resolve for write share
389
+ const resolved = resolveOwnedWebSessionId(session.id, shareUserId, true)
390
+ expect(resolved).toBe(session.id)
391
+ })
392
+
393
+ test('resolves session for user with read share (read-only)', () => {
394
+ const ownerId = seedUser(db, { role: 'member' })
395
+ const shareUserId = seedUser(db, {
396
+ username: 'reader2',
397
+ role: 'member',
398
+ })
399
+ const session = storeCreateSession({})
400
+ storeBindSession(session.id, ownerId)
401
+
402
+ const shareId = `share_${randomUUID().replace(/-/g, '')}`
403
+ const now = new Date().toISOString()
404
+ db.query(
405
+ `INSERT INTO session_shares (id, session_id, granted_to_user, permission, granted_by, granted_at)
406
+ VALUES ($id, $sessionId, $userId, 'read', $grantedBy, $now)`,
407
+ ).run({
408
+ $id: shareId,
409
+ $sessionId: session.id,
410
+ $userId: shareUserId,
411
+ $grantedBy: ownerId,
412
+ $now: now,
413
+ })
414
+
415
+ // Read-level check: should resolve
416
+ const resolved = resolveOwnedWebSessionId(session.id, shareUserId, false)
417
+ expect(resolved).toBe(session.id)
418
+
419
+ // Write-level check: should NOT resolve (read-only share)
420
+ const writeResolved = resolveOwnedWebSessionId(
421
+ session.id,
422
+ shareUserId,
423
+ true,
424
+ )
425
+ expect(writeResolved).toBeNull()
426
+ })
427
+
428
+ test('resolves session for team member when team owns session', () => {
429
+ const userId = seedUser(db, { role: 'member' })
430
+ const teamId = `team_${randomUUID().replace(/-/g, '')}`
431
+ const now = new Date().toISOString()
432
+
433
+ db.query(
434
+ `INSERT INTO teams (id, name, slug, created_by, created_at, updated_at)
435
+ VALUES ($id, 'Resolve Team', 'resolve-team-r2', $userId, $now, $now)`,
436
+ ).run({ $id: teamId, $userId: userId, $now: now })
437
+ db.query(
438
+ `INSERT INTO team_members (team_id, user_id, role, added_at, added_by)
439
+ VALUES ($teamId, $userId, 'owner', $now, $userId)`,
440
+ ).run({ $teamId: teamId, $userId: userId, $now: now })
441
+
442
+ const session = storeCreateSession({})
443
+ storeBindSession(session.id, teamId, 'team')
444
+
445
+ const resolved = resolveOwnedWebSessionId(session.id, userId, true)
446
+ expect(resolved).toBe(session.id)
447
+ })
448
+ })
449
+ })
450
+
451
+ // ===========================================================================
452
+ // Task 3: teams.ts admin created_by determinism
453
+ // ===========================================================================
454
+
455
+ describe('Task 3: admin created_by for team creation', () => {
456
+ let db: Database
457
+
458
+ beforeEach(() => {
459
+ storeReset()
460
+ db = freshDb()
461
+ })
462
+
463
+ test('admin query uses ORDER BY created_at ASC for determinism', () => {
464
+ // Create two admins with different creation times
465
+ const now1 = new Date('2026-01-01T00:00:00Z').toISOString()
466
+ const now2 = new Date('2026-06-01T00:00:00Z').toISOString()
467
+
468
+ db.query(
469
+ `INSERT INTO users (id, username, password_hash, role, created_at)
470
+ VALUES ('usr_second_admin', 'admin2', 'hash', 'admin', $now2)`,
471
+ ).run({ $now2: now2 })
472
+ db.query(
473
+ `INSERT INTO users (id, username, password_hash, role, created_at)
474
+ VALUES ('usr_first_admin', 'admin1', 'hash', 'admin', $now1)`,
475
+ ).run({ $now1: now1 })
476
+
477
+ // The query used in teams.ts should pick the earliest admin
478
+ const adminUser = db
479
+ .query(
480
+ "SELECT id FROM users WHERE role = 'admin' ORDER BY created_at ASC LIMIT 1",
481
+ )
482
+ .get() as { id: string } | null
483
+
484
+ expect(adminUser).not.toBeNull()
485
+ expect(adminUser!.id).toBe('usr_first_admin')
486
+ })
487
+
488
+ test('no admin user returns null (for 400 response)', () => {
489
+ // No admin users in DB
490
+ const adminUser = db
491
+ .query(
492
+ "SELECT id FROM users WHERE role = 'admin' ORDER BY created_at ASC LIMIT 1",
493
+ )
494
+ .get() as { id: string } | null
495
+
496
+ expect(adminUser).toBeNull()
497
+ })
498
+ })
499
+
500
+ // ===========================================================================
501
+ // Task 4: API key session creation should not bind __system__
502
+ // ===========================================================================
503
+
504
+ describe('Task 4: API key session creation skips __system__ binding', () => {
505
+ let db: Database
506
+
507
+ beforeEach(() => {
508
+ storeReset()
509
+ db = freshDb()
510
+ })
511
+
512
+ test('session created without binding when userId is __system__', () => {
513
+ const session = storeCreateSession({ source: 'web' })
514
+ // Simulate the fixed logic: skip bind when userId is __system__
515
+ const userId = '__system__'
516
+ if (userId !== '__system__') {
517
+ storeBindSession(session.id, userId)
518
+ }
519
+
520
+ // Verify no ownership was created
521
+ const isOwner = storeIsSessionOwner(session.id, '__system__')
522
+ expect(isOwner).toBe(false)
523
+ })
524
+
525
+ test('session is bound when X-User-Id header provides real user', () => {
526
+ const realUserId = seedUser(db, { role: 'member' })
527
+ const session = storeCreateSession({ source: 'web' })
528
+
529
+ // Simulate: API key auth + X-User-Id header
530
+ const userId = '__system__'
531
+ const headerUserId = realUserId
532
+ if (userId === '__system__' && headerUserId) {
533
+ storeBindSession(session.id, headerUserId)
534
+ } else if (userId !== '__system__') {
535
+ storeBindSession(session.id, userId)
536
+ }
537
+
538
+ expect(storeIsSessionOwner(session.id, realUserId)).toBe(true)
539
+ expect(storeIsSessionOwner(session.id, '__system__')).toBe(false)
540
+ })
541
+
542
+ test('session is orphan when API key without X-User-Id', () => {
543
+ const session = storeCreateSession({ source: 'web' })
544
+
545
+ // Simulate: API key auth without X-User-Id
546
+ const userId = '__system__'
547
+ const headerUserId: string | undefined = undefined
548
+ if (userId === '__system__' && headerUserId) {
549
+ storeBindSession(session.id, headerUserId)
550
+ } else if (userId !== '__system__') {
551
+ storeBindSession(session.id, userId)
552
+ }
553
+
554
+ expect(storeIsSessionOwner(session.id, '__system__')).toBe(false)
555
+ })
556
+ })