给会话加密码锁,把目录加密成密文保险箱
29.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/28 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add xevil3301/dsh-chatlock该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:仅索引
是什么
dsh 原生插件 · chat
装得上吗
本站尚未做安装检查
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 8 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件发起外部网络请求
查看扫描证据(共 26 处,展示前 26 条)
- 写入本地文件index.js:58
mkdirSync(dir, { recursive: true }) - 写入本地文件index.js:64
try { appendFileSync(logFile, line + '\n', 'utf8') } catch { } - 发起网络请求client.js:37
const res = await fetch(API + path, init) - 写入本地文件lib/state.mjs:48
mkdirSync(dir, { recursive: true }) - 读取本地文件lib/state.mjs:149
if (!existsSync(file)) return emptyState() - 读取本地文件lib/state.mjs:151
return normalizeState(JSON.parse(readFileSync(file, 'utf8'))) - 写入本地文件lib/state.mjs:155
renameSync(file, join(dir, `state.corrupt-${Date.now()}.json`)) - 写入本地文件lib/state.mjs:172
writeFileSync(tmp, body, { encoding: 'utf8', mode: 0o600 }) - 写入本地文件lib/state.mjs:173
try { chmodSync(tmp, 0o600) } catch { } - 写入本地文件lib/state.mjs:174
renameSync(tmp, file) - 写入本地文件lib/state.mjs:175
try { chmodSync(file, 0o600) } catch { } - 读取本地文件lib/state.mjs:176
try { return statSync(file).size } catch { return body.length } - 读取本地文件lib/routes.mjs:301
if (!existsSync(path)) return { status: 400, body: { ok: false, error: '目录不存在: ' + path } } - 读取本地文件lib/routes.mjs:370
if (!existsSync(vault.path)) return { status: 400, body: { ok: false, error: '目录不存在: ' + vault.path } } - 读取本地文件lib/vault.mjs:112
return existsSync(manifestPathOf(root)) - 写入本地文件lib/crypt.mjs:36
const out = createWriteStream(dst, { flags: 'wx', mode: 0o600 }) - 读取本地文件lib/crypt.mjs:38
await pipeline(createReadStream(src), cipher, out, { end: false }) - 读取本地文件lib/crypt.mjs:82
const body = createReadStream(src, { start: HEADER_BYTES, end: stat.size - TAG_BYTES - 1 }) - 写入本地文件lib/crypt.mjs:84
await pipeline(body, decipher, createWriteStream(dst, { flags: 'wx', mode: 0o600 })) - 读取本地文件install.mjs:32
if (!existsSync(profile)) { - 读取本地文件install.mjs:38
const present = FILES.filter((name) => existsSync(join(here, name))) - 写入本地文件install.mjs:48
mkdirSync(target, { recursive: true }) - 删除本地文件递归install.mjs:53
rmSync(to, { recursive: true, force: true }) - 读取本地文件install.mjs:63
let patch = existsSync(patchFile) ? readFileSync(patchFile, 'utf8') : '' - 读取本地文件install.mjs:63
let patch = existsSync(patchFile) ? readFileSync(patchFile, 'utf8') : '' - 写入本地文件install.mjs:78
writeFileSync(patchFile, patch.replace(/ *$/, '\n') + block, 'utf8')
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
DSH 聊天锁 / 保险箱:给会话上密码锁,把目录加密成保险箱
README
由 DeepSeek 最新模型翻译生成它做什么 ·安装 ·威胁模型 ·踩坑 ·自检
两件事
| 会话锁 | 保险箱 |
| 在侧栏给某个会话上锁,再打开时会话区模糊、弹密码框,口令错了就是错了。 | 把一个目录整体做成 AES-256-GCM 密文,锁定后磁盘上只剩 .bin,连原始文件名都读不出来。 |
两个能力共用一把口令。口令只存 scrypt 派生值,明文不落盘;「已解锁」这个状态只活在内存里,进程一重启就全没了,这也是最可靠的一把自动锁。
会话记录本身没有做磁盘加密,因为 DSH 启动要读它才能出会话列表。所以第一件事是界面锁,第二件才是磁盘锁。这个区别很重要,后面「威胁模型」那节会摊开讲。
flowchart LR
A["已锁会话"] -->|输入口令| B{"口令正确?"}
B -->|是| C["正文可见解锁态只在内存"]
B -->|否| A
D["普通目录"] -->|加密并锁定| E["密文 .bin清单也加密"]
E -->|解锁还原| D
三十秒装完
git clone https://github.com/xevil3301/dsh-chatlock
cd dsh-chatlock
node install.mjs # 默认装进 desktop profile
node install.mjs --profile web # 或者别的 profile
装完必须重启 dsh。
展开完整文档(README 剩余 1 节)
它做什么 ·安装 ·威胁模型 ·踩坑 ·自检
两件事
| 会话锁 | 保险箱 |
| 在侧栏给某个会话上锁,再打开时会话区模糊、弹密码框,口令错了就是错了。 | 把一个目录整体做成 AES-256-GCM 密文,锁定后磁盘上只剩 .bin,连原始文件名都读不出来。 |
两个能力共用一把口令。口令只存 scrypt 派生值,明文不落盘;「已解锁」这个状态只活在内存里,进程一重启就全没了,这也是最可靠的一把自动锁。
会话记录本身没有做磁盘加密,因为 DSH 启动要读它才能出会话列表。所以第一件事是界面锁,第二件才是磁盘锁。这个区别很重要,后面「威胁模型」那节会摊开讲。
flowchart LR
A["已锁会话"] -->|输入口令| B{"口令正确?"}
B -->|是| C["正文可见解锁态只在内存"]
B -->|否| A
D["普通目录"] -->|加密并锁定| E["密文 .bin清单也加密"]
E -->|解锁还原| D
三十秒装完
git clone https://github.com/xevil3301/dsh-chatlock
cd dsh-chatlock
node install.mjs # 默认装进 desktop profile
node install.mjs --profile web # 或者别的 profile
装完必须重启 dsh。宿主那半边不热重载,改文件等十秒日志里一行新东西都没有。
然后打开设置,「聊天锁」那一页,先设密码。回到侧栏,鼠标移到任意会话上会冒出一个锁,点它。
它能挡住谁
「别人打开本地文件夹必须经过 DSH」这句话,在应用层不成立。Windows 不会问一个进程「你经过 DSH 了吗」,Explorer、cmd、任何程序读文件走的都是文件系统。想真正实现「打开目录先弹密码」,只有挂一个文件系统驱动(WinFsp / Dokan),真实数据永远密文,解锁后由驱动透明解密。
那是另一个量级的工程。这一版给你的是下面三层里的第二层。
| 层 | 做到什么 | 挡得住谁 | 代价 |
| ① 界面锁 | 不输密码看不见会话内容 | 走到你电脑前、能操作 DSH 的人 | DOM 里仍有文字 |
| ② 磁盘锁 | 目录里只有密文,文件名也加密 | 打开或拷走目录的人、拿走硬盘的人 | 解锁期间磁盘上是明文 |
| ③ 虚拟盘 | 数据永远密文,驱动透明解密 | 除了解锁中的机器以外全部 | 要装驱动 + 自建 FS 后端,未做 |
还有一条正交的线,对方用的是哪个 Windows 账户。
另一个账户登录这台机器的话,NTFS ACL 就够了,icacls 一条命令,甚至不需要密码。加密真正派上用场是在文件被拷走、换机器、硬盘被拿走的时候。
同一个账户的话,ACL 一点用都没有。这种情况只有第三层才成立,第二层能做的是把明文的时间窗口压到最短。所以有了这三个开关。
- 解锁后密钥只留在内存,空闲十五分钟(可调)自动锁回去,不用再输密码
- 「立即锁全部保险箱」,同样用内存里的密钥
- 进程退出等于所有密钥蒸发
进程被强杀是没有清理钩子的。所以别把正在写入的工作区当保险箱,它是归档区。
三个把我打回来的坑
一 · 白底白字
密码框的主按钮一度是空白的,只有一个白框,什么字都没有。
查下来是配色。我用 --dsw-alias-brand-primary 当背景,又自己写死了 color: #fff。而这个变量在暗色主题里是 #f9fafb,近白。白底白字,按钮没有消失,它只是看不见。
正确的写法是用主题里本来就成对的那一组。
background: var(--dsw-alias-button-primary-fill);
color: var(--dsw-alias-label-primary-foreground);
二 · 一个根本不存在的变量
--dsw-alias-bg-layer-4 我拿来当输入框底色用了很久,样式没崩,因为 var() 有 fallback,不报错,静默吃默认值。
直到把主题里四百多个变量全拉出来对了一遍,才发现这个 token 一次都没定义过。现在整份 CSS 用的十四个变量,每一个都能在主题里找到定义,两套主题的值都核过。
三 · 加密了目录,却把文件名摊在磁盘上
保险箱加密了所有文件,但它的清单 manifest.json 里写着原始相对路径。别人打开目录,内容读不出来,却能一眼看到 客户资料/2026Q3/报价单.md。
加密了,等于没加密。现在清单也用同一把钥匙、同一套容器格式加密。
顺手修了一个更隐蔽的问题。拿错误的口令去锁一个已经锁着的保险箱,旧代码会把清单当成「没锁过」重新扫,然后用错的钥匙覆盖掉真正的文件清单,那个目录就永久救不回来了。现在这种情况直接拒绝,不动一个字节。
自检
| 命令 | 它证明什么 |
| node scripts/audit.mjs | 没有僵尸导出,没有多余的 import |
| node test/smoke.mjs | 口令哈希、授权过期、保险箱加解密往返 |
| node test/host-fake.mjs | 假 ctx 跑 host 半边,路由、ctx.fs 守卫、保险箱全流程 |
| node test/client-wire.mjs | 假 window 跑 client 半边,自注册与四个槽位 |
| node test/live-check.mjs | 真机验证,打运行中的实例 |
最后那个会按 DSH 自己的算法签一个浏览器会话 cookie,等价于一个已登录的标签页。原因很简单,DSH 的 /api 栅栏不是「回环就放行」,回环只是第一道,真正放行的是签名 cookie。命令行拿不到它,curl 一律 401,很容易误判成插件没装上。
node test/live-check.mjs --port <你的端口>
node test/live-check.mjs --mutate # 写入往返,跑完自己清干净
这堆文件是什么
index.js host 半边,状态、口令、授权表、路由、ctx.fs 守卫 client.js 浏览器半边,遮罩弹窗、侧栏锁标、上锁按钮、设置页 lib/state.mjs 状态读写与归一化,原子写,坏文件自愈 lib/secret.mjs 口令哈希、保险箱密钥派生、内存授权表 lib/crypt.mjs 文件级 AES-256-GCM,流式,tag 放尾部 lib/vault.mjs 保险箱,可中断的加密解密、加密清单、路径越界防护 lib/routes.mjs /api/chatlock/* 处理器与信任栅栏 demo/vault-demo.mjs 加密前后的目录对比,跑一次就懂 scripts/audit.mjs 死代码审计 scripts/make-assets.py banner 与图标的生成脚本 test/ 四个套件 docs/marketplace.md 怎么上架 DSH 市场
边界
- 聊天锁是界面锁,不是磁盘加密。要磁盘级保护,把导出的会话或私密资料目录登记成保险箱
- 保险箱是整目录上锁和解锁,不是实时透明加密。边用边透明需要的还是那个文件系统驱动
- 符号链接不跟随;单文件超过 512MB 会跳过并在结果里点名,不会静默漏掉
- 保险箱路径不允许互相嵌套,内外两把盐各管一半,加密状态会打架
- 保险箱忘记密码,数据不可恢复。scrypt 派生,没有后门,没有找回
最后
这东西一开始只是「加个密码」,最后变成一次把「我以为什么是安全的」全部推翻重来的过程。上面的表格、三个坑、四套自检,都是被真问题打出来的,不是设计出来的。
我自己的判断是,它能挡住大部分日常场景,室友、同事、来你家玩的朋友、以及那些不小心走错屋子的目光。挡不住的是有心人拿走了硬盘,或者你解锁的机器就摆在别人桌上。
想清楚这一点再用它,比多加密一层更有用。
用 DSH 写的,也用 DSH 验的 · MIT · 提 issue预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
xevil3301/dsh-chatlock
给会话加密码锁,把目录加密成密文保险箱
相关插件 · 对话 / 记忆
上下文中枢oceanbase/powercontext
上下文跟着工作走 —— 跨会话、跨智能体、跨人。
★ 1,489已汉化DSH
73.1
智能体记忆库plastic-labs/honcho
Honcho 是记忆基础设施,用来构建有状态的智能体。这些智能体能理解不断变化的人、智能体、群组、项目和想法。
★ 7,918已汉化DSH
71.7
长程智能体控制面loopx-project/loopx
给 Agent 一个目标,让工作持续向前。
★ 6,358已汉化DSH
71.3
智能体上下文数据库volcengine/OpenViking
给 AI 智能体用的上下文数据库
★ 41,453已汉化DSH
71.3
长效机器人团队Fei2411/DS-Bot
Download DS Bot for Windows 10/11 64-bit / 下载 Windows…
★ 5,293已汉化DSH
71.2
可携带记忆层EverMind-AI/EverOS
为什么选择 EverOS
★ 13,797已汉化DSH
71.1
这是你的仓库?认领条目