移除登录失败限流;修复连接信息被 e2e 串味为 127.0.0.1

- bootstrap.php/login.php:整体移除「5 次失败锁 10 分钟」限流,登录失败仅即时提示原因
- 新增 tools/fix-config.php:一键双写修正连接地址(默认 exam.nxxy335.top),清空账号密码让用户重输真实卷王凭据
- NY_DATA 隔离落地:run-all.sh 给写配置的 e2e 指向临时目录;修 Windows Git Bash /c/... 路径规范化 bug;.ny-test-data 加 .gitignore
- 清理 dead throttle 引用(e2e 脚本 + docs)
- 修 login.php 真实 bug:ny_is_auth() 分支在加载 $cfg 前引用导致 Undefined variable 警告
- 全量测试 116 通过(PHP 44 + e2e 72)
This commit is contained in:
2026-09-11 17:25:22 +08:00
parent 25a2e8a42c
commit 804b04de60
11 changed files with 151 additions and 113 deletions
+14 -12
View File
@@ -16,9 +16,20 @@ const PHP = process.env.PHP_BIN || 'C:/Users/Zhang/.workbuddy/binaries/php/php.e
const INI = process.env.PHP_INI || '-d extension_dir=C:/Users/Zhang/.workbuddy/binaries/php/ext -d extension=pdo_sqlite';
const DEBUG = !!process.env.NY_DEBUG;
const DATA = path.join(ROOT, 'data');
// 数据目录优先读 NY_DATA 环境变量(与 bootstrap.php 一致),让测试整体指向临时目录,
// 不污染生产库(曾因写 mock 配置把生产 base_url 改成 127.0.0.1)。
// Git Bash 风格 /c/Users/... 在 Windows 上 path.resolve 会误判成 C:\c\...,需还原;并把规范化后的
// Windows 绝对路径写回 process.env.NY_DATA,让子进程(PHP 内置服务器)也拿到正确路径。
function resolveDataDir() {
let p = process.env.NY_DATA || path.join(ROOT, 'data');
if (process.platform === 'win32' && /^\/[a-zA-Z]\//.test(p)) p = p[1].toUpperCase() + ':' + p.slice(2);
p = path.resolve(p);
process.env.NY_DATA = p;
return p;
}
const DATA = resolveDataDir();
fs.mkdirSync(DATA, { recursive: true });
const UPLOADS = path.join(DATA, 'uploads');
const throttleFile = path.join(DATA, 'login_fail.json');
// ---------- 备份 / 还原运行时数据 ----------
// ny.db 必须移走:配置是 DB 优先,留着库里的真实配置会盖掉本测试写入的 config.json。
@@ -41,13 +52,6 @@ for (const f of ['config.json', 'roster.json', 'project_config.json']) {
catch (e) { console.error(' 备份失败(复制)' + f + ':' + e.message); }
}
}
// 清空登录限流记录:用覆盖写而不是删除(部分环境下删除会被安全策略拦掉)
function clearThrottle() {
try { fs.writeFileSync(throttleFile, '{}'); } catch (e) {}
try { if (fs.existsSync(throttleFile)) fs.unlinkSync(throttleFile); } catch (e) {}
}
clearThrottle();
const cfgFile = path.join(DATA, 'config.json');
fs.writeFileSync(cfgFile, JSON.stringify({
base_url: 'http://127.0.0.1:' + MOCK_PORT,
@@ -81,7 +85,6 @@ function cleanup() {
const p = path.join(DATA, f);
try { if (fs.existsSync(p)) fs.unlinkSync(p); } catch (e) {}
}
clearThrottle();
// 统一用「覆盖写回 + 尽力删除备份」的方式还原,避免删除被拦导致还原失败
for (const [p, bak] of moved.concat(copied)) {
try { if (fs.existsSync(bak)) fs.copyFileSync(bak, p); } catch (e) {}
@@ -199,9 +202,8 @@ function chk(name, cond, extra) {
process.exit(1);
}
// 登录(失败会触发 5 次锁定,所以每次尝试前清掉限流记录)
// 登录(最多重试 3 次)
for (let i = 0; i < 3 && CSRF === ''; i++) {
clearThrottle(); // 上一次尝试若失败会累计限流,这里先清零
const lg = await formPost('/login.php', { username: 'mock', password: 'surveyking' });
const ac = await get('/api.php?action=auth_check');
if (DEBUG) {