@starreel/mcp 0.1.36 → 0.1.37

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/dist/client.js CHANGED
@@ -13,6 +13,7 @@
13
13
  import { createReadStream, statSync } from 'node:fs';
14
14
  import { basename } from 'node:path';
15
15
  import { Readable } from 'node:stream';
16
+ import { assertSafeLocalMediaPath } from './path-guard.js'; // v0.1.37 — P0③ 路径安全闸
16
17
  /** 扩展名 → MIME(presign 需要 content_type)。 */
17
18
  const MIME_BY_EXT = {
18
19
  '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.png': 'image/png', '.webp': 'image/webp',
@@ -159,6 +160,9 @@ export class StarReelClient {
159
160
  * 字节不经我们的业务服务器,只走 COS。kind: image(默认)/video/audio。
160
161
  */
161
162
  async uploadLocalFile(filePath, kind = 'image') {
163
+ // v0.1.37 — P0③:媒体扩展名白名单 + 隐藏/系统目录拒绝(realpath 后判,防符号链接绕过)。
164
+ const safePath = assertSafeLocalMediaPath(filePath, kind);
165
+ filePath = safePath;
162
166
  const size = statSync(filePath).size;
163
167
  const filename = basename(filePath);
164
168
  const ext = (filename.match(/\.[a-z0-9]+$/i)?.[0] || '').toLowerCase();
@@ -0,0 +1,45 @@
1
+ /**
2
+ * v0.1.37 — 本地文件上传的路径安全闸(安全评估 P0③)。
3
+ *
4
+ * uploadLocalFile 此前接受任意绝对路径:一个被注入的第三方 agent 可以把
5
+ * ~/.ssh/id_rsa、.env、浏览器资料库当"素材"上传到 COS(公共可读 URL)。
6
+ * 本闸不引入 workspace 概念(MCP 进程不知道调用方的工作目录语义),
7
+ * 而是用两条与"上传媒体素材"这一合法用途严格对齐的规则:
8
+ * ① 扩展名必须是对应 kind 的媒体白名单(.env/.pem/id_rsa 天然出局);
9
+ * ② realpath 后的路径中不得含任何以 '.' 开头的路径段(~/.ssh、~/.codex、
10
+ * ~/.aws、.git 等敏感目录全部命中),也不得落在系统配置区(/etc、/private/etc)。
11
+ * 符号链接先解析再判(防 media.jpg -> ~/.ssh/id_rsa 绕过)。
12
+ */
13
+ import { realpathSync } from 'node:fs';
14
+ import { sep } from 'node:path';
15
+ export const MEDIA_EXT_BY_KIND = {
16
+ image: new Set(['.jpg', '.jpeg', '.png', '.webp', '.gif']),
17
+ video: new Set(['.mp4', '.mov', '.webm', '.m4v']),
18
+ audio: new Set(['.mp3', '.wav', '.m4a', '.aac', '.flac', '.ogg']),
19
+ };
20
+ const SYSTEM_PREFIXES = ['/etc/', '/private/etc/', '/proc/', '/sys/'];
21
+ /** 校验通过返回解析后的真实路径;不通过抛 Error(消息面向第三方 agent,说清正路)。 */
22
+ export function assertSafeLocalMediaPath(filePath, kind, resolve = realpathSync) {
23
+ const ext = (filePath.match(/\.[a-z0-9]+$/i)?.[0] || '').toLowerCase();
24
+ if (!MEDIA_EXT_BY_KIND[kind].has(ext)) {
25
+ throw new Error(`file_path 只接受${kind === 'image' ? '图片' : kind === 'video' ? '视频' : '音频'}媒体文件`
26
+ + `(${[...MEDIA_EXT_BY_KIND[kind]].join('/')});收到 "${ext || '无扩展名'}"。`
27
+ + '不要用本工具上传配置/密钥/文档类文件。');
28
+ }
29
+ let real;
30
+ try {
31
+ real = resolve(filePath);
32
+ }
33
+ catch {
34
+ throw new Error(`file_path 不存在或不可读:${filePath}`);
35
+ }
36
+ const segments = real.split(sep);
37
+ if (segments.some(s => s.startsWith('.') && s.length > 1)) {
38
+ throw new Error(`file_path 位于隐藏目录(${real}),已拒绝——敏感目录(如 ~/.ssh、~/.aws、.git)不允许作为上传源。`
39
+ + '把素材放到普通目录再上传。');
40
+ }
41
+ if (SYSTEM_PREFIXES.some(p => real.startsWith(p))) {
42
+ throw new Error(`file_path 位于系统目录(${real}),已拒绝。`);
43
+ }
44
+ return real;
45
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@starreel/mcp",
3
- "version": "0.1.36",
3
+ "version": "0.1.37",
4
4
  "mcpName": "ai.starreel/starreel",
5
5
  "description": "StarReel MCP server — drive the AI short-drama production pipeline (script → storyboards → frames → video → final cut) from Claude, Cursor, or any MCP client",
6
6
  "license": "MIT",
package/server.json CHANGED
@@ -2,13 +2,13 @@
2
2
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
3
3
  "name": "ai.starreel/starreel",
4
4
  "description": "Turn a script into a finished, downloadable short-drama episode — via MCP or REST.",
5
- "version": "0.1.36",
5
+ "version": "0.1.37",
6
6
  "websiteUrl": "https://starreel.ai",
7
7
  "packages": [
8
8
  {
9
9
  "registryType": "npm",
10
10
  "identifier": "@starreel/mcp",
11
- "version": "0.1.36",
11
+ "version": "0.1.37",
12
12
  "transport": { "type": "stdio" },
13
13
  "environmentVariables": [
14
14
  {