dsh-cindy-host 0.1.29 → 0.1.30
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/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/src/host-media-fetch.js +6 -12
- package/src/host-version.js +1 -1
- package/src/host.js +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.30 — 2026-10-29
|
|
4
|
+
|
|
5
|
+
- Match Cindy native local media fetching: baseDir/workdir constraints are optional; absolute file references no longer fail with no-root. Explicit constraints, sensitive-path checks, regular-file checks and byte limits remain enforced.
|
|
6
|
+
- Fix the shared parser/resolver for all file types and original, thumbnail, prepareOnly and file-peer reads; no PNG-specific workaround or controller changes.
|
|
7
|
+
- Add contract regressions for 15 extensions, POSIX/Windows paths, both file/audio schemes, real filesystem preparation and rootless peer bytes/EOF.
|
|
8
|
+
- Minimal patch on published 0.1.29; preserves its runtime and queue/input-delivery behavior. Requires the same DSH 0.2.1-rc.3 carrier and Node >=22.16. Linux handset end-to-end acceptance requires deployment and is not implied by publication.
|
|
9
|
+
|
|
3
10
|
## 0.1.29 — 2026-10-29
|
|
4
11
|
|
|
5
12
|
- Publish from a clean, committed Git source tree; preserve the accepted 0.1.28 runtime behavior.
|
package/package.json
CHANGED
package/src/host-media-fetch.js
CHANGED
|
@@ -8,19 +8,14 @@
|
|
|
8
8
|
* (`apps/desktop/src/main/device-link/mediaFetch.ts`: 解析本机媒体 → 上传 OSS → 返回引用):
|
|
9
9
|
*
|
|
10
10
|
* ```
|
|
11
|
-
* request { url: 'xdt-file://open?path=<abs
|
|
11
|
+
* request { url: 'xdt-file://open?path=<abs>', thumbnail?, skipCache?, prepareOnly? }
|
|
12
12
|
* response { ossKey, mimeType, size } // the controller presign-gets the key
|
|
13
13
|
* ```
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* constraint" for old controllers; here a request that names no root (neither `baseDir`
|
|
20
|
-
* nor the `workdir` a chat image carries) is refused. Without that, any absolute path
|
|
21
|
-
* on this machine would be servable by anyone who can reach the Host.
|
|
22
|
-
* 2. **Realpath on both sides.** A symlink inside the workspace must not become a way out
|
|
23
|
-
* of it, and `/tmp` vs `/private/tmp` must not make a legitimate file look outside.
|
|
15
|
+
* Directory constraints are optional, matching Cindy's native media-fetch contract.
|
|
16
|
+
* A plain absolute `path` is accepted; when `baseDir` or `workdir` is supplied, both
|
|
17
|
+
* the file and the root are realpath'd before containment checks. This prevents a
|
|
18
|
+
* symlink from escaping a supplied root and handles `/tmp` vs `/private/tmp` aliases.
|
|
24
19
|
*
|
|
25
20
|
* Malformed constraint parameters are refused rather than ignored: silently degrading to
|
|
26
21
|
* "unconstrained" is how a constraint gets removed by a typo.
|
|
@@ -266,7 +261,6 @@ export function parseMediaFetchRequest(url) {
|
|
|
266
261
|
if (value.trim() === '' || !isAbsoluteMediaPath(value)) return { ok: false, reason: `invalid-${key}` };
|
|
267
262
|
roots.push(value);
|
|
268
263
|
}
|
|
269
|
-
if (roots.length === 0) return { ok: false, reason: 'no-root' };
|
|
270
264
|
|
|
271
265
|
let maxBytes = null;
|
|
272
266
|
const rawMaxBytes = parsed.searchParams.get('maxBytes');
|
|
@@ -316,7 +310,7 @@ export function createLocalFileResolver({
|
|
|
316
310
|
// A root that does not resolve cannot authorise anything; the others still can.
|
|
317
311
|
}
|
|
318
312
|
}
|
|
319
|
-
if (
|
|
313
|
+
if (request.roots.length > 0 && !allowedRoots.some((root) => isInsideDirectory(real, root))) {
|
|
320
314
|
return { ok: false, code: 'FORBIDDEN', message: 'the requested file is outside the directory the controller named' };
|
|
321
315
|
}
|
|
322
316
|
if (isBlockedMediaPath(real, blocked)) {
|
package/src/host-version.js
CHANGED
package/src/host.js
CHANGED
|
@@ -227,8 +227,8 @@ export async function startHost(initialSource, settings = DEFAULT_HOST_SETTINGS,
|
|
|
227
227
|
*
|
|
228
228
|
* The chat-image path: a picture the agent produced is referenced by path in the
|
|
229
229
|
* transcript, and the controller resolves it through `device-link:media:fetch`. Same
|
|
230
|
-
* uploader as the file browser's export ops
|
|
231
|
-
*
|
|
230
|
+
* uploader as the file browser's export ops. Directory constraints are optional, as
|
|
231
|
+
* in Cindy; when supplied, both the file and the root are realpath'd before checking.
|
|
232
232
|
*/
|
|
233
233
|
const fetchLocalMedia = createLocalMediaFetcher({ uploader: uploadMedia });
|
|
234
234
|
const resolvePeerFile = createLocalFileResolver({ maxBytes: FILE_PEER_MAX_BYTES });
|