You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

165 lines
4.4 KiB

import { logger } from "@/logger.js"
/**
* 环境变量验证配置
* required: 必需的环境变量
* optional: 可选的环境变量(提供默认值)
*/
const ENV_CONFIG = {
required: [
"SESSION_SECRET",
"JWT_SECRET"
],
optional: {
"NODE_ENV": "development",
"PORT": "3000",
"LOG_DIR": "logs",
"HTTPS_ENABLE": "off"
}
}
/**
* 验证必需的环境变量
* @returns {Object} 验证结果
*/
function validateRequiredEnv() {
const missing = []
const valid = {}
for (const key of ENV_CONFIG.required) {
const value = process.env[key]
if (!value || value.trim() === '') {
missing.push(key)
} else {
valid[key] = value
}
}
return { missing, valid }
}
/**
* 设置可选环境变量的默认值
* @returns {Object} 设置的默认值
*/
function setOptionalDefaults() {
const defaults = {}
for (const [key, defaultValue] of Object.entries(ENV_CONFIG.optional)) {
if (!process.env[key]) {
process.env[key] = defaultValue
defaults[key] = defaultValue
}
}
return defaults
}
/**
* 验证环境变量的格式和有效性
* @param {Object} env 环境变量对象
* @returns {Array} 错误列表
*/
function validateEnvFormat(env) {
const errors = []
// 验证 PORT 是数字
if (env.PORT && isNaN(parseInt(env.PORT))) {
errors.push("PORT must be a valid number")
}
// 验证 NODE_ENV 的值
const validNodeEnvs = ['development', 'production', 'test']
if (env.NODE_ENV && !validNodeEnvs.includes(env.NODE_ENV)) {
errors.push(`NODE_ENV must be one of: ${validNodeEnvs.join(', ')}`)
}
// 验证 SESSION_SECRET 至少包含一个密钥
if (env.SESSION_SECRET) {
const secrets = env.SESSION_SECRET.split(',').filter(s => s.trim())
if (secrets.length === 0) {
errors.push("SESSION_SECRET must contain at least one non-empty secret")
}
}
// 验证 JWT_SECRET 长度
if (env.JWT_SECRET && env.JWT_SECRET.length < 32) {
errors.push("JWT_SECRET must be at least 32 characters long for security")
}
return errors
}
/**
* 初始化和验证所有环境变量
* @returns {boolean} 验证是否成功
*/
export function validateEnvironment() {
logger.info("🔍 开始验证环境变量...")
// 1. 验证必需的环境变量
const { missing, valid } = validateRequiredEnv()
if (missing.length > 0) {
logger.error("❌ 缺少必需的环境变量:")
missing.forEach(key => {
logger.error(` - ${key}`)
})
logger.error("请设置这些环境变量后重新启动应用")
return false
}
// 2. 设置可选环境变量的默认值
const defaults = setOptionalDefaults()
if (Object.keys(defaults).length > 0) {
logger.info("⚙️ 设置默认环境变量:")
Object.entries(defaults).forEach(([key, value]) => {
logger.info(` - ${key}=${value}`)
})
}
// 3. 验证环境变量格式
const formatErrors = validateEnvFormat(process.env)
if (formatErrors.length > 0) {
logger.error("❌ 环境变量格式错误:")
formatErrors.forEach(error => {
logger.error(` - ${error}`)
})
return false
}
// 4. 记录有效的环境变量(敏感信息脱敏)
logger.info("✅ 环境变量验证成功:")
logger.info(` - NODE_ENV=${process.env.NODE_ENV}`)
logger.info(` - PORT=${process.env.PORT}`)
logger.info(` - LOG_DIR=${process.env.LOG_DIR}`)
logger.info(` - SESSION_SECRET=${maskSecret(process.env.SESSION_SECRET)}`)
logger.info(` - JWT_SECRET=${maskSecret(process.env.JWT_SECRET)}`)
return true
}
/**
* 脱敏显示敏感信息
* @param {string} secret 敏感字符串
* @returns {string} 脱敏后的字符串
*/
export function maskSecret(secret) {
if (!secret) return "未设置"
if (secret.length <= 8) return "*".repeat(secret.length)
return secret.substring(0, 4) + "*".repeat(secret.length - 8) + secret.substring(secret.length - 4)
}
/**
* 获取环境变量配置(用于生成 .env.example)
* @returns {Object} 环境变量配置
*/
export function getEnvConfig() {
return ENV_CONFIG
}
export default {
validateEnvironment,
getEnvConfig,
maskSecret
}