dsh-bit-login
把 DSH 接到北京理工大学的两套系统:
- 校园网(深澜 Srun 网关
http://10.0.0.55)——查在线状态与流量余额、登录 / 登出、一键排障,并把实时网络状态注入模型上下文; - 学校系统(成绩 / 课表 / 学籍 / 空闲教室 / 考试)——通过 BIT101 社区运维的 BIT-Login 网关用统一身份认证登录,查询本科成绩、课程表、学籍与学分进度,还能导出可信电子成绩单与课表日历(.ics),并查询教学中心的空闲教室与考试安排(校内直连优先,被拒或连不上时自动改走 webvpn)。
设置页里有一个实时面板,两套能力都能在那里点。
协议细节来自对 BIT-Login / bitsrun 的逆向分析结论,并与 BITNP/bitsrun、spencerwooo/bitsrun-rs 的实现交叉核对过;成绩 / 课表走的是 BIT101 网关的 REST 契约(POST /api/auth/start + X-Challenge-Token 轮询 + Authorization: Bearer)。
它做什么
| 能力 | 位置 |
|---|---|
| 在线状态 / 已用流量 / 在线时长 / 余额 | 工具 bit_login_status,面板顶部卡片 |
| 登录(账号 + 密码 + 运营商 + ac_id) | 工具 bit_login_login,面板登录表单 |
| 登出 | 工具 bit_login_logout,面板「登出」按钮 |
| 一键排障(网关可达性、ac_id 探测、challenge、在线状态、门户劫持) | 工具 bit_login_diagnose,面板「一键诊断」 |
| 成绩查询(本科教务) | 工具 bit_school_scores,面板「查询成绩」 |
| 课表查询(教学中心) | 工具 bit_school_schedule,面板「查询课表」 |
| 学籍 + 学分进度(教学中心) | 工具 bit_school_profile,面板「学籍 / 学分」 |
可信电子成绩单(综合教务 jwb_cjd) |
工具 bit_school_transcript,面板「成绩单」 |
课表日历 .ics 导出(30 分钟有效) |
工具 bit_school_ics,面板「课表日历」 |
| 空闲教室查询(教学中心,双通道) | 工具 bit_school_classroom,面板「查询空闲教室」 |
| 考试安排查询(教学中心,双通道) | 工具 bit_school_exam,面板「考试安排」 |
| 登录态保活(会话过期后自动静默重登) | 后台保活定时器,面板显示「登录态:会一直续到关闭 DSH」 |
| 统一身份认证登录 / 验证码 / 会话 / 登出 | 工具 bit_school_login / bit_school_verify / bit_school_status / bit_school_logout,面板下半部分 |
| 实时状态进模型上下文 | systemPrompt.section + systemPrompt.context(promptInjection 可关) |
| GUI 实时面板 | 设置 → 「BIT 校园服务」(15 秒轮询) |
安装
在本机 DSH profile 里(plugin_manager → install_bundle,target 用本目录的绝对路径):
<你克隆到的路径>\dsh-bit-login
新装 bundle 经 HMR 直接生效;替换已安装的同名包需要重启 DSH 才会加载新的 JS 模块代。
卸载:plugin_manager → remove_bundle target dsh-bit-login。
配置
改 cordis.patch.yml 的 config: 段(patch 层跨升级保留):
| 键 | 默认 | 说明 |
|---|---|---|
gateway |
http://10.0.0.55 |
Srun 网关地址,一般不用改 |
isp |
'' |
运营商后缀:''(校园网)/ cmcc / cmct / unicom,也可按次在 bit_login_login 的 isp 参数里覆盖 |
timeoutMs |
6000 |
单次 HTTP 超时 |
refreshSeconds |
60 |
后台状态采集间隔;0 关闭。校园网外自动退避,最长 15 分钟一次 |
promptInjection |
auto |
auto 仅网关可达或在线时注入 · always 恒注入 · off 关闭 |
routePrefix |
/dsh-bit-login |
面板调用的 Host 路由前缀 |
schoolEnabled |
true |
是否启用「学校系统 · 成绩 / 课表」工具与路由 |
schoolBaseUrl |
https://login.bit101.flwfdd.xyz |
BIT101 社区运维的 BIT-Login 网关(第三方) |
schoolServices |
['jwb','jxzxehall'] |
登录时申请的服务:jwb = 本科成绩,jxzxehall = 课表 / 空闲教室 / 考试 |
schoolTimeoutMs |
20000 |
网关单次请求超时 |
schoolPollBudgetMs |
25000 |
登录后轮询等待验证码的总时间预算 |
jxzxehallApp |
https://jxzxehallapp.bit.edu.cn |
教学中心直连地址(空闲教室 / 考试用)。直连被拒或连不上时自动改走 webvpn,无需手工配置 |
rememberCredentials |
true |
记住凭据(只在进程内存里)以便会话过期后静默重登;false 退化成「一次登录管 30 分钟」 |
keepAlive |
true |
后台保活:临近到期时自动续期,让登录态一直活到关闭 DSH |
keepAliveIntervalSeconds |
120 |
保活检查间隔(最小 15 秒) |
refreshBeforeSeconds |
300 |
剩余有效期少于这个秒数就去续期 |
凭据
插件不写盘、不落日志、不进 storageDomain。 账号密码只在两种时机出现:
- 模型/用户调用
bit_login_login({ username, password })或bit_school_login({ username, password })时按次传入; - 在设置面板的登录表单里当场输入,提交后立刻清空输入框。
默认 rememberCredentials: true:统一身份认证密码在登录成功后留在 DSH 进程的内存里(school.js 的 credentials 闭包变量),用来在网关会话(默认 30 分钟)过期后静默重登,这样登录态能一直撑到关掉 DSH。它不写盘、不回给调用方、不出现在任何返回值或 UI 里;在面板点「登出学校系统」或调用 bit_school_logout 会立刻连同会话一起清掉,关掉 DSH 自然也就没了。不想要这个行为就把 rememberCredentials 设成 false。
校园网的密码始终不保留:每次 bit_login_login 都要当次传入。学校系统会话的 challenge_id / access_token 同样只存在内存里,不回给调用方。
安全边界
- 校园网网关是 明文 HTTP(
http://10.0.0.55),密码会以明文/可逆编码出现在局域网报文里——这是深澜协议本身的性质,任何 BIT 登录脚本都一样。别在不可信网络里用。 - 成绩 / 课表必须经过第三方网关:统一身份认证密码会经 HTTPS 提交到
login.bit101.flwfdd.xyz(BIT101 / flwfdd 等社区个人、社团运维,非学校官方)。开了rememberCredentials(默认)后,密码还会在本进程内存里留到登出或关掉 DSH,用于自动重登——这不会增加外发次数(重登仍是发给同一个网关),但确实延长了「密码在进程里存在」的时间窗。不信任第三方就别用这部分;schoolEnabled: false可整体关掉,rememberCredentials: false可只关掉记忆。 - 面板调用走 Host 的
webServer路由,login/logout/ 学校系统的写操作都做了同源校验(Origin与Host不一致直接 403)。 - 工具与路由的返回值都过
sanitize(),递归剔除password/info/chksum/hmd5/token/challenge/access_token/challenge_id/authorization,避免把签名材料和口令回灌进模型上下文。 - 自 2020-10-09 起校园网账号即学校统一身份认证账号,用它做自动化等同于把统一身份凭据交给脚本,请自行评估合规风险。
实现说明
- 纯 Node,零第三方依赖:MD5 / SHA1 / HMAC-MD5 / XXTEA / 魔改 Base64 全部自实现(
srun.js),不使用node:crypto。 srun.js是独立的协议层,可单独import复用;createSrunClient({ gateway, timeoutMs })返回status / login / logout / diagnose等。- 关键常量:
n=200、type=1、enc=srun_bx1、info_prefix=SRBX1;hmd5 = HMAC-MD5(key=token, msg="");chksum = SHA1(token+username+token+hmd5+token+ac_id+token+ip+token+200+token+1+token+info);ac_id从门户页/bit.edu.cn302 动态探测,不写死。 school.js是 BIT101 网关客户端(同样是零依赖、纯fetch):createSchoolClient({ baseUrl, timeoutMs })管 HTTP 与信封解包,createSchoolAuth({ client, services, pollBudgetMs, rememberCredentials })管挑战状态机(running→waiting_sms/waiting_captcha→ready)与登录态保活:凭据只留在闭包变量里,ensureReady()/withService()在会话过期或缺少某个服务权限时静默重登,maybeRefresh()供后台保活定时器调用(fresh/no-credentials/blocked/awaiting-code),撞上短信或图形验证码就停下等用户、不反复触发学校风控。展示层纯函数(成绩行、课表行、周次压缩、学籍、成绩单 URL、ICS 信息)与它放在一起,便于单测。jxzxehall.js是教学中心客户端(零依赖、纯fetch):createJxzxehallDirect({ appBase, webvpnAppBase, timeoutMs, webvpnTimeoutMs, totalBudgetMs, fetchImpl })返回freeClassrooms / exams / currentTerm / uninstallWebvpnDnsBridge,实现空闲教室(kxjas)与考试安排(wdksapMobile)的模块化流程(init 会话 GET → 表单编码 POST → 分页,页数上限MAX_PAGES = 100,超过报too-many-pages)。请求先经schoolAuth.jxzxehallCookies()从网关拿cookie,再先试校内直连,http-401/network/timeout/not-json任意一种失败都自动改走 webvpn:BIT-Login 网关部署在校外,它自己的 jxzxehall 会话是经 webvpn 建立的(service.py: initialize_network()/patch_webvpn()),返回的 cookie 只对 webvpn 地址有效,直连必然 401;直连被门户劫持时还会返回 200 + 登录页 HTML(即not-json)——两种都会触发回退。整次调用有总预算totalBudgetMs(默认 60000,0表示不限),每步超时会被压到剩余预算内、用完报timeout且带budgetExhausted: true,避免「每步各 20 秒、链路一长必然超时」。另外webvpn.bit.edu.cn在校园解析器里没有记录,所以走 webvpn 前会用 DoH(WEBVPN_DOH_ENDPOINTS,首选纯 IP 的223.5.5.5)解析出 IP,并给dns.lookup装一个只拦这一个域名的补丁(Node 的 fetch 不吃自定义 lookup,Electron 里又 require 不到 undici,这是不引依赖的唯一办法)。补丁是惰性安装的(首次真要访问 webvpn 之前才装,装不上只记一个标志、不炸请求),uninstallWebvpnDnsBridge()能精确还原,插件卸载时由index.js的ctx.effectdispose 自动调用;DoH 失败的原因会带进 webvpn 通道的超时 / 网络错误文案(webvpnDohLastError()),便于区分「域名查不到」和「网络不通」。
测试
装了 Node ≥ 20 和 DSH 的话,一条命令跑全部 7 套(零第三方依赖、不需要 npm install、不需要联网;其中 schema / validate-patch 两套会直接 import DSH 自己的 JSON Schema 校验器与 YAML 实现,DSH 装在非默认路径时用 DSH_APP_DIR 覆盖):
npm test
也可以按下面的方式单独跑(开发机没有把 node 放进 PATH 时,用 DSH 自带的 Electron 当 Node 使):
$env:ELECTRON_RUN_AS_NODE = '1'
$exe = 'C:\Program Files\DSH Desktop\DSH Desktop.exe'
& $exe test\srun.test.mjs # 协议层(深澜)
& $exe test\school.test.mjs # BIT101 网关客户端(node:http mock)
& $exe test\jxzxehall.test.mjs # 教学中心直连客户端(注入 fetch 驱动空闲教室 / 考试)
& $exe test\plugin.test.mjs # Host 半边(假 Cordis ctx)
& $exe test\schema.test.mjs # 工具 schema 子集(DSH 真实校验器)
& $exe test\client.test.mjs # Client 半边冒烟(假 __ModuleLoader__ + React 桩)
& $exe test\validate-patch.mjs # cordis.patch.yml 结构与 YAML 合法性(用 DSH 自带的 js-yaml)
# 可选:真实网关结构探针(需要网络 + 用假账号,不进入自动测试集)
& $exe test\live-gateway.mjs
用
& $exe <脚本>时必须传绝对路径;Electron 的输出不经过 PowerShell 管道,所以>、2>&1 | Select-Object -Last 20这类写法都会拿到空结果。要么直接让它在控制台打印,要么用cmd重定向到文件:cmd /c "`"C:\Program Files\DSH Desktop\DSH Desktop.exe`" `"$PWD\test\srun.test.mjs`" > out.txt 2>&1"
test/srun.test.mjs:MD5 / SHA1 / HMAC-MD5 与node:crypto逐字节比对(含 0/1/55/56/57/63/64/65/119/120 字节与中文边界);XXTEA 与魔改 Base64 与test/reference.py(逐字复制BITNP/bitsrun的utils.py)比对。test/school.test.mjs:用node:http起一个假网关,验证POST /api/auth/start的请求形状与content-type、轮询次数与X-Challenge-Token、waiting_sms/waiting_captcha两条验证码路径、failed快照、401 与{detail:{message}}两种错误信封、Bearer 业务调用的 body({challenge_id, ...})、缺服务权限、会话过期、logout 的DELETE、超时 / 网络不可达 / 轮询预算耗尽,以及publicSnapshot的脱敏;后半段专测保活:会话过期后静默重登(断言又发起了challenge且用的还是记住的账号)、maybeRefresh的fresh/no-credentials/blocked分支、rememberCredentials:false、登出清凭据、自动重登撞上短信验证码时停下(relogin-need-sms→ 再调变成pending-verification、retention().blocked === true)、captcha路由 404 映射成captcha-unavailable、成绩单 / 课表日历 / 学籍三个新方法的路径与请求体、缺jwb_cjd时自动补一次带该服务的登录、以及jxzxehallCookies()的请求形状(/api/jxzxehall/cookies+ Bearer +{challenge_id})。test/jxzxehall.test.mjs:注入fetch驱动createJxzxehallDirect,验证空闲教室 / 考试安排的模块化流程(init 会话 GET、表单编码 POST、querySettingJSON 字段、周次 XQJ 优先、分页、*order排序、JC 状态解析、缺 fetch 报错)以及纯函数(currentKksj/getBuildingCoord/cookieString/freeSectionRanges/formatClassroomRows/formatExamRows)。test/plugin.test.mjs:用假 Cordis ctx 驱动apply(),验证 15 个工具、提示词开合、15 条路由、同源拒绝、凭据校验、学校系统未登录返回 409、敏感字段不外泄与渲染分支;末尾还有一段端到端——用node:http起一个本地假网关,走真实的createSchoolAuth状态机、真实路由与真实工具,覆盖「密码错误 →failed」「要求短信验证码 →need_sms」「提交验证码 →ready」「查成绩 / 查课表」「Bearer +{challenge_id}请求形状」「登出后回idle」;再桩掉globalThis.fetch只接管jxzxehallapp.bit.edu.cn,端到端验证空闲教室 / 考试安排「拿网关 cookie → 直连教学中心」的完整链路。test/schema.test.mjs:把 DSH 自己的assertSupportedJsonSchema/assertObjectJsonSchema/validateJsonSchemaValue直接 import 进来(dsh-tools/lib/index.js与dsh-tools/lib/types/json-schema.js两份副本都跑),校验 15 个工具的parameters与output.schema,并带防回归断言。可用DSH_APP_DIR覆盖 DSH 的resources/app路径。test/validate-patch.mjs:用 DSH 自带的js-yaml解析cordis.patch.yml,校验insert[0].id/name/config结构、schoolServices是数组、新配置键的默认值与index.js的DEFAULTS一致——YAML 写坏会让 profile 启动时就崩。test/client.test.mjs:用假window.__ModuleLoader__捕获客户端模块,检查只require('react')、inject:['slots']、settings.section注册参数(id: bit-login、order: 65、label)以及面板确实渲染出校园网与学校系统两块。
⚠️ 改 schema 前必读:
ctx.tools.register会用assertSupportedJsonSchema校验output.schema,而 DSH 只支持一个 JSON Schema 子集:type必须是单个字符串({ type: ['string','null'] }会抛JsonSchemaError: … type must be a single type string (type arrays are not supported)),可空字段要写成oneOf: [{type:'string'},{type:'null'}];oneOf不得与properties/required/additionalProperties/items/enum/const同级;没有type/oneOf时不允许出现properties;required里的名字必须在properties中。这个错误会让整个apply()中断(工具与 HTTP 路由全部不注册,面板报 404),而且只在宿主激活时暴露——所以改完务必跑test/schema.test.mjs,再重启 DSH。
验证状态(2026-10-09)
分两层看:v1.3.0 的加固与回归(2026-10-09 复核),以及实网验证(校园网侧 2026-10-09 复核;学校侧数据来自 2026-10-04 的实网全量跑通)。
v1.3.0 加固与回归(2026-10-09)
- ✅ 两份只读审计的结论已全部收口:
index.js:collect()加 single-flight(工具调用 / 面板 15 秒轮询 / 后台定时器不再并发打网关,慢的旧响应也不会覆盖新缓存);登录 / 登出后刷新状态改走refreshStatusQuietly()(网关抖动不再把「登录成功」变成工具报错);请求体超过 64 KiB 直接回 413(不再destroy()让调用方看不到原因);总 catch 加headersSent守卫;sanitize()深度超限由 fail-open 改 fail-closed,字符串值里的password=/chksum也会被擦;captchaImage换成[omitted:captcha-image]之后才回给模型;/status新增lastFailure(脱敏后的后台失败记录)与routePrefix。client.js:路由前缀不再写死,改为从/status回传的routePrefix学习(改了routePrefix配置面板不会再全 404);请求带 20 秒超时与AbortController(busy 不会永不复位、按钮不会永久变灰);四个动作改用同步在途守卫(双击 / 连按回车不再发两次,也不会「先完成者提前解锁」);schoolEnabled: false时学校区真正禁用。school.js:login()加 per-instance single-flight(保活定时器与用户调用不再互抢pending/session,也不再把失败误置成autoBlocked、污染已经好的会话)。jxzxehall.js:回退集合补上not-json(直连被门户劫持返回 200 + 登录页 HTML 时也会改走 webvpn);分页上限MAX_PAGES = 100(超过报too-many-pages)+ 整链总预算totalBudgetMs(默认 60000,用完报timeout且带budgetExhausted: true);日期加回读校验(2026-02-30不再被new Date静默滚成 3/2,改报bad-date);DoH 的dns.lookup补丁改成惰性安装、可由uninstallWebvpnDnsBridge()精确还原(插件 dispose 时自动调用),不再一激活就永久替换宿主的解析器。srun.js:路由错误改走srunErrorPayload(),不再丢掉SrunError.details。
- ✅ 七套测试全绿:
validate-patch·schema·client·srun·school·jxzxehall·plugin全部exit=0/ ALL OK;其中jxzxehall从 53 条涨到 68 条。从 zip 解压出的副本再跑一遍,同样全绿。 - ✅ 开源前 PII 已清理:真实学号与个人成绩数据已从
README.md/test/school.test.mjs换成占位值,本机绝对路径与仓库外链已去掉;对全仓库(含提交历史)扫描真实学号、本机用户名、绝对路径与 IP,零命中。 - ✅ 宿主半边 v1.3.0 已加载:
cordis_inspect_query的Tool.listTools实测能列出 4 个bit_login_*+ 11 个bit_school_*= 15 个工具(不再是 v1.2.0 那一代)。
实网验证
- ✅ 面板:用户在「设置 → BIT 校园服务」实测正常显示(校园网与学校系统两块),2026-10-09 又用真实账号在面板里完成了一次登录,状态卡片与按钮态(登录中… → 已认证在线)都正常。v1.3.0 对面板的改动(前缀学习、在途守卫、请求超时)另由
test/client.test.mjs的假__ModuleLoader__冒烟覆盖。 - ✅ 校园网实网复核(2026-10-09,校园网内):
bit_login_diagnose5/5 全过 —— 网关http://10.0.0.55返回 HTTP 200 且识别到 srun 门户特征;ac_id动态探测出ac_id=1(来源srun_portal_pc);在线状态读到当前账号与本机校内 IP;get_challenge签发成功(有效期 180s);访问http://www.bit.edu.cn/未发现门户劫持。bit_login_status({ fresh: true })返回在线 / 已用 3.36 GiB / 在线 22 小时 3 分钟 / 余额 10.00 元 / 剩余流量 296.22 GiB。 - ✅ 学校系统实网全量跑通(2026-10-04):用户在面板里登录成功后,
bit_school_scores取到多学期全部成绩记录(含学分与加权均分),bit_school_schedule取到 2026-2027-1 学期 22 行 / 5 门课。这次登录一次就authenticated,没有触发验证码(实网探针里假账号回的是captcha=no、risk=ustc-token,说明图形验证码是条件触发、设备风控由网关自己完成)。v1.3.0 对学校侧只做了加固(single-flight、错误码透传、脱敏),对外契约未变、由 7 套测试覆盖;本轮没有再次登录实网复测(进程重启后会话已清空,bit_school_status现在返回「未登录」)。 - ✅ 空闲教室 / 考试安排实网跑通(2026-10-04,教学中心双通道):根因是 BIT-Login 网关部署在校外(
service.py: initialize_network()判webvpn_mode=True、patch_webvpn()换 session),所以POST /api/jxzxehall/cookies返回的是 webvpn 会话 cookie,直连jxzxehallapp.bit.edu.cn必然 401(校内实测:kxjas 首页 200,dqxnxqcx.do/cxjsqk.do无会话 401;网关也没有 classroom / exam 路由,只能自连)。改成「401 / 网络层失败 / 非 JSON 自动回退 webvpn」后又撞上「webvpn.bit.edu.cn在校园解析器里没有记录」(但公网可达 183.243.192.32、校内 TCP 443 通、curl --resolve得 302),于是加了 DoH 兜底 + 只拦这一个域名的dns.lookup补丁。重启 DSH 后实网验证通过:bit_school_classroom(理教)返回 58 间教室 × 13 节的占用明细(带排课 / 借用占用原因),bit_school_exam(2025-2026-1)返回 4 条考试(时间、地点、座位号、教师);2026-2027-1 暂无考试数据。webvpn 会话不绑 IP,跨机器也能复用网关的 cookie。 - ✅ 学校系统链路端到端(本地假网关):真
schoolAuth状态机 + 真路由 + 真工具跑通了「密码错误 →failed」「要短信验证码 →need_sms」「提交验证码 →ready」「成绩 / 课表查询」「登出 →idle」。这一步当场抓出两个真 bug —— 面板读的是schoolState.readyServices(status()实际返回services,会让「已授权」一行永不渲染),以及路由层把网关的 4xx 错误统一吞成 502(现按网关状态码透传)——均已修复并加了回归断言。 - ✅ BIT101 网关的结构契约已实网核对(
test/live-gateway.mjs,假账号、未用任何真实凭据):GET /返回{"message":"BIT Login Services API is running"};POST /api/auth/start用假账号返回 HTTP 200 +{challenge_id, status:"failed", requested_services:["jwb"], ready_services:[], expires_in:299, error:"用户名或密码错误 [status=401, redirects=0, risk=ustc-token, ticket=[redacted], flow=replaced, captcha=no]", access_token}—— 端点路径、请求体形状、快照字段名、expires_in、凭据错误时的错误文案都与本插件的假设一致(access_token/challenge_id已被publicSnapshot剔除);不存在的 challenge 在GET/DELETE /api/auth/{id}上返回 404、业务端点/api/jwb/all_score与/api/jxzxehall/courses返回 409,错误体都是{"detail":"unknown or expired authentication challenge"},路由层已按网关状态码透传。 - ⛔ 外部 HTTP 访问会被 DSH 拦掉(2026-10-09 复核):
curl或普通浏览器标签访问http://127.0.0.1:43120/、/dsh-bit-login/status、/dsh-bit-login/diagnose全部返回403 Forbidden——这是 DSH web server 自身的访问控制,不是本插件的问题;面板在 DSH GUI 内部调用这些路由是正常的。不要指望从外部脚本调这套 API。 - ✅ 校园网登录已用真实账号实测(2026-10-09):用户在面板里用真实账号点了「登录」,网关接受了请求并返回成功,面板随即刷新为「已认证在线」。需要说明的是,这次是在本机已经在线的情况下做的重登(网关报的在线时长没有归零,一直是 22 小时那一档),所以它证明的是「
get_challenge→n=200/enc=srun_bx1/chksum的拼法被网关接受、不再被判定为认证失败」,而不是「从零建立会话」的完整冷启动链路;协议常量本身仍来自对BITNP/bitsrun的逐行核对。 - ⚠️ 校园网登出仍未用真实账号实测:
bit_login_logout(工具与面板「登出」按钮)没有用真实账号调用过。点它会立刻断掉本机当前的在线会话、必须紧接着重新登录,所以一直没做;它的实现(/cgi-bin/rad_user_dm+sign拼法)只经过 mock 单测与协议源码交叉核对。 - ℹ️ 「没登录也显示在线」是正常的,不是面板读错了状态:校园网会话是按本机 IP 记在网关上的,插件调
/status只是拿本机 IP 去问网关「这个 IP 现在算不算在线」,所以只要本机此前已经认证过(别的客户端、系统门户、上一次会话……),面板一打开就会显示「已认证在线」,不需要先在面板里登录。面板的登录表单只用于「本机当前没有会话」时建立会话;反过来说,在校园网里看到已在线时再点一次登录是无害的(网关会接受这次重登)。 - ⚠️ 验证码路径仍未被真实触发:真实登录这次没要验证码,所以
bit_school_verify(短信)与面板的验证码输入框只做过 mock 网关单测;另外线上部署是 BIT-Login-Python 旧版,图形验证码提交路由 404,插件会把它翻译成「改用短信验证码或去教务页面登录」(captcha-unavailable)。 - ⚠️ 配色未经截图核对:只用两个已证实的
--dsw-alias-*令牌,未逐色比对设计稿。
No comments yet. Be the first to write one.