@synopackageland/sdk 0.9.5 → 0.9.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synopackageland/sdk",
3
- "version": "0.9.5",
3
+ "version": "0.9.6",
4
4
  "description": "Frontend SDK for DSM packages built with synopkgland: headless client and Vue components",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/synopackageland/syno-pkg-land-sdk/tree/main/ts#readme",
@@ -53,7 +53,7 @@
53
53
  },
54
54
  "devDependencies": {
55
55
  "@lucide/vue": "1.48.0",
56
- "@synopackageland/ui": "0.9.1",
56
+ "@synopackageland/ui": "0.9.2",
57
57
  "@types/node": "24.19.2",
58
58
  "@vitejs/plugin-vue": "6.0.9",
59
59
  "jsdom": "27.4.0",
@@ -40,9 +40,13 @@ the executor against the vectors here.
40
40
  `dsm_synotoken` and `remote_addr` (since 0.9.4), the browser's address
41
41
  (REMOTE_ADDR). DSM's Application Privileges are evaluated for that address;
42
42
  an op that checks them MUST be refused with `APP_DENIED` when a present
43
- `auth` has no usable `remote_addr`. Requests without `auth` are checked as
44
- coming from 127.0.0.1. A present `auth` is always treated as caller
45
- authentication, never ignored, even when empty. Ops whose schema says
43
+ `auth` has no usable `remote_addr`. A grant records the `remote_addr` of the
44
+ `delegate.create` that made it (creating it again records the new one), and
45
+ an operation records the address of its `files.moveFromStaging` (since
46
+ 0.9.6). A request without `auth` under a grant, and the operation's
47
+ background revalidation, are checked from that recorded address; work with no
48
+ recorded address is checked as coming from 127.0.0.1. A present `auth` is
49
+ always treated as caller authentication, never ignored, even when empty. Ops whose schema says
46
50
  `"auth": "required"` MUST be refused with `AUTH_DENIED` without a valid DSM
47
51
  session.
48
52
  - `params` MUST be an object valid against `schema/<op>.json`. A member that
@@ -70,9 +74,46 @@ the executor against the vectors here.
70
74
  ## Status
71
75
 
72
76
  `status` answers `version` (`"1"`), `ready`, `disabled`, `executor_digest`
73
- and `policy_digest`. The executor MUST NOT report the SDK version; the binary
77
+ and `policy_digest`. With `auth` (since 0.9.6) it also answers `allowed`:
78
+ whether DSM's Application Privileges let the caller use the App and File
79
+ Station from `remote_addr`, the check `delegate.create` makes; an invalid
80
+ session is `AUTH_DENIED`. A CGI sends the caller's `auth` so an App the
81
+ executor would refuse is never shown as ready. The executor MUST NOT report the SDK version; the binary
74
82
  digest MUST change only when the executor source changes.
75
83
 
84
+ ## Application Portal
85
+
86
+ Since 0.9.6. A policy MAY carry `"portal": {"application": "<display name>",
87
+ "alias": "<default alias>"}` together with both `portal.register` and
88
+ `portal.unregister`; a policy with only some of the three is invalid. The
89
+ executor then registers the App's Application Portal entry the way DSM's
90
+ web-config worker does, on every DSM version: an App whose `os_min_ver` is
91
+ below 7.2 cannot declare that resource, since DSM 7.1 refuses it for unsigned
92
+ packages.
93
+
94
+ - Both ops take no params and require the session of an administrator whom
95
+ Application Privileges allow to use the App (`ADMIN_REQUIRED`,
96
+ `APP_DENIED`). The alias itself stays an administrator's
97
+ `SYNO.Core.AppPortal set`; the executor never writes it.
98
+ - `portal.register` writes `/usr/syno/etc/www/app.d/<package>.mustache`, then
99
+ `<package>.json` (id `SYNO.SDS.<package>.Instance`), runs
100
+ `synow3tool --gen-app=<package>`, and requires `nginx -t` and the App in
101
+ `SYNO.Core.AppPortal list`. Registering again rewrites the same files.
102
+ - `portal.unregister` removes both app.d files and
103
+ `/usr/syno/etc/packages/<package>/AppPortal.json`, disables and
104
+ unregisters every `{dsm,www,alias,.alias}.syno-app-portal.<package>.conf`
105
+ conf and `{server,.server}` site still enabled or still in DSM's registry,
106
+ and reloads nginx once `nginx -t` passes. A step with nothing to remove is
107
+ skipped, so the op MAY be repeated.
108
+ - A failed change is `PORTAL_FAILED`. A failed register is undone the same
109
+ way. Until a later `portal.unregister` succeeds, `status` reports
110
+ `portal` `cleanup-required`.
111
+ - The executor MUST remove the entry when it purges for an uninstall; DSM
112
+ does not.
113
+ - `status` answers `portal` for such a policy: `registered` (the executor's
114
+ own files and DSM's generated conf), `unregistered`, or `cleanup-required`
115
+ (anything else, including a failed change).
116
+
76
117
  ## Grants
77
118
 
78
119
  - A time-limited grant (`job_id`, `ttl_seconds` ≤ 30 days) covers the listed
@@ -86,11 +127,12 @@ digest MUST change only when the executor source changes.
86
127
  Application Privileges, scope, directory identity and write permission
87
128
  against DSM. A failure the user or an administrator can undo MUST fail only
88
129
  that operation and MUST keep the grant: `PERMISSION_DENIED` (the ACL refuses
89
- the write) and `not-found` (the granted folder is not at its path). Once the
90
- cause is fixed, a new operation under the same grant succeeds. Any other
91
- revalidation failure (`DELEGATION_DENIED`, `INELIGIBLE`, `APP_DENIED`,
92
- `SCOPE_DENIED`, including a different folder at the granted path) MUST
93
- revoke the grant; the user then chooses the destination again.
130
+ the write), `not-found` (the granted folder is not at its path) and, since
131
+ 0.9.6, `APP_DENIED` (an Application Privileges rule refuses the account from
132
+ the checked address). Once the cause is fixed, a new operation under the same
133
+ grant succeeds. Any other revalidation failure (`DELEGATION_DENIED`,
134
+ `INELIGIBLE`, `SCOPE_DENIED`, including a different folder at the granted
135
+ path) MUST revoke the grant; the user then chooses the destination again.
94
136
  - `files.taskStatus` and `files.taskCancel` follow the task's op and MUST NOT
95
137
  be granted directly.
96
138
  - An administrator MAY turn the integration off with `delegate.disable`; then
@@ -154,6 +154,14 @@
154
154
  "en": "The root operation exited with a non-zero status or failed to run.",
155
155
  "zh-TW": "root 操作以非零狀態結束,或無法執行。"
156
156
  },
157
+ {
158
+ "code": "PORTAL_FAILED",
159
+ "kind": "refusal",
160
+ "retryable": true,
161
+ "httpStatus": 502,
162
+ "en": "DSM did not accept the Application Portal change; status portal says whether the entry needs another removal.",
163
+ "zh-TW": "DSM 未接受應用程式入口的變更;status 的 portal 說明是否需要再移除一次。"
164
+ },
157
165
  {
158
166
  "code": "NO_SPACE",
159
167
  "kind": "refusal",
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/synopackageland/syno-pkg-land-sdk/spec/protocol/v1/schema/portal.register.json",
4
+ "title": "portal.register",
5
+ "description": "Administrator: register the policy's Application Portal entry in DSM's app.d (DSM before 7.2 refuses the web-config resource of unsigned packages).",
6
+ "since": "0.9.6",
7
+ "auth": "required",
8
+ "type": "object",
9
+ "properties": {},
10
+ "additionalProperties": false
11
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/synopackageland/syno-pkg-land-sdk/spec/protocol/v1/schema/portal.unregister.json",
4
+ "title": "portal.unregister",
5
+ "description": "Administrator: remove the App's Application Portal entry, its saved alias and every nginx conf DSM generated for it.",
6
+ "since": "0.9.6",
7
+ "auth": "required",
8
+ "type": "object",
9
+ "properties": {},
10
+ "additionalProperties": false
11
+ }
@@ -0,0 +1,8 @@
1
+ {"name":"register","request":{"v":1,"op":"portal.register","auth":{"dsm_cookie":"admin","dsm_synotoken":"contract-token","remote_addr":"192.0.2.1"},"params":{}},"policy":{"v":1,"package":"contract","app":"app","operations":["status","portal.register","portal.unregister"],"portal":{"application":"Contract","alias":"contract"}},"state":{},"expect":{"ok":true,"result":{"entry":"registered"}}}
2
+ {"name":"unregister","request":{"v":1,"op":"portal.unregister","auth":{"dsm_cookie":"admin","dsm_synotoken":"contract-token","remote_addr":"192.0.2.1"},"params":{}},"policy":{"v":1,"package":"contract","app":"app","operations":["status","portal.register","portal.unregister"],"portal":{"application":"Contract","alias":"contract"}},"state":{},"expect":{"ok":true,"result":{"entry":"unregistered"}}}
3
+ {"name":"register-not-admin","request":{"v":1,"op":"portal.register","auth":{"dsm_cookie":"alice","dsm_synotoken":"contract-token","remote_addr":"192.0.2.1"},"params":{}},"policy":{"v":1,"package":"contract","app":"app","operations":["status","portal.register","portal.unregister"],"portal":{"application":"Contract","alias":"contract"}},"state":{},"expect":{"ok":false,"code":"ADMIN_REQUIRED"}}
4
+ {"name":"unregister-not-admin","request":{"v":1,"op":"portal.unregister","auth":{"dsm_cookie":"alice","dsm_synotoken":"contract-token","remote_addr":"192.0.2.1"},"params":{}},"policy":{"v":1,"package":"contract","app":"app","operations":["status","portal.register","portal.unregister"],"portal":{"application":"Contract","alias":"contract"}},"state":{},"expect":{"ok":false,"code":"ADMIN_REQUIRED"}}
5
+ {"name":"register-without-auth","request":{"v":1,"op":"portal.register","params":{}},"policy":{"v":1,"package":"contract","app":"app","operations":["status","portal.register","portal.unregister"],"portal":{"application":"Contract","alias":"contract"}},"state":{},"expect":{"ok":false,"code":"AUTH_DENIED"}}
6
+ {"name":"register-outside-policy","request":{"v":1,"op":"portal.register","auth":{"dsm_cookie":"admin","dsm_synotoken":"contract-token","remote_addr":"192.0.2.1"},"params":{}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run"],"destinations":["save"],"lifetime":"until-revoked","root":{}},"state":{},"expect":{"ok":false,"code":"POLICY_DENIED"}}
7
+ {"name":"register-with-params","request":{"v":1,"op":"portal.register","auth":{"dsm_cookie":"admin","dsm_synotoken":"contract-token","remote_addr":"192.0.2.1"},"params":{"alias":"x"}},"policy":{"v":1,"package":"contract","app":"app","operations":["status","portal.register","portal.unregister"],"portal":{"application":"Contract","alias":"contract"}},"state":{},"expect":{"ok":false,"code":"INVALID_REQUEST"}}
8
+ {"name":"status-entry","request":{"v":1,"op":"status","params":{}},"policy":{"v":1,"package":"contract","app":"app","operations":["status","portal.register","portal.unregister"],"portal":{"application":"Contract","alias":"contract"}},"state":{},"expect":{"ok":true,"result":{"portal":"unregistered"}}}
@@ -1,2 +1,3 @@
1
1
  {"name":"ready","request":{"v":1,"op":"status","params":{}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run"],"destinations":["save"],"lifetime":"until-revoked","root":{}},"state":{},"expect":{"ok":true,"result":{"version":"1","ready":true,"disabled":false,"executor_digest":"<any>","policy_digest":"<any>"}}}
2
2
  {"name":"disabled","request":{"v":1,"op":"status","params":{}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run"],"destinations":["save"],"lifetime":"until-revoked","root":{}},"state":{"disabled":true},"expect":{"ok":true,"result":{"version":"1","ready":true,"disabled":true,"executor_digest":"<any>","policy_digest":"<any>"}}}
3
+ {"name":"caller-allowed","request":{"v":1,"op":"status","params":{},"auth":{"dsm_cookie":"alice","dsm_synotoken":"contract-token","remote_addr":"192.0.2.1"}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run"],"destinations":["save"],"lifetime":"until-revoked","root":{}},"state":{},"expect":{"ok":true,"result":{"allowed":true}}}