Files
LoveChengke 3880eee08e feat(desktop,island,shared): 灵动岛支持多条通知竖排列表 + 触摸模式 + 收回动画,产物加凭据门禁
灵动岛列表:多条通知时展开为竖排列表,默认显示 3 条,点「展开更多」铺到屏幕容纳
上限,放不下的收进「更多请前往应用内操作」。卡片高度由主进程与渲染进程各算一次
同一个数 —— 度量表 ISLAND_LIST_METRICS 与排序权重 PRIORITY_RANK 放在 shared,
窗口包围盒随之长高(不够高会把底部按钮裁掉)。

触摸模式:触摸屏上手指既不产生 mousemove、也不移动系统光标,原先两条命中链路都会
让窗口永远停在穿透态、手指点不开岛。现按 navigator.maxTouchPoints 上报后,主进程把
窗口贴合岛体并始终接收输入;非触摸屏机器完全不走这条路。

收回动画:main 先发 island:closing,渲染进程形变收敛后回 closing-done 才淡出,
不再靠猜时长(rAF 被节流时会把卡片缩到一半窗口就没了)。

安全门禁:新增 scripts/check-bundle-secrets.mjs 并接进 build:desktop ——
dist 产物会被打进 app.asar 发到每台学生机、且可解包,冒烟凭据一律改由环境变量注入,
产物里出现种子口令即构建失败。
2026-10-02 00:25:10 +08:00

76 lines
3.0 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* 构建产物凭据自检:`dist` 里不允许出现种子账号 / 口令字面量。
*
* 为什么单独立一条门禁:`dist/main/index.js` 与 `dist/renderer/assets/*.js` 会被 electron-builder
* 打进 `app.asar`,随安装包发到每台学生机,而 **asar 可以直接解包**。
* 冒烟/自检代码里写死 `teacher1 / teacher123` 这类字面量,等于把教师账号随安装包一起发出去
* (历史上真的发生过:`grep teacher123 dist/main/index.js` 命中 3 次)。
*
* 凭据一律由 `scripts/smoke.mjs` / `scripts/verify-packaged.mjs` 通过环境变量提供
* (`ELECTRON_SMOKE_USER` / `ELECTRON_SMOKE_PASSWORD` / `ELECTRON_SMOKE_CLASS_CODE` / `..._CLASS_PASSWORD`),
* 那两个脚本不进安装包。
*
* 命中即构建失败(exit 1)。
*/
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const distDir = path.join(root, 'dist');
/** 明确的种子口令:任何情况下都不该出现在产物里 */
const FORBIDDEN_STRINGS = ['teacher123', 'admin123', 'student123'];
/** 组合形态:把种子班级码 / 默认班级密码当凭据使用的写法 */
const FORBIDDEN_PATTERNS = [
{ label: '种子班级码当凭据', pattern: /["'](?:code|classCode)["']\s*[:=]\s*["']G(?:101|102|203)["']/ },
{
label: '默认班级密码当凭据',
pattern: /["'](?:password|classPassword)["']\s*[:=]\s*["']123456["']/,
},
];
/** 递归收集文件(跳过 sourcemap 与二进制) */
function collectFiles(dir) {
const found = [];
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) {
found.push(...collectFiles(full));
} else if (/\.(?:js|mjs|cjs|html|json|css)$/i.test(entry.name)) {
found.push(full);
}
}
return found;
}
if (!fs.existsSync(distDir)) {
console.log('[check-secrets] 未找到 dist(尚未构建),跳过凭据自检');
process.exit(0);
}
const hits = [];
for (const file of collectFiles(distDir)) {
const content = fs.readFileSync(file, 'utf8');
const relative = path.relative(root, file);
for (const needle of FORBIDDEN_STRINGS) {
if (content.includes(needle)) hits.push(`${relative}:出现种子口令「${needle}」`);
}
for (const { label, pattern } of FORBIDDEN_PATTERNS) {
if (pattern.test(content)) hits.push(`${relative}:${label}`);
}
}
if (hits.length > 0) {
console.error('[check-secrets] 构建产物里出现了种子凭据(asar 可被解包,不能随包分发):');
for (const hit of hits) console.error(` - ${hit}`);
console.error(
'\n请把凭据改为从环境变量读取(见 scripts/smoke.mjs 的 ELECTRON_SMOKE_USER 等),不要写进源码。',
);
process.exit(1);
}
console.log(`[check-secrets] 通过:${collectFiles(distDir).length} 个产物文件里没有任何种子凭据字面量`);