dsh-plugin-tool-management 0.5.0 → 0.6.0
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 +300 -236
- package/README_EN.md +300 -290
- package/cordis.patch.yml +9 -55
- package/docs/Changelog.md +108 -435
- package/docs/images/1/345/234/272/346/231/257.png +0 -0
- package/docs/images/1/345/234/272/346/231/257_en.png +0 -0
- package/docs/images/2MCP.png +0 -0
- package/docs/images/2MCP_en.png +0 -0
- package/docs/images/3/346/212/200/350/203/275.png +0 -0
- package/docs/images/3/346/212/200/350/203/275_en.png +0 -0
- package/docs/images/4/345/255/220/346/231/272/350/203/275/344/275/223.png +0 -0
- package/docs/images/4/345/255/220/346/231/272/350/203/275/344/275/223_en.png +0 -0
- package/docs/images/5/346/217/220/347/244/272/350/257/215.png +0 -0
- package/docs/images/5/346/217/220/347/244/272/350/257/215_en.png +0 -0
- package/docs/images/6/350/256/260/345/277/206.png +0 -0
- package/docs/images/6/350/256/260/345/277/206_en.png +0 -0
- package/docs/images/7/344/274/232/350/257/235.png +0 -0
- package/docs/images/7/344/274/232/350/257/235_en.png +0 -0
- package/docs/images/8/345/205/274/345/256/271.png +0 -0
- package/docs/images/8/345/205/274/345/256/271_en.png +0 -0
- package/docs/update.md +54 -0
- package/lib/agents-md/preset-id.js +49 -0
- package/lib/agents-md/service.js +138 -56
- package/lib/client.js +4142 -3489
- package/lib/compat/probe.js +665 -0
- package/lib/history/bridge.js +293 -0
- package/lib/history/workspace.js +498 -52
- package/lib/http-fence.js +73 -0
- package/lib/index.js +511 -126
- package/lib/rules/provider.js +3 -3
- package/lib/rules/service.js +264 -30
- package/lib/scene-prompt-sync.js +112 -0
- package/lib/skills/core.js +112 -35
- package/lib/skills/service.js +6 -1
- package/package.json +5 -3
- package/screenshots.json +8 -7
- package/docs/images/MCP.png +0 -0
- package/docs/images//344/274/232/350/257/235.png +0 -0
- package/docs/images//345/234/272/346/231/257.png +0 -0
- package/docs/images//345/255/220/346/231/272/350/203/275/344/275/223.png +0 -0
- package/docs/images//346/212/200/350/203/275.png +0 -0
- package/docs/images//346/217/220/347/244/272/350/257/215.png +0 -0
- package/docs/images//350/256/260/345/277/206.png +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// 插件 HTTP 路由的请求栅栏。
|
|
2
|
+
//
|
|
3
|
+
// 为什么需要它:宿主的 BrowserAuth 栅栏**只包在宿主自己注册的路由上**
|
|
4
|
+
// (dsh-client-connection 的 register()/upgrade、dsh-api-gateway、
|
|
5
|
+
// dsh-host-open-in-app),dsh-host-webserver 本身没有全局中间件。宿主生态的
|
|
6
|
+
// 既定约定是每个注册方自己调 `connection.requestRejection(req)`,它做两件事:
|
|
7
|
+
//
|
|
8
|
+
// 1. Host/Origin 栅栏 —— Host 必须是回环地址、deployment 派生的 LAN IP 字面量
|
|
9
|
+
// 或声明的 trustedHosts。Host 是 DNS rebinding 唯一伪造不了的头:攻击者
|
|
10
|
+
// 控制域名 → 浏览器发 `Host: evil.com`,但插件的自比对式 Origin 检查
|
|
11
|
+
// (origin.host === host)会同时成立,于是被误判为同源。
|
|
12
|
+
// 2. browser-session cookie 鉴权(HttpOnly + SameSite=Strict,Path=/)。
|
|
13
|
+
//
|
|
14
|
+
// 只查公开常量 `x-dsh-plugin` 与自比对 Origin 等于没鉴权:本机任意进程都能调写 op,
|
|
15
|
+
// 而写 op 里包含 `mcpm-add`(command/args 无白名单,宿主 stdio 传输会 spawn 它
|
|
16
|
+
// → 任意命令执行)与 `history-delete`(永久删除会话)。
|
|
17
|
+
const headerValue = (req, name) => {
|
|
18
|
+
const v = req.headers?.[name];
|
|
19
|
+
return Array.isArray(v) ? v[0] ?? '' : v ?? '';
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* 判定请求是否应被拒(返回 null = 放行)。
|
|
23
|
+
*
|
|
24
|
+
* 优先用宿主栅栏;它不在场时(非 web 组合、服务未注册)退回等价的本地判定,
|
|
25
|
+
* 而不是静默放行。栅栏自身抛错时同样退回本地判定 —— 宁可拒绝也不要因为宿主
|
|
26
|
+
* 内部变动而变成开放路由。
|
|
27
|
+
*
|
|
28
|
+
* @param req - Node 请求对象(只读 headers)。
|
|
29
|
+
* @param connection - ctx.get('connection'),可缺失。
|
|
30
|
+
*/
|
|
31
|
+
export function fenceRejection(req, connection) {
|
|
32
|
+
try {
|
|
33
|
+
const rejection = connection?.requestRejection?.(req);
|
|
34
|
+
if (typeof rejection === 'number') {
|
|
35
|
+
return {
|
|
36
|
+
status: rejection,
|
|
37
|
+
error: rejection === 401
|
|
38
|
+
? '未通过宿主的浏览器鉴权:请在 DSH Web GUI 内操作,或为本插件配置访问令牌(config.token / DSH_PLUGIN_TOOL_MANAGEMENT_TOKEN)'
|
|
39
|
+
: 'Host/Origin 栅栏拒绝:该请求不是发往本机地址的同源请求',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// 栅栏在场且未返回拒绝码 ⇒ 已通过,不再叠加本地判定(宿主的 trustedHosts
|
|
43
|
+
// 部署信息这里拿不到,重复判定只会更松或更严,都不对)。
|
|
44
|
+
if (typeof connection?.requestRejection === 'function')
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
catch (e) { /* 见上方说明:退回本地判定 */ }
|
|
48
|
+
const hostHdr = headerValue(req, 'host');
|
|
49
|
+
let host;
|
|
50
|
+
try {
|
|
51
|
+
host = new URL('http://' + hostHdr);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return { status: 403, error: 'Host 头缺失或无法解析' };
|
|
55
|
+
}
|
|
56
|
+
const loopback = host.hostname === 'localhost' || host.hostname === '[::1]'
|
|
57
|
+
|| /^127(?:\.\d{1,3}){3}$/.test(host.hostname);
|
|
58
|
+
if (!loopback)
|
|
59
|
+
return { status: 403, error: 'Host 必须是本机回环地址(防 DNS rebinding)' };
|
|
60
|
+
if (headerValue(req, 'sec-fetch-site') === 'cross-site')
|
|
61
|
+
return { status: 403, error: '跨站请求被拒' };
|
|
62
|
+
const origin = headerValue(req, 'origin');
|
|
63
|
+
if (origin) {
|
|
64
|
+
try {
|
|
65
|
+
if (new URL(origin).host !== host.host)
|
|
66
|
+
return { status: 403, error: '跨源请求被拒' };
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return { status: 403, error: 'Origin 头无法解析' };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|