Skip to main content
L

dsh-browser-takeover

l1818346/dsh-browser-takeover

Browser takeover for sign-in-gated sites: keeps a list of addresses that need a login (URL and date only, no credentials), answers before a visit whether an address is already on it, reports whether the debug browser is signed in there from the session-cookie names of that site (certain, likely, or not signed in — anonymous cookies such as _gh_sess never count), and opens saved addresses in that browser by navigating and clicking one element by its visible text, searching every iframe. One click per call, no crawling.

Install

dsh plugin --profile web add github:l1818346/dsh-browser-takeover

README

浏览器网址接管 · dsh-browser-takeover

让 DSH 里的模型在你已经登录的浏览器里走过去:打开网址、按页面上的可见文字点一个入口; 同时维护一份「要登录的网址」清单——Agent 访问网址前先查这份清单,清单里的优先走这个插件。


0.9.1 修了什么

  • GitHub 登录后仍显示"未登录":原来的登录判定只认学习通/B 站那套 cookie 名字 (SESSDATA、JSESSIONID、UID…),GitHub 用的是 user_session / logged_in / dotcom_user, 一个都不在白名单里。现在白名单补齐了 GitHub、Google、Microsoft、知乎、微博等常见名字, 并加了一条通用规则兜底。
  • 判定分两档:命中已知名字 → confidence: 'certain'(界面显示"已登录"); 只命中通用规则(名字里有 session / sso / auth / token / ticket 且值不为空)→ 'likely' (界面显示"可能已登录",不冒充确定)。logged_in 这类开关型 cookie 按值判断, logged_in=no 不算登录。
  • 反例也钉住了:GitHub 未登录时同样有 _gh_sess,所以通用规则刻意不收 sess, 否则会把没登录的 GitHub 说成"可能已登录"。

0.9.0 改了什么

  • 清单从空开始:不再预置任何网址,也不读别的插件留下的 video-storyboard-sites.json。 装好之后清单是空的,要加什么由你自己加(设置页,或 web_open({ …, remember: true }))。
  • CDP 收成一个小模块 src/cdp.js:只留这个插件真正用到的几件事——找页面目标、 在页面/每个 iframe 上下文里求值、读 cookie、回答端口状态、按端口拉起浏览器。 视频时代的位置读取、封面/转码 cookie 导出等全部删掉。
  • 浏览器状态只有四种:open(端口已开)/ closed(端口不通)/ unconfigured(没配端口)/ error。 设置页不再出现"页面里没有视频"这类词。
  • 端口只认 ~/.dsh/browser.json(不再读 video.json)。
  • 许可证正文保留,版权声明行已删除。

0.8.0 新增了什么

  • web_sites:访问网址前先查一次清单——这条地址存过没有、那个浏览器此刻登录着没有。 零副作用,不启动浏览器、不打开页面。
  • web_open 带上判断:返回里始终有 site(清单命中:完全一致 / 同主机 / 同域名) 与 signIn(登录态);新参数 remember 先记进清单再打开,launch 端口没开就自己拉起浏览器。
  • 系统提示里的约定:Agent 访问网址时会先 web_sites,清单里的用 web_open, 不用 web_fetch 抓 HTML 顶替(抓不到登录后的内容)。
  • 清单匹配独立成 src/lookup.js(纯函数),登录态判断抽到 src/session.js; 新增 test/ 下的单元测试。升级后需重启一次 DSH Desktop,工具与提示词才会重新组装。

0.9.2 做了什么

把登录判定表从"认得几个站点"扩成三层表,覆盖市面上常见平台、框架与单点登录:

层含义界面例子
身份 cookie只有登录后才出现已登录user_session · SESSDATA · BDUSS · z_c0 · _tb_token_ · pt_key · li_at · ESTSAUTH · KEYCLOAK_IDENTITY · __Secure-next-auth.session-token
框架会话匿名访客也会拿到可能已登录PHPSESSID · JSESSIONID · laravel_session · connect.sid · MoodleSession · sid
匿名噪音与登录无关,永不计数不计入_gh_sess · csrftoken · _ga · _hjSessionUser_* · AWSALB · NID · datr · color_mode
兜底规则名字含 session / sso / auth / token / ticket… 且值不短可能已登录表里没有的站点靠它

表在 src/session-cookies.js,一个名字一行;遇到"登录了却显示未登录", 把该站的 cookie 名字加进 IDENTITY_COOKIES 即可(npm test 会顺手验证没把别人带歪)。

功能

能力入口说明
查清单工具 web_sites零副作用:这条网址存过没有、那个浏览器此刻登录着没有。不启动浏览器、不打开页面
页面导航 / 按文字点击工具 web_open在带调试端口的浏览器里打开地址,按可见文字点一个元素;会搜所有 iframe
网址清单设置 → 浏览器网址接管只存 URL 与添加时间,不存账号密码
登录状态同上依据该站点的会话 cookie 名字判断(三层表 + 兜底规则),cookie 的值不离开宿主进程
打开登录页同上端口开着就开新标签,没开就带调试参数启动浏览器

一次调用最多点一个元素;不做循环点击、不批量爬取。

Agent 访问网址的顺序

插件往系统提示里写了一段约定(src/prompt.js),所以「去访问某个网址」时 Agent 会:

  1. 先调 web_sites({ url }) —— 零成本,回答这条网址在不在清单里;
  2. 在清单里(saved: true,或 hostSite 命中同一站点)→ 用 web_open 打开, 而不是 web_fetch 抓 HTML(抓不到登录后的内容);
  3. 清单里没有 → 也优先 web_open;需要登录的站点先让你在那个窗口里登录一次, 再用 remember: true 记进清单,下次就自动算"清单里的网址"。

web_open 的返回里一直带着这些判断,所以即使 Agent 直接开了工具,也看得到 「这条网址存过没有、登录着没有」:

{
  "ok": true,
  "saved": true,
  "site": {
    "asked": "https://hdu.fanya.chaoxing.com/portal",
    "saved": true,
    "match": "exact",
    "hostSite": null,
    "domainSite": null,
    "note": "清单里有这条网址(…)——用 web_open 在插件浏览器里打开,那里是用户已登录的会话。"
  },
  "signIn": { "conclusive": true, "signedIn": true, "sessionCookieNames": ["JSESSIONID"] }
}

匹配规则:完全一样 > 同一主机(登录态同样适用)> 同注册域名(只作提示)。 比较时忽略 www.、末尾斜杠、query 和 hash;差异会原样回显,不替你拍板。

安装

git clone git@github.com:L1818346/dsh-browser-takeover.git
cd dsh-browser-takeover
node scripts/install-dev.mjs     # 用 junction 挂进 desktop profile 并注册 bundle

然后重启 DSH Desktop(插件树与系统提示都在进程启动时组装;工具与提示词的改动 不重启不会生效)。装好之后清单是空的,没有任何预置网址——第一条要你自己加。

要求:

  • Node.js ≥ 20
  • Edge 或 Chrome(要能开 --remote-debugging-port,即 CDP)

浏览器准备

插件不会读你的主浏览器 profile —— Chromium 136 起明确禁止在默认 profile 上开调试端口 (官方说明),而换路径去看同一份 profile 又会因为 App-Bound Encryption 拿不到已登录的 cookie。所以它要的是一只带调试端口 的独立窗口,默认端口 9333:

scripts\start-edge-debug.cmd

脚本用 ~/.dsh/edge-watch 作为独立 profile 启动 Edge,并打开调试端口。 在这个窗口里登录一次,之后插件都复用这份登录态;你平时的 Edge 可以照常开着。

也可以自己起:

msedge.exe --remote-debugging-port=9333 --user-data-dir="%USERPROFILE%\.dsh\edge-watch"

配置

~/.dsh/browser.json:

{
  "browserPort": 9333,
  "launchBrowser": true
}
键默认说明
browserPort无调试端口;工具里显式传 browserPort 优先,其次这个文件,最后落到 9333
launchBrowserfalse清单里的站点在端口没开时,是否允许插件自己拉起浏览器。打开后"优先走插件"才真的不用你动手

端口只该有一个说法。

用法

清单初始是空的:第一条网址要么在设置页点「添加」,要么打开时顺手用 remember: true 记下来。

// 1. 先查:这条网址存过没有?(零成本)
web_sites({ url: "https://hdu.fanya.chaoxing.com/portal" })

// 2. 再开:清单里的网址直接走插件浏览器(带登录态)
web_open({ url: "https://hdu.fanya.chaoxing.com/portal", match: "学习空间" })

// 3. 需要登录的新站点:先登录,再记进清单
web_open({ url: "https://example.com/app", match: "我的课程", remember: true })

// 4. 端口没开时,让插件自己拉起浏览器再打开
web_open({ url: "https://example.com/app", launch: true })

// 5. 先看看页面把入口叫什么(不点击)
web_open({ match: "国家安全教育", listOnly: true })

// 6. 同名元素不止一个时用 index 选
web_open({ match: "国家安全教育", index: 0 })

匹配规则:完全相同 > 以它开头 > 包含;<a> 链接在平手时优先。 匹配不到时会把候选列出来,而不是猜一个。

数据与隐私

  • 网址清单在 ~/.dsh/browser-takeover-sites.json,只存 URL 和时间戳;初始为空, 插件不预置、也不从别的文件名里捞。
  • 不读、不填账号密码输入框;不导出 cookie 的值。设置页和 web_sites 只回显会话 cookie 的 名字(如 SESSDATA、user_session)。唯一的例外是 logged_in 这类开关型 cookie: 只拿 yes/no 做判断,值本身不外传。
  • 登录状态分三档:已登录(命中身份 cookie)/ 可能已登录(框架会话或兜底规则)/ 未登录;端口没开时是「无法判断」,而不是冒充「未登录」。判定表在 src/session-cookies.js,名字可以自己往里加。

故障排查

现象原因处理
no-debug-port浏览器没带调试参数启动跑 scripts\start-edge-debug.cmd,或 web_open({ …, launch: true })
Agent 没先查清单插件是在加这段提示之前加载的重启 DSH Desktop
设置页显示「端口未开」同上,或端口不是 9333检查 browser.json
点了没反应站点用 window.open,被弹窗拦截对 <a href> 插件会直接导航;其余元素只能真点
登录状态「无法判断」浏览器没开,读不到 cookie先启动调试浏览器
明明登录了却显示「未登录」该站的登录 cookie 名字不在 src/session-cookies.js 的 IDENTITY_COOKIES 里把名字加进那个数组;兜底规则一般会先兜成「可能已登录」
显示「可能已登录」只命中框架会话(PHPSESSID 等)或兜底规则一般就是登录了;想更确定就把名字加进 IDENTITY_COOKIES
没登录却说「已登录」某个匿名 cookie 被当成了身份 cookie把名字挪进 ANONYMOUS_COOKIES,并补一条测试

开发

npm run check     # 逐文件 node --check(含 client.js 与 test/)
npm test          # node --test:清单匹配与系统提示段的单元测试
npm run smoke     # 用假的 defineTool 跑一遍 apply(),并真的执行两个工具(不碰浏览器)

npm test 会 fork 子进程;如果你的环境禁止 fork(某些沙箱),直接跑 node test/lookup.test.mjs 也能执行(同一进程内)。

许可

MIT。条款见 LICENSE。

Related plugins