文件
kdbx-viewer/config.js
T
wangchuanli 02e83f5b73 feat: 初始化 kdbx-viewer 项目
实现服务端解密的 KeePass 网页查看器,包含登录门户口令与验证码、RSA+会话级 AES 加密通道、审计日志持久化、HTTPS 自动证书、Docker 部署配置及端到端测试。
2026-08-26 10:42:48 +08:00

92 行
3.9 KiB
JavaScript
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
'use strict';
const process = require('process');
const path = require('path');
// ===== 环境变量优先的取数助手 =====
// 配置写在 config.js,敏感值(口令固定串、SESSION_SECRET)可用同名环境变量覆盖,
// 便于 Docker 注入密钥,避免把密钥明文写进仓库。
const env = process.env;
const pick = (key, fallback) =>
(env[key] !== undefined && env[key] !== '') ? env[key] : fallback;
// 解析带单位的体积(如 5M / 1024K / 5242880),返回字节数;非法时回退到 fallbackBytes
function parseSize(val, fallbackBytes = 5 * 1024 * 1024) {
if (typeof val === 'number') return val > 0 ? val : fallbackBytes;
const s = String(val).trim().toLowerCase();
const m = s.match(/^(\d+(?:\.\d+)?)\s*([kmg]?b?)$/);
if (!m) return fallbackBytes;
const n = parseFloat(m[1]);
const unit = m[2];
const mult = unit.startsWith('k') ? 1024
: unit.startsWith('m') ? 1024 * 1024
: unit.startsWith('g') ? 1024 * 1024 * 1024
: 1;
return Math.floor(n * mult);
}
// 日期格式化(默认 yyyymmdd)
function formatDate(d, fmt) {
const y = String(d.getFullYear());
const m = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
return fmt.replace(/yyyy/g, y).replace(/mm/g, m).replace(/dd/g, day);
}
const config = {
// 1) APP 门户口令:dynamic = 当天日期 + 固定串;static = 固定口令
// 敏感值必须来自环境变量(.env / docker environment),不要在文件里写死真实值
appPassword: {
mode: pick('APP_PW_MODE', 'dynamic'), // 'dynamic' | 'static'
dateFormat: pick('APP_PW_DATE_FMT', 'yyyymmdd'),
datePosition: pick('APP_PW_DATE_POS', 'prefix'), // 'prefix' | 'suffix'
dynamicSecret: pick('APP_PW_DYNAMIC', ''),
staticPassword: pick('APP_PW_STATIC', ''),
},
// 2) 密码库 / 密钥文件路径(容器内路径,由 docker-compose 挂载)
kdbxPath: pick('KDBX_PATH', '/app/vault/vault.kdbx'),
keyfilePath: pick('KEYFILE_PATH', '/app/vault/vault.key'),
// 3) 权限:默认只读;true 时开放网页端编辑并写回 kdbx
// 注意:WRITABLE=true 时必须把 docker-compose 里 vault 挂载从 :ro 改为 :rw
writable: pick('WRITABLE', 'false') === 'true',
// 4) 会话与安全
sessionSecret: pick('SESSION_SECRET', ''),
sessionMaxAge: parseInt(pick('SESSION_MAX_AGE', String(30 * 60 * 1000)), 10),
// 审计日志:本地文件持久化目录(可按大小自动切分),默认 ./logs
logDir: pick('LOG_DIR', path.join(__dirname, 'logs')),
// 审计日志单文件切分阈值(字节),默认 5MB;支持 K/M 单位
auditFileMax: parseSize(pick('AUDIT_FILE_MAX', '5M')),
// 审计日志切分文件最多保留份数(audit.1.log ~ audit.N.log),默认 10
auditFileKeep: parseInt(pick('AUDIT_FILE_KEEP', '10'), 10),
port: parseInt(pick('PORT', '3000'), 10),
// 缺失敏感值的友好提示(仅提醒,不阻断启动)
_warnMissing: [],
};
if (!config.appPassword.dynamicSecret && !config.appPassword.staticPassword)
config._warnMissing.push('APP_PW_DYNAMIC / APP_PW_STATIC 均未设置,登录将失败');
// 今日期望的 APP 口令(服务端动态计算,前端/用户都看不到拼接逻辑)
config.getExpectedAppPassword = function () {
const ap = this.appPassword;
if (ap.mode === 'static') return ap.staticPassword;
const dateStr = formatDate(new Date(), ap.dateFormat);
return ap.datePosition === 'suffix'
? ap.dynamicSecret + dateStr
: dateStr + ap.dynamicSecret; // 默认:20260825 + 固定串
};
// 启动前检查必要敏感值是否已从环境变量注入
if (!config.sessionSecret) config._warnMissing.push('SESSION_SECRET 未设置');
if (config._warnMissing.length) {
console.warn('[config] 警告:以下敏感值未从环境变量取得,请检查 .env:\n - ' +
config._warnMissing.join('\n - '));
}
module.exports = config;