Skip to content

✨ 提议增强:公网自动开 + Bark 推送,扫码直达 DSH(已实现可参考) #35

Description

@bibibabawuwuwuwu

✨ 提议增强:公网自动开 + Bark 推送,扫码直达 DSH(已实现)

感谢 dsh-pocket —— 出门远程用 DSH 全靠它,体验很好 🐾

最近加了个增强:DSH 启动时自动开公网 + 自动 Bark 推送 → 点推送直接进 DSH。手机端体验从「4 步」变「1 步」,整理一下分享,作者觉得合适可以吸收进主仓库。

🎯 做了什么

  1. 配置项 autoStartPublic:勾上后 DSH web 启动后自动开公网隧道
  2. 配置项 push.bark:填 Bark App 设备 key,公网 ready 后自动推 Bark 通知
  3. 推送带 ?token= 魔法链接:点推送 → Edge/Safari → proxy 验证 + 种 cookie → 进 DSH

最终体验:DSH web 启动 → 自动开公网 + 自动推 Bark → iPhone 点推送 → 进 DSH(零手动操作)。

📁 改动清单(9 个文件)

文件 改动
lib/push.mjs 新增 —— push provider 抽象 + Bark 实现 + 配置加载(~100 行)
lib/settings.mjs 加 push + autoStartPublic re-export
lib/index.js apply() 读配置 + onTunnelReady 触发 push + autoStartPublic 钩子
lib/service.mjs 暴露 tunnelUrl getter
lib/web-rpc.js 加 4 个 RPC 端点(push.config.set/clearpush.testautoStartPublic.set)+ status 增 2 字段
lib/proxy.mjs ⚠️ 顺手修一个 bug?token= 路径下也种 cookie(详见下方)
client/api.js 加 4 个端点常量
client/index.jsx 设置页加「🚀 全自动」配置 block

⚠️ 顺手修的真 bug:公网首访白屏

现象:从外网首次访问公网 URL 带 ?token=<密码> 时,主页 200 但所有 <script src="/assets/*.js"><link href="/assets/*.css"> 子资源 401,页面只剩空 div → 白屏。

根因lib/proxy.mjsauthCheck() 通过 query 参数验证后直接放行,没种 HttpOnly cookie(种 cookie 只在 POST /pocket-login 路径做了)。浏览器并发请求子资源时,子资源 URL 没 ?token= 也没 cookie → 401。

复现:清空 iPhone 上 trycloudflare 域名 cookie → 访问 https://<公网URL>/?token=<当前密码> → Network 看子资源全 401。

修复(新增 maybeSeedAuthCookie,约 20 行):

function maybeSeedAuthCookie(req, res, token) {
  if (!token) return;
  if (parseCookies(req.headers.cookie)[TOKEN_COOKIE] === token) return;
  const origWriteHead = res.writeHead.bind(res);
  res.writeHead = function (statusCode, headers) {
    const h = { ...(headers ?? {}) };
    h['set-cookie'] = `${TOKEN_COOKIE}=${token}; HttpOnly; SameSite=Lax; Path=/`;
    return origWriteHead(statusCode, h);
  };
}

主流程 authCheck 通过后调用,WS upgrade 路径不需要(浏览器发 WS 前已经收到 Set-Cookie)。

🔑 关键 diff 片段

lib/index.js —— onTunnelReady 触发 push

 onTunnelReady: () => {
 const fresh = rotateAccessToken();
+      const url = service.tunnelUrl;
+      if (url) {
+        const magicUrl = `${url}${url.includes('?') ? '&' : '?'}token=${fresh}`;
+        void sendPocketPush({ url: magicUrl, body: '📶 点此直接进入(密码已自动填好)' })
+          .then((r) => {
+            if (r.ok) logger.info('dsh-pocket: Bark push sent');
+            else logger.warn('dsh-pocket: Bark push failed: %s', r.error);
+          });
+      }
       return fresh;
     },

lib/index.js —— apply() 加 autoStartPublic 钩子

   void service.startProxy().then((proxy) => {
     ...
     void service.restoreTunnelIfNeeded?.().catch(() => {});
+    if (readAutoStartPublic()) {
+      setTimeout(() => {
+        if (service.tunnelUrl !== null) return;
+        service.startTunnel().catch((err) => {
+          logger.error('dsh-pocket: autoStartPublic failed: %s', err?.message ?? err);
+        });
+      }, 1500);
+    }
   })

⚙️ settings.json 形态

{
  "lanAuthEnabled": false,
  "autoStartPublic": true,
  "push": {
    "provider": "bark",
    "key": "<your-bark-device-key-from-ios-app>"
  }
}

(向后兼容:缺 push / autoStartPublic 字段都视为关闭,老用户无感。Bark key 从 iOS Bark App 主界面获取。)

🤔 设计取舍

  • 先只做 Bark,provider 抽象留扩展点ntfy / webhook 一段 if 即可)—— 国内 iOS 推送 Bark 几乎是事实标准,先解决主要矛盾
  • 推送失败静默(fire-and-forget):不阻塞公网隧道本身,下次重启会重推
  • ?token= 复用现有 authCheck:零新接口、零安全妥协
  • WS 路径不重复种 cookie:浏览器收 HTML 的 Set-Cookie 后才发 WS
  • 不引入新依赖:用 Node 内置 fetch(>=18),无需 node-fetch
  • cookie SameSite=Lax:和现有 dsh_pocket_token 一致

🧪 验证步骤

  1. iPhone 装 Bark → 复制设备 key
  2. 设置页填 key → 保存 → 测试推送
  3. 勾上「启动时自动开公网」
  4. 重启 dsh web → iPhone 应自动收到「📱 DSH 已就绪」推送 → 进 DSH
  5. 之后再重启 → 又自动推送 → 又自动进

🐾 是否愿意 merge

如果合适可以拆两个 PR:

如果 idea 不错但不想合 Bark(避免单一 provider 绑定),可以做成官方文档 + 第三方脚本形式(独立 bin/dsh-pocket-push.mjs CLI),不动主插件代码。我这边已实现但保留剥离余地。


再次感谢这个项目 ——「把 DSH 装进口袋」对经常出差的开发者真的是刚需喵 🐾

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions