Files
Toolbox/public/tools/token_lab/index.html
T
yangxiangyuan a3e8911deb feat: 新增作息报时器功能并替换短链接前缀为/to/
- 新增作息报时器独立模块,包含完整的日程管理、语音播报和待机功能
- 短链接正式前缀由/l/改为/to/,解决手机小屏下与I、i、1字形混淆问题
- 保留旧前缀/l/、/L/、/I/、/i/兼容已分发的旧短链
- 新增短码大小写兜底匹配,仅唯一匹配时生效避免歧义
- 新增防爆紧急替换功能,可轮换首页鉴权并替换短链接
- 新增多个调试和集成测试脚本,保障数据安全和功能回归
2026-10-09 14:05:36 +08:00

233 lines
11 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
<meta name="theme-color" content="#0b1020">
<title>令牌工坊</title>
<link rel="stylesheet" href="/tools/token_lab/token_lab.css">
</head>
<body>
<section id="authScreen" class="auth-screen">
<div class="auth-card">
<input id="authUsername" class="input" type="text" autocomplete="off" autocapitalize="none" spellcheck="false" placeholder="账号">
<input id="authPassword" class="input" type="password" autocomplete="off" placeholder="密码">
<button id="btnAuthLogin" class="btn btn-primary auth-submit">登录</button>
<div id="authHint" class="auth-hint"></div>
</div>
</section>
<div id="workshopShell" class="page-shell" hidden>
<header class="hero">
<div>
<div class="eyebrow">Token Lab</div>
<h1>令牌工坊</h1>
<p>首页导航令牌与 Tool 令牌的生成、验证、信息回看,都放在这里统一处理。</p>
</div>
<div class="hero-side">
<div id="globalNotice" class="notice" hidden></div>
<button id="btnAuthLogout" class="btn" hidden>退出工坊登录</button>
</div>
</header>
<nav id="toolTabs" class="tab-nav" hidden>
<button class="tab-btn" data-tab="emergency">首页导航防爆紧急替换</button>
<button class="tab-btn active" data-tab="nav">首页导航生成器</button>
<button class="tab-btn" data-tab="tool">Tool 令牌生成器</button>
</nav>
<main id="appMain" hidden>
<section class="tab-panel" data-panel="emergency">
<div class="layout-grid">
<section class="card">
<div class="card-head">
<h2>首页导航防爆紧急替换</h2>
</div>
<p class="card-desc">
怀疑首页 token 或短链接被窥屏、被泄露,或有危险预感时,按顺序点下面两个按钮即可完成更换。
旧 token 与旧短链接都会<strong>立即失效</strong>,无需手工改文件、改数据库。
</p>
<div class="actions wrap">
<button id="btnEmergencyRotate" class="btn btn-primary">自动生成向后 X 个月的鉴权,且当前鉴权立即失效</button>
<select id="emergencyMonths" class="input emergency-months" title="有效期(月)"></select>
<button id="btnEmergencyRelink" class="btn btn-primary">将新的首页鉴权token,自动生成新的短链接,且当前短链接立即失效</button>
</div>
<label class="field">
<span>执行过程</span>
<textarea id="emergencyLog" class="textarea mono emergency-log" rows="14" readonly wrap="off" placeholder="点击上方按钮后,这里会滚动显示每一步的执行过程…"></textarea>
</label>
<label class="field">
<span>最终 token(第 1 步产出)</span>
<textarea id="emergencyTokenOut" class="textarea mono" rows="4" readonly wrap="off" placeholder="第 1 步完成后,新的首页鉴权 token 会显示在这里"></textarea>
</label>
<div class="actions">
<button id="btnEmergencyCopyToken" class="btn">复制 token</button>
</div>
<label class="field">
<span>最终短链接(第 2 步产出)</span>
<textarea id="emergencyShortUrlOut" class="textarea mono" rows="2" readonly wrap="off" placeholder="第 2 步完成后,新的短链接会显示在这里"></textarea>
</label>
<div class="actions">
<button id="btnEmergencyCopyShortUrl" class="btn">复制短链接</button>
</div>
<div id="emergencyMeta" class="result-grid"></div>
<details class="raw-details">
<summary>说明与回滚</summary>
<div class="card-desc">
第 1 步:轮换导航密钥对(`config/nav-private.jwk.json` 与 `config/nav.jwk.json`),
并用新私钥签发一枚有效期 30 天的首页 token。旧 token 会因旧公钥离开信任池而立即失效。<br>
第 2 步:把新 token 绑到一条全新的短链接上,同时把旧的首页短链置为停用,旧短链立即失效。<br>
两步执行前都会自动备份(密钥文件 + 短链库)到 `config/_nav-key-backup-时间戳/`,需要回滚时把备份覆盖回原位即可。<br>
原有的手工做法(首页导航生成器 / Tool 令牌生成器 / 物理替换文件)全部保留有效,本页签只是快捷通道。
</div>
</details>
</section>
</div>
</section>
<section class="tab-panel active" data-panel="nav">
<div class="layout-grid">
<section class="card">
<div class="card-head">
<h2>生成首页导航令牌</h2>
</div>
<p class="card-desc">服务端使用当前导航私钥签发首页长链接,适合你自己的首页入口轮换。</p>
<div class="form-grid">
<label class="field">
<span>基础地址</span>
<input id="navBaseUrl" class="input" type="text" placeholder="https://traesite.umersoft.com:8975/">
</label>
<label class="field">
<span>过期时间</span>
<input id="navExpiry" class="input" type="datetime-local">
</label>
</div>
<div class="actions">
<button id="btnNavGenerate" class="btn btn-primary">生成首页令牌</button>
<button id="btnNavCopy" class="btn">复制链接</button>
</div>
<label class="field">
<span>生成结果</span>
<textarea id="navLinkOutput" class="textarea mono" rows="5" readonly wrap="off"></textarea>
</label>
<div id="navGenerateMeta" class="result-grid"></div>
</section>
<section class="card">
<div class="card-head">
<h2>验证首页导航令牌</h2>
</div>
<p class="card-desc">可以粘贴完整链接或纯 token,快速看签名、过期时间、剩余时长和载荷字段。</p>
<label class="field">
<span>待验证内容</span>
<textarea id="navVerifyInput" class="textarea mono" rows="6" placeholder="粘贴 https://.../?token=... 或直接粘贴 token" wrap="off"></textarea>
</label>
<div class="actions">
<button id="btnNavVerify" class="btn btn-primary">验证首页令牌</button>
</div>
<div id="navVerifyMeta" class="result-grid"></div>
<details class="raw-details">
<summary>详细输出</summary>
<pre id="navVerifyRaw" class="result-box"></pre>
</details>
</section>
</div>
</section>
<section class="tab-panel" data-panel="tool">
<div class="layout-grid">
<section class="card">
<div class="card-head">
<h2>生成 Tool 令牌</h2>
</div>
<p class="card-desc">这部分沿用原 WinForm 的思路:浏览器本地持有 RSA 私钥,本地完成签名,不把 tool 私钥交给服务器。</p>
<div class="form-grid">
<label class="field">
<span>站点预设</span>
<select id="toolPresetSelect" class="input"></select>
</label>
<label class="field">
<span>预设名称</span>
<input id="toolPresetName" class="input" type="text" placeholder="expense">
</label>
<label class="field field-span-2">
<span>基础地址</span>
<input id="toolBaseUrl" class="input" type="text" placeholder="https://traesite.umersoft.com:8975/tools/expense">
</label>
<label class="field">
<span>设备别名</span>
<input id="toolAlias" class="input" type="text" placeholder="nav-private">
</label>
<label class="field">
<span>过期时间</span>
<input id="toolExpiry" class="input" type="datetime-local">
</label>
<label class="field field-span-2">
<span>自定义密码</span>
<input id="toolPassword" class="input" type="password" placeholder="可留空">
</label>
</div>
<div class="actions wrap">
<button id="btnToolGenerateKey" class="btn">生成 RSA 密钥</button>
<button id="btnToolImportXml" class="btn">导入私钥 XML</button>
<button id="btnToolExportXml" class="btn">导出私钥 XML</button>
<button id="btnToolCopyJwk" class="btn">复制公钥 JWK</button>
<button id="btnToolNewPreset" class="btn">新建预设</button>
<button id="btnToolSavePreset" class="btn">保存当前预设</button>
<button id="btnToolDeletePreset" class="btn">删除当前预设</button>
</div>
<input id="toolXmlFile" type="file" accept=".xml,text/xml" hidden>
<div id="toolKeyMeta" class="result-grid"></div>
<label class="field">
<span>公钥 JWK</span>
<textarea id="toolPublicJwk" class="textarea mono" rows="5" readonly wrap="off"></textarea>
</label>
<div class="actions">
<button id="btnToolGenerateToken" class="btn btn-primary">生成 Tool 令牌</button>
<button id="btnToolCopyLink" class="btn">复制链接</button>
</div>
<label class="field">
<span>生成结果</span>
<textarea id="toolLinkOutput" class="textarea mono" rows="5" readonly wrap="off"></textarea>
</label>
<div id="toolGenerateMeta" class="result-grid"></div>
</section>
<section class="card">
<div class="card-head">
<h2>验证 Tool 令牌</h2>
</div>
<p class="card-desc">粘贴旧链接或旧 token,马上就能看出 alias、到期时间、剩余时长,以及当前密钥是否验得过。</p>
<label class="field">
<span>待验证内容</span>
<textarea id="toolVerifyInput" class="textarea mono" rows="6" placeholder="粘贴 https://.../?token=... 或直接粘贴 token" wrap="off"></textarea>
</label>
<div class="actions">
<button id="btnToolVerify" class="btn btn-primary">验证 Tool 令牌</button>
</div>
<div id="toolVerifyMeta" class="result-grid"></div>
<details class="raw-details">
<summary>详细输出</summary>
<pre id="toolVerifyRaw" class="result-box"></pre>
</details>
</section>
</div>
</section>
</main>
</div>
<script src="/tools/token_lab/token_lab.js"></script>
</body>
</html>