npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dsh-permission-gate

v1.2.0

Published

UI-level access gate + process-wide agent tool brake for DeepSeek Harness: shared session, strict 60-minute idle lock, native settings module. NOT server-side authentication.

Readme

dsh-permission-gate

DeepSeek Harness(dsh)的 界面级访问闸门 + 全进程 agent 工具制动。

登录一次 → 所有打开的 DSH 页面解锁。没人登录 → 连 agent 自己都跑不动一个工具。


⚠️ 先读这一段:这不是身份认证

DSH 的 /api 表面本身没有认证 —— 这是 harness 的设计事实,不是本插件能修的东西。 harness 自己的源码是这么描述它那道请求围栏的:

trustedHosts is a DNS-rebinding fence, explicitly not authentication

任何能连上 DSH 端口的客户端,都可以直接调用 HTTP API 完全绕过本插件。 本插件只拦两件事:

  • ✅ 浏览器页面(每次页面加载注入的全屏锁页)
  • ✅ agent 的工具调用(tools.guard 全进程制动)

它不拦 HTTP 表面。它既不是反向代理,也不是会话层,更不是授权系统。

务必配合一道真实边界使用:

| 真实边界 | 它能给你什么 | |---|---| | 把 DSH 绑在回环(dsh web 的默认行为) | 网络上根本没有任何东西能碰到它 | | VPN / overlay(WireGuard、Tailscale、ZeroTier) | 只有你自己的设备能路由到这个端口 | | 带真实认证的 TLS 反向代理 | 真正的认证层只能落在这里 |

如果你把它丢在公网端口上,然后以为安全了 —— 那比什么都不装更糟,因为你不会再去找真正的问题。


它做什么

  • 全屏锁页。 通过官方文档化的 webserver/index-inject 通道注入到每次页面加载 —— 不需要客户端插件包、不需要模块加载器、不需要跟 SPA 保持同步。
  • 全局共享会话。 整个进程只有一个会话、一个空闲时钟。手机登录 → 电脑页面在下一次轮询时自动解锁; 时钟到期 → 所有页面一起回落登录页。
  • 严格 60 分钟空闲锁。 没有宽限期,任务运行中也不例外。这是刻意的:闸门就是一道亡灵开关。
  • 全进程工具制动。 无人登录期间,ctx.tools.guard 拒绝 agent 的每一个工具调用 —— 读不了文件、跑不了命令、上不了网、起不了子代理。
  • 真实凭据。 scrypt + 随机盐,存于 ~/.dsh/permission-gate.json(权限 0600)。 会话只在内存,所以重启后必须重新登录 —— 但口令不会被重置。
  • 服务端退路。 /gate 是宿主半边直出的纯 HTML 页面,即使注入脚本坏掉或被缓存住也一定能用。
  • 原生设置模块。 DSH 设置里多出一个「权限闸门」页,可以关闭闸门 —— 而关闭需要输入口令。
  • 可收起的悬浮胶囊。 角上的倒计时胶囊可以收起到右侧边缘变成一条窄把手,点一下就展开; 偏好记在 localStorage 里。

安装

本包声明了 dsh.bundle,所以它是一个 profile layer:装就是一行命令, 组合由 DSH 自动对账,没有需要你手改的补丁文件。

dsh plugin --profile web add dsh-permission-gate

# 重启 DSH 一次 —— 客户端名单只在启动时扫描

bundle 会自己插入这一行(见 cordis.patch.yml):

- insert:
    - id: permission-gate
      name: dsh-permission-gate

从手动安装迁移过来的? 请先把你自己的 ~/.dsh/profiles/web/cordis.patch.yml 里同样那一行删掉 —— 现在由 bundle 插入,同一个 id 出现两次会冲突。

下一次页面加载就会出现锁页。首次访问让你设置口令,之后每次让你输入口令。

HTTP 接口

全部由宿主半边提供,与 DSH 同源。

| 方法 | 路径 | 用途 | |---|---|---| | GET | /gate | 服务端渲染的登录页,永远可用 | | GET | /gate/ui.js | 注入浏览器的脚本(cache-control: no-store) | | GET | /gate/status | { state, expires, remainingMs, idleMs, hasCredential, authenticated } | | POST | /gate/login | { password, mode } —— 首次用 mode: "setup",成功后下发会话 cookie | | POST | /gate/touch | 「有人在」—— 续期空闲时钟 | | POST | /gate/lock | 丢弃会话并清除 cookie | | POST | /gate/mode | { password, enable } —— 关闭/开启闸门,必须输入口令 |

state 取值:setup · locked · unlocked · disabled。

威胁模型

| 场景 | 挡得住吗 | |---|---| | 有人拿起你没锁屏的手机/电脑,打开浏览器 | ✅ 全屏锁页 | | 你走开了,自治 agent 还在继续干活 | ✅ 严格空闲锁 + 工具制动 | | 另一台设备上开着的页面 | ✅ 共享会话逻辑,所有页面镜像服务端状态 | | 你 tailnet 里的人直接调 /api | ❌ 挡不住 —— 这正是真实边界的职责 | | 有人能改 cordis.patch.yml 或插件目录 | ❌ 挡不住 —— 插件无法对抗加载它的 composition | | 有人重启 DSH 进程 | ❌ 挡不住 —— 闸门活在进程里,重启同时清空会话 |

刻意保留的豁免

锁定时仍有三个工具可调用,因为它们碰不到任何文件、命令、会话内容或凭据:

get_goal · update_goal · todo_write

它们的存在是为了让被锁住的 agent 仍能汇报状态、收尾自己的记账。 想要零豁免闸门,删掉 lib/index.js 里 BOOKKEEPING_TOOLS 那一行即可。

出事怎么办

| 情况 | 做法 | |---|---| | 忘了口令 | 删掉 ~/.dsh/permission-gate.json → 下次访问会让你设一个新的 | | 注入的界面坏了 / 被缓存 | 直接访问 /gate,它是服务端渲染的 | | 彻底被锁在外面 | 把 cordis.patch.yml 里那一行改成 disabled: true,或删掉整块。该文件是热加载的,通常不用重启 | | 想看当前状态 | curl http://127.0.0.1:3080/gate/status |

设计笔记

这个插件是在「用手机远程操控 DSH」的实战里长出来的。三个 bug 被我写进了注释和测试, 因为任何人给 DSH 写注入式界面都会踩到它们:

  1. 静默的渲染崩溃比看得见的报错危险得多。 锁页曾经在最常见的路径上每次渲染都抛异常 (没有「确认口令」输入框时 appendChild(null))—— 宿主侧拦截照常工作,而界面上什么都没有, 表现为「没有权限,但还能聊天」。修法:永不 append null,并把整个渲染包进会显示错误的兜底。
  2. 绝不要用定时器重绘表单。 一次 5 秒的状态轮询会重建登录表单、清空你正在输入的口令。 修法:只在状态真的变化时重绘,并且把已输入内容跨重绘带过去。
  3. 全局会话不能要求按浏览器的 cookie。 /gate/touch 原本要求 cookie 与会话 token 匹配。 重启后只有登录过的那个浏览器持有有效 cookie,其它页面全部 401 —— 倒计时只减不增。 修法:touch 不授予任何权限,它只要求共享会话处于解锁状态。

开发

冒烟测试会把真实的 lib/ui.js 跑在一个最小 DOM 桩上 —— 那个桩的 appendChild 遇到 null 会像真实 DOM 一样抛错。不需要浏览器。

npm test

兼容性

针对 DSH 0.1.1-rc.2 / cordis 4.x 开发,依赖这些 harness 能力:

  • 宿主:webServer.register · webserver/index-inject · tools.guard
  • 客户端:settings.section 槽位 · slots 与 timer 服务

它们属于偏内部的 API,DSH 升级后可能需要同步更新本插件。

许可

MIT