@ -1,3 +1,5 @@
import path from "node:path" ;
function trimSlashes ( input : string ) : string {
return input . trim ( ) . replace ( /^\/+|\/+$/g , "" ) ;
}
@ -9,16 +11,18 @@ function hasParentSegment(input: string): boolean {
. some ( ( part ) = > part === ".." ) ;
}
function ensureRelativeDir ( input : string , fallback : string , envName : string ) : string {
const value = input . trim ( ) ;
if ( ! value ) {
/** 允许相对项目根或绝对路径;禁止含 `..` 的路径片段(防止配置逃逸)。 */
function ensureConfigurableDir ( input : string , fallback : string , envName : string ) : string {
const raw = input . trim ( ) ;
if ( ! raw ) {
return fallback ;
}
// 仅允许相对目录;绝对路径会绕过项目根约束。
if ( value . startsWith ( "/" ) ) {
throw new Error ( ` ${ envName } must be a relative directory path ` ) ;
const normalized = path . normalize ( raw ) ;
const segments = normalized . split ( path . sep ) ;
if ( segments . some ( ( part ) = > part === ".." ) ) {
throw new Error ( ` ${ envName } must not contain ".." path segments ` ) ;
}
return value ;
return normalized ;
}
function ensureSafeSubdir ( input : string , fallback : string , envName : string ) : string {
@ -35,8 +39,8 @@ function ensureSafeSubdir(input: string, fallback: string, envName: string): str
/** 静态资源 URL 前缀固定为 `/static`,不允许通过环境变量覆写。 */
export const STATIC_PUBLIC_PREFIX = "/static" ;
/** 静态资源根目录,默认 `static` */
export const STATIC_DIR = ensureRelativ eDir ( process . env . STATIC_DIR ? ? "static" , "static" , "STATIC_DIR" ) ;
/** 静态资源根目录(相对项目根或绝对路径) ,默认 `static` */
export const STATIC_DIR = ensureConfigurabl eDir ( process . env . STATIC_DIR ? ? "static" , "static" , "STATIC_DIR" ) ;
/** 媒体上传子目录(相对 STATIC_DIR),默认 `media` */
export const MEDIA_UPLOAD_SUBDIR = ensureSafeSubdir (
@ -45,11 +49,11 @@ export const MEDIA_UPLOAD_SUBDIR = ensureSafeSubdir(
"MEDIA_UPLOAD_SUBDIR" ,
) ;
/** 媒体上传目录(相对项目根 ),默认 `static/media` */
export const RELATIVE_ASSETS_DIR = ` ${ STATIC_DIR } / ${ MEDIA_UPLOAD_SUBDIR } ` ;
/** 媒体上传目录(与 STATIC_DIR 同为相对或绝对 ),默认 `static/media` */
export const RELATIVE_ASSETS_DIR = path . join ( STATIC_DIR , MEDIA_UPLOAD_SUBDIR ) ;
/** 临时目录(相对项目根),默认 `.tmp` */
export const RELATIVE_TMP_DIR = ensureRelativ eDir ( process . env . TMP_DIR ? ? ".tmp" , ".tmp" , "TMP_DIR" ) ;
/** 临时目录(相对项目根或绝对路径 ),默认 `.tmp` */
export const RELATIVE_TMP_DIR = ensureConfigurabl eDir ( process . env . TMP_DIR ? ? ".tmp" , ".tmp" , "TMP_DIR" ) ;
/** 与 `media` 返回及静态路径一致,无前导 host */
export const POST_MEDIA_PUBLIC_PREFIX = ` ${ STATIC_PUBLIC_PREFIX } / ${ MEDIA_UPLOAD_SUBDIR } / ` ;