Files
competition-website/scripts/_db.cjs

62 lines
2.6 KiB
JavaScript
Raw Normal View History

'use strict';
/**
* 后端运维脚本共用:数据库连接配置解析(**唯一入口**)
* ============================================================
*
* 为什么单独成文件
* ------------------------------------------------------------
* 任何"需要连库"的运维脚本(弱口令扫描 / 口令策略接口验证 / 后续新增)都必须
* 用同一套优先级与同一条凭据纪律。各自实现必然漂移 —— 例如某处"缺口令时兜底成
* 空串"就能静默连上无口令的库,而另一处明确失败,两者行为不一致却都"看起来正常"。
*
* 读取优先级(与 scripts/_creds.py 完全同源)
* ------------------------------------------------------------
* 1. 环境变量 DB_HOST / DB_PORT / DB_USER / DB_PASSWORD / DB_NAME(CI / 服务器注入优先)
* 2. 仓库根 `scripts/.creds.local.json`(本机开发,已被 .gitignore 排除)
* 3. 明确失败 —— ⛔ **刻意不提供明文兜底**:口令为空时直接抛错,
* 绝不静默尝试空口令连库(那会掩盖"凭据没注入"这一真实故障)。
*
* ⚠️ Python 侧对应实现见 `scripts/_creds.py`,两侧口径必须一致;
* 如需增删键,**两边同时改**。
*
* @returns {{host: string, port: number, user: string, password: string, database: string}}
*/
const fs = require('fs');
const path = require('path');
function loadDbConfig() {
const env = process.env;
let local = {};
// backend/scripts/ → 仓库根/scripts/.creds.local.json
const localFile = path.join(__dirname, '..', '..', 'scripts', '.creds.local.json');
try {
local = JSON.parse(fs.readFileSync(localFile, 'utf8'));
} catch (e) {
// 文件不存在是允许的(走环境变量);但**损坏**必须报错,不静默降级
if (e.code !== 'ENOENT') {
throw new Error(`凭据文件解析失败 ${localFile}: ${e.message}`);
}
}
const cfg = {
host: env.DB_HOST || local.db_host || '127.0.0.1',
port: parseInt(env.DB_PORT || local.db_port || 3306, 10),
user: env.DB_USER || local.db_user || 'root',
password: env.DB_PASSWORD || local.db_password || '',
database: env.DB_NAME || local.db_name || 'competition_db',
};
if (!cfg.password) {
throw new Error(
'未取到数据库口令。请任选其一:\n' +
' ① 设置环境变量 DB_PASSWORD\n' +
' ② 创建 scripts/.creds.local.json(形如 {"db_password":"..."})\n' +
'⛔ 本模块刻意不提供明文兜底:缺凭据时明确失败,不静默连库。'
);
}
return cfg;
}
module.exports = { loadDbConfig };