import type { ServerConfig } from '../config/server-config'; /** 数据库 objectKey 已含上传前缀;逐段编码且拒绝越界,不再次拼接前缀。 */ export function publicObjectUrl( domain: string | null, objectKey: string, ): string | null { const parts = objectKey.split('/'); if ( !domain || objectKey.includes('\\') || [...objectKey].some( (char) => char.charCodeAt(0) < 32 || char.charCodeAt(0) === 127, ) || parts.some((part) => !part || part === '.' || part === '..') ) return null; return `${domain}/${parts.map(encodeURIComponent).join('/')}`; } /** 字体等固定公开资源传备份相对路径,由配置统一补上传前缀;不解析旧 cloud 引用。 */ export function publicResourceUrl( config: Pick, relativePath: string, ): string | null { // 先独立验证相对路径,防止空路径或绝对路径被前缀掩盖。 if (!publicObjectUrl(config.qiniuPublicDomain, relativePath)) return null; return publicObjectUrl( config.qiniuPublicDomain, `${config.qiniuKeyPrefix}${relativePath}`, ); }