22// 错误中间件沿用旧实现的设计:对外只回通用提示 + 错误码 ref,日志记完整信息(脱敏)。
33import { Hono } from 'hono'
44import type { AppBindings , Env } from './types'
5+ import { clientIp , rateLimit } from './lib/ratelimit'
56import modRoutes from './routes/mod'
67import authRoutes from './routes/auth'
78import publicRoutes from './routes/public'
@@ -59,9 +60,16 @@ app.onError((err, c) => {
5960app . get ( '/healthz' , ( c ) => c . json ( { ok : true , ts : new Date ( ) . toISOString ( ) } ) )
6061
6162app . get ( '/_ping' , async ( c ) => {
62- // 只报告「是否已设置」,绝不回显任何值 —— 这是个公开端点。
63- // 登录链路要求 issuer/clientId/clientSecret/teamId 四项俱全,缺一项就整体
64- // 降级为「登录未配置」,不这样列出来的话没法判断到底缺哪个。
63+ // 公开端点,加一道限流:它要查一次 D1,被刷会白白消耗配额
64+ const limit = await rateLimit ( c . env . KV , `ping:${ clientIp ( c . req . raw . headers ) } ` , 30 , 60 )
65+ if ( ! limit . ok ) return c . json ( { ok : false , error : '请求过于频繁' } , 429 )
66+
67+ // 逐项状态只报布尔值,且**仅在尚未配置齐全时**返回。
68+ //
69+ // 部署阶段需要它定位缺哪一项(clientSecret 是 secret,不在 wrangler.toml 里,
70+ // 最容易漏);而那个阶段站点本来就不可用,暴露这点信息没什么可失去的。
71+ // 一旦配齐就不再输出 —— 稳定运行的站点没有理由对外公开自己的配置矩阵,
72+ // 那只会告诉攻击者哪块功能尚未就绪、值得试探。
6573 const config = {
6674 PRISM_ISSUER : ! ! c . env ?. PRISM_ISSUER ,
6775 PRISM_CLIENT_ID : ! ! c . env ?. PRISM_CLIENT_ID ,
@@ -72,16 +80,13 @@ app.get('/_ping', async (c) => {
7280 MOD_LICENSE_PRIVATE_KEY : ! ! c . env ?. MOD_LICENSE_PRIVATE_KEY ,
7381 WEBHOOK_SECRET : ! ! c . env ?. WEBHOOK_SECRET ,
7482 }
83+ const allConfigured = Object . values ( config ) . every ( Boolean )
7584
7685 const out : Record < string , unknown > = {
7786 bindings : { DB : ! ! c . env ?. DB , KV : ! ! c . env ?. KV , R2 : ! ! c . env ?. R2 } ,
78- config,
79- loginConfigured :
80- config . PRISM_ISSUER &&
81- config . PRISM_CLIENT_ID &&
82- config . PRISM_CLIENT_SECRET &&
83- config . PRISM_TEAM_ID ,
87+ configured : allConfigured ,
8488 }
89+ if ( ! allConfigured ) out . config = config
8590
8691 try {
8792 const r = await c . env . DB . prepare ( 'SELECT COUNT(*) AS n FROM roles' ) . first < { n : number } > ( )
0 commit comments