import assert from 'node:assert/strict'; import { test } from 'node:test'; import { getServerConfig } from '../src/config/server-config'; const env = { JWT_SECRET: 'test-configuration-secret-12345678901234567890', DATABASE_URL: 'postgresql://test:test@127.0.0.1:1/doodle_test?schema=public', WECHAT_MINI_APP_ID: 'wx0123456789abcdef', WECHAT_MINI_APP_SECRET: 'test-only-wechat-secret', }; test('启动配置必须提供有效 JWT 密钥,不使用共享默认密钥', () => { for (const secret of [ undefined, '', 'short', 'change-me-123456789012345678901234567890', ]) { assert.throws( () => getServerConfig( secret === undefined ? {} : { JWT_SECRET: secret }, ), /JWT_SECRET/, ); } }); test('Swagger 开发默认开启,生产默认关闭,支持显式开关', () => { assert.equal(getServerConfig(env).swaggerEnabled, true); assert.equal( getServerConfig({ ...env, NODE_ENV: 'production' }).swaggerEnabled, false, ); assert.equal( getServerConfig({ ...env, SWAGGER_ENABLED: 'false' }).swaggerEnabled, false, ); }); test('真实登录接入后微信配置必须完整,缺省或留空都拒绝启动', () => { for (const entry of [ { WECHAT_MINI_APP_ID: undefined, WECHAT_MINI_APP_SECRET: undefined }, { WECHAT_MINI_APP_ID: '', WECHAT_MINI_APP_SECRET: '' }, { WECHAT_MINI_APP_ID: ' ', WECHAT_MINI_APP_SECRET: '\t' }, ]) { assert.throws( () => getServerConfig({ ...env, ...entry }), /WECHAT_MINI_APP/, ); } }); test('成对读取微信配置并去除首尾空白', () => { const config = getServerConfig({ ...env, WECHAT_MINI_APP_ID: ' wx0123456789abcdef ', WECHAT_MINI_APP_SECRET: ' test-only-wechat-secret ', }); assert.equal(config.wechatMiniAppId, 'wx0123456789abcdef'); assert.equal(config.wechatMiniAppSecret, 'test-only-wechat-secret'); }); test('拒绝不完整或含内部空白的微信配置,错误不回显配置值', () => { for (const entry of [ { WECHAT_MINI_APP_ID: 'wx0123456789abcdef', WECHAT_MINI_APP_SECRET: undefined, }, { WECHAT_MINI_APP_ID: undefined, WECHAT_MINI_APP_SECRET: 'test-only-wechat-secret', }, { WECHAT_MINI_APP_ID: 'wx0123456789abcdef', WECHAT_MINI_APP_SECRET: ' ', }, { WECHAT_MINI_APP_ID: 'wx0123 456789abcdef', WECHAT_MINI_APP_SECRET: 'test-only-wechat-secret', }, { WECHAT_MINI_APP_ID: 'wx0123456789abcdef', WECHAT_MINI_APP_SECRET: 'test-only\nwechat-secret', }, ]) { assert.throws( () => getServerConfig({ ...env, ...entry }), (error: unknown) => { assert.ok(error instanceof Error); assert.match(error.message, /WECHAT_MINI_APP/); for (const value of Object.values(entry)) { if (value?.trim()) assert.ok(!error.message.includes(value)); } return true; }, ); } }); test('数据库连接必须为 PostgreSQL public schema,校验不回显含密码的 URL', () => { for (const databaseUrl of [ '', 'mysql://user:private-password@localhost/db', 'postgresql:///db', 'postgresql://localhost', 'postgresql://localhost/db?schema=other', ]) assert.throws( () => getServerConfig({ ...env, DATABASE_URL: databaseUrl }), /DATABASE_URL/, ); assert.equal(getServerConfig(env).databaseUrl, env.DATABASE_URL); }); test('拒绝非法 body、JWT 有效期、日志级别、布尔开关和跨域配置', () => { for (const entry of [ { API_BODY_LIMIT_BYTES: '0' }, { API_BODY_LIMIT_BYTES: '1e6' }, { JWT_EXPIRES_IN_SECONDS: '0' }, { SWAGGER_ENABLED: 'yes' }, { LOG_LEVEL: 'all' }, { NODE_ENV: 'staging' }, { JWT_ISSUER: ' ' }, { CORS_ORIGINS: '*' }, { CORS_ORIGINS: 'https://example.com/path' }, { TRUSTED_PROXY_CIDRS: 'true' }, ]) assert.throws(() => getServerConfig({ ...env, ...entry })); assert.deepEqual( getServerConfig({ ...env, CORS_ORIGINS: 'https://example.com,http://localhost:3001', }).corsOrigins, ['https://example.com', 'http://localhost:3001'], ); }); test('题型新品窗口与公共资源域名校验,缺省域名不构造七牛地址', () => { assert.equal(getServerConfig(env).worksheetNewWindowDays, 30); assert.equal(getServerConfig(env).qiniuPublicDomain, null); assert.equal( getServerConfig({ ...env, QINIU_PUBLIC_DOMAIN: 'https://assets.example.test/', }).qiniuPublicDomain, 'https://assets.example.test', ); for (const value of ['0', '366', '1e2', '']) assert.throws(() => getServerConfig({ ...env, WORKSHEET_NEW_WINDOW_DAYS: value }), ); for (const value of [ 'http://assets.example.test', 'https://user:secret@example.test', 'https://example.test/path', 'https://example.test?sign=private', 'https://example.test#hash', ]) assert.throws( () => getServerConfig({ ...env, QINIU_PUBLIC_DOMAIN: value }), /QINIU_PUBLIC_DOMAIN/, ); }); test('七牛空间与路径前缀校验,允许空前缀且不回显非法配置', () => { const config = getServerConfig({ ...env, QINIU_KEY_PREFIX: 'doodle-assets///', QINIU_BUCKET: 'doodle-cn', }); assert.equal(config.qiniuKeyPrefix, 'doodle-assets/'); assert.equal(config.qiniuBucket, 'doodle-cn'); assert.equal( getServerConfig({ ...env, QINIU_KEY_PREFIX: '' }).qiniuKeyPrefix, '', ); for (const value of [ '/absolute', '/', '../escape', 'a/../b', 'a//b', 'a\\b', 'a\n', ]) assert.throws( () => getServerConfig({ ...env, QINIU_KEY_PREFIX: value }), /QINIU_KEY_PREFIX/, ); assert.throws( () => getServerConfig({ ...env, QINIU_BUCKET: 'bad/bucket' }), /QINIU_BUCKET/, ); }); test('七牛上传凭据成对校验且不泄漏值,刷新小时限制为 UTC 0~23', () => { assert.equal(getServerConfig(env).qiniuAk, ''); for (const fields of [ { QINIU_AK: 'private-ak' }, { QINIU_SK: 'private-sk' }, { QINIU_AK: 'a b', QINIU_SK: 'private-sk' }, { QINIU_REGION: '../escape' }, { SITE_REFRESH_HOUR_UTC: '24' }, ]) assert.throws( () => getServerConfig({ ...env, ...fields }), (error: unknown) => error instanceof Error && !error.message.includes('private-'), ); assert.equal( getServerConfig({ ...env, SITE_REFRESH_HOUR_UTC: '8' }) .siteRefreshHourUtc, 8, ); });