dsh-workspace-migrate 0.5.2 → 0.5.4
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 +6 -1
- package/index.js +23 -17
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,12 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/dsh-workspace-migrate)
|
|
4
4
|
[](https://www.dshplugin.store/plugin/lij0000-arch/dsh-workspace-migrate)
|
|
5
|
+
[](https://dshopen.org/plugins/dsh-workspace-migrate)
|
|
5
6
|
[](https://github.com/lij0000-arch/dsh-workspace-migrate/releases)
|
|
6
7
|
[](https://github.com/lij0000-arch/dsh-workspace-migrate)
|
|
7
8
|
[](LICENSE)
|
|
8
9
|
|
|
9
10
|
换电脑,把 DeepSeek Harness 里的**项目、对话和文件**一起带走,而且搬过去的旧对话还能接着聊。
|
|
10
11
|
|
|
12
|
+
> 已被 [awesome-dsh-plugin](https://awesome-dsh-plugin.com/zh/p/lij0000-arch/dsh-workspace-migrate/) 收录 · npm 周下载 700+ · 适配 DSH 0.2.1(rc.2 – rc.5)
|
|
13
|
+
|
|
14
|
+
> ⚠️ **请安装 0.5.3 及以上**。0.5.2 及更早版本的本地接口只做了同源检查,缺少宿主身份认证;0.5.3 起每个请求都过 `ctx.connection` 凭据校验,无认证服务时直接返回 503。
|
|
15
|
+
|
|
11
16
|
**和别的迁移工具不一样的三点:**
|
|
12
17
|
|
|
13
18
|
- **按工作区选**,不是整机全量:勾哪个项目就带走哪个项目的会话、归属、置顶/归档、文件和附件。
|
|
@@ -42,7 +47,7 @@ dsh plugin --profile desktop add dsh-workspace-migrate
|
|
|
42
47
|
- **写**:经公开服务新建会话与项目登记(`sessionPersistence` / `workspaceRegistry`)、按路径映射复制项目文件与附件
|
|
43
48
|
- **删**:只有「撤销这次导入」会删,而且只删**本次进程内由本插件创建**的项目登记与会话目录,其它 id 一律拒绝
|
|
44
49
|
- **网络**:不向外发起请求;仅在本机 `127.0.0.1` 注册 `/api/dsh-migrate` 供当前页面调用
|
|
45
|
-
- **鉴权**:每个请求都经宿主 `ctx.connection.
|
|
50
|
+
- **鉴权**:每个请求都经宿主 `ctx.connection.requestRejection()` 校验浏览器签名凭据,被拒返回 401/403;宿主没有该服务时**直接返回 503**,不回退到 Origin/Host 比较(请求头可以伪造,不能当身份凭据)
|
|
46
51
|
- **凭据**:不读取、不导出 `~/.dsh/.credentials.yaml`
|
|
47
52
|
- **隐私**:迁移包含完整对话与项目文件,导出目录不要放在公开位置
|
|
48
53
|
|
package/index.js
CHANGED
|
@@ -1176,33 +1176,39 @@ export function apply(ctx, config = {}) {
|
|
|
1176
1176
|
* 没有该服务(老宿主)时退回 Origin 检查,并额外要求 Origin 存在——
|
|
1177
1177
|
* 缺 Origin 的请求只可能来自非浏览器客户端。
|
|
1178
1178
|
*/
|
|
1179
|
+
/**
|
|
1180
|
+
* 身份认证。只认宿主的 `connection` 服务:
|
|
1181
|
+
* ctx.connection.requestRejection({ headers }) —— 宿主自带的 Host/Origin 围栏
|
|
1182
|
+
* + 浏览器签名凭据(login-token cookie)校验,被拒时返回 401/403。
|
|
1183
|
+
* 没有这个服务就**直接拒绝**:Origin/Host 只是请求头,客户端可以随便写,
|
|
1184
|
+
* 不能当身份凭据用。迁移、回滚、清理这类会写盘的操作宁可不可用,也不可无认证。
|
|
1185
|
+
*/
|
|
1179
1186
|
function authenticate(req) {
|
|
1180
1187
|
const connection = ctx.get('connection')
|
|
1181
|
-
if (connection) {
|
|
1182
|
-
try {
|
|
1183
|
-
const admission = connection.admit({ headers: req.headers })
|
|
1184
|
-
if (admission && admission.rejection) return { status: admission.rejection }
|
|
1185
|
-
return {}
|
|
1186
|
-
} catch {
|
|
1187
|
-
return { status: 401 }
|
|
1188
|
-
}
|
|
1189
|
-
}
|
|
1190
|
-
const origin = req.headers.origin
|
|
1191
|
-
if (!origin) return { status: 401 }
|
|
1188
|
+
if (!connection) return { status: 503, reason: 'unavailable' }
|
|
1192
1189
|
try {
|
|
1193
|
-
if (
|
|
1190
|
+
if (typeof connection.requestRejection === 'function') {
|
|
1191
|
+
const rejection = connection.requestRejection({ headers: req.headers })
|
|
1192
|
+
return rejection ? { status: rejection } : {}
|
|
1193
|
+
}
|
|
1194
|
+
const admission = connection.admit({ headers: req.headers })
|
|
1195
|
+
if (admission && admission.rejection) return { status: admission.rejection }
|
|
1196
|
+
return {}
|
|
1194
1197
|
} catch {
|
|
1195
|
-
return { status:
|
|
1198
|
+
return { status: 401 }
|
|
1196
1199
|
}
|
|
1197
|
-
return {}
|
|
1198
1200
|
}
|
|
1199
1201
|
|
|
1200
1202
|
async function handler(req, res) {
|
|
1201
1203
|
const auth = authenticate(req)
|
|
1202
1204
|
if (auth.status) {
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1205
|
+
const message =
|
|
1206
|
+
auth.reason === 'unavailable'
|
|
1207
|
+
? '宿主未提供 connection 认证服务,已拒绝处理(不做无身份校验的迁移)'
|
|
1208
|
+
: auth.status === 401
|
|
1209
|
+
? '需要先在 Harness 中登录(缺少或无效的浏览器凭据)'
|
|
1210
|
+
: '拒绝跨站请求'
|
|
1211
|
+
sendJson(res, auth.status, { error: message })
|
|
1206
1212
|
return
|
|
1207
1213
|
}
|
|
1208
1214
|
const url = new URL(req.url ?? '/', 'http://localhost')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-workspace-migrate",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "把 DeepSeek Harness 的工作区、项目成果和对话内容整体迁到另一台电脑",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"session"
|
|
15
15
|
],
|
|
16
16
|
"engines": {
|
|
17
|
-
"dsh": "
|
|
17
|
+
"dsh": ">=0.2.1-rc.2 <0.3.0 || >=0.2.2-rc.1 <0.3.0"
|
|
18
18
|
},
|
|
19
19
|
"repository": {
|
|
20
20
|
"type": "git",
|