@synopackageland/cli 0.4.1 → 0.5.3

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 (699) hide show
  1. package/README.md +7 -3
  2. package/dist/authorization-sdk.d.ts +5 -0
  3. package/dist/authorization-sdk.js +5 -0
  4. package/dist/build-spk/delete-app-data.d.ts +27 -7
  5. package/dist/build-spk/delete-app-data.js +35 -34
  6. package/dist/build-spk/dsm-arch.d.ts +6 -1
  7. package/dist/build-spk/dsm-arch.js +25 -1
  8. package/dist/build-spk/dsm-version.d.ts +14 -0
  9. package/dist/build-spk/dsm-version.js +47 -0
  10. package/dist/build-spk/gateway.d.ts +31 -0
  11. package/dist/build-spk/gateway.js +55 -0
  12. package/dist/build-spk/generator.d.ts +5 -0
  13. package/dist/build-spk/generator.js +103 -107
  14. package/dist/build-spk/install-wizard.d.ts +20 -0
  15. package/dist/build-spk/install-wizard.js +76 -0
  16. package/dist/build-spk/native-lifecycle.d.ts +5 -0
  17. package/dist/build-spk/native-lifecycle.js +12 -2
  18. package/dist/build-spk/resource-worker.d.ts +9 -4
  19. package/dist/build-spk/resource-worker.js +15 -6
  20. package/dist/build-spk/share-combobox.d.ts +3 -0
  21. package/dist/build-spk/share-combobox.js +27 -0
  22. package/dist/build-spk/uninstall-wizard.d.ts +14 -0
  23. package/dist/build-spk/uninstall-wizard.js +33 -0
  24. package/dist/build-spk/wizard-i18n.d.ts +18 -0
  25. package/dist/build-spk/wizard-i18n.js +38 -0
  26. package/dist/build-spk/wizard-messages.d.ts +388 -0
  27. package/dist/build-spk/wizard-messages.js +387 -0
  28. package/dist/cli.js +132 -32
  29. package/dist/compose/analyze.d.ts +20 -0
  30. package/dist/compose/analyze.js +75 -11
  31. package/dist/contract/validate.js +33 -1
  32. package/dist/contract/web-launch.d.ts +22 -0
  33. package/dist/contract/web-launch.js +37 -0
  34. package/dist/deploy/deploy.d.ts +3 -0
  35. package/dist/deploy/deploy.js +11 -2
  36. package/dist/error-registry.js +62 -3
  37. package/dist/host/dsm-port-profile.d.ts +1 -1
  38. package/dist/host/dsm-port-profile.js +1 -1
  39. package/dist/host/open-url.d.ts +2 -0
  40. package/dist/host/open-url.js +4 -1
  41. package/dist/images/pin.d.ts +52 -0
  42. package/dist/images/pin.js +249 -0
  43. package/dist/init.d.ts +27 -3
  44. package/dist/init.js +126 -16
  45. package/dist/inspect.d.ts +3 -0
  46. package/dist/inspect.js +15 -3
  47. package/dist/standalone/authorization-window.d.ts +2 -0
  48. package/dist/standalone/authorization-window.js +28 -0
  49. package/dist/standalone/authorization.d.ts +48 -0
  50. package/dist/standalone/authorization.js +116 -0
  51. package/dist/standalone/background.d.ts +21 -0
  52. package/dist/standalone/background.js +52 -0
  53. package/dist/standalone/binary.d.ts +1 -0
  54. package/dist/standalone/binary.js +1 -1
  55. package/dist/standalone/build.d.ts +2 -0
  56. package/dist/standalone/build.js +54 -10
  57. package/dist/standalone/dsm-window.js +10 -3
  58. package/dist/standalone/helper-inventory.d.ts +15 -0
  59. package/dist/standalone/helper-inventory.js +9 -0
  60. package/dist/standalone/helper.d.ts +1 -0
  61. package/dist/standalone/helper.js +29 -11
  62. package/dist/standalone/host-adapter.d.ts +1 -1
  63. package/dist/standalone/host-adapter.js +33 -15
  64. package/dist/standalone/host-file-navigation.d.ts +7 -0
  65. package/dist/standalone/host-file-navigation.js +172 -0
  66. package/dist/standalone/inspect-helper.js +21 -6
  67. package/dist/standalone/inspect-spk.d.ts +1 -1
  68. package/dist/standalone/inspect-spk.js +211 -7
  69. package/dist/standalone/job-diagnostics.d.ts +1 -0
  70. package/dist/standalone/job-diagnostics.js +49 -0
  71. package/dist/standalone/lifecycle-helper.d.ts +1 -1
  72. package/dist/standalone/lifecycle-helper.js +2 -2
  73. package/dist/standalone/lifecycle.d.ts +1 -1
  74. package/dist/standalone/lifecycle.js +14 -4
  75. package/dist/standalone/manifest.d.ts +15 -2
  76. package/dist/standalone/manifest.js +37 -6
  77. package/dist/standalone/native-layout.d.ts +74 -0
  78. package/dist/standalone/native-layout.js +318 -0
  79. package/dist/standalone/resource.d.ts +11 -0
  80. package/dist/standalone/resource.js +13 -0
  81. package/dist/standalone/root-ops.d.ts +2 -0
  82. package/dist/standalone/root-ops.js +10 -0
  83. package/dist/standalone/root-window.d.ts +3 -1
  84. package/dist/standalone/root-window.js +156 -38
  85. package/dist/standalone/shared-folder.d.ts +39 -0
  86. package/dist/standalone/shared-folder.js +141 -0
  87. package/dist/standalone/spk.d.ts +4 -0
  88. package/dist/standalone/spk.js +47 -3
  89. package/dist/standalone/worker-contract-json.d.ts +8 -0
  90. package/dist/standalone/worker-contract-json.js +141 -0
  91. package/dist/standalone/worker-contract.d.ts +189 -0
  92. package/dist/standalone/worker-contract.js +175 -0
  93. package/dist/standalone/worker-registry.d.ts +40 -0
  94. package/dist/standalone/worker-registry.js +167 -0
  95. package/dist/templates/_authorization/main.go +104 -0
  96. package/dist/templates/_authorization/main_test.go +35 -0
  97. package/dist/templates/_daemon/go.mod +2 -0
  98. package/dist/templates/_gateway/auth.go +101 -0
  99. package/dist/templates/_gateway/auth_test.go +216 -0
  100. package/dist/templates/_gateway/cgi.go +133 -0
  101. package/dist/templates/_gateway/cgi_test.go +156 -0
  102. package/dist/templates/_gateway/csrf.go +73 -0
  103. package/dist/templates/_gateway/csrf_test.go +155 -0
  104. package/dist/templates/_gateway/directory.go +108 -0
  105. package/dist/templates/_gateway/directory_test.go +202 -0
  106. package/dist/templates/_gateway/gateway.go +412 -0
  107. package/dist/templates/_gateway/gateway_test.go +676 -0
  108. package/dist/templates/_gateway/go.mod +3 -0
  109. package/dist/templates/_gateway/groups.go +66 -0
  110. package/dist/templates/_gateway/main.go +45 -0
  111. package/dist/templates/binary/synology-app.yaml +1 -1
  112. package/dist/templates/compose-import/compose.yaml +1 -1
  113. package/dist/templates/compose-import/synology-app.yaml +1 -1
  114. package/dist/templates/hello-files/compose.yaml +1 -1
  115. package/dist/templates/hello-files/synology-app.yaml +1 -1
  116. package/dist/templates/native-go/README.md +118 -5
  117. package/dist/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +3 -1
  118. package/dist/templates/native-go/backend/cmd/app/main.go +25 -6
  119. package/dist/templates/native-go/backend/cmd/app/sdk_main.go +62 -0
  120. package/dist/templates/native-go/backend/cmd/background-worker/main.go +38 -0
  121. package/dist/templates/native-go/backend/cmd/helper/main.go +27 -1
  122. package/dist/templates/native-go/backend/cmd/helper/sdk_registry.go +19 -0
  123. package/dist/templates/native-go/backend/go.mod +5 -3
  124. package/dist/templates/native-go/backend/go.sum +4 -4
  125. package/dist/templates/native-go/backend/internal/api/registry.go +17 -6
  126. package/dist/templates/native-go/backend/internal/api/server.go +7 -1
  127. package/dist/templates/native-go/backend/internal/app/authorization_none.go +5 -0
  128. package/dist/templates/native-go/backend/internal/app/background.go +270 -0
  129. package/dist/templates/native-go/backend/internal/app/background_none.go +8 -0
  130. package/dist/templates/native-go/backend/internal/app/background_owner.go +59 -0
  131. package/dist/templates/native-go/backend/internal/app/background_owner_test.go +145 -0
  132. package/dist/templates/native-go/backend/internal/app/background_schedule.go +74 -0
  133. package/dist/templates/native-go/backend/internal/app/background_schedule_test.go +62 -0
  134. package/dist/templates/native-go/backend/internal/app/background_test.go +346 -0
  135. package/dist/templates/native-go/backend/internal/app/integration_state.go +16 -0
  136. package/dist/templates/native-go/backend/internal/app/migrations.go +41 -0
  137. package/dist/templates/native-go/backend/internal/app/migrations_test.go +41 -0
  138. package/dist/templates/native-go/backend/internal/app/nas_cgi_artifact_test.go +8 -0
  139. package/dist/templates/native-go/backend/internal/app/routes.go +22 -5
  140. package/dist/templates/native-go/backend/internal/app/routes_test.go +20 -3
  141. package/dist/templates/native-go/backend/internal/app/sdk_jobs.go +70 -0
  142. package/dist/templates/native-go/backend/internal/app/sdk_jobs_test.go +116 -0
  143. package/dist/templates/native-go/backend/internal/app/sdk_routes.go +177 -0
  144. package/dist/templates/native-go/backend/internal/app/session_files.go +15 -0
  145. package/dist/templates/native-go/backend/internal/app/session_files_test.go +26 -0
  146. package/dist/templates/native-go/backend/internal/app/shared_folder.go +144 -0
  147. package/dist/templates/native-go/backend/internal/app/shared_folder_test.go +158 -0
  148. package/dist/templates/native-go/backend/internal/background/access.go +57 -0
  149. package/dist/templates/native-go/backend/internal/background/owner_test.go +126 -0
  150. package/dist/templates/native-go/backend/internal/background/runner.go +185 -0
  151. package/dist/templates/native-go/backend/internal/background/runner_test.go +209 -0
  152. package/dist/templates/native-go/backend/internal/background/schedule.go +300 -0
  153. package/dist/templates/native-go/backend/internal/background/schedule_test.go +335 -0
  154. package/dist/templates/native-go/backend/internal/background/store.go +807 -0
  155. package/dist/templates/native-go/backend/internal/background/store_test.go +407 -0
  156. package/dist/templates/native-go/backend/internal/datamigrate/migrate.go +191 -0
  157. package/dist/templates/native-go/backend/internal/datamigrate/migrate_test.go +177 -0
  158. package/dist/templates/native-go/backend/internal/filestation/browse_test.go +67 -0
  159. package/dist/templates/native-go/backend/internal/filestation/client.go +251 -0
  160. package/dist/templates/native-go/backend/internal/filestation/client_test.go +155 -0
  161. package/dist/templates/native-go/backend/internal/filestation/doc.go +4 -0
  162. package/dist/templates/native-go/backend/internal/filestation/read_file_test.go +90 -0
  163. package/dist/templates/native-go/backend/internal/filestation/repository.go +207 -0
  164. package/dist/templates/native-go/backend/internal/filestation/repository_test.go +104 -0
  165. package/dist/templates/native-go/backend/internal/filestation/sdk_session.go +241 -0
  166. package/dist/templates/native-go/backend/internal/filestation/sdk_session_test.go +183 -0
  167. package/dist/templates/native-go/backend/internal/filestation/service.go +254 -0
  168. package/dist/templates/native-go/backend/internal/filestation/service_test.go +94 -0
  169. package/dist/templates/native-go/backend/internal/filestation/session_semantics_test.go +383 -0
  170. package/dist/templates/native-go/backend/internal/filestation/write.go +72 -0
  171. package/dist/templates/native-go/backend/internal/filestation/write_test.go +123 -0
  172. package/dist/templates/native-go/backend/internal/helper/background_proof.go +163 -0
  173. package/dist/templates/native-go/backend/internal/helper/background_proof_contract.go +46 -0
  174. package/dist/templates/native-go/backend/internal/helper/background_proof_test.go +161 -0
  175. package/dist/templates/native-go/backend/internal/helper/data_contract.go +3 -0
  176. package/dist/templates/native-go/backend/internal/helper/data_protocol.go +3 -0
  177. package/dist/templates/native-go/backend/internal/helper/data_protocol_test.go +1 -1
  178. package/dist/templates/native-go/backend/internal/helper/grant_authority.go +3 -0
  179. package/dist/templates/native-go/backend/internal/helper/grant_authority_test.go +1 -1
  180. package/dist/templates/native-go/backend/internal/helper/grant_repository_linux.go +2 -1
  181. package/dist/templates/native-go/backend/internal/helper/grant_repository_linux_test.go +4 -3
  182. package/dist/templates/native-go/backend/internal/helper/grant_snapshot.go +3 -0
  183. package/dist/templates/native-go/backend/internal/helper/jobcontract/bindings.go +48 -0
  184. package/dist/templates/native-go/backend/internal/helper/jobcontract/contract_test.go +436 -0
  185. package/dist/templates/native-go/backend/internal/helper/jobcontract/decode.go +185 -0
  186. package/dist/templates/native-go/backend/internal/helper/jobcontract/digest.go +55 -0
  187. package/dist/templates/native-go/backend/internal/helper/jobcontract/registry.go +85 -0
  188. package/dist/templates/native-go/backend/internal/helper/jobcontract/registry_test.go +73 -0
  189. package/dist/templates/native-go/backend/internal/helper/jobcontract/result.go +53 -0
  190. package/dist/templates/native-go/backend/internal/helper/jobcontract/stub.go +8 -0
  191. package/dist/templates/native-go/backend/internal/helper/jobcontract/testdata/input-digests.json +127 -0
  192. package/dist/templates/native-go/backend/internal/helper/jobcontract/types.go +234 -0
  193. package/dist/templates/native-go/backend/internal/helper/jobcontract/types_test.go +29 -0
  194. package/dist/templates/native-go/backend/internal/helper/jobcontract/validate.go +462 -0
  195. package/dist/templates/native-go/backend/internal/helper/legacy_authority_schema_linux_test.go +34 -0
  196. package/dist/templates/native-go/backend/internal/helper/legacy_authority_schema_test.go +6 -0
  197. package/dist/templates/native-go/backend/internal/helper/management.go +86 -0
  198. package/dist/templates/native-go/backend/internal/helper/observation.go +42 -2
  199. package/dist/templates/native-go/backend/internal/helper/observation_health_test.go +13 -1
  200. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic.go +56 -10
  201. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic_linux_test.go +6 -0
  202. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic_writer.go +40 -0
  203. package/dist/templates/native-go/backend/internal/helper/process_linux.go +3 -0
  204. package/dist/templates/native-go/backend/internal/helper/purge.go +115 -0
  205. package/dist/templates/native-go/backend/internal/helper/purge_test.go +59 -0
  206. package/dist/templates/native-go/backend/internal/helper/query_deadline_linux_test.go +115 -0
  207. package/dist/templates/native-go/backend/internal/helper/query_pending_diagnostic_test.go +254 -0
  208. package/dist/templates/native-go/backend/internal/helper/relaxed_invalidation.go +3 -0
  209. package/dist/templates/native-go/backend/internal/helper/revoke.go +109 -0
  210. package/dist/templates/native-go/backend/internal/helper/revoke_test.go +121 -0
  211. package/dist/templates/native-go/backend/internal/helper/s1r_actor_races_linux_test.go +23 -4
  212. package/dist/templates/native-go/backend/internal/helper/sdk_assembly_linux.go +51 -0
  213. package/dist/templates/native-go/backend/internal/helper/sdk_attach.go +83 -0
  214. package/dist/templates/native-go/backend/internal/helper/sdk_attach_contract.go +32 -0
  215. package/dist/templates/native-go/backend/internal/helper/sdk_attach_test.go +184 -0
  216. package/dist/templates/native-go/backend/internal/helper/sdk_authority_schema_test.go +6 -0
  217. package/dist/templates/native-go/backend/internal/helper/sdk_background_authority.go +832 -0
  218. package/dist/templates/native-go/backend/internal/helper/sdk_background_authority_test.go +714 -0
  219. package/dist/templates/native-go/backend/internal/helper/sdk_background_invalidation.go +218 -0
  220. package/dist/templates/native-go/backend/internal/helper/sdk_background_lease.go +218 -0
  221. package/dist/templates/native-go/backend/internal/helper/sdk_background_snapshot.go +110 -0
  222. package/dist/templates/native-go/backend/internal/helper/sdk_background_store_linux_test.go +261 -0
  223. package/dist/templates/native-go/backend/internal/helper/sdk_background_store_test.go +58 -0
  224. package/dist/templates/native-go/backend/internal/helper/sdk_bindings.go +60 -0
  225. package/dist/templates/native-go/backend/internal/helper/sdk_data_contract.go +251 -0
  226. package/dist/templates/native-go/backend/internal/helper/sdk_data_protocol.go +424 -0
  227. package/dist/templates/native-go/backend/internal/helper/sdk_dispatch_absence_test.go +51 -0
  228. package/dist/templates/native-go/backend/internal/helper/sdk_display.go +488 -0
  229. package/dist/templates/native-go/backend/internal/helper/sdk_display_contract.go +121 -0
  230. package/dist/templates/native-go/backend/internal/helper/sdk_display_test.go +459 -0
  231. package/dist/templates/native-go/backend/internal/helper/sdk_grant_authority.go +559 -0
  232. package/dist/templates/native-go/backend/internal/helper/sdk_grant_repository_linux.go +417 -0
  233. package/dist/templates/native-go/backend/internal/helper/sdk_grant_snapshot.go +94 -0
  234. package/dist/templates/native-go/backend/internal/helper/sdk_history.go +80 -0
  235. package/dist/templates/native-go/backend/internal/helper/sdk_history_test.go +76 -0
  236. package/dist/templates/native-go/backend/internal/helper/sdk_job.go +697 -0
  237. package/dist/templates/native-go/backend/internal/helper/sdk_job_child_linux.go +309 -0
  238. package/dist/templates/native-go/backend/internal/helper/sdk_job_contract.go +122 -0
  239. package/dist/templates/native-go/backend/internal/helper/sdk_job_linux_test.go +159 -0
  240. package/dist/templates/native-go/backend/internal/helper/sdk_job_process_linux.go +327 -0
  241. package/dist/templates/native-go/backend/internal/helper/sdk_job_test.go +501 -0
  242. package/dist/templates/native-go/backend/internal/helper/sdk_job_vm_linux_test.go +343 -0
  243. package/dist/templates/native-go/backend/internal/helper/sdk_journal.go +77 -0
  244. package/dist/templates/native-go/backend/internal/helper/sdk_journal_linux.go +244 -0
  245. package/dist/templates/native-go/backend/internal/helper/sdk_journal_linux_test.go +295 -0
  246. package/dist/templates/native-go/backend/internal/helper/sdk_journal_test.go +71 -0
  247. package/dist/templates/native-go/backend/internal/helper/sdk_picker_test.go +50 -0
  248. package/dist/templates/native-go/backend/internal/helper/sdk_process_linux.go +184 -0
  249. package/dist/templates/native-go/backend/internal/helper/sdk_public_vm_linux_test.go +129 -0
  250. package/dist/templates/native-go/backend/internal/helper/sdk_relaxed_invalidation.go +242 -0
  251. package/dist/templates/native-go/backend/internal/helper/sdk_rpc.go +299 -0
  252. package/dist/templates/native-go/backend/internal/helper/sdk_rpc_contract.go +70 -0
  253. package/dist/templates/native-go/backend/internal/helper/sdk_rpc_test.go +135 -0
  254. package/dist/templates/native-go/backend/internal/helper/sdk_server_linux.go +161 -0
  255. package/dist/templates/native-go/backend/internal/helper/sdk_session.go +677 -0
  256. package/dist/templates/native-go/backend/internal/helper/sdk_session_contract.go +72 -0
  257. package/dist/templates/native-go/backend/internal/helper/sdk_session_fence_test.go +215 -0
  258. package/dist/templates/native-go/backend/internal/helper/sdk_session_test.go +475 -0
  259. package/dist/templates/native-go/backend/internal/helper/sdk_supervisor_frame.go +78 -0
  260. package/dist/templates/native-go/backend/internal/helper/sdk_supervisor_linux.go +414 -0
  261. package/dist/templates/native-go/backend/internal/helper/sdk_transport.go +79 -0
  262. package/dist/templates/native-go/backend/internal/helper/sdk_transport_linux.go +82 -0
  263. package/dist/templates/native-go/backend/internal/helper/sdk_transport_test.go +64 -0
  264. package/dist/templates/native-go/backend/internal/helper/server_linux.go +14 -2
  265. package/dist/templates/native-go/backend/internal/helper/stale_management_linux_test.go +126 -0
  266. package/dist/templates/native-go/backend/internal/helper/stale_management_test.go +122 -0
  267. package/dist/templates/native-go/backend/internal/helper/startup_diagnostic.go +68 -0
  268. package/dist/templates/native-go/backend/internal/helper/startup_diagnostic_linux_test.go +126 -0
  269. package/dist/templates/native-go/backend/internal/helper/startup_diagnostic_test.go +117 -0
  270. package/dist/templates/native-go/backend/internal/helper/status.go +22 -13
  271. package/dist/templates/native-go/backend/internal/helper/status_test.go +45 -0
  272. package/dist/templates/native-go/backend/internal/helper/supervision.go +1 -1
  273. package/dist/templates/native-go/backend/internal/helper/supervisor_frame.go +3 -0
  274. package/dist/templates/native-go/backend/internal/helper/supervisor_linux.go +6 -2
  275. package/dist/templates/native-go/backend/internal/helper/unit_connection_test.go +22 -4
  276. package/dist/templates/native-go/backend/internal/helper/unit_linux.go +7 -3
  277. package/dist/templates/native-go/backend/internal/helper/unit_query_linux.go +5 -1
  278. package/dist/templates/native-go/backend/internal/helper/write_files_linux.go +7 -4
  279. package/dist/templates/native-go/backend/internal/helper/write_files_linux_test.go +26 -0
  280. package/dist/templates/native-go/dsm-package.yaml +2 -2
  281. package/dist/templates/native-go-authorization/backend/internal/app/authorization.go +298 -0
  282. package/dist/templates/native-go-authorization/backend/internal/app/authorization_test.go +96 -0
  283. package/dist/templates/native-go-authorization/frontend/src/authorization/AuthorizationGate.vue +89 -0
  284. package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/de.json +36 -0
  285. package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/en.json +36 -0
  286. package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/es.json +36 -0
  287. package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/fr.json +36 -0
  288. package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/index.ts +15 -0
  289. package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/it.json +36 -0
  290. package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/ja.json +36 -0
  291. package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/ko.json +36 -0
  292. package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/zh-CN.json +36 -0
  293. package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/zh-TW.json +36 -0
  294. package/dist/templates/native-go-authorization/frontend/test/authorization-preview.html +14 -0
  295. package/dist/templates/native-go-authorization/frontend/test/authorization.test.ts +59 -0
  296. package/dist/templates/native-go-background/BACKGROUND.md +111 -0
  297. package/dist/templates/native-go-background/backend/internal/app/background_on.go +7 -0
  298. package/dist/templates/native-go-background/backend/internal/app/background_routes_test.go +32 -0
  299. package/dist/templates/native-go-background/frontend/src/background/BackgroundPanel.vue +178 -0
  300. package/dist/templates/native-go-background/frontend/src/background/i18n/de.json +83 -0
  301. package/dist/templates/native-go-background/frontend/src/background/i18n/en.json +83 -0
  302. package/dist/templates/native-go-background/frontend/src/background/i18n/es.json +83 -0
  303. package/dist/templates/native-go-background/frontend/src/background/i18n/fr.json +83 -0
  304. package/dist/templates/native-go-background/frontend/src/background/i18n/it.json +83 -0
  305. package/dist/templates/native-go-background/frontend/src/background/i18n/ja.json +83 -0
  306. package/dist/templates/native-go-background/frontend/src/background/i18n/ko.json +83 -0
  307. package/dist/templates/native-go-background/frontend/src/background/i18n/zh-CN.json +83 -0
  308. package/dist/templates/native-go-background/frontend/src/background/i18n/zh-TW.json +83 -0
  309. package/dist/templates/native-go-background/frontend/src/background/i18n.ts +19 -0
  310. package/dist/templates/native-go-background/frontend/src/background/picker-provider.ts +13 -0
  311. package/dist/templates/native-go-background/frontend/test/background.test.ts +179 -0
  312. package/dist/templates/native-go-integration/backend/internal/app/personal.go +2 -2
  313. package/dist/templates/native-go-integration/backend/internal/app/personal_test.go +37 -0
  314. package/dist/templates/native-go-vue/README.md +38 -7
  315. package/dist/templates/native-go-vue/frontend/DESIGN.md +15 -3
  316. package/dist/templates/native-go-vue/frontend/README-JOBS.md +75 -0
  317. package/dist/templates/native-go-vue/frontend/README-M2.md +64 -0
  318. package/dist/templates/native-go-vue/frontend/package-lock.json +5 -4
  319. package/dist/templates/native-go-vue/frontend/package.json +1 -1
  320. package/dist/templates/native-go-vue/frontend/src/App.vue +39 -11
  321. package/dist/templates/native-go-vue/frontend/src/M2App.vue +57 -0
  322. package/dist/templates/native-go-vue/frontend/src/SDKApp.vue +203 -0
  323. package/dist/templates/native-go-vue/frontend/src/context.ts +3 -0
  324. package/dist/templates/native-go-vue/frontend/src/jobs/InteractiveJobForm.vue +70 -0
  325. package/dist/templates/native-go-vue/frontend/src/jobs/JobsAdminPanel.vue +33 -0
  326. package/dist/templates/native-go-vue/frontend/src/jobs/JobsPanel.vue +135 -0
  327. package/dist/templates/native-go-vue/frontend/src/jobs/connected-provider.ts +179 -0
  328. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/de.json +62 -0
  329. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/en.json +62 -0
  330. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/es.json +62 -0
  331. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/fr.json +62 -0
  332. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/it.json +62 -0
  333. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/ja.json +62 -0
  334. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/ko.json +62 -0
  335. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/zh-CN.json +62 -0
  336. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/zh-TW.json +62 -0
  337. package/dist/templates/native-go-vue/frontend/src/jobs/i18n.ts +15 -0
  338. package/dist/templates/native-go-vue/frontend/src/jobs/mock-provider.ts +67 -0
  339. package/dist/templates/native-go-vue/frontend/src/jobs/provider.ts +60 -0
  340. package/dist/templates/native-go-vue/frontend/src/jobs/validate.ts +44 -0
  341. package/dist/templates/native-go-vue/frontend/src/m2-main.ts +21 -0
  342. package/dist/templates/native-go-vue/frontend/src/m2-style.css +7 -0
  343. package/dist/templates/native-go-vue/frontend/src/nas/M2Files.vue +94 -0
  344. package/dist/templates/native-go-vue/frontend/src/nas/M2PathPicker.vue +70 -0
  345. package/dist/templates/native-go-vue/frontend/src/nas/M2Settings.vue +69 -0
  346. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/de.json +56 -0
  347. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/en.json +56 -0
  348. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/es.json +56 -0
  349. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/fr.json +56 -0
  350. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/it.json +56 -0
  351. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/ja.json +56 -0
  352. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/ko.json +56 -0
  353. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-CN.json +56 -0
  354. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-TW.json +56 -0
  355. package/dist/templates/native-go-vue/frontend/src/nas/m2-contract.ts +33 -0
  356. package/dist/templates/native-go-vue/frontend/src/nas/m2-i18n.ts +24 -0
  357. package/dist/templates/native-go-vue/frontend/src/nas/m2-provider.ts +104 -0
  358. package/dist/templates/native-go-vue/frontend/src/nas/use-m2-request.ts +18 -0
  359. package/dist/templates/native-go-vue/frontend/src/sdk-main.ts +39 -0
  360. package/dist/templates/native-go-vue/frontend/src/shell/AppShell.vue +48 -0
  361. package/dist/templates/native-go-vue/frontend/src/shell/i18n/de.json +10 -0
  362. package/dist/templates/native-go-vue/frontend/src/shell/i18n/en.json +10 -0
  363. package/dist/templates/native-go-vue/frontend/src/shell/i18n/es.json +10 -0
  364. package/dist/templates/native-go-vue/frontend/src/shell/i18n/fr.json +10 -0
  365. package/dist/templates/native-go-vue/frontend/src/shell/i18n/it.json +10 -0
  366. package/dist/templates/native-go-vue/frontend/src/shell/i18n/ja.json +10 -0
  367. package/dist/templates/native-go-vue/frontend/src/shell/i18n/ko.json +10 -0
  368. package/dist/templates/native-go-vue/frontend/src/shell/i18n/zh-CN.json +10 -0
  369. package/dist/templates/native-go-vue/frontend/src/shell/i18n/zh-TW.json +10 -0
  370. package/dist/templates/native-go-vue/frontend/src/shell/i18n.ts +17 -0
  371. package/dist/templates/native-go-vue/frontend/src/shell/pages.ts +34 -0
  372. package/dist/templates/native-go-vue/frontend/src/style.css +2 -6
  373. package/dist/templates/native-go-vue/frontend/test/apps.test.ts +21 -0
  374. package/dist/templates/native-go-vue/frontend/test/jobs-connected.test.ts +163 -0
  375. package/dist/templates/native-go-vue/frontend/test/jobs-preview.html +22 -0
  376. package/dist/templates/native-go-vue/frontend/test/jobs.test.ts +176 -0
  377. package/dist/templates/native-go-vue/frontend/test/m2-preview.html +27 -0
  378. package/dist/templates/native-go-vue/frontend/test/m2-provider.test.ts +87 -0
  379. package/dist/templates/native-go-vue/frontend/test/m2-ui.test.ts +209 -0
  380. package/dist/templates/native-go-vue/frontend/test/native-controls.test.ts +27 -0
  381. package/dist/templates/native-go-vue/frontend/test/picker-wire.test.ts +110 -0
  382. package/dist/templates/native-go-vue/frontend/test/shell-preview.html +19 -0
  383. package/dist/templates/native-go-vue/frontend/test/shell-sdk.test.ts +73 -0
  384. package/dist/templates/native-go-vue/frontend/test/shell-ui.test.ts +114 -0
  385. package/dist/templates/native-go-vue/frontend/test/shell.test.ts +45 -0
  386. package/dist/templates/native-go-vue/frontend/vite.config.ts +2 -2
  387. package/dist/types.d.ts +1 -1
  388. package/dist/validate.js +6 -3
  389. package/package.json +5 -2
  390. package/schema/synology-app.schema.json +19 -0
  391. package/skills/reference/create.md +6 -2
  392. package/templates/_authorization/main.go +104 -0
  393. package/templates/_authorization/main_test.go +35 -0
  394. package/templates/_daemon/go.mod +2 -0
  395. package/templates/_gateway/auth.go +101 -0
  396. package/templates/_gateway/auth_test.go +216 -0
  397. package/templates/_gateway/cgi.go +133 -0
  398. package/templates/_gateway/cgi_test.go +156 -0
  399. package/templates/_gateway/csrf.go +73 -0
  400. package/templates/_gateway/csrf_test.go +155 -0
  401. package/templates/_gateway/directory.go +108 -0
  402. package/templates/_gateway/directory_test.go +202 -0
  403. package/templates/_gateway/gateway.go +412 -0
  404. package/templates/_gateway/gateway_test.go +676 -0
  405. package/templates/_gateway/go.mod +3 -0
  406. package/templates/_gateway/groups.go +66 -0
  407. package/templates/_gateway/main.go +45 -0
  408. package/templates/binary/synology-app.yaml +1 -1
  409. package/templates/compose-import/compose.yaml +1 -1
  410. package/templates/compose-import/synology-app.yaml +1 -1
  411. package/templates/hello-files/compose.yaml +1 -1
  412. package/templates/hello-files/synology-app.yaml +1 -1
  413. package/templates/native-go/README.md +118 -5
  414. package/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +3 -1
  415. package/templates/native-go/backend/cmd/app/main.go +25 -6
  416. package/templates/native-go/backend/cmd/app/sdk_main.go +62 -0
  417. package/templates/native-go/backend/cmd/background-worker/main.go +38 -0
  418. package/templates/native-go/backend/cmd/helper/main.go +27 -1
  419. package/templates/native-go/backend/cmd/helper/sdk_registry.go +19 -0
  420. package/templates/native-go/backend/go.mod +5 -3
  421. package/templates/native-go/backend/go.sum +4 -4
  422. package/templates/native-go/backend/internal/api/registry.go +17 -6
  423. package/templates/native-go/backend/internal/api/server.go +7 -1
  424. package/templates/native-go/backend/internal/app/authorization_none.go +5 -0
  425. package/templates/native-go/backend/internal/app/background.go +270 -0
  426. package/templates/native-go/backend/internal/app/background_none.go +8 -0
  427. package/templates/native-go/backend/internal/app/background_owner.go +59 -0
  428. package/templates/native-go/backend/internal/app/background_owner_test.go +145 -0
  429. package/templates/native-go/backend/internal/app/background_schedule.go +74 -0
  430. package/templates/native-go/backend/internal/app/background_schedule_test.go +62 -0
  431. package/templates/native-go/backend/internal/app/background_test.go +346 -0
  432. package/templates/native-go/backend/internal/app/integration_state.go +16 -0
  433. package/templates/native-go/backend/internal/app/migrations.go +41 -0
  434. package/templates/native-go/backend/internal/app/migrations_test.go +41 -0
  435. package/templates/native-go/backend/internal/app/nas_cgi_artifact_test.go +8 -0
  436. package/templates/native-go/backend/internal/app/routes.go +22 -5
  437. package/templates/native-go/backend/internal/app/routes_test.go +20 -3
  438. package/templates/native-go/backend/internal/app/sdk_jobs.go +70 -0
  439. package/templates/native-go/backend/internal/app/sdk_jobs_test.go +116 -0
  440. package/templates/native-go/backend/internal/app/sdk_routes.go +177 -0
  441. package/templates/native-go/backend/internal/app/session_files.go +15 -0
  442. package/templates/native-go/backend/internal/app/session_files_test.go +26 -0
  443. package/templates/native-go/backend/internal/app/shared_folder.go +144 -0
  444. package/templates/native-go/backend/internal/app/shared_folder_test.go +158 -0
  445. package/templates/native-go/backend/internal/background/access.go +57 -0
  446. package/templates/native-go/backend/internal/background/owner_test.go +126 -0
  447. package/templates/native-go/backend/internal/background/runner.go +185 -0
  448. package/templates/native-go/backend/internal/background/runner_test.go +209 -0
  449. package/templates/native-go/backend/internal/background/schedule.go +300 -0
  450. package/templates/native-go/backend/internal/background/schedule_test.go +335 -0
  451. package/templates/native-go/backend/internal/background/store.go +807 -0
  452. package/templates/native-go/backend/internal/background/store_test.go +407 -0
  453. package/templates/native-go/backend/internal/datamigrate/migrate.go +191 -0
  454. package/templates/native-go/backend/internal/datamigrate/migrate_test.go +177 -0
  455. package/templates/native-go/backend/internal/filestation/browse_test.go +67 -0
  456. package/templates/native-go/backend/internal/filestation/client.go +251 -0
  457. package/templates/native-go/backend/internal/filestation/client_test.go +155 -0
  458. package/templates/native-go/backend/internal/filestation/doc.go +4 -0
  459. package/templates/native-go/backend/internal/filestation/read_file_test.go +90 -0
  460. package/templates/native-go/backend/internal/filestation/repository.go +207 -0
  461. package/templates/native-go/backend/internal/filestation/repository_test.go +104 -0
  462. package/templates/native-go/backend/internal/filestation/sdk_session.go +241 -0
  463. package/templates/native-go/backend/internal/filestation/sdk_session_test.go +183 -0
  464. package/templates/native-go/backend/internal/filestation/service.go +254 -0
  465. package/templates/native-go/backend/internal/filestation/service_test.go +94 -0
  466. package/templates/native-go/backend/internal/filestation/session_semantics_test.go +383 -0
  467. package/templates/native-go/backend/internal/filestation/write.go +72 -0
  468. package/templates/native-go/backend/internal/filestation/write_test.go +123 -0
  469. package/templates/native-go/backend/internal/helper/background_proof.go +163 -0
  470. package/templates/native-go/backend/internal/helper/background_proof_contract.go +46 -0
  471. package/templates/native-go/backend/internal/helper/background_proof_test.go +161 -0
  472. package/templates/native-go/backend/internal/helper/data_contract.go +3 -0
  473. package/templates/native-go/backend/internal/helper/data_protocol.go +3 -0
  474. package/templates/native-go/backend/internal/helper/data_protocol_test.go +1 -1
  475. package/templates/native-go/backend/internal/helper/grant_authority.go +3 -0
  476. package/templates/native-go/backend/internal/helper/grant_authority_test.go +1 -1
  477. package/templates/native-go/backend/internal/helper/grant_repository_linux.go +2 -1
  478. package/templates/native-go/backend/internal/helper/grant_repository_linux_test.go +4 -3
  479. package/templates/native-go/backend/internal/helper/grant_snapshot.go +3 -0
  480. package/templates/native-go/backend/internal/helper/jobcontract/bindings.go +48 -0
  481. package/templates/native-go/backend/internal/helper/jobcontract/contract_test.go +436 -0
  482. package/templates/native-go/backend/internal/helper/jobcontract/decode.go +185 -0
  483. package/templates/native-go/backend/internal/helper/jobcontract/digest.go +55 -0
  484. package/templates/native-go/backend/internal/helper/jobcontract/registry.go +85 -0
  485. package/templates/native-go/backend/internal/helper/jobcontract/registry_test.go +73 -0
  486. package/templates/native-go/backend/internal/helper/jobcontract/result.go +53 -0
  487. package/templates/native-go/backend/internal/helper/jobcontract/stub.go +8 -0
  488. package/templates/native-go/backend/internal/helper/jobcontract/testdata/input-digests.json +127 -0
  489. package/templates/native-go/backend/internal/helper/jobcontract/types.go +234 -0
  490. package/templates/native-go/backend/internal/helper/jobcontract/types_test.go +29 -0
  491. package/templates/native-go/backend/internal/helper/jobcontract/validate.go +462 -0
  492. package/templates/native-go/backend/internal/helper/legacy_authority_schema_linux_test.go +34 -0
  493. package/templates/native-go/backend/internal/helper/legacy_authority_schema_test.go +6 -0
  494. package/templates/native-go/backend/internal/helper/management.go +86 -0
  495. package/templates/native-go/backend/internal/helper/observation.go +42 -2
  496. package/templates/native-go/backend/internal/helper/observation_health_test.go +13 -1
  497. package/templates/native-go/backend/internal/helper/observer_diagnostic.go +56 -10
  498. package/templates/native-go/backend/internal/helper/observer_diagnostic_linux_test.go +6 -0
  499. package/templates/native-go/backend/internal/helper/observer_diagnostic_writer.go +40 -0
  500. package/templates/native-go/backend/internal/helper/process_linux.go +3 -0
  501. package/templates/native-go/backend/internal/helper/purge.go +115 -0
  502. package/templates/native-go/backend/internal/helper/purge_test.go +59 -0
  503. package/templates/native-go/backend/internal/helper/query_deadline_linux_test.go +115 -0
  504. package/templates/native-go/backend/internal/helper/query_pending_diagnostic_test.go +254 -0
  505. package/templates/native-go/backend/internal/helper/relaxed_invalidation.go +3 -0
  506. package/templates/native-go/backend/internal/helper/revoke.go +109 -0
  507. package/templates/native-go/backend/internal/helper/revoke_test.go +121 -0
  508. package/templates/native-go/backend/internal/helper/s1r_actor_races_linux_test.go +23 -4
  509. package/templates/native-go/backend/internal/helper/sdk_assembly_linux.go +51 -0
  510. package/templates/native-go/backend/internal/helper/sdk_attach.go +83 -0
  511. package/templates/native-go/backend/internal/helper/sdk_attach_contract.go +32 -0
  512. package/templates/native-go/backend/internal/helper/sdk_attach_test.go +184 -0
  513. package/templates/native-go/backend/internal/helper/sdk_authority_schema_test.go +6 -0
  514. package/templates/native-go/backend/internal/helper/sdk_background_authority.go +832 -0
  515. package/templates/native-go/backend/internal/helper/sdk_background_authority_test.go +714 -0
  516. package/templates/native-go/backend/internal/helper/sdk_background_invalidation.go +218 -0
  517. package/templates/native-go/backend/internal/helper/sdk_background_lease.go +218 -0
  518. package/templates/native-go/backend/internal/helper/sdk_background_snapshot.go +110 -0
  519. package/templates/native-go/backend/internal/helper/sdk_background_store_linux_test.go +261 -0
  520. package/templates/native-go/backend/internal/helper/sdk_background_store_test.go +58 -0
  521. package/templates/native-go/backend/internal/helper/sdk_bindings.go +60 -0
  522. package/templates/native-go/backend/internal/helper/sdk_data_contract.go +251 -0
  523. package/templates/native-go/backend/internal/helper/sdk_data_protocol.go +424 -0
  524. package/templates/native-go/backend/internal/helper/sdk_dispatch_absence_test.go +51 -0
  525. package/templates/native-go/backend/internal/helper/sdk_display.go +488 -0
  526. package/templates/native-go/backend/internal/helper/sdk_display_contract.go +121 -0
  527. package/templates/native-go/backend/internal/helper/sdk_display_test.go +459 -0
  528. package/templates/native-go/backend/internal/helper/sdk_grant_authority.go +559 -0
  529. package/templates/native-go/backend/internal/helper/sdk_grant_repository_linux.go +417 -0
  530. package/templates/native-go/backend/internal/helper/sdk_grant_snapshot.go +94 -0
  531. package/templates/native-go/backend/internal/helper/sdk_history.go +80 -0
  532. package/templates/native-go/backend/internal/helper/sdk_history_test.go +76 -0
  533. package/templates/native-go/backend/internal/helper/sdk_job.go +697 -0
  534. package/templates/native-go/backend/internal/helper/sdk_job_child_linux.go +309 -0
  535. package/templates/native-go/backend/internal/helper/sdk_job_contract.go +122 -0
  536. package/templates/native-go/backend/internal/helper/sdk_job_linux_test.go +159 -0
  537. package/templates/native-go/backend/internal/helper/sdk_job_process_linux.go +327 -0
  538. package/templates/native-go/backend/internal/helper/sdk_job_test.go +501 -0
  539. package/templates/native-go/backend/internal/helper/sdk_job_vm_linux_test.go +343 -0
  540. package/templates/native-go/backend/internal/helper/sdk_journal.go +77 -0
  541. package/templates/native-go/backend/internal/helper/sdk_journal_linux.go +244 -0
  542. package/templates/native-go/backend/internal/helper/sdk_journal_linux_test.go +295 -0
  543. package/templates/native-go/backend/internal/helper/sdk_journal_test.go +71 -0
  544. package/templates/native-go/backend/internal/helper/sdk_picker_test.go +50 -0
  545. package/templates/native-go/backend/internal/helper/sdk_process_linux.go +184 -0
  546. package/templates/native-go/backend/internal/helper/sdk_public_vm_linux_test.go +129 -0
  547. package/templates/native-go/backend/internal/helper/sdk_relaxed_invalidation.go +242 -0
  548. package/templates/native-go/backend/internal/helper/sdk_rpc.go +299 -0
  549. package/templates/native-go/backend/internal/helper/sdk_rpc_contract.go +70 -0
  550. package/templates/native-go/backend/internal/helper/sdk_rpc_test.go +135 -0
  551. package/templates/native-go/backend/internal/helper/sdk_server_linux.go +161 -0
  552. package/templates/native-go/backend/internal/helper/sdk_session.go +677 -0
  553. package/templates/native-go/backend/internal/helper/sdk_session_contract.go +72 -0
  554. package/templates/native-go/backend/internal/helper/sdk_session_fence_test.go +215 -0
  555. package/templates/native-go/backend/internal/helper/sdk_session_test.go +475 -0
  556. package/templates/native-go/backend/internal/helper/sdk_supervisor_frame.go +78 -0
  557. package/templates/native-go/backend/internal/helper/sdk_supervisor_linux.go +414 -0
  558. package/templates/native-go/backend/internal/helper/sdk_transport.go +79 -0
  559. package/templates/native-go/backend/internal/helper/sdk_transport_linux.go +82 -0
  560. package/templates/native-go/backend/internal/helper/sdk_transport_test.go +64 -0
  561. package/templates/native-go/backend/internal/helper/server_linux.go +14 -2
  562. package/templates/native-go/backend/internal/helper/stale_management_linux_test.go +126 -0
  563. package/templates/native-go/backend/internal/helper/stale_management_test.go +122 -0
  564. package/templates/native-go/backend/internal/helper/startup_diagnostic.go +68 -0
  565. package/templates/native-go/backend/internal/helper/startup_diagnostic_linux_test.go +126 -0
  566. package/templates/native-go/backend/internal/helper/startup_diagnostic_test.go +117 -0
  567. package/templates/native-go/backend/internal/helper/status.go +22 -13
  568. package/templates/native-go/backend/internal/helper/status_test.go +45 -0
  569. package/templates/native-go/backend/internal/helper/supervision.go +1 -1
  570. package/templates/native-go/backend/internal/helper/supervisor_frame.go +3 -0
  571. package/templates/native-go/backend/internal/helper/supervisor_linux.go +6 -2
  572. package/templates/native-go/backend/internal/helper/unit_connection_test.go +22 -4
  573. package/templates/native-go/backend/internal/helper/unit_linux.go +7 -3
  574. package/templates/native-go/backend/internal/helper/unit_query_linux.go +5 -1
  575. package/templates/native-go/backend/internal/helper/write_files_linux.go +7 -4
  576. package/templates/native-go/backend/internal/helper/write_files_linux_test.go +26 -0
  577. package/templates/native-go/dsm-package.yaml +2 -2
  578. package/templates/native-go-authorization/backend/internal/app/authorization.go +298 -0
  579. package/templates/native-go-authorization/backend/internal/app/authorization_test.go +96 -0
  580. package/templates/native-go-authorization/frontend/src/authorization/AuthorizationGate.vue +89 -0
  581. package/templates/native-go-authorization/frontend/src/authorization/i18n/de.json +36 -0
  582. package/templates/native-go-authorization/frontend/src/authorization/i18n/en.json +36 -0
  583. package/templates/native-go-authorization/frontend/src/authorization/i18n/es.json +36 -0
  584. package/templates/native-go-authorization/frontend/src/authorization/i18n/fr.json +36 -0
  585. package/templates/native-go-authorization/frontend/src/authorization/i18n/index.ts +15 -0
  586. package/templates/native-go-authorization/frontend/src/authorization/i18n/it.json +36 -0
  587. package/templates/native-go-authorization/frontend/src/authorization/i18n/ja.json +36 -0
  588. package/templates/native-go-authorization/frontend/src/authorization/i18n/ko.json +36 -0
  589. package/templates/native-go-authorization/frontend/src/authorization/i18n/zh-CN.json +36 -0
  590. package/templates/native-go-authorization/frontend/src/authorization/i18n/zh-TW.json +36 -0
  591. package/templates/native-go-authorization/frontend/test/authorization-preview.html +14 -0
  592. package/templates/native-go-authorization/frontend/test/authorization.test.ts +59 -0
  593. package/templates/native-go-background/BACKGROUND.md +111 -0
  594. package/templates/native-go-background/backend/internal/app/background_on.go +7 -0
  595. package/templates/native-go-background/backend/internal/app/background_routes_test.go +32 -0
  596. package/templates/native-go-background/frontend/src/background/BackgroundPanel.vue +178 -0
  597. package/templates/native-go-background/frontend/src/background/i18n/de.json +83 -0
  598. package/templates/native-go-background/frontend/src/background/i18n/en.json +83 -0
  599. package/templates/native-go-background/frontend/src/background/i18n/es.json +83 -0
  600. package/templates/native-go-background/frontend/src/background/i18n/fr.json +83 -0
  601. package/templates/native-go-background/frontend/src/background/i18n/it.json +83 -0
  602. package/templates/native-go-background/frontend/src/background/i18n/ja.json +83 -0
  603. package/templates/native-go-background/frontend/src/background/i18n/ko.json +83 -0
  604. package/templates/native-go-background/frontend/src/background/i18n/zh-CN.json +83 -0
  605. package/templates/native-go-background/frontend/src/background/i18n/zh-TW.json +83 -0
  606. package/templates/native-go-background/frontend/src/background/i18n.ts +19 -0
  607. package/templates/native-go-background/frontend/src/background/picker-provider.ts +13 -0
  608. package/templates/native-go-background/frontend/test/background.test.ts +179 -0
  609. package/templates/native-go-integration/backend/internal/app/personal.go +2 -2
  610. package/templates/native-go-integration/backend/internal/app/personal_test.go +37 -0
  611. package/templates/native-go-vue/README.md +38 -7
  612. package/templates/native-go-vue/frontend/DESIGN.md +15 -3
  613. package/templates/native-go-vue/frontend/README-JOBS.md +75 -0
  614. package/templates/native-go-vue/frontend/README-M2.md +64 -0
  615. package/templates/native-go-vue/frontend/package-lock.json +5 -4
  616. package/templates/native-go-vue/frontend/package.json +1 -1
  617. package/templates/native-go-vue/frontend/src/App.vue +39 -11
  618. package/templates/native-go-vue/frontend/src/M2App.vue +57 -0
  619. package/templates/native-go-vue/frontend/src/SDKApp.vue +203 -0
  620. package/templates/native-go-vue/frontend/src/context.ts +3 -0
  621. package/templates/native-go-vue/frontend/src/jobs/InteractiveJobForm.vue +70 -0
  622. package/templates/native-go-vue/frontend/src/jobs/JobsAdminPanel.vue +33 -0
  623. package/templates/native-go-vue/frontend/src/jobs/JobsPanel.vue +135 -0
  624. package/templates/native-go-vue/frontend/src/jobs/connected-provider.ts +179 -0
  625. package/templates/native-go-vue/frontend/src/jobs/i18n/de.json +62 -0
  626. package/templates/native-go-vue/frontend/src/jobs/i18n/en.json +62 -0
  627. package/templates/native-go-vue/frontend/src/jobs/i18n/es.json +62 -0
  628. package/templates/native-go-vue/frontend/src/jobs/i18n/fr.json +62 -0
  629. package/templates/native-go-vue/frontend/src/jobs/i18n/it.json +62 -0
  630. package/templates/native-go-vue/frontend/src/jobs/i18n/ja.json +62 -0
  631. package/templates/native-go-vue/frontend/src/jobs/i18n/ko.json +62 -0
  632. package/templates/native-go-vue/frontend/src/jobs/i18n/zh-CN.json +62 -0
  633. package/templates/native-go-vue/frontend/src/jobs/i18n/zh-TW.json +62 -0
  634. package/templates/native-go-vue/frontend/src/jobs/i18n.ts +15 -0
  635. package/templates/native-go-vue/frontend/src/jobs/mock-provider.ts +67 -0
  636. package/templates/native-go-vue/frontend/src/jobs/provider.ts +60 -0
  637. package/templates/native-go-vue/frontend/src/jobs/validate.ts +44 -0
  638. package/templates/native-go-vue/frontend/src/m2-main.ts +21 -0
  639. package/templates/native-go-vue/frontend/src/m2-style.css +7 -0
  640. package/templates/native-go-vue/frontend/src/nas/M2Files.vue +94 -0
  641. package/templates/native-go-vue/frontend/src/nas/M2PathPicker.vue +70 -0
  642. package/templates/native-go-vue/frontend/src/nas/M2Settings.vue +69 -0
  643. package/templates/native-go-vue/frontend/src/nas/i18n/m2/de.json +56 -0
  644. package/templates/native-go-vue/frontend/src/nas/i18n/m2/en.json +56 -0
  645. package/templates/native-go-vue/frontend/src/nas/i18n/m2/es.json +56 -0
  646. package/templates/native-go-vue/frontend/src/nas/i18n/m2/fr.json +56 -0
  647. package/templates/native-go-vue/frontend/src/nas/i18n/m2/it.json +56 -0
  648. package/templates/native-go-vue/frontend/src/nas/i18n/m2/ja.json +56 -0
  649. package/templates/native-go-vue/frontend/src/nas/i18n/m2/ko.json +56 -0
  650. package/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-CN.json +56 -0
  651. package/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-TW.json +56 -0
  652. package/templates/native-go-vue/frontend/src/nas/m2-contract.ts +33 -0
  653. package/templates/native-go-vue/frontend/src/nas/m2-i18n.ts +24 -0
  654. package/templates/native-go-vue/frontend/src/nas/m2-provider.ts +104 -0
  655. package/templates/native-go-vue/frontend/src/nas/use-m2-request.ts +18 -0
  656. package/templates/native-go-vue/frontend/src/sdk-main.ts +39 -0
  657. package/templates/native-go-vue/frontend/src/shell/AppShell.vue +48 -0
  658. package/templates/native-go-vue/frontend/src/shell/i18n/de.json +10 -0
  659. package/templates/native-go-vue/frontend/src/shell/i18n/en.json +10 -0
  660. package/templates/native-go-vue/frontend/src/shell/i18n/es.json +10 -0
  661. package/templates/native-go-vue/frontend/src/shell/i18n/fr.json +10 -0
  662. package/templates/native-go-vue/frontend/src/shell/i18n/it.json +10 -0
  663. package/templates/native-go-vue/frontend/src/shell/i18n/ja.json +10 -0
  664. package/templates/native-go-vue/frontend/src/shell/i18n/ko.json +10 -0
  665. package/templates/native-go-vue/frontend/src/shell/i18n/zh-CN.json +10 -0
  666. package/templates/native-go-vue/frontend/src/shell/i18n/zh-TW.json +10 -0
  667. package/templates/native-go-vue/frontend/src/shell/i18n.ts +17 -0
  668. package/templates/native-go-vue/frontend/src/shell/pages.ts +34 -0
  669. package/templates/native-go-vue/frontend/src/style.css +2 -6
  670. package/templates/native-go-vue/frontend/test/apps.test.ts +21 -0
  671. package/templates/native-go-vue/frontend/test/jobs-connected.test.ts +163 -0
  672. package/templates/native-go-vue/frontend/test/jobs-preview.html +22 -0
  673. package/templates/native-go-vue/frontend/test/jobs.test.ts +176 -0
  674. package/templates/native-go-vue/frontend/test/m2-preview.html +27 -0
  675. package/templates/native-go-vue/frontend/test/m2-provider.test.ts +87 -0
  676. package/templates/native-go-vue/frontend/test/m2-ui.test.ts +209 -0
  677. package/templates/native-go-vue/frontend/test/native-controls.test.ts +27 -0
  678. package/templates/native-go-vue/frontend/test/picker-wire.test.ts +110 -0
  679. package/templates/native-go-vue/frontend/test/shell-preview.html +19 -0
  680. package/templates/native-go-vue/frontend/test/shell-sdk.test.ts +73 -0
  681. package/templates/native-go-vue/frontend/test/shell-ui.test.ts +114 -0
  682. package/templates/native-go-vue/frontend/test/shell.test.ts +45 -0
  683. package/templates/native-go-vue/frontend/vite.config.ts +2 -2
  684. package/dist/templates/hello-web/compose.yaml +0 -21
  685. package/dist/templates/hello-web/html/app.js +0 -1
  686. package/dist/templates/hello-web/html/index.html +0 -13
  687. package/dist/templates/hello-web/synology-app.yaml +0 -13
  688. package/dist/templates/hello-web-page/compose.yaml +0 -21
  689. package/dist/templates/hello-web-page/html/app.js +0 -1
  690. package/dist/templates/hello-web-page/html/index.html +0 -13
  691. package/dist/templates/hello-web-page/synology-app.yaml +0 -13
  692. package/templates/hello-web/compose.yaml +0 -21
  693. package/templates/hello-web/html/app.js +0 -1
  694. package/templates/hello-web/html/index.html +0 -13
  695. package/templates/hello-web/synology-app.yaml +0 -13
  696. package/templates/hello-web-page/compose.yaml +0 -21
  697. package/templates/hello-web-page/html/app.js +0 -1
  698. package/templates/hello-web-page/html/index.html +0 -13
  699. package/templates/hello-web-page/synology-app.yaml +0 -13
@@ -0,0 +1,133 @@
1
+ package main
2
+
3
+ import (
4
+ "bufio"
5
+ "bytes"
6
+ "errors"
7
+ "fmt"
8
+ "io"
9
+ "net"
10
+ "net/http"
11
+ "time"
12
+ )
13
+
14
+ // serveCGI answers one request the way net/http/cgi.Serve does: "Status:" and headers, a blank line, the body
15
+ // on `out`. It is its own copy so that the reply can be hijacked: the handler then owns `in` and `out`, which
16
+ // is how a WebSocket passes through DSM's CGI interface.
17
+ func serveCGI(h http.Handler, req *http.Request, in io.Reader, out io.Writer) error {
18
+ if req.Body == nil {
19
+ req.Body = http.NoBody
20
+ }
21
+ rw := &cgiResponse{req: req, header: make(http.Header), in: in, out: out, bufw: bufio.NewWriter(out)}
22
+ h.ServeHTTP(rw, req)
23
+ if rw.hijacked {
24
+ return nil
25
+ }
26
+ rw.Write(nil) // make sure a reply is sent
27
+ return rw.bufw.Flush()
28
+ }
29
+
30
+ type cgiResponse struct {
31
+ req *http.Request
32
+ header http.Header
33
+ code int
34
+ wroteHeader bool
35
+ wroteCGI bool
36
+ hijacked bool
37
+ in io.Reader
38
+ out io.Writer
39
+ bufw *bufio.Writer
40
+ }
41
+
42
+ func (r *cgiResponse) Header() http.Header { return r.header }
43
+
44
+ func (r *cgiResponse) Flush() {
45
+ if !r.hijacked {
46
+ r.bufw.Flush()
47
+ }
48
+ }
49
+
50
+ func (r *cgiResponse) WriteHeader(code int) {
51
+ if r.wroteHeader {
52
+ return
53
+ }
54
+ r.wroteHeader, r.code = true, code
55
+ }
56
+
57
+ func (r *cgiResponse) Write(p []byte) (int, error) {
58
+ if r.hijacked {
59
+ return 0, http.ErrHijacked
60
+ }
61
+ if !r.wroteHeader {
62
+ r.WriteHeader(http.StatusOK)
63
+ }
64
+ if !r.wroteCGI {
65
+ r.writeCGIHeader(p)
66
+ }
67
+ return r.bufw.Write(p)
68
+ }
69
+
70
+ // writeCGIHeader sends the header block; p, the first chunk of the body, is sniffed for a missing Content-Type.
71
+ func (r *cgiResponse) writeCGIHeader(p []byte) {
72
+ r.wroteCGI = true
73
+ fmt.Fprintf(r.bufw, "Status: %d %s\r\n", r.code, http.StatusText(r.code))
74
+ if _, hasType := r.header["Content-Type"]; !hasType {
75
+ r.header.Set("Content-Type", http.DetectContentType(p))
76
+ }
77
+ r.header.Write(r.bufw)
78
+ r.bufw.WriteString("\r\n")
79
+ r.bufw.Flush()
80
+ }
81
+
82
+ // Hijack hands stdin and stdout to the handler. The first thing it writes is an HTTP/1.1 status line and
83
+ // headers (that is what httputil.ReverseProxy writes for a 101); the CGI interface wants "Status: 101 ..."
84
+ // there, so cgiConn rewrites the status line and leaves everything after the blank line alone.
85
+ func (r *cgiResponse) Hijack() (net.Conn, *bufio.ReadWriter, error) {
86
+ if r.wroteHeader || r.wroteCGI || r.hijacked {
87
+ return nil, nil, errors.New("cgi: Hijack after the reply began")
88
+ }
89
+ r.hijacked = true
90
+ c := &cgiConn{in: r.in, out: r.out}
91
+ return c, bufio.NewReadWriter(bufio.NewReader(c), bufio.NewWriter(c)), nil
92
+ }
93
+
94
+ type cgiConn struct {
95
+ in io.Reader
96
+ out io.Writer
97
+ head []byte // the header block, held back until it is complete
98
+ headSent bool
99
+ }
100
+
101
+ func (c *cgiConn) Read(p []byte) (int, error) { return c.in.Read(p) }
102
+
103
+ func (c *cgiConn) Write(p []byte) (int, error) {
104
+ if c.headSent {
105
+ return c.out.Write(p)
106
+ }
107
+ c.head = append(c.head, p...)
108
+ end := bytes.Index(c.head, []byte("\r\n\r\n"))
109
+ if end < 0 {
110
+ return len(p), nil
111
+ }
112
+ c.headSent = true
113
+ statusLine, headers, _ := bytes.Cut(c.head[:end+4], []byte("\r\n"))
114
+ _, status, _ := bytes.Cut(statusLine, []byte(" ")) // "HTTP/1.1 101 Switching Protocols" -> "101 Switching Protocols"
115
+ rewritten := append(append([]byte("Status: "), status...), "\r\n"...)
116
+ rewritten = append(append(rewritten, headers...), c.head[end+4:]...)
117
+ if _, err := c.out.Write(rewritten); err != nil {
118
+ return 0, err
119
+ }
120
+ return len(p), nil
121
+ }
122
+
123
+ func (c *cgiConn) Close() error { return nil }
124
+ func (c *cgiConn) LocalAddr() net.Addr { return cgiAddr{} }
125
+ func (c *cgiConn) RemoteAddr() net.Addr { return cgiAddr{} }
126
+ func (c *cgiConn) SetDeadline(time.Time) error { return nil }
127
+ func (c *cgiConn) SetReadDeadline(time.Time) error { return nil }
128
+ func (c *cgiConn) SetWriteDeadline(time.Time) error { return nil }
129
+
130
+ type cgiAddr struct{}
131
+
132
+ func (cgiAddr) Network() string { return "cgi" }
133
+ func (cgiAddr) String() string { return "cgi" }
@@ -0,0 +1,156 @@
1
+ package main
2
+
3
+ import (
4
+ "bufio"
5
+ "bytes"
6
+ "io"
7
+ "net/http"
8
+ "net/http/httptest"
9
+ "strings"
10
+ "testing"
11
+ )
12
+
13
+ func cgiRequest(t *testing.T) *http.Request {
14
+ t.Helper()
15
+ return httptest.NewRequest("GET", "/webman/3rdparty/App/cgi/gateway.cgi/", nil)
16
+ }
17
+
18
+ func TestCGIReplyIsAStatusLineThenHeadersThenBody(t *testing.T) {
19
+ var out bytes.Buffer
20
+ err := serveCGI(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
21
+ w.Header().Set("Content-Type", "text/plain")
22
+ w.Header().Set("X-Thing", "1")
23
+ w.WriteHeader(404)
24
+ io.WriteString(w, "nope")
25
+ }), cgiRequest(t), strings.NewReader(""), &out)
26
+ if err != nil {
27
+ t.Fatal(err)
28
+ }
29
+ if want := "Status: 404 Not Found\r\nContent-Type: text/plain\r\nX-Thing: 1\r\n\r\nnope"; out.String() != want {
30
+ t.Fatalf("got %q\nwant %q", out.String(), want)
31
+ }
32
+ }
33
+
34
+ func TestCGIReplyWithoutAWriteStillCarriesAStatus(t *testing.T) {
35
+ var out bytes.Buffer
36
+ if err := serveCGI(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}), cgiRequest(t), strings.NewReader(""), &out); err != nil {
37
+ t.Fatal(err)
38
+ }
39
+ if !strings.HasPrefix(out.String(), "Status: 200 OK\r\n") || !strings.HasSuffix(out.String(), "\r\n\r\n") {
40
+ t.Fatalf("got %q", out.String())
41
+ }
42
+ }
43
+
44
+ func TestCGIReplySniffsAMissingContentType(t *testing.T) {
45
+ var out bytes.Buffer
46
+ serveCGI(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "<html></html>") }), cgiRequest(t), strings.NewReader(""), &out)
47
+ if !strings.Contains(out.String(), "Content-Type: text/html; charset=utf-8\r\n") {
48
+ t.Fatalf("got %q", out.String())
49
+ }
50
+ }
51
+
52
+ // flushRecorder notes how many bytes were out when the handler was still running.
53
+ type flushRecorder struct {
54
+ bytes.Buffer
55
+ atFlush int
56
+ }
57
+
58
+ func TestCGIFlushSendsWhatIsBufferedAtOnce(t *testing.T) {
59
+ var out flushRecorder
60
+ serveCGI(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
61
+ w.Header().Set("Content-Type", "text/event-stream")
62
+ io.WriteString(w, "data: one\n\n")
63
+ w.(http.Flusher).Flush()
64
+ out.atFlush = out.Len()
65
+ io.WriteString(w, "data: two\n\n")
66
+ }), cgiRequest(t), strings.NewReader(""), &out)
67
+ if !strings.HasSuffix(out.String(), "data: one\n\ndata: two\n\n") || out.atFlush < len("data: one\n\n") {
68
+ t.Fatalf("flushed %d bytes before the handler ended; total %q", out.atFlush, out.String())
69
+ }
70
+ }
71
+
72
+ // After a hijack stdin and stdout belong to the handler. What it writes first is an HTTP/1.1 status line;
73
+ // DSM's CGI interface wants "Status:" instead.
74
+ func TestCGIHijackTurnsTheStatusLineIntoACGIHeaderAndPassesBytesBothWays(t *testing.T) {
75
+ in, inW := io.Pipe()
76
+ outR, out := io.Pipe()
77
+ done := make(chan error, 1)
78
+ go func() {
79
+ done <- serveCGI(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
80
+ conn, brw, err := w.(http.Hijacker).Hijack()
81
+ if err != nil {
82
+ t.Error(err)
83
+ return
84
+ }
85
+ defer conn.Close()
86
+ io.WriteString(brw, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\n\r\n")
87
+ brw.Flush()
88
+ buf := make([]byte, 16)
89
+ n, _ := brw.Read(buf)
90
+ io.WriteString(conn, "got:"+string(buf[:n]))
91
+ }), cgiRequest(t), in, out)
92
+ out.Close()
93
+ }()
94
+ r := bufio.NewReader(outR)
95
+ for _, want := range []string{"Status: 101 Switching Protocols", "Upgrade: websocket", "Connection: Upgrade", ""} {
96
+ if line, _ := r.ReadString('\n'); strings.TrimRight(line, "\r\n") != want {
97
+ t.Fatalf("header line %q, want %q", line, want)
98
+ }
99
+ }
100
+ io.WriteString(inW, "ping")
101
+ rest, _ := io.ReadAll(r)
102
+ if string(rest) != "got:ping" {
103
+ t.Fatalf("after the header block: %q (nothing, not even a second status, may follow the handler's bytes)", rest)
104
+ }
105
+ if err := <-done; err != nil {
106
+ t.Fatal(err)
107
+ }
108
+ }
109
+
110
+ func TestCGIReplyCannotBeWrittenAfterAHijack(t *testing.T) {
111
+ var out bytes.Buffer
112
+ serveCGI(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
113
+ if _, _, err := w.(http.Hijacker).Hijack(); err != nil {
114
+ t.Fatal(err)
115
+ }
116
+ if _, err := w.Write([]byte("late")); err == nil {
117
+ t.Error("Write after Hijack succeeded")
118
+ }
119
+ }), cgiRequest(t), strings.NewReader(""), &out)
120
+ if out.Len() != 0 {
121
+ t.Fatalf("output after a bare hijack: %q", out.String())
122
+ }
123
+ }
124
+
125
+ // The whole chain as DSM runs it: a WebSocket upgrade enters through the CGI environment and the container's
126
+ // bytes come back on stdout.
127
+ func TestWebSocketThroughTheCGIEnvironment(t *testing.T) {
128
+ up := newUpstream(t, wsEchoHandler)
129
+ g := newTestGateway(t, config{Access: "users"}, &fakeAuth{id: identity{User: "bob"}}, up)
130
+ req := httptest.NewRequest("GET", base+"/ws", nil)
131
+ req.Host = "nas.example:5001"
132
+ req.Header.Set("Cookie", "id=abc")
133
+ req.Header.Set("Connection", "Upgrade")
134
+ req.Header.Set("Upgrade", "websocket")
135
+ req.Header.Set("Origin", "https://nas.example:5001")
136
+ in, inW := io.Pipe()
137
+ outR, out := io.Pipe()
138
+ done := make(chan error, 1)
139
+ go func() { done <- serveCGI(g, req, in, out); out.Close() }()
140
+ r := bufio.NewReader(outR)
141
+ if line, _ := r.ReadString('\n'); strings.TrimSpace(line) != "Status: 101 Switching Protocols" {
142
+ t.Fatalf("first line %q", line)
143
+ }
144
+ for line, _ := r.ReadString('\n'); strings.TrimSpace(line) != ""; line, _ = r.ReadString('\n') {
145
+ }
146
+ io.WriteString(inW, "hello")
147
+ got := make([]byte, len("echo:hello"))
148
+ if _, err := io.ReadFull(r, got); err != nil || string(got) != "echo:hello" {
149
+ t.Fatalf("echo = %q, %v", got, err)
150
+ }
151
+ inW.Close() // DSM closes stdin when the browser goes away
152
+ io.Copy(io.Discard, r)
153
+ if err := <-done; err != nil {
154
+ t.Fatal(err)
155
+ }
156
+ }
@@ -0,0 +1,73 @@
1
+ package main
2
+
3
+ // CSRF defence for state-changing requests. DSM issues a SynoToken only when
4
+ // "Enhance CSRF protection" (enable_syno_token in synoinfo.conf) is on; when it
5
+ // is off, DSM hands every session the same placeholder and validates nothing,
6
+ // so the token alone proves nothing. The gateway therefore needs evidence that
7
+ // the browser itself made the request from the gateway's own origin, and it
8
+ // never stores or trusts a token value of its own.
9
+
10
+ import (
11
+ "net/http"
12
+ "net/url"
13
+ "strings"
14
+ )
15
+
16
+ const maxTokenLen = 256
17
+
18
+ // wellFormedToken accepts any printable ASCII value of sane length. Whether the
19
+ // value is the right one is DSM's call (authenticate.cgi gets it on every
20
+ // request); the gateway only refuses requests that carry nothing usable.
21
+ func wellFormedToken(token string) bool {
22
+ if token == "" || len(token) > maxTokenLen {
23
+ return false
24
+ }
25
+ for i := 0; i < len(token); i++ {
26
+ if token[i] < 0x20 || token[i] > 0x7e {
27
+ return false
28
+ }
29
+ }
30
+ return true
31
+ }
32
+
33
+ // sameOrigin reports whether the browser says the request came from the page's
34
+ // own origin. Sec-Fetch-Site, when present, must say same-origin; Origin, when
35
+ // present, must be the request's own host. At least one must be present: a
36
+ // browser sends Origin on every cross-origin and every non-GET request, so a
37
+ // state-changing request with neither is not from a browser that can be trusted
38
+ // to scope it (browsers without either, such as IE 11, are refused).
39
+ func sameOrigin(r *http.Request) bool {
40
+ site := r.Header.Get("Sec-Fetch-Site")
41
+ origin := r.Header.Get("Origin")
42
+ if site == "" && origin == "" {
43
+ return false
44
+ }
45
+ if site != "" && site != "same-origin" {
46
+ return false
47
+ }
48
+ return origin == "" || originMatchesHost(origin, r.Host)
49
+ }
50
+
51
+ // originMatchesHost compares an Origin header (scheme://host[:port], no path)
52
+ // with the Host the request was addressed to. The scheme only decides which
53
+ // port is the default, because a CGI does not reliably learn whether the
54
+ // connection was TLS.
55
+ func originMatchesHost(origin, host string) bool {
56
+ u, err := url.Parse(origin)
57
+ if err != nil || u.Host == "" || (u.Scheme != "http" && u.Scheme != "https") || (u.Path != "" && u.Path != "/") || u.User != nil || u.RawQuery != "" || u.Fragment != "" {
58
+ return false
59
+ }
60
+ return withDefaultPort(u.Host, u.Scheme) == withDefaultPort(host, u.Scheme)
61
+ }
62
+
63
+ func withDefaultPort(host, scheme string) string {
64
+ host = strings.ToLower(host)
65
+ i := strings.LastIndex(host, ":")
66
+ if i >= 0 && !strings.Contains(host[i:], "]") {
67
+ return host
68
+ }
69
+ if scheme == "https" {
70
+ return host + ":443"
71
+ }
72
+ return host + ":80"
73
+ }
@@ -0,0 +1,155 @@
1
+ package main
2
+
3
+ import (
4
+ "net/http"
5
+ "net/http/httptest"
6
+ "strings"
7
+ "testing"
8
+ )
9
+
10
+ // browserPost is what a browser sends for a same-origin fetch to the gateway
11
+ // (httptest requests are addressed to example.com).
12
+ func browserPost(token string) map[string]string {
13
+ return map[string]string{
14
+ "Cookie": "id=abc",
15
+ "X-SYNO-TOKEN": token,
16
+ "Origin": "http://example.com",
17
+ "Sec-Fetch-Site": "same-origin",
18
+ }
19
+ }
20
+
21
+ func with(hdr map[string]string, kv ...string) map[string]string {
22
+ out := map[string]string{}
23
+ for k, v := range hdr {
24
+ out[k] = v
25
+ }
26
+ for i := 0; i < len(kv); i += 2 {
27
+ if kv[i+1] == "" {
28
+ delete(out, kv[i])
29
+ } else {
30
+ out[kv[i]] = kv[i+1]
31
+ }
32
+ }
33
+ return out
34
+ }
35
+
36
+ func csrfGateway(t *testing.T) (http.Handler, *upstream) {
37
+ t.Helper()
38
+ up := newUpstream(t, hello)
39
+ return newTestGateway(t, config{Access: "users"}, &fakeAuth{id: identity{User: "bob"}}, up), up
40
+ }
41
+
42
+ func TestSameOriginStateChangeReachesContainer(t *testing.T) {
43
+ g, up := csrfGateway(t)
44
+ cases := map[string]map[string]string{
45
+ "origin and fetch metadata": browserPost("tok"),
46
+ "origin only (no fetch metadata, e.g. Safari < 16.4)": with(browserPost("tok"), "Sec-Fetch-Site", ""),
47
+ "fetch metadata only": with(browserPost("tok"), "Origin", ""),
48
+ "host case and default port": with(browserPost("tok"), "Origin", "http://EXAMPLE.com:80"),
49
+ }
50
+ for name, hdr := range cases {
51
+ if w := do(g, "POST", base+"/save", hdr, "x"); w.Code != 200 {
52
+ t.Errorf("%s: %d %q", name, w.Code, w.Body.String())
53
+ }
54
+ }
55
+ if up.hits.Load() != int32(len(cases)) {
56
+ t.Fatalf("hits=%d", up.hits.Load())
57
+ }
58
+ }
59
+
60
+ func TestCrossSiteStateChangeIsRefusedBeforeTheContainer(t *testing.T) {
61
+ g, up := csrfGateway(t)
62
+ cases := map[string]map[string]string{
63
+ "foreign origin": with(browserPost("tok"), "Origin", "https://evil.example", "Sec-Fetch-Site", ""),
64
+ "foreign origin, claims same": with(browserPost("tok"), "Origin", "https://evil.example"),
65
+ "origin null": with(browserPost("tok"), "Origin", "null", "Sec-Fetch-Site", ""),
66
+ "origin is not a URL": with(browserPost("tok"), "Origin", "::::", "Sec-Fetch-Site", ""),
67
+ "origin has a path": with(browserPost("tok"), "Origin", "http://example.com/x", "Sec-Fetch-Site", ""),
68
+ "same host other port": with(browserPost("tok"), "Origin", "http://example.com:5001", "Sec-Fetch-Site", ""),
69
+ "sub-domain of the host": with(browserPost("tok"), "Origin", "http://evil.example.com", "Sec-Fetch-Site", ""),
70
+ "fetch metadata cross-site": with(browserPost("tok"), "Sec-Fetch-Site", "cross-site"),
71
+ "fetch metadata same-site": with(browserPost("tok"), "Sec-Fetch-Site", "same-site"),
72
+ "fetch metadata none": with(browserPost("tok"), "Sec-Fetch-Site", "none"),
73
+ "fetch metadata unknown": with(browserPost("tok"), "Sec-Fetch-Site", "whatever"),
74
+ "fetch cross-site, origin same": with(browserPost("tok"), "Sec-Fetch-Site", "cross-site", "Origin", "http://example.com"),
75
+ }
76
+ for name, hdr := range cases {
77
+ w := do(g, "POST", base+"/save", hdr, "x")
78
+ if !refusedAsForbidden(w, "cross_site_blocked") {
79
+ t.Errorf("%s: %d %q", name, w.Code, w.Body.String())
80
+ }
81
+ }
82
+ if up.hits.Load() != 0 {
83
+ t.Fatalf("hits=%d", up.hits.Load())
84
+ }
85
+ }
86
+
87
+ func TestStateChangeWithoutAnyOriginEvidenceIsRefused(t *testing.T) {
88
+ g, up := csrfGateway(t)
89
+ hdr := with(browserPost("tok"), "Origin", "", "Sec-Fetch-Site", "")
90
+ w := do(g, "POST", base+"/save", hdr, "x")
91
+ if !refusedAsForbidden(w, "cross_site_blocked") || up.hits.Load() != 0 {
92
+ t.Fatalf("%d %q hits=%d", w.Code, w.Body.String(), up.hits.Load())
93
+ }
94
+ }
95
+
96
+ func TestStateChangeNeedsAWellFormedToken(t *testing.T) {
97
+ g, up := csrfGateway(t)
98
+ for name, token := range map[string]string{
99
+ "missing": "",
100
+ "too long": strings.Repeat("a", 257),
101
+ "control bytes": "to\x01ken",
102
+ "non ASCII": "tök",
103
+ } {
104
+ hdr := with(browserPost("tok"), "X-SYNO-TOKEN", "")
105
+ if token != "" {
106
+ hdr["X-SYNO-TOKEN"] = token
107
+ }
108
+ w := do(g, "POST", base+"/save", hdr, "x")
109
+ if !refusedAsForbidden(w, "token_required") {
110
+ t.Errorf("%s: %d %q", name, w.Code, w.Body.String())
111
+ }
112
+ }
113
+ if up.hits.Load() != 0 {
114
+ t.Fatalf("hits=%d", up.hits.Load())
115
+ }
116
+ }
117
+
118
+ func TestSafeRequestsIgnoreOriginEvidence(t *testing.T) {
119
+ g, _ := csrfGateway(t)
120
+ hdr := map[string]string{"Cookie": "id=abc", "Origin": "https://evil.example", "Sec-Fetch-Site": "cross-site"}
121
+ for _, method := range []string{"GET", "HEAD"} {
122
+ if w := do(g, method, base+"/", hdr, ""); w.Code != 200 {
123
+ t.Errorf("%s: %d", method, w.Code)
124
+ }
125
+ }
126
+ }
127
+
128
+ func TestOriginMatchIgnoresDefaultPortsOnly(t *testing.T) {
129
+ cases := []struct {
130
+ origin, host string
131
+ want bool
132
+ }{
133
+ {"http://nas.local:5000", "nas.local:5000", true},
134
+ {"https://nas.local:5001", "nas.local:5001", true},
135
+ {"https://nas.local", "nas.local:443", true},
136
+ {"http://nas.local", "nas.local", true},
137
+ {"https://nas.local:5001", "nas.local:5000", false},
138
+ {"http://[::1]:5000", "[::1]:5000", true},
139
+ {"http://nas.local", "nas.local:5000", false},
140
+ {"", "nas.local", false},
141
+ }
142
+ for _, c := range cases {
143
+ if got := originMatchesHost(c.origin, c.host); got != c.want {
144
+ t.Errorf("originMatchesHost(%q, %q) = %v", c.origin, c.host, got)
145
+ }
146
+ }
147
+ }
148
+
149
+ // refusedAsForbidden: the gateway means 403, but DSM would replace a 403 body, so it sends 401
150
+ // with the intended status and the reason in headers.
151
+ func refusedAsForbidden(w *httptest.ResponseRecorder, code string) bool {
152
+ h := w.Header()
153
+ return w.Code == http.StatusUnauthorized && h.Get("X-Synopkgland-Status") == "403" &&
154
+ h.Get("X-Synopkgland-Error") == code && strings.Contains(w.Body.String(), code)
155
+ }
@@ -0,0 +1,108 @@
1
+ package main
2
+
3
+ import (
4
+ "context"
5
+ "errors"
6
+ "fmt"
7
+ "os/exec"
8
+ "regexp"
9
+ "strconv"
10
+ "strings"
11
+ "time"
12
+ )
13
+
14
+ const maxDirectoryOutput = 64 << 10
15
+ const maxDirectoryGroups = 256
16
+
17
+ // DSM's dynamic /usr/bin/id uses libc NSS; os/user in the static CGI does not.
18
+ // A fixed executable, a single validated username argument and a clean locale
19
+ // environment keep the browser's credentials and process environment out of NSS.
20
+ // No SDK cache: query once per authenticated request, with a two-second limit.
21
+ type directoryLookup struct {
22
+ timeout time.Duration
23
+ run func(context.Context, string, []string, []string) ([]byte, error)
24
+ }
25
+
26
+ func (d directoryLookup) groups(ctx context.Context, user string) ([]string, error) {
27
+ if !userName.MatchString(user) || strings.HasPrefix(user, "-") {
28
+ return nil, errors.New("invalid directory account")
29
+ }
30
+ ctx, cancel := context.WithTimeout(ctx, d.timeout)
31
+ defer cancel()
32
+ out, err := d.run(ctx, "/usr/bin/id", []string{user}, []string{"LC_ALL=C"})
33
+ if ctx.Err() != nil {
34
+ return nil, fmt.Errorf("directory groups: %w", ctx.Err())
35
+ }
36
+ if err != nil {
37
+ return nil, errors.New("directory group lookup failed")
38
+ }
39
+ return parseDirectoryGroups(out)
40
+ }
41
+
42
+ // Bounded stdout also bounds memory if a directory returns an excessive list.
43
+ // Never include command output in errors: it is not a diagnostic credential path.
44
+ type directoryOutput struct{ data []byte }
45
+
46
+ func (b *directoryOutput) Write(p []byte) (int, error) {
47
+ if len(p) > maxDirectoryOutput-len(b.data) {
48
+ return 0, errors.New("directory output exceeds limit")
49
+ }
50
+ b.data = append(b.data, p...)
51
+ return len(p), nil
52
+ }
53
+ func runDirectoryCommand(ctx context.Context, path string, args, env []string) ([]byte, error) {
54
+ cmd := exec.CommandContext(ctx, path, args...)
55
+ cmd.Env = env
56
+ cmd.WaitDelay = 100 * time.Millisecond
57
+ var out directoryOutput
58
+ cmd.Stdout = &out
59
+ err := cmd.Run()
60
+ return out.data, err
61
+ }
62
+
63
+ var directoryIDLine = regexp.MustCompile(`^uid=([0-9]+)\(([^()\r\n]+)\) gid=([0-9]+)\(([^()\r\n]+)\) groups=([^\r\n]+)\n?$`)
64
+ var directoryGroupEntry = regexp.MustCompile(`^([0-9]+)\(([^()\r\n]+)\)$`)
65
+
66
+ // Parse full id output, not id -Gn: the latter loses boundaries when AD group
67
+ // names contain spaces (for example VT-NAS\Domain Users). Require every gid to
68
+ // resolve to a bounded valid name, and require the primary group in the list.
69
+ // Unresolved numeric gids, partial/malformed output and ambiguous delimiters deny.
70
+ func parseDirectoryGroups(out []byte) ([]string, error) {
71
+ invalid := errors.New("incomplete or invalid directory groups")
72
+ if len(out) > maxDirectoryOutput {
73
+ return nil, invalid
74
+ }
75
+ m := directoryIDLine.FindStringSubmatch(string(out))
76
+ if m == nil || !validDirectoryID(m[1]) || !validDirectoryID(m[3]) || !userName.MatchString(m[2]) || !groupName.MatchString(m[4]) {
77
+ return nil, invalid
78
+ }
79
+ entries := strings.Split(m[5], ",")
80
+ if len(entries) > maxDirectoryGroups {
81
+ return nil, invalid
82
+ }
83
+ groups := make([]string, 0, len(entries))
84
+ seen := map[string]bool{}
85
+ primary := false
86
+ for _, entry := range entries {
87
+ g := directoryGroupEntry.FindStringSubmatch(entry)
88
+ if g == nil || !validDirectoryID(g[1]) || !groupName.MatchString(g[2]) || seen[g[1]] {
89
+ return nil, invalid
90
+ }
91
+ seen[g[1]] = true
92
+ if g[1] == m[3] {
93
+ if g[2] != m[4] {
94
+ return nil, invalid
95
+ }
96
+ primary = true
97
+ }
98
+ groups = append(groups, g[2])
99
+ }
100
+ if !primary {
101
+ return nil, invalid
102
+ }
103
+ return groups, nil
104
+ }
105
+ func validDirectoryID(value string) bool {
106
+ n, err := strconv.ParseUint(value, 10, 32)
107
+ return err == nil && n < 1<<32-1 && strconv.FormatUint(n, 10) == value
108
+ }