kczx-user-management 1.4.1 → 1.5.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/README.md +91 -2
- package/client/bundle.js +407 -45
- package/client/index.js +407 -45
- package/package.json +3 -3
- package/src/gateway-core.js +90 -21
- package/src/index.js +240 -10
- package/src/workspace-create.js +158 -0
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# kczx-user-management
|
|
2
2
|
|
|
3
3
|
> **本包是本地扩展版(1.0.0),已把 dsh-passwords 的账号 / 权限 / 配额 / 台账能力并入,不再是上游 0.9.5 的功能集。**
|
|
4
|
-
> 上游同名包(npm 上的 `@weibaohui/user-management
|
|
4
|
+
> 上游同名包(npm 上的 `@weibaohui/user-management`)仅提供登录门禁与两步验证;本版额外提供工作区白名单与归属跟踪、新建账号即建工作区、
|
|
5
5
|
> token 与时长配额、沙盒档位下限、上传 / git / 运维面门控、历史沙盒降级与隐藏字符清洗。
|
|
6
6
|
> 为便于从 registry 安装,本版以独立包名 **`kczx-user-management`** 发布,与上游互不覆盖。
|
|
7
7
|
|
|
@@ -88,6 +88,7 @@ node scripts/ensure-deps.mjs # 仅当上述解析不到 sche
|
|
|
88
88
|
|---|---|
|
|
89
89
|
| 用户增删改查 | 用户表每行一个「编辑」**全屏页**:基本资料(部门 / 角色)+ 账号操作(重置密码 / 重置两步验证 / 禁用启用 / 删除)+ 权限与配额,集中一屏;改动类走「保存」,破坏性操作仍是各自带确认的按钮 |
|
|
90
90
|
| 所属部门 | 账号资料字段(trim 后 ≤ 64 字,控制字符剔除):新增用户时可填,编辑页可随时改或清空;变更写进操作日志 |
|
|
91
|
+
| 新建账号即建工作区 | 新增用户时勾选「同时创建该用户的工作区」:路径预填 `<harness 根>/<部门>/<用户名>`(可改成任意绝对路径);提交后目录按需创建、登记进 dsh 工作区列表,并把该路径写进这个账号的工作区白名单 |
|
|
91
92
|
| 工作区白名单 | **留空 = 不允许任何工作区**(白名单默认拒绝);填写后只允许这些目录下的工作区;条目 `*` = 允许全部。Windows 路径折叠大小写,末尾斜杠自动忽略 |
|
|
92
93
|
| 工作区归属跟踪 | 谁创建的工作区归谁:别人看不到、也不能删改;删除后释放,账号删除后清理 |
|
|
93
94
|
| 每小时 token 配额 | 由浏览器上报 dsh 自身的用量投影增量,服务端按小时窗口累计并拦截 |
|
|
@@ -145,6 +146,7 @@ user-management:
|
|
|
145
146
|
# ── 会话与请求策略(全部即时生效) ──
|
|
146
147
|
sessionDays: 7 # 会话有效期(天,滑动续期:过半后续一次)
|
|
147
148
|
maxBodyBytes: 65536 # 本插件 API 的 JSON 请求体上限(字节)
|
|
149
|
+
workspaceRoot: '' # 新建账号工作区的根路径;'' = 问宿主(dsh 的工作区根,默认即 harness 所在目录)
|
|
148
150
|
otpFailLimit: 5 # 两步验证连续错误几次后锁定
|
|
149
151
|
otpLockoutSeconds: 60 # 锁定多久
|
|
150
152
|
```
|
|
@@ -189,6 +191,93 @@ user-management:
|
|
|
189
191
|
- 隐私开关:`user-management.auditConversationText: false`(设置页「会话与请求策略」里也有这一项)关掉即完全不抓。台账是
|
|
190
192
|
`$DSH_HOME/user-management/audit.jsonl` 明文文件,提示词可能含口令 / 密钥时请关闭。
|
|
191
193
|
|
|
194
|
+
### 新建用户时一并创建工作区(1.5.0 起)
|
|
195
|
+
|
|
196
|
+
「用户 → 新增用户」多了一个复选框「同时创建该用户的工作区」。勾上后出现路径框,**预填**默认路径
|
|
197
|
+
`<harness 根>/<部门>/<用户名>`(部门留空就少一层,只到用户名),可以直接改成任意绝对路径;下方一行小字写着默认值,
|
|
198
|
+
改过之后还有「恢复默认」。不勾选则一切照旧。
|
|
199
|
+
|
|
200
|
+
提交时服务端按这个顺序做事,**能失败的都在写账号之前失败**:
|
|
201
|
+
|
|
202
|
+
1. **校验路径**:自定义路径必须以盘符或 `/` 开头(相对路径会报错,不会被悄悄拼到进程 cwd 上);根路径本身
|
|
203
|
+
(harness 目录)不能当工作区;路径长度 ≤ 1024。部门是管理员随手写的自由文本,所以它会被折成**一段**合法的目录名
|
|
204
|
+
(`\` `/` `:` `*` `?` `"` `<` `>` `|` 与控制字符 → `-`,纯点号(`..`)直接丢掉),绝不允许它多出一层目录或跳出根路径。
|
|
205
|
+
2. **归属冲突**:这个路径已经属于别的账号 → 409,账号和目录都不会建。既有的目录(别人放的文件)会被**领养**而不是重新创建。
|
|
206
|
+
3. **建目录**(`mkdir -p`,已存在则复用);失败则 400,**不建账号**。
|
|
207
|
+
4. **建账号**,并把该路径写进它的**工作区白名单**(`allowedFolders`)。白名单是默认拒绝的:不放开的话,账号
|
|
208
|
+
根本看不到自己那块地。第 3 步建出来的空目录在账号写入失败时会被回收(只删空目录)。
|
|
209
|
+
5. **登记进 dsh 工作区列表**:通过宿主的 `workspaceRegistry` 服务(运行期 `ctx.inject`,不写死依赖)。
|
|
210
|
+
这一步失败**不回滚**——目录和账号都是真的,接口把 `registered: false` 和原因一起返回,界面提示
|
|
211
|
+
「用户已创建、目录已建好,但未登记进工作区列表」。dsh 的工作区列表用 realpath 后的规范路径,所以登记返回的
|
|
212
|
+
规范路径也会一并加进白名单(软链接根目录 / Windows 大小写差异下,账号才看得到自己的那块地)。
|
|
213
|
+
6. **认领归属**:把该路径记到这个账号名下——别人看不到、也不能删改(见「工作区归属跟踪」)。
|
|
214
|
+
|
|
215
|
+
接口:`POST /user-management/api/users` 增加 `createWorkspace: true` 与可选的 `workspacePath`(留空 = 服务端按默认规则生成),
|
|
216
|
+
响应多一个 `workspace` 报告(`{ ok, path, source, directory, registered, owner, error }`,没勾选时为 `null`);
|
|
217
|
+
`GET /user-management/api/workspace-root`(管理员)回 `{ root, sep }`,新增用户弹窗用它预填路径。
|
|
218
|
+
根路径优先取 `user-management.workspaceRoot`,未配置则问宿主的 `sandboxPolicy.workspaceRoot`(dsh 默认就是进程 cwd,
|
|
219
|
+
即 harness 所在目录),最后兜底 `process.cwd()`。
|
|
220
|
+
|
|
221
|
+
### 被拒绝时提示什么(1.5.1 起)
|
|
222
|
+
|
|
223
|
+
被网关拦下的请求(没有建工作区的权限、目录不在白名单、配额用完、上传 / git 被关、沙盒提权被拒……)过去一律回 HTTP 403。
|
|
224
|
+
而 dsh 的浏览器客户端**把任何非 2xx 都当成传输故障**、根本不读响应体,于是用户看到的是:
|
|
225
|
+
|
|
226
|
+
> workspace create failed: internal: transport failure for /api/workspace.create: HTTP 403
|
|
227
|
+
|
|
228
|
+
这读起来像程序坏了,而不像「你的账号没有这个权限」。现在这类拒绝改走 RPC 协议自带的错误位:**HTTP 200 + `result.ok: false`**,
|
|
229
|
+
原因写在 `error.message` 里,各处 dsh 界面都会原样显示:
|
|
230
|
+
|
|
231
|
+
> workspace create failed: internal: 本账号没有创建 / 管理工作区的权限(请联系管理员在「用户管理 → 编辑用户 → 权限与配额」中开启「允许创建工作区」)
|
|
232
|
+
|
|
233
|
+
只有**不是 RPC 调用**的请求(没有 `rpcId` 可回显的裸请求、GET)仍回原来的 403 JSON —— 给它们编一个 rpcId 只会把「被拒绝」
|
|
234
|
+
变成客户端的协议错误,比原样回报更糟。
|
|
235
|
+
|
|
236
|
+
顺带修好一个盲区:被拒绝的请求以前**完全不进操作日志**(它没到上游,写日志的钩子永远不会触发)。现在会记一行
|
|
237
|
+
**403 + `已拒绝:<原因>`**,管理员在「用户管理 → 操作日志」里直接看得到谁、想做什么、为什么被挡下来。
|
|
238
|
+
|
|
239
|
+
### 控制台页头的位置(1.5.3 起)
|
|
240
|
+
|
|
241
|
+
「用户管理」整页原来的页头是一条**横贯屏幕**的标题栏:宽屏上标题孤零零贴在左上角、按钮贴在右上角,和下面的
|
|
242
|
+
tab 条与内容列毫无关系。现在标题与 tab 收进**居中内容列**,而「退出登录」单独钉在**窗口的右上角**:
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
[⏻ 退出登录] ← 贴窗口右上角(与「编辑用户」页那颗同一位置)
|
|
246
|
+
用户管理 ← 内容列内,与 tab 条左对齐
|
|
247
|
+
[用户][登录记录][访问记录][操作日志][IP 封禁][证书][2FA] [返回设置]
|
|
248
|
+
…表格 / 台账…
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
「用户管理」这一行是「这一页是什么」,与内容左对齐;「返回设置」与 tab 条同一条线、右边缘对齐。退出登录之所以
|
|
252
|
+
不跟着内容列走,是因为上一层「编辑用户」页把自己的退出登录放在窗口右上角——同一个按钮不能因为进出一层就横向挪位。
|
|
253
|
+
普通用户没有 tab 条,但「返回设置」仍然落在同一条线上(右对齐),两个视图因此读起来还是同一页。观察者模式
|
|
254
|
+
(dsh-passwords 在前)没有退出登录,只有「返回设置」。
|
|
255
|
+
|
|
256
|
+
「退出登录」现在**先问一句**(`确定退出登录?退出后需要重新输入用户名和密码。`):控制台页头和账号菜单里各有一个入口,
|
|
257
|
+
且都离用户正在做的事只差一次误点——确认放在共用的 `doLogout()` 里,谁都绕不过去。
|
|
258
|
+
|
|
259
|
+
「编辑用户」整页自带一个退出登录,钉在**页面最右上角**(关闭 / 保存之后隔一条竖线,不跟表单按钮混在一起):
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
┌ 编辑用户 · bob ─────────────────────────────────────────────┐
|
|
263
|
+
│ [关闭] [保存] │ [⏻ 退出登录] │
|
|
264
|
+
└─────────────────────────────────────────────────────────────┘
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
同一时刻屏幕上只有一个退出登录:打开这一页时,控制台那个**窗口右上角的退出登录收起来**(位置本来就是同一个,只是避免两颗同时存在)。不透明浮层确实盖住了它,
|
|
268
|
+
但「盖住」不等于「不在文档里」——那时它离一次 Tab+Enter 只有一步,而这颗按钮结束的是整个会话。收放由一个模块级的
|
|
269
|
+
小订阅(`setFullPageOverlay`)广播,编辑页挂载时置位、卸载时清除。
|
|
270
|
+
|
|
271
|
+
### 欢迎页右上角的账号信息(1.5.4 起)
|
|
272
|
+
|
|
273
|
+
会话头部只在**有会话**时才存在,于是落地页(欢迎页 / 新建会话页)成了唯一一个不说「你是谁」的页面——连账号菜单里
|
|
274
|
+
仅有的两件事(改密码、退出登录)也没地方点。现在账号芯片(头像 + 用户名,点开即账号菜单)还会落在**shell 的全局
|
|
275
|
+
overlay 座位**(ui-layout 的 `shell.overlay`,一个可叠加的 list 槽)上,固定在窗口**右上角**;一旦有会话成为当前会话,
|
|
276
|
+
这个芯片立刻消失,把位置让回会话头部那一个,不会出现两个。
|
|
277
|
+
|
|
278
|
+
实现上用的是该座位给每个全局占用者注入的 `useSessions`:`state.current` 就是框架自己对「现在有没有打开会话」的回答,
|
|
279
|
+
不需要去偷看 DOM。hero 上的三个座位(品牌标记 / 工作区选择器 / 代理预设)都是单占位且已被占用,所以走 overlay 座位。
|
|
280
|
+
|
|
192
281
|
### 在设置页里改(1.1.0 起)
|
|
193
282
|
|
|
194
283
|
上面这些字段也可以在 **设置 → 通用设置** 里改,就在「语言」「外观」那几行下面:「登录页与策略配置」一行,
|
|
@@ -237,7 +326,7 @@ node scripts/import-from-dsh-passwords.mjs --from E:\path\to\dsh-passwords --ove
|
|
|
237
326
|
## 测试
|
|
238
327
|
|
|
239
328
|
```bash
|
|
240
|
-
npm test #
|
|
329
|
+
npm test # 203 项:策略纯函数、store、API 层、客户端契约、以及真实网关的端到端用例
|
|
241
330
|
npm run check # 全量语法检查
|
|
242
331
|
```
|
|
243
332
|
|