chanjs 2.8.3 → 2.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/core/Repository.js
CHANGED
|
@@ -188,21 +188,26 @@ class Repository extends BaseComponent {
|
|
|
188
188
|
return row;
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
-
/**
|
|
192
|
-
|
|
191
|
+
/**
|
|
192
|
+
* 查询全部。上限口径统一收口到 config.LIMIT_MAX(this.limit):
|
|
193
|
+
* 未传 limit 时默认取 this.limit;显式传入的 limit 也会被钳制到 [1, this.limit],
|
|
194
|
+
* 避免"all 默认 1000 / 分页上限 300"两套口径并存。
|
|
195
|
+
*/
|
|
196
|
+
async all({ query={}, sort={}, fields=[], limit }={}) {
|
|
193
197
|
const err = this._guard({ query });
|
|
194
198
|
if (err) return err;
|
|
195
|
-
const
|
|
199
|
+
const size = Math.min(Math.max(Number(limit) || this.limit, 1), this.limit);
|
|
200
|
+
const list = await this._buildBaseQuery({query,sort,fields}).limit(size);
|
|
196
201
|
return { success:true, code:CODE_OK, msg:"查询成功", data: list };
|
|
197
202
|
}
|
|
198
203
|
|
|
199
|
-
/**
|
|
204
|
+
/** 分页偏移查询(limit 同 all() 口径,钳制到 config.LIMIT_MAX) */
|
|
200
205
|
async find({ query={}, sort={}, fields=[], limit, offset }={}) {
|
|
201
206
|
const err = this._guard({ query });
|
|
202
207
|
if (err) return err;
|
|
203
208
|
let q = this._buildBaseQuery({query,sort,fields});
|
|
204
209
|
typeof offset === 'number' && (q = q.offset(offset));
|
|
205
|
-
typeof limit === 'number' && (q = q.limit(limit));
|
|
210
|
+
typeof limit === 'number' && (q = q.limit(Math.min(Math.max(limit, 1), this.limit)));
|
|
206
211
|
return { success:true, code:CODE_OK, msg:"查询成功", data: await q };
|
|
207
212
|
}
|
|
208
213
|
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
} from "../../middleware/index.js";
|
|
5
5
|
import { health } from "../../middleware/health.js";
|
|
6
6
|
import { BODY_LIMIT } from "../../config/index.js";
|
|
7
|
+
import logger from "../../utils/logger.js";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* 注册核心中间件(顺序固化:不可随意调整)
|
|
@@ -17,6 +18,19 @@ export async function registerCoreMiddleware(chan) {
|
|
|
17
18
|
await waf(app, cfg.waf ?? { enabled: false });
|
|
18
19
|
// 1.5 健康检查端点(默认开启,config.health = {enabled,path} 可调;浅模式零 IO)
|
|
19
20
|
app.use(health(chan, cfg.health ?? {}));
|
|
21
|
+
// 1.6 宿主全局中间件插槽:config.middleware 数组,按声明顺序注册。
|
|
22
|
+
// 元素支持两种形态:express 中间件本身 (req,res,next);或工厂 () => express 中间件(需闭包 chan/config 时用)。
|
|
23
|
+
// 注册位置在核心链早期、模块路由之前,保证对所有响应(含静态资源)生效。
|
|
24
|
+
// 注意:app/router.js(loadCommonRouter)的执行时机在模块路由之后,app.use 在那里
|
|
25
|
+
// 只罩得住 404 兜底请求,安全响应头等全局策略应经本插槽注册而非写在 router.js。
|
|
26
|
+
for (const mw of cfg.middleware ?? []) {
|
|
27
|
+
const fn = typeof mw === "function" && mw.length <= 1 ? mw(chan) : mw;
|
|
28
|
+
if (typeof fn !== "function") {
|
|
29
|
+
logger.warn(`[Chan] config.middleware 含非法项(须为中间件或中间件工厂),已跳过: ${String(mw)}`);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
app.use(fn);
|
|
33
|
+
}
|
|
20
34
|
// 2. Favicon
|
|
21
35
|
favicon(app);
|
|
22
36
|
// 3. 静态资源
|
|
@@ -172,7 +172,8 @@ const otherDb = app.dbManager.get("logs");
|
|
|
172
172
|
| `REDIS_ENABLED` / `REDIS` | Redis 配置 |
|
|
173
173
|
| `JWT_SECRET` | JWT 签名密钥 |
|
|
174
174
|
| `LOCALE` | i18n 默认语言(默认 `zh-CN`)|
|
|
175
|
-
| `LIMIT_MAX` | Repository 单页上限(默认 300
|
|
175
|
+
| `LIMIT_MAX` | Repository 单页上限(默认 300);`all()`/`find()` 显式 limit 亦被钳制到该值 |
|
|
176
|
+
| `middleware` | 宿主全局中间件插槽:数组,元素为 express 中间件或中间件工厂 `(chan) => mw`,注册于核心链早期(健康检查后、静态资源前),对所有响应生效 |
|
|
176
177
|
| `SLOW_THRESHOLD` | 数据库慢查询阈值(ms,默认 200),超过记 warn 日志 |
|
|
177
178
|
| `SHUTDOWN_TIMEOUT` | 优雅停机强制退出超时(ms,默认 5000)|
|
|
178
179
|
| `BODY_LIMIT` | 请求体上限(默认 `10mb`)|
|
package/middleware/header.js
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* 品牌响应头中间件:隐藏原生 Express 标识,统一输出 ChanCMS。
|
|
3
|
+
*
|
|
4
|
+
* 注:安全响应头(X-Content-Type-Options / HSTS / Referrer-Policy /
|
|
5
|
+
* Permissions-Policy / CSP 等)属于宿主业务策略,不在框架层默认设置——
|
|
6
|
+
* 由各项目的 security-headers 中间件统一收敛(本项目见 app/middleware/security-headers.js)。
|
|
7
|
+
* 尤其 CSP frame-ancestors 一旦在框架写死 'self',会与需要被第三方
|
|
8
|
+
* iframe 嵌入的宿主业务直接冲突,故不在此声明。
|
|
5
9
|
*/
|
|
6
10
|
export const header = (app, opts = {}) => {
|
|
7
11
|
const appName = opts.APP_NAME || "ChanCMS";
|
|
8
12
|
const appVer = opts.APP_VERSION || "";
|
|
9
13
|
const poweredBy = appVer ? `${appName}/${appVer}` : appName;
|
|
14
|
+
// 静态资源在核心链第 3 步即被接住、到不了本中间件,Express 会默认补
|
|
15
|
+
// X-Powered-By: Express 泄露技术栈——先禁用默认注入,品牌头只由下方显式设置
|
|
16
|
+
app.disable("x-powered-by");
|
|
10
17
|
|
|
11
18
|
app.use((_, res, next) => {
|
|
12
19
|
res.setHeader("X-Powered-By", poweredBy);
|
|
13
|
-
// 常驻安全响应头:无论 WAF 是否启用都生效
|
|
14
|
-
// 禁止 MIME 嗅探(防 XSS 利用 Content-Type 歧义)
|
|
15
|
-
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
16
|
-
// 防点击劫持:仅允许同源 iframe 嵌套(如需被第三方嵌入请按需放宽)
|
|
17
|
-
res.setHeader("Content-Security-Policy", "frame-ancestors 'self'");
|
|
18
20
|
next();
|
|
19
21
|
});
|
|
20
|
-
};
|
|
22
|
+
};
|