@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,90 @@
|
|
|
1
|
+
package filestation
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"encoding/json"
|
|
6
|
+
"fmt"
|
|
7
|
+
"net/http"
|
|
8
|
+
"net/http/httptest"
|
|
9
|
+
"testing"
|
|
10
|
+
|
|
11
|
+
"dsmapp/internal/api"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
// identityServer answers like DSM for user "alice" with one 5-byte file.
|
|
15
|
+
func identityServer(t *testing.T, size int, user string) *Client {
|
|
16
|
+
return fakeClient(t, func(w http.ResponseWriter, r *http.Request) {
|
|
17
|
+
r.ParseForm()
|
|
18
|
+
switch r.Form.Get("method") {
|
|
19
|
+
case "get":
|
|
20
|
+
fmt.Fprintf(w, `{"success":true,"data":{"username":%q}}`, user)
|
|
21
|
+
case "getinfo":
|
|
22
|
+
isdir := "false"
|
|
23
|
+
if r.Form.Get("path") == `["/home"]` {
|
|
24
|
+
isdir = "true"
|
|
25
|
+
}
|
|
26
|
+
fmt.Fprintf(w, `{"success":true,"data":{"files":[{"path":%s,"name":"x","isdir":%s,"additional":{"size":%d}}]}}`, r.Form.Get("path")[1:len(r.Form.Get("path"))-1], isdir, size)
|
|
27
|
+
case "download":
|
|
28
|
+
w.Header().Set("Content-Disposition", `attachment; filename="x"`)
|
|
29
|
+
fmt.Fprint(w, "hello")
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
func fileService(t *testing.T, c *Client) (*Service, string) {
|
|
35
|
+
s := NewService(c, NewGrantRepository(t.TempDir()))
|
|
36
|
+
s.lookupUID = func(string) (string, error) { return "1000", nil }
|
|
37
|
+
return s, "/home"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
func alice(t *testing.T) api.Caller {
|
|
41
|
+
var got api.Caller
|
|
42
|
+
srv, _ := api.NewServer(testAuth{"alice"}, api.UserRequest("a.b", func(_ context.Context, c api.Caller, _ *http.Request, _ json.RawMessage) (any, error) {
|
|
43
|
+
got = c
|
|
44
|
+
return nil, nil
|
|
45
|
+
}))
|
|
46
|
+
r := sessionRequest()
|
|
47
|
+
r.Body = ioNop([]byte(`{"method":"a.b","params":{}}`))
|
|
48
|
+
r.Header.Set("Content-Type", "application/json")
|
|
49
|
+
srv.ServeHTTP(httptest.NewRecorder(), r)
|
|
50
|
+
return got
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
func TestReadFileReturnsSelectedFileThroughCurrentSession(t *testing.T) {
|
|
54
|
+
s, folder := fileService(t, identityServer(t, 5, "alice"))
|
|
55
|
+
data, err := s.ReadFile(context.Background(), alice(t), sessionRequest(), folder, "docs/x.txt")
|
|
56
|
+
if err != nil || string(data) != "hello" {
|
|
57
|
+
t.Fatalf("%q %v", data, err)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
func TestReadFileRefusesWhenSessionBelongsToAnotherUser(t *testing.T) {
|
|
62
|
+
s, folder := fileService(t, identityServer(t, 5, "mallory"))
|
|
63
|
+
if _, err := s.ReadFile(context.Background(), alice(t), sessionRequest(), folder, "x.txt"); err == nil {
|
|
64
|
+
t.Fatal("a session that resolves to another user must be refused")
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
func TestReadFileRefusesNonFoldersTraversalAndOversize(t *testing.T) {
|
|
69
|
+
s, folder := fileService(t, identityServer(t, MaxBytes+1, "alice"))
|
|
70
|
+
ctx, c := context.Background(), alice(t)
|
|
71
|
+
if _, err := s.ReadFile(ctx, c, sessionRequest(), folder, "x.txt"); err == nil {
|
|
72
|
+
t.Fatal("oversize file must be refused before download")
|
|
73
|
+
}
|
|
74
|
+
if _, err := s.ReadFile(ctx, c, sessionRequest(), "/home/x.txt", "x.txt"); err == nil {
|
|
75
|
+
t.Fatal("a folder that is not a directory must be refused")
|
|
76
|
+
}
|
|
77
|
+
if _, err := s.ReadFile(ctx, c, sessionRequest(), folder, "../etc/passwd"); err == nil {
|
|
78
|
+
t.Fatal("traversal must be refused")
|
|
79
|
+
}
|
|
80
|
+
if _, err := s.ReadFile(ctx, c, sessionRequest(), folder, ""); err == nil {
|
|
81
|
+
t.Fatal("the selected folder itself is not a file")
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
func TestReadFileOnNilServiceIsUnavailable(t *testing.T) {
|
|
86
|
+
var s *Service
|
|
87
|
+
if _, err := s.ReadFile(context.Background(), api.Caller{}, sessionRequest(), "x", "y"); err == nil {
|
|
88
|
+
t.Fatal("nil service must refuse")
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
package filestation
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"crypto/rand"
|
|
6
|
+
"encoding/hex"
|
|
7
|
+
"encoding/json"
|
|
8
|
+
"errors"
|
|
9
|
+
"io"
|
|
10
|
+
"os"
|
|
11
|
+
"path"
|
|
12
|
+
"strings"
|
|
13
|
+
"time"
|
|
14
|
+
|
|
15
|
+
"golang.org/x/sys/unix"
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
// Selection records user consent, never DSM authority. Unlike helper grants it
|
|
19
|
+
// cannot authorize an offline worker. Names/UIDs follow the relaxed identity
|
|
20
|
+
// contract: recreating the same name and UID can reuse a selection.
|
|
21
|
+
type Selection struct {
|
|
22
|
+
ID string `json:"grantId"`
|
|
23
|
+
User string `json:"user"`
|
|
24
|
+
UID string `json:"uid"`
|
|
25
|
+
Folder string `json:"folder"`
|
|
26
|
+
Writable bool `json:"writable"`
|
|
27
|
+
}
|
|
28
|
+
type GrantRepository struct{ dir string }
|
|
29
|
+
|
|
30
|
+
func NewGrantRepository(dir string) *GrantRepository { return &GrantRepository{dir: dir} }
|
|
31
|
+
|
|
32
|
+
// withStore serializes CGI processes, including in-flight operations and revoke.
|
|
33
|
+
// Local files are package-owned metadata only. No NAS data path is ever opened.
|
|
34
|
+
func (r *GrantRepository) withStore(ctx context.Context, fn func(*[]Selection) (bool, error)) error {
|
|
35
|
+
if r == nil || r.dir == "" {
|
|
36
|
+
return fail("unavailable")
|
|
37
|
+
}
|
|
38
|
+
root, e := os.OpenRoot(r.dir)
|
|
39
|
+
if e != nil {
|
|
40
|
+
return fail("unavailable")
|
|
41
|
+
}
|
|
42
|
+
defer root.Close()
|
|
43
|
+
lock, e := root.OpenFile("session-selections.lock", os.O_CREATE|os.O_RDWR|unix.O_NOFOLLOW, 0600)
|
|
44
|
+
if e != nil {
|
|
45
|
+
return fail("unavailable")
|
|
46
|
+
}
|
|
47
|
+
defer lock.Close()
|
|
48
|
+
info, e := lock.Stat()
|
|
49
|
+
if e != nil || !info.Mode().IsRegular() || info.Mode().Perm()&0077 != 0 {
|
|
50
|
+
return fail("unavailable")
|
|
51
|
+
}
|
|
52
|
+
for {
|
|
53
|
+
e = unix.Flock(int(lock.Fd()), unix.LOCK_EX|unix.LOCK_NB)
|
|
54
|
+
if e == nil {
|
|
55
|
+
break
|
|
56
|
+
}
|
|
57
|
+
if !errors.Is(e, unix.EWOULDBLOCK) {
|
|
58
|
+
return fail("unavailable")
|
|
59
|
+
}
|
|
60
|
+
select {
|
|
61
|
+
case <-ctx.Done():
|
|
62
|
+
return fail("canceled")
|
|
63
|
+
case <-time.After(10 * time.Millisecond):
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
defer unix.Flock(int(lock.Fd()), unix.LOCK_UN)
|
|
67
|
+
if ctx.Err() != nil {
|
|
68
|
+
return fail("canceled")
|
|
69
|
+
}
|
|
70
|
+
var entries []Selection
|
|
71
|
+
f, e := root.OpenFile("session-selections.json", os.O_RDONLY|unix.O_NOFOLLOW, 0)
|
|
72
|
+
if e == nil {
|
|
73
|
+
info, se := f.Stat()
|
|
74
|
+
b, re := io.ReadAll(io.LimitReader(f, maxMetadata+1))
|
|
75
|
+
f.Close()
|
|
76
|
+
if se != nil || !info.Mode().IsRegular() || info.Mode().Perm()&0077 != 0 || re != nil || len(b) > maxMetadata || json.Unmarshal(b, &entries) != nil {
|
|
77
|
+
return fail("unavailable")
|
|
78
|
+
}
|
|
79
|
+
} else if !errors.Is(e, os.ErrNotExist) {
|
|
80
|
+
return fail("unavailable")
|
|
81
|
+
}
|
|
82
|
+
seen := map[string]bool{}
|
|
83
|
+
if len(entries) > 256 {
|
|
84
|
+
return fail("unavailable")
|
|
85
|
+
}
|
|
86
|
+
for _, g := range entries {
|
|
87
|
+
if !validID(g.ID) || g.User == "" || g.UID == "" || !validPath(g.Folder) || seen[g.ID] {
|
|
88
|
+
return fail("unavailable")
|
|
89
|
+
}
|
|
90
|
+
seen[g.ID] = true
|
|
91
|
+
}
|
|
92
|
+
change, e := fn(&entries)
|
|
93
|
+
if e != nil || !change {
|
|
94
|
+
return e
|
|
95
|
+
}
|
|
96
|
+
b, e := json.Marshal(entries)
|
|
97
|
+
if e != nil || len(b) > maxMetadata {
|
|
98
|
+
return fail("limit-exceeded")
|
|
99
|
+
}
|
|
100
|
+
nonce := make([]byte, 16)
|
|
101
|
+
if _, e = rand.Read(nonce); e != nil {
|
|
102
|
+
return fail("unavailable")
|
|
103
|
+
}
|
|
104
|
+
tmp := ".session-selections-" + hex.EncodeToString(nonce)
|
|
105
|
+
out, e := root.OpenFile(tmp, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0600)
|
|
106
|
+
if e != nil {
|
|
107
|
+
return fail("unavailable")
|
|
108
|
+
}
|
|
109
|
+
defer root.Remove(tmp)
|
|
110
|
+
_, e = out.Write(b)
|
|
111
|
+
if e == nil {
|
|
112
|
+
e = out.Sync()
|
|
113
|
+
}
|
|
114
|
+
ce := out.Close()
|
|
115
|
+
if e != nil || ce != nil {
|
|
116
|
+
return fail("unavailable")
|
|
117
|
+
}
|
|
118
|
+
dir, e := root.Open(".")
|
|
119
|
+
if e != nil {
|
|
120
|
+
return fail("commit-uncertain")
|
|
121
|
+
}
|
|
122
|
+
defer dir.Close()
|
|
123
|
+
if unix.Renameat(int(dir.Fd()), tmp, int(dir.Fd()), "session-selections.json") != nil {
|
|
124
|
+
return fail("commit-uncertain")
|
|
125
|
+
}
|
|
126
|
+
if dir.Sync() != nil {
|
|
127
|
+
return fail("commit-uncertain")
|
|
128
|
+
}
|
|
129
|
+
return nil
|
|
130
|
+
}
|
|
131
|
+
func validID(id string) bool { b, e := hex.DecodeString(id); return e == nil && len(b) == 32 }
|
|
132
|
+
func (r *GrantRepository) Confirm(ctx context.Context, user, uid, folder string, writable bool) (Selection, error) {
|
|
133
|
+
var g Selection
|
|
134
|
+
if user == "" || uid == "" || !validPath(folder) {
|
|
135
|
+
return g, fail("invalid-request")
|
|
136
|
+
}
|
|
137
|
+
b := make([]byte, 32)
|
|
138
|
+
if _, e := rand.Read(b); e != nil {
|
|
139
|
+
return g, fail("unavailable")
|
|
140
|
+
}
|
|
141
|
+
g = Selection{hex.EncodeToString(b), user, uid, folder, writable}
|
|
142
|
+
e := r.withStore(ctx, func(gs *[]Selection) (bool, error) {
|
|
143
|
+
if len(*gs) >= 256 {
|
|
144
|
+
return false, fail("limit-exceeded")
|
|
145
|
+
}
|
|
146
|
+
*gs = append(*gs, g)
|
|
147
|
+
return true, nil
|
|
148
|
+
})
|
|
149
|
+
return g, e
|
|
150
|
+
}
|
|
151
|
+
func (r *GrantRepository) WithGrant(ctx context.Context, user, uid, id string, write bool, fn func(Selection) error) error {
|
|
152
|
+
if !validID(id) {
|
|
153
|
+
return fail("denied")
|
|
154
|
+
}
|
|
155
|
+
return r.withStore(ctx, func(gs *[]Selection) (bool, error) {
|
|
156
|
+
for _, g := range *gs {
|
|
157
|
+
if g.ID == id && g.User == user && g.UID == uid && (!write || g.Writable) {
|
|
158
|
+
return false, fn(g)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return false, fail("denied")
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
func (r *GrantRepository) List(ctx context.Context, user, uid string) ([]Selection, error) {
|
|
165
|
+
out := []Selection{}
|
|
166
|
+
e := r.withStore(ctx, func(gs *[]Selection) (bool, error) {
|
|
167
|
+
for _, g := range *gs {
|
|
168
|
+
if g.User == user && g.UID == uid {
|
|
169
|
+
out = append(out, g)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return false, nil
|
|
173
|
+
})
|
|
174
|
+
return out, e
|
|
175
|
+
}
|
|
176
|
+
func (r *GrantRepository) Revoke(ctx context.Context, user, uid, id string) error {
|
|
177
|
+
return r.withStore(ctx, func(gs *[]Selection) (bool, error) {
|
|
178
|
+
for i, g := range *gs {
|
|
179
|
+
if g.ID == id && g.User == user && g.UID == uid {
|
|
180
|
+
*gs = append((*gs)[:i], (*gs)[i+1:]...)
|
|
181
|
+
return true, nil
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return false, fail("denied")
|
|
185
|
+
})
|
|
186
|
+
}
|
|
187
|
+
func relative(root, rel string) (string, error) {
|
|
188
|
+
if !validPath(root) {
|
|
189
|
+
return "", fail("denied")
|
|
190
|
+
}
|
|
191
|
+
if rel == "" {
|
|
192
|
+
return root, nil
|
|
193
|
+
}
|
|
194
|
+
if strings.HasPrefix(rel, "/") || path.Clean(rel) != rel {
|
|
195
|
+
return "", fail("invalid-request")
|
|
196
|
+
}
|
|
197
|
+
for _, s := range strings.Split(rel, "/") {
|
|
198
|
+
if !validName(s) {
|
|
199
|
+
return "", fail("invalid-request")
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
p := root + "/" + rel
|
|
203
|
+
if !validPath(p) {
|
|
204
|
+
return "", fail("invalid-request")
|
|
205
|
+
}
|
|
206
|
+
return p, nil
|
|
207
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
package filestation
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"os"
|
|
6
|
+
"strings"
|
|
7
|
+
"testing"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
func TestSelectionPersistenceOwnershipAndRevoke(t *testing.T) {
|
|
11
|
+
dir := t.TempDir()
|
|
12
|
+
r := NewGrantRepository(dir)
|
|
13
|
+
ctx := context.Background()
|
|
14
|
+
g, e := r.Confirm(ctx, "alice", "1000", "/home", true)
|
|
15
|
+
if e != nil {
|
|
16
|
+
t.Fatal(e)
|
|
17
|
+
}
|
|
18
|
+
r = NewGrantRepository(dir)
|
|
19
|
+
called := false
|
|
20
|
+
if e = r.WithGrant(ctx, "alice", "1000", g.ID, false, func(g Selection) error { called = true; return nil }); e != nil || !called {
|
|
21
|
+
t.Fatal(e)
|
|
22
|
+
}
|
|
23
|
+
for _, owner := range [][2]string{{"bob", "1001"}, {"alice", "1001"}, {"bob", "1000"}} {
|
|
24
|
+
if e = r.WithGrant(ctx, owner[0], owner[1], g.ID, false, func(Selection) error { t.Fatal("cross user"); return nil }); e == nil {
|
|
25
|
+
t.Fatal("accepted")
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if e = r.Revoke(ctx, "alice", "1000", g.ID); e != nil {
|
|
29
|
+
t.Fatal(e)
|
|
30
|
+
}
|
|
31
|
+
if e = r.WithGrant(ctx, "alice", "1000", g.ID, false, func(Selection) error { t.Fatal("revoked"); return nil }); e == nil {
|
|
32
|
+
t.Fatal("accepted")
|
|
33
|
+
}
|
|
34
|
+
b, _ := os.ReadFile(dir + "/session-selections.json")
|
|
35
|
+
if strings.Contains(string(b), "test-session") {
|
|
36
|
+
t.Fatal("credentials persisted")
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
func TestReadonlySelectionAndTraversal(t *testing.T) {
|
|
40
|
+
r := NewGrantRepository(t.TempDir())
|
|
41
|
+
g, e := r.Confirm(context.Background(), "alice", "1000", "/home", false)
|
|
42
|
+
if e != nil {
|
|
43
|
+
t.Fatal(e)
|
|
44
|
+
}
|
|
45
|
+
if e = r.WithGrant(context.Background(), "alice", "1000", g.ID, true, func(Selection) error { t.Fatal("write admitted"); return nil }); e == nil {
|
|
46
|
+
t.Fatal("accepted")
|
|
47
|
+
}
|
|
48
|
+
for _, p := range []string{"../x", "a/../x", "/x", "a//x", "a\\x", "a,b", "a/./b"} {
|
|
49
|
+
if _, e := relative("/home", p); e == nil {
|
|
50
|
+
t.Fatal(p)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if p, e := relative("/home", "a/b"); e != nil || p != "/home/a/b" {
|
|
54
|
+
t.Fatal(p, e)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
func TestRevokeWaitsForActiveOperationAcrossRepositoryInstances(t *testing.T) {
|
|
59
|
+
dir := t.TempDir()
|
|
60
|
+
a, b := NewGrantRepository(dir), NewGrantRepository(dir)
|
|
61
|
+
ctx := context.Background()
|
|
62
|
+
g, e := a.Confirm(ctx, "alice", "1000", "/home", true)
|
|
63
|
+
if e != nil {
|
|
64
|
+
t.Fatal(e)
|
|
65
|
+
}
|
|
66
|
+
entered, release, done := make(chan struct{}), make(chan struct{}), make(chan error, 1)
|
|
67
|
+
go func() {
|
|
68
|
+
done <- a.WithGrant(ctx, "alice", "1000", g.ID, true, func(Selection) error { close(entered); <-release; return nil })
|
|
69
|
+
}()
|
|
70
|
+
<-entered
|
|
71
|
+
canceled, cancel := context.WithCancel(ctx)
|
|
72
|
+
cancel()
|
|
73
|
+
if e = b.Revoke(canceled, "alice", "1000", g.ID); e == nil {
|
|
74
|
+
t.Fatal("revoked through active lock")
|
|
75
|
+
}
|
|
76
|
+
close(release)
|
|
77
|
+
if e = <-done; e != nil {
|
|
78
|
+
t.Fatal(e)
|
|
79
|
+
}
|
|
80
|
+
if e = b.Revoke(ctx, "alice", "1000", g.ID); e != nil {
|
|
81
|
+
t.Fatal(e)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
func TestCorruptAndSymlinkStoresFailClosed(t *testing.T) {
|
|
86
|
+
for _, data := range []string{`broken`, `[{"grantId":"bad","folder":"/home"}]`} {
|
|
87
|
+
dir := t.TempDir()
|
|
88
|
+
if e := os.WriteFile(dir+"/session-selections.json", []byte(data), 0600); e != nil {
|
|
89
|
+
t.Fatal(e)
|
|
90
|
+
}
|
|
91
|
+
if _, e := NewGrantRepository(dir).List(context.Background(), "alice", "1000"); e == nil {
|
|
92
|
+
t.Fatal("corrupt accepted")
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
dir := t.TempDir()
|
|
96
|
+
target := t.TempDir() + "/outside"
|
|
97
|
+
os.WriteFile(target, []byte(`[]`), 0600)
|
|
98
|
+
if e := os.Symlink(target, dir+"/session-selections.json"); e != nil {
|
|
99
|
+
t.Fatal(e)
|
|
100
|
+
}
|
|
101
|
+
if _, e := NewGrantRepository(dir).List(context.Background(), "alice", "1000"); e == nil {
|
|
102
|
+
t.Fatal("symlink accepted")
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
//go:build synopkgland_sdk_workers
|
|
2
|
+
|
|
3
|
+
package filestation
|
|
4
|
+
|
|
5
|
+
import (
|
|
6
|
+
"context"
|
|
7
|
+
"dsmapp/internal/api"
|
|
8
|
+
"dsmapp/internal/helper/jobcontract"
|
|
9
|
+
"encoding/json"
|
|
10
|
+
"errors"
|
|
11
|
+
"golang.org/x/sys/unix"
|
|
12
|
+
"io"
|
|
13
|
+
"mime"
|
|
14
|
+
"net/http"
|
|
15
|
+
"os"
|
|
16
|
+
"strconv"
|
|
17
|
+
"strings"
|
|
18
|
+
"time"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
// SessionIdentity is authenticated per request, not an offline grant, account
|
|
22
|
+
// incarnation or a local ACL calculation. Admin is DSM administrators membership.
|
|
23
|
+
type SessionIdentity struct {
|
|
24
|
+
User, UID string
|
|
25
|
+
Admin bool
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
func (s *Service) CheckSession(ctx context.Context, auth api.Authenticator, r *http.Request) (SessionIdentity, error) {
|
|
29
|
+
if s == nil || s.client == nil || auth == nil || r == nil {
|
|
30
|
+
return SessionIdentity{}, fail("unavailable")
|
|
31
|
+
}
|
|
32
|
+
a, e := auth.Authenticate(r.WithContext(ctx))
|
|
33
|
+
if e != nil || a.User == "" {
|
|
34
|
+
return SessionIdentity{}, fail("session_required")
|
|
35
|
+
}
|
|
36
|
+
if e = s.client.Verify(ctx, r, a.User); e != nil {
|
|
37
|
+
return SessionIdentity{}, e
|
|
38
|
+
}
|
|
39
|
+
uid, e := s.lookupUID(a.User)
|
|
40
|
+
n, parse := strconv.ParseUint(uid, 10, 32)
|
|
41
|
+
if e != nil || parse != nil || n == 0 || strconv.FormatUint(n, 10) != uid || ctx.Err() != nil {
|
|
42
|
+
return SessionIdentity{}, fail("denied")
|
|
43
|
+
}
|
|
44
|
+
return SessionIdentity{User: a.User, UID: uid, Admin: a.Admin}, nil
|
|
45
|
+
}
|
|
46
|
+
func (s *Service) JobSelection(ctx context.Context, id SessionIdentity, grant string) error {
|
|
47
|
+
if s == nil || s.repository == nil {
|
|
48
|
+
return fail("unavailable")
|
|
49
|
+
}
|
|
50
|
+
return s.repository.withJobGrant(ctx, id, grant, func(Selection) error { return nil })
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Fixed, counter-only read plans. No NAS path is opened with POSIX APIs. This
|
|
54
|
+
// shares M2 selection/revoke locking and path semantics, not inode confinement.
|
|
55
|
+
func (s *Service) JobStep(ctx context.Context, r *http.Request, id SessionIdentity, grant string, step jobcontract.Step) (jobcontract.Result, error) {
|
|
56
|
+
out := jobcontract.Result{ResultSchema: 1}
|
|
57
|
+
if s == nil || s.client == nil || s.repository == nil {
|
|
58
|
+
return out, fail("unavailable")
|
|
59
|
+
}
|
|
60
|
+
if step.Action != jobcontract.List && step.Action != jobcontract.Stat && step.Action != jobcontract.Read {
|
|
61
|
+
return out, fail("unsupported")
|
|
62
|
+
}
|
|
63
|
+
for _, segment := range step.Segments {
|
|
64
|
+
if !validName(segment) {
|
|
65
|
+
return out, fail("invalid-request")
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
e := s.repository.withJobGrant(ctx, id, grant, func(g Selection) error {
|
|
69
|
+
target, e := relative(g.Folder, strings.Join(step.Segments, "/"))
|
|
70
|
+
if e != nil {
|
|
71
|
+
return e
|
|
72
|
+
}
|
|
73
|
+
switch step.Action {
|
|
74
|
+
case jobcontract.List:
|
|
75
|
+
if step.Limit == nil || *step.Limit == 0 || *step.Limit > PageSize {
|
|
76
|
+
return fail("limit-exceeded")
|
|
77
|
+
}
|
|
78
|
+
p, e := s.client.jobList(ctx, r, target, *step.Limit)
|
|
79
|
+
if e != nil {
|
|
80
|
+
return e
|
|
81
|
+
}
|
|
82
|
+
out.Entries = min(uint64(len(p.Files)), *step.Limit)
|
|
83
|
+
case jobcontract.Stat:
|
|
84
|
+
if _, e = s.client.Stat(ctx, r, target); e != nil {
|
|
85
|
+
return e
|
|
86
|
+
}
|
|
87
|
+
out.Entries = 1
|
|
88
|
+
case jobcontract.Read:
|
|
89
|
+
if step.MaxBytes == nil || *step.MaxBytes == 0 || *step.MaxBytes > MaxBytes {
|
|
90
|
+
return fail("limit-exceeded")
|
|
91
|
+
}
|
|
92
|
+
item, e := s.client.Stat(ctx, r, target)
|
|
93
|
+
if e != nil {
|
|
94
|
+
return e
|
|
95
|
+
}
|
|
96
|
+
if item.IsDir || item.Additional.Size < 0 {
|
|
97
|
+
return fail("denied")
|
|
98
|
+
}
|
|
99
|
+
if uint64(item.Additional.Size) > *step.MaxBytes {
|
|
100
|
+
return fail("limit-exceeded")
|
|
101
|
+
}
|
|
102
|
+
b, e := s.client.jobRead(ctx, r, target, *step.MaxBytes)
|
|
103
|
+
defer clear(b)
|
|
104
|
+
if e != nil {
|
|
105
|
+
return e
|
|
106
|
+
}
|
|
107
|
+
if uint64(len(b)) > *step.MaxBytes {
|
|
108
|
+
return fail("limit-exceeded")
|
|
109
|
+
}
|
|
110
|
+
out.BytesRead = uint64(len(b))
|
|
111
|
+
}
|
|
112
|
+
if ctx.Err() != nil {
|
|
113
|
+
return fail("canceled")
|
|
114
|
+
}
|
|
115
|
+
out.CompletedSteps = 1
|
|
116
|
+
return nil
|
|
117
|
+
})
|
|
118
|
+
return out, e
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Honor the exact step bounds at the WebAPI boundary, including a file that
|
|
122
|
+
// grows after getinfo. The extra byte detects overflow and is never counted or
|
|
123
|
+
// returned as a successful read.
|
|
124
|
+
func (c *Client) jobRead(ctx context.Context, r *http.Request, p string, limit uint64) ([]byte, error) {
|
|
125
|
+
v := fields("SYNO.FileStation.Download", "download", "2")
|
|
126
|
+
v.Set("path", array(p))
|
|
127
|
+
v.Set("mode", "download")
|
|
128
|
+
resp, e := c.send(ctx, r, strings.NewReader(v.Encode()), "")
|
|
129
|
+
if e != nil {
|
|
130
|
+
return nil, e
|
|
131
|
+
}
|
|
132
|
+
disposition, _, _ := mime.ParseMediaType(resp.Header.Get("Content-Disposition"))
|
|
133
|
+
if disposition != "attachment" {
|
|
134
|
+
e = decode(resp, nil)
|
|
135
|
+
if e == nil {
|
|
136
|
+
e = fail("unavailable")
|
|
137
|
+
}
|
|
138
|
+
return nil, e
|
|
139
|
+
}
|
|
140
|
+
defer resp.Body.Close()
|
|
141
|
+
b, e := io.ReadAll(io.LimitReader(resp.Body, int64(limit)+1))
|
|
142
|
+
if e != nil {
|
|
143
|
+
clear(b)
|
|
144
|
+
return nil, fail("read_failed")
|
|
145
|
+
}
|
|
146
|
+
if uint64(len(b)) > limit {
|
|
147
|
+
clear(b)
|
|
148
|
+
return nil, fail("limit-exceeded")
|
|
149
|
+
}
|
|
150
|
+
if resp.ContentLength >= 0 && resp.ContentLength != int64(len(b)) {
|
|
151
|
+
clear(b)
|
|
152
|
+
return nil, fail("read_failed")
|
|
153
|
+
}
|
|
154
|
+
return b, nil
|
|
155
|
+
}
|
|
156
|
+
func (c *Client) jobList(ctx context.Context, r *http.Request, p string, limit uint64) (Page, error) {
|
|
157
|
+
v := fields("SYNO.FileStation.List", "list", "2")
|
|
158
|
+
v.Set("folder_path", p)
|
|
159
|
+
v.Set("offset", "0")
|
|
160
|
+
v.Set("limit", strconv.FormatUint(limit, 10))
|
|
161
|
+
v.Set("additional", `["size"]`)
|
|
162
|
+
var page Page
|
|
163
|
+
e := c.call(ctx, r, v, &page)
|
|
164
|
+
if uint64(len(page.Files)) > limit || len(page.Shares) > 0 {
|
|
165
|
+
return Page{}, fail("limit-exceeded")
|
|
166
|
+
}
|
|
167
|
+
return page, e
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// The supervisor is root, while the M2 selection store is package-owned. This
|
|
171
|
+
// read-only entry never creates, rewrites or follows a metadata file. NONBLOCK
|
|
172
|
+
// plus fstat rejects FIFO/device substitutions before reading. The same flock
|
|
173
|
+
// stays held through each HTTP step, serializing M2 revoke with admission.
|
|
174
|
+
func (r *GrantRepository) withJobGrant(ctx context.Context, id SessionIdentity, grant string, fn func(Selection) error) error {
|
|
175
|
+
if r == nil || r.dir == "" || !validID(grant) {
|
|
176
|
+
return fail("denied")
|
|
177
|
+
}
|
|
178
|
+
root, e := os.OpenRoot(r.dir)
|
|
179
|
+
if e != nil {
|
|
180
|
+
return fail("unavailable")
|
|
181
|
+
}
|
|
182
|
+
defer root.Close()
|
|
183
|
+
open := func(name string) (*os.File, error) {
|
|
184
|
+
f, e := root.OpenFile(name, os.O_RDONLY|unix.O_NOFOLLOW|unix.O_NONBLOCK, 0)
|
|
185
|
+
if e != nil {
|
|
186
|
+
return nil, fail("unavailable")
|
|
187
|
+
}
|
|
188
|
+
st, e := f.Stat()
|
|
189
|
+
if e != nil || !st.Mode().IsRegular() || st.Mode().Perm()&0077 != 0 || st.Size() > maxMetadata {
|
|
190
|
+
f.Close()
|
|
191
|
+
return nil, fail("unavailable")
|
|
192
|
+
}
|
|
193
|
+
return f, nil
|
|
194
|
+
}
|
|
195
|
+
lock, e := open("session-selections.lock")
|
|
196
|
+
if e != nil {
|
|
197
|
+
return e
|
|
198
|
+
}
|
|
199
|
+
defer lock.Close()
|
|
200
|
+
for {
|
|
201
|
+
e = unix.Flock(int(lock.Fd()), unix.LOCK_EX|unix.LOCK_NB)
|
|
202
|
+
if e == nil {
|
|
203
|
+
break
|
|
204
|
+
}
|
|
205
|
+
if !errors.Is(e, unix.EWOULDBLOCK) {
|
|
206
|
+
return fail("unavailable")
|
|
207
|
+
}
|
|
208
|
+
select {
|
|
209
|
+
case <-ctx.Done():
|
|
210
|
+
return fail("canceled")
|
|
211
|
+
case <-time.After(10 * time.Millisecond):
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
defer unix.Flock(int(lock.Fd()), unix.LOCK_UN)
|
|
215
|
+
if ctx.Err() != nil {
|
|
216
|
+
return fail("canceled")
|
|
217
|
+
}
|
|
218
|
+
f, e := open("session-selections.json")
|
|
219
|
+
if e != nil {
|
|
220
|
+
return e
|
|
221
|
+
}
|
|
222
|
+
defer f.Close()
|
|
223
|
+
raw, e := io.ReadAll(io.LimitReader(f, maxMetadata+1))
|
|
224
|
+
var entries []Selection
|
|
225
|
+
if e != nil || len(raw) > maxMetadata || json.Unmarshal(raw, &entries) != nil || len(entries) > 256 {
|
|
226
|
+
return fail("unavailable")
|
|
227
|
+
}
|
|
228
|
+
seen := map[string]bool{}
|
|
229
|
+
for _, g := range entries {
|
|
230
|
+
if !validID(g.ID) || g.User == "" || g.UID == "" || !validPath(g.Folder) || seen[g.ID] {
|
|
231
|
+
return fail("unavailable")
|
|
232
|
+
}
|
|
233
|
+
seen[g.ID] = true
|
|
234
|
+
}
|
|
235
|
+
for _, g := range entries {
|
|
236
|
+
if g.ID == grant && g.User == id.User && g.UID == id.UID {
|
|
237
|
+
return fn(g)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return fail("denied")
|
|
241
|
+
}
|