@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.
- package/README.md +7 -3
- package/dist/authorization-sdk.d.ts +5 -0
- package/dist/authorization-sdk.js +5 -0
- package/dist/build-spk/delete-app-data.d.ts +27 -7
- package/dist/build-spk/delete-app-data.js +35 -34
- package/dist/build-spk/dsm-arch.d.ts +6 -1
- package/dist/build-spk/dsm-arch.js +25 -1
- package/dist/build-spk/dsm-version.d.ts +14 -0
- package/dist/build-spk/dsm-version.js +47 -0
- package/dist/build-spk/gateway.d.ts +31 -0
- package/dist/build-spk/gateway.js +55 -0
- package/dist/build-spk/generator.d.ts +5 -0
- package/dist/build-spk/generator.js +103 -107
- package/dist/build-spk/install-wizard.d.ts +20 -0
- package/dist/build-spk/install-wizard.js +76 -0
- package/dist/build-spk/native-lifecycle.d.ts +5 -0
- package/dist/build-spk/native-lifecycle.js +12 -2
- package/dist/build-spk/resource-worker.d.ts +9 -4
- package/dist/build-spk/resource-worker.js +15 -6
- package/dist/build-spk/share-combobox.d.ts +3 -0
- package/dist/build-spk/share-combobox.js +27 -0
- package/dist/build-spk/uninstall-wizard.d.ts +14 -0
- package/dist/build-spk/uninstall-wizard.js +33 -0
- package/dist/build-spk/wizard-i18n.d.ts +18 -0
- package/dist/build-spk/wizard-i18n.js +38 -0
- package/dist/build-spk/wizard-messages.d.ts +388 -0
- package/dist/build-spk/wizard-messages.js +387 -0
- package/dist/cli.js +132 -32
- package/dist/compose/analyze.d.ts +20 -0
- package/dist/compose/analyze.js +75 -11
- package/dist/contract/validate.js +33 -1
- package/dist/contract/web-launch.d.ts +22 -0
- package/dist/contract/web-launch.js +37 -0
- package/dist/deploy/deploy.d.ts +3 -0
- package/dist/deploy/deploy.js +11 -2
- package/dist/error-registry.js +62 -3
- package/dist/host/dsm-port-profile.d.ts +1 -1
- package/dist/host/dsm-port-profile.js +1 -1
- package/dist/host/open-url.d.ts +2 -0
- package/dist/host/open-url.js +4 -1
- package/dist/images/pin.d.ts +52 -0
- package/dist/images/pin.js +249 -0
- package/dist/init.d.ts +27 -3
- package/dist/init.js +126 -16
- package/dist/inspect.d.ts +3 -0
- package/dist/inspect.js +15 -3
- package/dist/standalone/authorization-window.d.ts +2 -0
- package/dist/standalone/authorization-window.js +28 -0
- package/dist/standalone/authorization.d.ts +48 -0
- package/dist/standalone/authorization.js +116 -0
- package/dist/standalone/background.d.ts +21 -0
- package/dist/standalone/background.js +52 -0
- package/dist/standalone/binary.d.ts +1 -0
- package/dist/standalone/binary.js +1 -1
- package/dist/standalone/build.d.ts +2 -0
- package/dist/standalone/build.js +54 -10
- package/dist/standalone/dsm-window.js +10 -3
- package/dist/standalone/helper-inventory.d.ts +15 -0
- package/dist/standalone/helper-inventory.js +9 -0
- package/dist/standalone/helper.d.ts +1 -0
- package/dist/standalone/helper.js +29 -11
- package/dist/standalone/host-adapter.d.ts +1 -1
- package/dist/standalone/host-adapter.js +33 -15
- package/dist/standalone/host-file-navigation.d.ts +7 -0
- package/dist/standalone/host-file-navigation.js +172 -0
- package/dist/standalone/inspect-helper.js +21 -6
- package/dist/standalone/inspect-spk.d.ts +1 -1
- package/dist/standalone/inspect-spk.js +211 -7
- package/dist/standalone/job-diagnostics.d.ts +1 -0
- package/dist/standalone/job-diagnostics.js +49 -0
- package/dist/standalone/lifecycle-helper.d.ts +1 -1
- package/dist/standalone/lifecycle-helper.js +2 -2
- package/dist/standalone/lifecycle.d.ts +1 -1
- package/dist/standalone/lifecycle.js +14 -4
- package/dist/standalone/manifest.d.ts +15 -2
- package/dist/standalone/manifest.js +37 -6
- package/dist/standalone/native-layout.d.ts +74 -0
- package/dist/standalone/native-layout.js +318 -0
- package/dist/standalone/resource.d.ts +11 -0
- package/dist/standalone/resource.js +13 -0
- package/dist/standalone/root-ops.d.ts +2 -0
- package/dist/standalone/root-ops.js +10 -0
- package/dist/standalone/root-window.d.ts +3 -1
- package/dist/standalone/root-window.js +156 -38
- package/dist/standalone/shared-folder.d.ts +39 -0
- package/dist/standalone/shared-folder.js +141 -0
- package/dist/standalone/spk.d.ts +4 -0
- package/dist/standalone/spk.js +47 -3
- package/dist/standalone/worker-contract-json.d.ts +8 -0
- package/dist/standalone/worker-contract-json.js +141 -0
- package/dist/standalone/worker-contract.d.ts +189 -0
- package/dist/standalone/worker-contract.js +175 -0
- package/dist/standalone/worker-registry.d.ts +40 -0
- package/dist/standalone/worker-registry.js +167 -0
- package/dist/templates/_authorization/main.go +104 -0
- package/dist/templates/_authorization/main_test.go +35 -0
- package/dist/templates/_daemon/go.mod +2 -0
- package/dist/templates/_gateway/auth.go +101 -0
- package/dist/templates/_gateway/auth_test.go +216 -0
- package/dist/templates/_gateway/cgi.go +133 -0
- package/dist/templates/_gateway/cgi_test.go +156 -0
- package/dist/templates/_gateway/csrf.go +73 -0
- package/dist/templates/_gateway/csrf_test.go +155 -0
- package/dist/templates/_gateway/directory.go +108 -0
- package/dist/templates/_gateway/directory_test.go +202 -0
- package/dist/templates/_gateway/gateway.go +412 -0
- package/dist/templates/_gateway/gateway_test.go +676 -0
- package/dist/templates/_gateway/go.mod +3 -0
- package/dist/templates/_gateway/groups.go +66 -0
- package/dist/templates/_gateway/main.go +45 -0
- package/dist/templates/binary/synology-app.yaml +1 -1
- package/dist/templates/compose-import/compose.yaml +1 -1
- package/dist/templates/compose-import/synology-app.yaml +1 -1
- package/dist/templates/hello-files/compose.yaml +1 -1
- package/dist/templates/hello-files/synology-app.yaml +1 -1
- package/dist/templates/native-go/README.md +118 -5
- package/dist/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +3 -1
- package/dist/templates/native-go/backend/cmd/app/main.go +25 -6
- package/dist/templates/native-go/backend/cmd/app/sdk_main.go +62 -0
- package/dist/templates/native-go/backend/cmd/background-worker/main.go +38 -0
- package/dist/templates/native-go/backend/cmd/helper/main.go +27 -1
- package/dist/templates/native-go/backend/cmd/helper/sdk_registry.go +19 -0
- package/dist/templates/native-go/backend/go.mod +5 -3
- package/dist/templates/native-go/backend/go.sum +4 -4
- package/dist/templates/native-go/backend/internal/api/registry.go +17 -6
- package/dist/templates/native-go/backend/internal/api/server.go +7 -1
- package/dist/templates/native-go/backend/internal/app/authorization_none.go +5 -0
- package/dist/templates/native-go/backend/internal/app/background.go +270 -0
- package/dist/templates/native-go/backend/internal/app/background_none.go +8 -0
- package/dist/templates/native-go/backend/internal/app/background_owner.go +59 -0
- package/dist/templates/native-go/backend/internal/app/background_owner_test.go +145 -0
- package/dist/templates/native-go/backend/internal/app/background_schedule.go +74 -0
- package/dist/templates/native-go/backend/internal/app/background_schedule_test.go +62 -0
- package/dist/templates/native-go/backend/internal/app/background_test.go +346 -0
- package/dist/templates/native-go/backend/internal/app/integration_state.go +16 -0
- package/dist/templates/native-go/backend/internal/app/migrations.go +41 -0
- package/dist/templates/native-go/backend/internal/app/migrations_test.go +41 -0
- package/dist/templates/native-go/backend/internal/app/nas_cgi_artifact_test.go +8 -0
- package/dist/templates/native-go/backend/internal/app/routes.go +22 -5
- package/dist/templates/native-go/backend/internal/app/routes_test.go +20 -3
- package/dist/templates/native-go/backend/internal/app/sdk_jobs.go +70 -0
- package/dist/templates/native-go/backend/internal/app/sdk_jobs_test.go +116 -0
- package/dist/templates/native-go/backend/internal/app/sdk_routes.go +177 -0
- package/dist/templates/native-go/backend/internal/app/session_files.go +15 -0
- package/dist/templates/native-go/backend/internal/app/session_files_test.go +26 -0
- package/dist/templates/native-go/backend/internal/app/shared_folder.go +144 -0
- package/dist/templates/native-go/backend/internal/app/shared_folder_test.go +158 -0
- package/dist/templates/native-go/backend/internal/background/access.go +57 -0
- package/dist/templates/native-go/backend/internal/background/owner_test.go +126 -0
- package/dist/templates/native-go/backend/internal/background/runner.go +185 -0
- package/dist/templates/native-go/backend/internal/background/runner_test.go +209 -0
- package/dist/templates/native-go/backend/internal/background/schedule.go +300 -0
- package/dist/templates/native-go/backend/internal/background/schedule_test.go +335 -0
- package/dist/templates/native-go/backend/internal/background/store.go +807 -0
- package/dist/templates/native-go/backend/internal/background/store_test.go +407 -0
- package/dist/templates/native-go/backend/internal/datamigrate/migrate.go +191 -0
- package/dist/templates/native-go/backend/internal/datamigrate/migrate_test.go +177 -0
- package/dist/templates/native-go/backend/internal/filestation/browse_test.go +67 -0
- package/dist/templates/native-go/backend/internal/filestation/client.go +251 -0
- package/dist/templates/native-go/backend/internal/filestation/client_test.go +155 -0
- package/dist/templates/native-go/backend/internal/filestation/doc.go +4 -0
- package/dist/templates/native-go/backend/internal/filestation/read_file_test.go +90 -0
- package/dist/templates/native-go/backend/internal/filestation/repository.go +207 -0
- package/dist/templates/native-go/backend/internal/filestation/repository_test.go +104 -0
- package/dist/templates/native-go/backend/internal/filestation/sdk_session.go +241 -0
- package/dist/templates/native-go/backend/internal/filestation/sdk_session_test.go +183 -0
- package/dist/templates/native-go/backend/internal/filestation/service.go +254 -0
- package/dist/templates/native-go/backend/internal/filestation/service_test.go +94 -0
- package/dist/templates/native-go/backend/internal/filestation/session_semantics_test.go +383 -0
- package/dist/templates/native-go/backend/internal/filestation/write.go +72 -0
- package/dist/templates/native-go/backend/internal/filestation/write_test.go +123 -0
- package/dist/templates/native-go/backend/internal/helper/background_proof.go +163 -0
- package/dist/templates/native-go/backend/internal/helper/background_proof_contract.go +46 -0
- package/dist/templates/native-go/backend/internal/helper/background_proof_test.go +161 -0
- package/dist/templates/native-go/backend/internal/helper/data_contract.go +3 -0
- package/dist/templates/native-go/backend/internal/helper/data_protocol.go +3 -0
- package/dist/templates/native-go/backend/internal/helper/data_protocol_test.go +1 -1
- package/dist/templates/native-go/backend/internal/helper/grant_authority.go +3 -0
- package/dist/templates/native-go/backend/internal/helper/grant_authority_test.go +1 -1
- package/dist/templates/native-go/backend/internal/helper/grant_repository_linux.go +2 -1
- package/dist/templates/native-go/backend/internal/helper/grant_repository_linux_test.go +4 -3
- package/dist/templates/native-go/backend/internal/helper/grant_snapshot.go +3 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/bindings.go +48 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/contract_test.go +436 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/decode.go +185 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/digest.go +55 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/registry.go +85 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/registry_test.go +73 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/result.go +53 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/stub.go +8 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/testdata/input-digests.json +127 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/types.go +234 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/types_test.go +29 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/validate.go +462 -0
- package/dist/templates/native-go/backend/internal/helper/legacy_authority_schema_linux_test.go +34 -0
- package/dist/templates/native-go/backend/internal/helper/legacy_authority_schema_test.go +6 -0
- package/dist/templates/native-go/backend/internal/helper/management.go +86 -0
- package/dist/templates/native-go/backend/internal/helper/observation.go +42 -2
- package/dist/templates/native-go/backend/internal/helper/observation_health_test.go +13 -1
- package/dist/templates/native-go/backend/internal/helper/observer_diagnostic.go +56 -10
- package/dist/templates/native-go/backend/internal/helper/observer_diagnostic_linux_test.go +6 -0
- package/dist/templates/native-go/backend/internal/helper/observer_diagnostic_writer.go +40 -0
- package/dist/templates/native-go/backend/internal/helper/process_linux.go +3 -0
- package/dist/templates/native-go/backend/internal/helper/purge.go +115 -0
- package/dist/templates/native-go/backend/internal/helper/purge_test.go +59 -0
- package/dist/templates/native-go/backend/internal/helper/query_deadline_linux_test.go +115 -0
- package/dist/templates/native-go/backend/internal/helper/query_pending_diagnostic_test.go +254 -0
- package/dist/templates/native-go/backend/internal/helper/relaxed_invalidation.go +3 -0
- package/dist/templates/native-go/backend/internal/helper/revoke.go +109 -0
- package/dist/templates/native-go/backend/internal/helper/revoke_test.go +121 -0
- package/dist/templates/native-go/backend/internal/helper/s1r_actor_races_linux_test.go +23 -4
- package/dist/templates/native-go/backend/internal/helper/sdk_assembly_linux.go +51 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_attach.go +83 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_attach_contract.go +32 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_attach_test.go +184 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_authority_schema_test.go +6 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_background_authority.go +832 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_background_authority_test.go +714 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_background_invalidation.go +218 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_background_lease.go +218 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_background_snapshot.go +110 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_background_store_linux_test.go +261 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_background_store_test.go +58 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_bindings.go +60 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_data_contract.go +251 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_data_protocol.go +424 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_dispatch_absence_test.go +51 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_display.go +488 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_display_contract.go +121 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_display_test.go +459 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_grant_authority.go +559 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_grant_repository_linux.go +417 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_grant_snapshot.go +94 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_history.go +80 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_history_test.go +76 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_job.go +697 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_job_child_linux.go +309 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_job_contract.go +122 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_job_linux_test.go +159 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_job_process_linux.go +327 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_job_test.go +501 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_job_vm_linux_test.go +343 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_journal.go +77 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_journal_linux.go +244 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_journal_linux_test.go +295 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_journal_test.go +71 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_picker_test.go +50 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_process_linux.go +184 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_public_vm_linux_test.go +129 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_relaxed_invalidation.go +242 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_rpc.go +299 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_rpc_contract.go +70 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_rpc_test.go +135 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_server_linux.go +161 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_session.go +677 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_session_contract.go +72 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_session_fence_test.go +215 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_session_test.go +475 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_supervisor_frame.go +78 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_supervisor_linux.go +414 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_transport.go +79 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_transport_linux.go +82 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_transport_test.go +64 -0
- package/dist/templates/native-go/backend/internal/helper/server_linux.go +14 -2
- package/dist/templates/native-go/backend/internal/helper/stale_management_linux_test.go +126 -0
- package/dist/templates/native-go/backend/internal/helper/stale_management_test.go +122 -0
- package/dist/templates/native-go/backend/internal/helper/startup_diagnostic.go +68 -0
- package/dist/templates/native-go/backend/internal/helper/startup_diagnostic_linux_test.go +126 -0
- package/dist/templates/native-go/backend/internal/helper/startup_diagnostic_test.go +117 -0
- package/dist/templates/native-go/backend/internal/helper/status.go +22 -13
- package/dist/templates/native-go/backend/internal/helper/status_test.go +45 -0
- package/dist/templates/native-go/backend/internal/helper/supervision.go +1 -1
- package/dist/templates/native-go/backend/internal/helper/supervisor_frame.go +3 -0
- package/dist/templates/native-go/backend/internal/helper/supervisor_linux.go +6 -2
- package/dist/templates/native-go/backend/internal/helper/unit_connection_test.go +22 -4
- package/dist/templates/native-go/backend/internal/helper/unit_linux.go +7 -3
- package/dist/templates/native-go/backend/internal/helper/unit_query_linux.go +5 -1
- package/dist/templates/native-go/backend/internal/helper/write_files_linux.go +7 -4
- package/dist/templates/native-go/backend/internal/helper/write_files_linux_test.go +26 -0
- package/dist/templates/native-go/dsm-package.yaml +2 -2
- package/dist/templates/native-go-authorization/backend/internal/app/authorization.go +298 -0
- package/dist/templates/native-go-authorization/backend/internal/app/authorization_test.go +96 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/AuthorizationGate.vue +89 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/de.json +36 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/en.json +36 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/es.json +36 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/fr.json +36 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/index.ts +15 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/it.json +36 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/ja.json +36 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/ko.json +36 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/zh-CN.json +36 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/zh-TW.json +36 -0
- package/dist/templates/native-go-authorization/frontend/test/authorization-preview.html +14 -0
- package/dist/templates/native-go-authorization/frontend/test/authorization.test.ts +59 -0
- package/dist/templates/native-go-background/BACKGROUND.md +111 -0
- package/dist/templates/native-go-background/backend/internal/app/background_on.go +7 -0
- package/dist/templates/native-go-background/backend/internal/app/background_routes_test.go +32 -0
- package/dist/templates/native-go-background/frontend/src/background/BackgroundPanel.vue +178 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n/de.json +83 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n/en.json +83 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n/es.json +83 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n/fr.json +83 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n/it.json +83 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n/ja.json +83 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n/ko.json +83 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n/zh-CN.json +83 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n/zh-TW.json +83 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n.ts +19 -0
- package/dist/templates/native-go-background/frontend/src/background/picker-provider.ts +13 -0
- package/dist/templates/native-go-background/frontend/test/background.test.ts +179 -0
- package/dist/templates/native-go-integration/backend/internal/app/personal.go +2 -2
- package/dist/templates/native-go-integration/backend/internal/app/personal_test.go +37 -0
- package/dist/templates/native-go-vue/README.md +38 -7
- package/dist/templates/native-go-vue/frontend/DESIGN.md +15 -3
- package/dist/templates/native-go-vue/frontend/README-JOBS.md +75 -0
- package/dist/templates/native-go-vue/frontend/README-M2.md +64 -0
- package/dist/templates/native-go-vue/frontend/package-lock.json +5 -4
- package/dist/templates/native-go-vue/frontend/package.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/App.vue +39 -11
- package/dist/templates/native-go-vue/frontend/src/M2App.vue +57 -0
- package/dist/templates/native-go-vue/frontend/src/SDKApp.vue +203 -0
- package/dist/templates/native-go-vue/frontend/src/context.ts +3 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/InteractiveJobForm.vue +70 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/JobsAdminPanel.vue +33 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/JobsPanel.vue +135 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/connected-provider.ts +179 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n/de.json +62 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n/en.json +62 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n/es.json +62 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n/fr.json +62 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n/it.json +62 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n/ja.json +62 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n/ko.json +62 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n/zh-CN.json +62 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n/zh-TW.json +62 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n.ts +15 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/mock-provider.ts +67 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/provider.ts +60 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/validate.ts +44 -0
- package/dist/templates/native-go-vue/frontend/src/m2-main.ts +21 -0
- package/dist/templates/native-go-vue/frontend/src/m2-style.css +7 -0
- package/dist/templates/native-go-vue/frontend/src/nas/M2Files.vue +94 -0
- package/dist/templates/native-go-vue/frontend/src/nas/M2PathPicker.vue +70 -0
- package/dist/templates/native-go-vue/frontend/src/nas/M2Settings.vue +69 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/de.json +56 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/en.json +56 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/es.json +56 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/fr.json +56 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/it.json +56 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/ja.json +56 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/ko.json +56 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-CN.json +56 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-TW.json +56 -0
- package/dist/templates/native-go-vue/frontend/src/nas/m2-contract.ts +33 -0
- package/dist/templates/native-go-vue/frontend/src/nas/m2-i18n.ts +24 -0
- package/dist/templates/native-go-vue/frontend/src/nas/m2-provider.ts +104 -0
- package/dist/templates/native-go-vue/frontend/src/nas/use-m2-request.ts +18 -0
- package/dist/templates/native-go-vue/frontend/src/sdk-main.ts +39 -0
- package/dist/templates/native-go-vue/frontend/src/shell/AppShell.vue +48 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/de.json +10 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/en.json +10 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/es.json +10 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/fr.json +10 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/it.json +10 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/ja.json +10 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/ko.json +10 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/zh-CN.json +10 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/zh-TW.json +10 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n.ts +17 -0
- package/dist/templates/native-go-vue/frontend/src/shell/pages.ts +34 -0
- package/dist/templates/native-go-vue/frontend/src/style.css +2 -6
- package/dist/templates/native-go-vue/frontend/test/apps.test.ts +21 -0
- package/dist/templates/native-go-vue/frontend/test/jobs-connected.test.ts +163 -0
- package/dist/templates/native-go-vue/frontend/test/jobs-preview.html +22 -0
- package/dist/templates/native-go-vue/frontend/test/jobs.test.ts +176 -0
- package/dist/templates/native-go-vue/frontend/test/m2-preview.html +27 -0
- package/dist/templates/native-go-vue/frontend/test/m2-provider.test.ts +87 -0
- package/dist/templates/native-go-vue/frontend/test/m2-ui.test.ts +209 -0
- package/dist/templates/native-go-vue/frontend/test/native-controls.test.ts +27 -0
- package/dist/templates/native-go-vue/frontend/test/picker-wire.test.ts +110 -0
- package/dist/templates/native-go-vue/frontend/test/shell-preview.html +19 -0
- package/dist/templates/native-go-vue/frontend/test/shell-sdk.test.ts +73 -0
- package/dist/templates/native-go-vue/frontend/test/shell-ui.test.ts +114 -0
- package/dist/templates/native-go-vue/frontend/test/shell.test.ts +45 -0
- package/dist/templates/native-go-vue/frontend/vite.config.ts +2 -2
- package/dist/types.d.ts +1 -1
- package/dist/validate.js +6 -3
- package/package.json +5 -2
- package/schema/synology-app.schema.json +19 -0
- package/skills/reference/create.md +6 -2
- package/templates/_authorization/main.go +104 -0
- package/templates/_authorization/main_test.go +35 -0
- package/templates/_daemon/go.mod +2 -0
- package/templates/_gateway/auth.go +101 -0
- package/templates/_gateway/auth_test.go +216 -0
- package/templates/_gateway/cgi.go +133 -0
- package/templates/_gateway/cgi_test.go +156 -0
- package/templates/_gateway/csrf.go +73 -0
- package/templates/_gateway/csrf_test.go +155 -0
- package/templates/_gateway/directory.go +108 -0
- package/templates/_gateway/directory_test.go +202 -0
- package/templates/_gateway/gateway.go +412 -0
- package/templates/_gateway/gateway_test.go +676 -0
- package/templates/_gateway/go.mod +3 -0
- package/templates/_gateway/groups.go +66 -0
- package/templates/_gateway/main.go +45 -0
- package/templates/binary/synology-app.yaml +1 -1
- package/templates/compose-import/compose.yaml +1 -1
- package/templates/compose-import/synology-app.yaml +1 -1
- package/templates/hello-files/compose.yaml +1 -1
- package/templates/hello-files/synology-app.yaml +1 -1
- package/templates/native-go/README.md +118 -5
- package/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +3 -1
- package/templates/native-go/backend/cmd/app/main.go +25 -6
- package/templates/native-go/backend/cmd/app/sdk_main.go +62 -0
- package/templates/native-go/backend/cmd/background-worker/main.go +38 -0
- package/templates/native-go/backend/cmd/helper/main.go +27 -1
- package/templates/native-go/backend/cmd/helper/sdk_registry.go +19 -0
- package/templates/native-go/backend/go.mod +5 -3
- package/templates/native-go/backend/go.sum +4 -4
- package/templates/native-go/backend/internal/api/registry.go +17 -6
- package/templates/native-go/backend/internal/api/server.go +7 -1
- package/templates/native-go/backend/internal/app/authorization_none.go +5 -0
- package/templates/native-go/backend/internal/app/background.go +270 -0
- package/templates/native-go/backend/internal/app/background_none.go +8 -0
- package/templates/native-go/backend/internal/app/background_owner.go +59 -0
- package/templates/native-go/backend/internal/app/background_owner_test.go +145 -0
- package/templates/native-go/backend/internal/app/background_schedule.go +74 -0
- package/templates/native-go/backend/internal/app/background_schedule_test.go +62 -0
- package/templates/native-go/backend/internal/app/background_test.go +346 -0
- package/templates/native-go/backend/internal/app/integration_state.go +16 -0
- package/templates/native-go/backend/internal/app/migrations.go +41 -0
- package/templates/native-go/backend/internal/app/migrations_test.go +41 -0
- package/templates/native-go/backend/internal/app/nas_cgi_artifact_test.go +8 -0
- package/templates/native-go/backend/internal/app/routes.go +22 -5
- package/templates/native-go/backend/internal/app/routes_test.go +20 -3
- package/templates/native-go/backend/internal/app/sdk_jobs.go +70 -0
- package/templates/native-go/backend/internal/app/sdk_jobs_test.go +116 -0
- package/templates/native-go/backend/internal/app/sdk_routes.go +177 -0
- package/templates/native-go/backend/internal/app/session_files.go +15 -0
- package/templates/native-go/backend/internal/app/session_files_test.go +26 -0
- package/templates/native-go/backend/internal/app/shared_folder.go +144 -0
- package/templates/native-go/backend/internal/app/shared_folder_test.go +158 -0
- package/templates/native-go/backend/internal/background/access.go +57 -0
- package/templates/native-go/backend/internal/background/owner_test.go +126 -0
- package/templates/native-go/backend/internal/background/runner.go +185 -0
- package/templates/native-go/backend/internal/background/runner_test.go +209 -0
- package/templates/native-go/backend/internal/background/schedule.go +300 -0
- package/templates/native-go/backend/internal/background/schedule_test.go +335 -0
- package/templates/native-go/backend/internal/background/store.go +807 -0
- package/templates/native-go/backend/internal/background/store_test.go +407 -0
- package/templates/native-go/backend/internal/datamigrate/migrate.go +191 -0
- package/templates/native-go/backend/internal/datamigrate/migrate_test.go +177 -0
- package/templates/native-go/backend/internal/filestation/browse_test.go +67 -0
- package/templates/native-go/backend/internal/filestation/client.go +251 -0
- package/templates/native-go/backend/internal/filestation/client_test.go +155 -0
- package/templates/native-go/backend/internal/filestation/doc.go +4 -0
- package/templates/native-go/backend/internal/filestation/read_file_test.go +90 -0
- package/templates/native-go/backend/internal/filestation/repository.go +207 -0
- package/templates/native-go/backend/internal/filestation/repository_test.go +104 -0
- package/templates/native-go/backend/internal/filestation/sdk_session.go +241 -0
- package/templates/native-go/backend/internal/filestation/sdk_session_test.go +183 -0
- package/templates/native-go/backend/internal/filestation/service.go +254 -0
- package/templates/native-go/backend/internal/filestation/service_test.go +94 -0
- package/templates/native-go/backend/internal/filestation/session_semantics_test.go +383 -0
- package/templates/native-go/backend/internal/filestation/write.go +72 -0
- package/templates/native-go/backend/internal/filestation/write_test.go +123 -0
- package/templates/native-go/backend/internal/helper/background_proof.go +163 -0
- package/templates/native-go/backend/internal/helper/background_proof_contract.go +46 -0
- package/templates/native-go/backend/internal/helper/background_proof_test.go +161 -0
- package/templates/native-go/backend/internal/helper/data_contract.go +3 -0
- package/templates/native-go/backend/internal/helper/data_protocol.go +3 -0
- package/templates/native-go/backend/internal/helper/data_protocol_test.go +1 -1
- package/templates/native-go/backend/internal/helper/grant_authority.go +3 -0
- package/templates/native-go/backend/internal/helper/grant_authority_test.go +1 -1
- package/templates/native-go/backend/internal/helper/grant_repository_linux.go +2 -1
- package/templates/native-go/backend/internal/helper/grant_repository_linux_test.go +4 -3
- package/templates/native-go/backend/internal/helper/grant_snapshot.go +3 -0
- package/templates/native-go/backend/internal/helper/jobcontract/bindings.go +48 -0
- package/templates/native-go/backend/internal/helper/jobcontract/contract_test.go +436 -0
- package/templates/native-go/backend/internal/helper/jobcontract/decode.go +185 -0
- package/templates/native-go/backend/internal/helper/jobcontract/digest.go +55 -0
- package/templates/native-go/backend/internal/helper/jobcontract/registry.go +85 -0
- package/templates/native-go/backend/internal/helper/jobcontract/registry_test.go +73 -0
- package/templates/native-go/backend/internal/helper/jobcontract/result.go +53 -0
- package/templates/native-go/backend/internal/helper/jobcontract/stub.go +8 -0
- package/templates/native-go/backend/internal/helper/jobcontract/testdata/input-digests.json +127 -0
- package/templates/native-go/backend/internal/helper/jobcontract/types.go +234 -0
- package/templates/native-go/backend/internal/helper/jobcontract/types_test.go +29 -0
- package/templates/native-go/backend/internal/helper/jobcontract/validate.go +462 -0
- package/templates/native-go/backend/internal/helper/legacy_authority_schema_linux_test.go +34 -0
- package/templates/native-go/backend/internal/helper/legacy_authority_schema_test.go +6 -0
- package/templates/native-go/backend/internal/helper/management.go +86 -0
- package/templates/native-go/backend/internal/helper/observation.go +42 -2
- package/templates/native-go/backend/internal/helper/observation_health_test.go +13 -1
- package/templates/native-go/backend/internal/helper/observer_diagnostic.go +56 -10
- package/templates/native-go/backend/internal/helper/observer_diagnostic_linux_test.go +6 -0
- package/templates/native-go/backend/internal/helper/observer_diagnostic_writer.go +40 -0
- package/templates/native-go/backend/internal/helper/process_linux.go +3 -0
- package/templates/native-go/backend/internal/helper/purge.go +115 -0
- package/templates/native-go/backend/internal/helper/purge_test.go +59 -0
- package/templates/native-go/backend/internal/helper/query_deadline_linux_test.go +115 -0
- package/templates/native-go/backend/internal/helper/query_pending_diagnostic_test.go +254 -0
- package/templates/native-go/backend/internal/helper/relaxed_invalidation.go +3 -0
- package/templates/native-go/backend/internal/helper/revoke.go +109 -0
- package/templates/native-go/backend/internal/helper/revoke_test.go +121 -0
- package/templates/native-go/backend/internal/helper/s1r_actor_races_linux_test.go +23 -4
- package/templates/native-go/backend/internal/helper/sdk_assembly_linux.go +51 -0
- package/templates/native-go/backend/internal/helper/sdk_attach.go +83 -0
- package/templates/native-go/backend/internal/helper/sdk_attach_contract.go +32 -0
- package/templates/native-go/backend/internal/helper/sdk_attach_test.go +184 -0
- package/templates/native-go/backend/internal/helper/sdk_authority_schema_test.go +6 -0
- package/templates/native-go/backend/internal/helper/sdk_background_authority.go +832 -0
- package/templates/native-go/backend/internal/helper/sdk_background_authority_test.go +714 -0
- package/templates/native-go/backend/internal/helper/sdk_background_invalidation.go +218 -0
- package/templates/native-go/backend/internal/helper/sdk_background_lease.go +218 -0
- package/templates/native-go/backend/internal/helper/sdk_background_snapshot.go +110 -0
- package/templates/native-go/backend/internal/helper/sdk_background_store_linux_test.go +261 -0
- package/templates/native-go/backend/internal/helper/sdk_background_store_test.go +58 -0
- package/templates/native-go/backend/internal/helper/sdk_bindings.go +60 -0
- package/templates/native-go/backend/internal/helper/sdk_data_contract.go +251 -0
- package/templates/native-go/backend/internal/helper/sdk_data_protocol.go +424 -0
- package/templates/native-go/backend/internal/helper/sdk_dispatch_absence_test.go +51 -0
- package/templates/native-go/backend/internal/helper/sdk_display.go +488 -0
- package/templates/native-go/backend/internal/helper/sdk_display_contract.go +121 -0
- package/templates/native-go/backend/internal/helper/sdk_display_test.go +459 -0
- package/templates/native-go/backend/internal/helper/sdk_grant_authority.go +559 -0
- package/templates/native-go/backend/internal/helper/sdk_grant_repository_linux.go +417 -0
- package/templates/native-go/backend/internal/helper/sdk_grant_snapshot.go +94 -0
- package/templates/native-go/backend/internal/helper/sdk_history.go +80 -0
- package/templates/native-go/backend/internal/helper/sdk_history_test.go +76 -0
- package/templates/native-go/backend/internal/helper/sdk_job.go +697 -0
- package/templates/native-go/backend/internal/helper/sdk_job_child_linux.go +309 -0
- package/templates/native-go/backend/internal/helper/sdk_job_contract.go +122 -0
- package/templates/native-go/backend/internal/helper/sdk_job_linux_test.go +159 -0
- package/templates/native-go/backend/internal/helper/sdk_job_process_linux.go +327 -0
- package/templates/native-go/backend/internal/helper/sdk_job_test.go +501 -0
- package/templates/native-go/backend/internal/helper/sdk_job_vm_linux_test.go +343 -0
- package/templates/native-go/backend/internal/helper/sdk_journal.go +77 -0
- package/templates/native-go/backend/internal/helper/sdk_journal_linux.go +244 -0
- package/templates/native-go/backend/internal/helper/sdk_journal_linux_test.go +295 -0
- package/templates/native-go/backend/internal/helper/sdk_journal_test.go +71 -0
- package/templates/native-go/backend/internal/helper/sdk_picker_test.go +50 -0
- package/templates/native-go/backend/internal/helper/sdk_process_linux.go +184 -0
- package/templates/native-go/backend/internal/helper/sdk_public_vm_linux_test.go +129 -0
- package/templates/native-go/backend/internal/helper/sdk_relaxed_invalidation.go +242 -0
- package/templates/native-go/backend/internal/helper/sdk_rpc.go +299 -0
- package/templates/native-go/backend/internal/helper/sdk_rpc_contract.go +70 -0
- package/templates/native-go/backend/internal/helper/sdk_rpc_test.go +135 -0
- package/templates/native-go/backend/internal/helper/sdk_server_linux.go +161 -0
- package/templates/native-go/backend/internal/helper/sdk_session.go +677 -0
- package/templates/native-go/backend/internal/helper/sdk_session_contract.go +72 -0
- package/templates/native-go/backend/internal/helper/sdk_session_fence_test.go +215 -0
- package/templates/native-go/backend/internal/helper/sdk_session_test.go +475 -0
- package/templates/native-go/backend/internal/helper/sdk_supervisor_frame.go +78 -0
- package/templates/native-go/backend/internal/helper/sdk_supervisor_linux.go +414 -0
- package/templates/native-go/backend/internal/helper/sdk_transport.go +79 -0
- package/templates/native-go/backend/internal/helper/sdk_transport_linux.go +82 -0
- package/templates/native-go/backend/internal/helper/sdk_transport_test.go +64 -0
- package/templates/native-go/backend/internal/helper/server_linux.go +14 -2
- package/templates/native-go/backend/internal/helper/stale_management_linux_test.go +126 -0
- package/templates/native-go/backend/internal/helper/stale_management_test.go +122 -0
- package/templates/native-go/backend/internal/helper/startup_diagnostic.go +68 -0
- package/templates/native-go/backend/internal/helper/startup_diagnostic_linux_test.go +126 -0
- package/templates/native-go/backend/internal/helper/startup_diagnostic_test.go +117 -0
- package/templates/native-go/backend/internal/helper/status.go +22 -13
- package/templates/native-go/backend/internal/helper/status_test.go +45 -0
- package/templates/native-go/backend/internal/helper/supervision.go +1 -1
- package/templates/native-go/backend/internal/helper/supervisor_frame.go +3 -0
- package/templates/native-go/backend/internal/helper/supervisor_linux.go +6 -2
- package/templates/native-go/backend/internal/helper/unit_connection_test.go +22 -4
- package/templates/native-go/backend/internal/helper/unit_linux.go +7 -3
- package/templates/native-go/backend/internal/helper/unit_query_linux.go +5 -1
- package/templates/native-go/backend/internal/helper/write_files_linux.go +7 -4
- package/templates/native-go/backend/internal/helper/write_files_linux_test.go +26 -0
- package/templates/native-go/dsm-package.yaml +2 -2
- package/templates/native-go-authorization/backend/internal/app/authorization.go +298 -0
- package/templates/native-go-authorization/backend/internal/app/authorization_test.go +96 -0
- package/templates/native-go-authorization/frontend/src/authorization/AuthorizationGate.vue +89 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/de.json +36 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/en.json +36 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/es.json +36 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/fr.json +36 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/index.ts +15 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/it.json +36 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/ja.json +36 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/ko.json +36 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/zh-CN.json +36 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/zh-TW.json +36 -0
- package/templates/native-go-authorization/frontend/test/authorization-preview.html +14 -0
- package/templates/native-go-authorization/frontend/test/authorization.test.ts +59 -0
- package/templates/native-go-background/BACKGROUND.md +111 -0
- package/templates/native-go-background/backend/internal/app/background_on.go +7 -0
- package/templates/native-go-background/backend/internal/app/background_routes_test.go +32 -0
- package/templates/native-go-background/frontend/src/background/BackgroundPanel.vue +178 -0
- package/templates/native-go-background/frontend/src/background/i18n/de.json +83 -0
- package/templates/native-go-background/frontend/src/background/i18n/en.json +83 -0
- package/templates/native-go-background/frontend/src/background/i18n/es.json +83 -0
- package/templates/native-go-background/frontend/src/background/i18n/fr.json +83 -0
- package/templates/native-go-background/frontend/src/background/i18n/it.json +83 -0
- package/templates/native-go-background/frontend/src/background/i18n/ja.json +83 -0
- package/templates/native-go-background/frontend/src/background/i18n/ko.json +83 -0
- package/templates/native-go-background/frontend/src/background/i18n/zh-CN.json +83 -0
- package/templates/native-go-background/frontend/src/background/i18n/zh-TW.json +83 -0
- package/templates/native-go-background/frontend/src/background/i18n.ts +19 -0
- package/templates/native-go-background/frontend/src/background/picker-provider.ts +13 -0
- package/templates/native-go-background/frontend/test/background.test.ts +179 -0
- package/templates/native-go-integration/backend/internal/app/personal.go +2 -2
- package/templates/native-go-integration/backend/internal/app/personal_test.go +37 -0
- package/templates/native-go-vue/README.md +38 -7
- package/templates/native-go-vue/frontend/DESIGN.md +15 -3
- package/templates/native-go-vue/frontend/README-JOBS.md +75 -0
- package/templates/native-go-vue/frontend/README-M2.md +64 -0
- package/templates/native-go-vue/frontend/package-lock.json +5 -4
- package/templates/native-go-vue/frontend/package.json +1 -1
- package/templates/native-go-vue/frontend/src/App.vue +39 -11
- package/templates/native-go-vue/frontend/src/M2App.vue +57 -0
- package/templates/native-go-vue/frontend/src/SDKApp.vue +203 -0
- package/templates/native-go-vue/frontend/src/context.ts +3 -0
- package/templates/native-go-vue/frontend/src/jobs/InteractiveJobForm.vue +70 -0
- package/templates/native-go-vue/frontend/src/jobs/JobsAdminPanel.vue +33 -0
- package/templates/native-go-vue/frontend/src/jobs/JobsPanel.vue +135 -0
- package/templates/native-go-vue/frontend/src/jobs/connected-provider.ts +179 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n/de.json +62 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n/en.json +62 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n/es.json +62 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n/fr.json +62 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n/it.json +62 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n/ja.json +62 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n/ko.json +62 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n/zh-CN.json +62 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n/zh-TW.json +62 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n.ts +15 -0
- package/templates/native-go-vue/frontend/src/jobs/mock-provider.ts +67 -0
- package/templates/native-go-vue/frontend/src/jobs/provider.ts +60 -0
- package/templates/native-go-vue/frontend/src/jobs/validate.ts +44 -0
- package/templates/native-go-vue/frontend/src/m2-main.ts +21 -0
- package/templates/native-go-vue/frontend/src/m2-style.css +7 -0
- package/templates/native-go-vue/frontend/src/nas/M2Files.vue +94 -0
- package/templates/native-go-vue/frontend/src/nas/M2PathPicker.vue +70 -0
- package/templates/native-go-vue/frontend/src/nas/M2Settings.vue +69 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/m2/de.json +56 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/m2/en.json +56 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/m2/es.json +56 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/m2/fr.json +56 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/m2/it.json +56 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/m2/ja.json +56 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/m2/ko.json +56 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-CN.json +56 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-TW.json +56 -0
- package/templates/native-go-vue/frontend/src/nas/m2-contract.ts +33 -0
- package/templates/native-go-vue/frontend/src/nas/m2-i18n.ts +24 -0
- package/templates/native-go-vue/frontend/src/nas/m2-provider.ts +104 -0
- package/templates/native-go-vue/frontend/src/nas/use-m2-request.ts +18 -0
- package/templates/native-go-vue/frontend/src/sdk-main.ts +39 -0
- package/templates/native-go-vue/frontend/src/shell/AppShell.vue +48 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/de.json +10 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/en.json +10 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/es.json +10 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/fr.json +10 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/it.json +10 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/ja.json +10 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/ko.json +10 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/zh-CN.json +10 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/zh-TW.json +10 -0
- package/templates/native-go-vue/frontend/src/shell/i18n.ts +17 -0
- package/templates/native-go-vue/frontend/src/shell/pages.ts +34 -0
- package/templates/native-go-vue/frontend/src/style.css +2 -6
- package/templates/native-go-vue/frontend/test/apps.test.ts +21 -0
- package/templates/native-go-vue/frontend/test/jobs-connected.test.ts +163 -0
- package/templates/native-go-vue/frontend/test/jobs-preview.html +22 -0
- package/templates/native-go-vue/frontend/test/jobs.test.ts +176 -0
- package/templates/native-go-vue/frontend/test/m2-preview.html +27 -0
- package/templates/native-go-vue/frontend/test/m2-provider.test.ts +87 -0
- package/templates/native-go-vue/frontend/test/m2-ui.test.ts +209 -0
- package/templates/native-go-vue/frontend/test/native-controls.test.ts +27 -0
- package/templates/native-go-vue/frontend/test/picker-wire.test.ts +110 -0
- package/templates/native-go-vue/frontend/test/shell-preview.html +19 -0
- package/templates/native-go-vue/frontend/test/shell-sdk.test.ts +73 -0
- package/templates/native-go-vue/frontend/test/shell-ui.test.ts +114 -0
- package/templates/native-go-vue/frontend/test/shell.test.ts +45 -0
- package/templates/native-go-vue/frontend/vite.config.ts +2 -2
- package/dist/templates/hello-web/compose.yaml +0 -21
- package/dist/templates/hello-web/html/app.js +0 -1
- package/dist/templates/hello-web/html/index.html +0 -13
- package/dist/templates/hello-web/synology-app.yaml +0 -13
- package/dist/templates/hello-web-page/compose.yaml +0 -21
- package/dist/templates/hello-web-page/html/app.js +0 -1
- package/dist/templates/hello-web-page/html/index.html +0 -13
- package/dist/templates/hello-web-page/synology-app.yaml +0 -13
- package/templates/hello-web/compose.yaml +0 -21
- package/templates/hello-web/html/app.js +0 -1
- package/templates/hello-web/html/index.html +0 -13
- package/templates/hello-web/synology-app.yaml +0 -13
- package/templates/hello-web-page/compose.yaml +0 -21
- package/templates/hello-web-page/html/app.js +0 -1
- package/templates/hello-web-page/html/index.html +0 -13
- 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
|
+
}
|