服务器配置
This commit is contained in:
1 parent
a1b4a63552
commit
fa7c8244b0
33 files changed
+1882
-363
No files matched your search
+157
-11
@@ -10,6 +10,12 @@ import {
|
||||
SETTINGS_STORAGE_USE_DATE_PATH,
|
||||
SETTINGS_IMAGE_BASE_URL,
|
||||
SETTINGS_SITE_BASE_URL,
|
||||
SETTINGS_VIDEO_BASE_URL,
|
||||
SETTINGS_FILE_BASE_URL,
|
||||
SETTINGS_DOMAIN_SEPARATION,
|
||||
SETTINGS_IMAGE_DOMAIN_SEPARATED,
|
||||
SETTINGS_VIDEO_DOMAIN_SEPARATED,
|
||||
SETTINGS_FILE_DOMAIN_SEPARATED,
|
||||
SETTINGS_FILE_BED_ACCESS,
|
||||
SETTINGS_WEBP_QUALITY,
|
||||
SETTINGS_LOGIN_VERIFICATION_METHOD,
|
||||
@@ -84,6 +90,14 @@ export function normalizeSiteBaseUrl(raw: string): string {
|
||||
return normalizeBaseUrl(raw)
|
||||
}
|
||||
|
||||
export function normalizeVideoBaseUrl(raw: string): string {
|
||||
return normalizeBaseUrl(raw)
|
||||
}
|
||||
|
||||
export function normalizeFileBaseUrl(raw: string): string {
|
||||
return normalizeBaseUrl(raw)
|
||||
}
|
||||
|
||||
export function hostnameFromBaseUrl(value: string): string | null {
|
||||
if (!value) return null
|
||||
try {
|
||||
@@ -137,6 +151,38 @@ export function getSiteBaseUrlConfigured(event: H3Event): string {
|
||||
return getSiteBaseUrlFromEnv(event)
|
||||
}
|
||||
|
||||
export function getVideoBaseUrlFromEnv(event: H3Event): string {
|
||||
return normalizeVideoBaseUrl(getRuntimeEnv(event, 'VIDEO_BASE_URL', 'videoBaseUrl'))
|
||||
}
|
||||
|
||||
export function getVideoBaseUrlSource(event: H3Event): SettingSource {
|
||||
if (getSetting(SETTINGS_VIDEO_BASE_URL) !== null) return 'db'
|
||||
if (getVideoBaseUrlFromEnv(event)) return 'env'
|
||||
return 'none'
|
||||
}
|
||||
|
||||
export function getVideoBaseUrlConfigured(event: H3Event): string {
|
||||
const dbRaw = getSetting(SETTINGS_VIDEO_BASE_URL)
|
||||
if (dbRaw !== null) return normalizeVideoBaseUrl(dbRaw)
|
||||
return getVideoBaseUrlFromEnv(event)
|
||||
}
|
||||
|
||||
export function getFileBaseUrlFromEnv(event: H3Event): string {
|
||||
return normalizeFileBaseUrl(getRuntimeEnv(event, 'FILE_BASE_URL', 'fileBaseUrl'))
|
||||
}
|
||||
|
||||
export function getFileBaseUrlSource(event: H3Event): SettingSource {
|
||||
if (getSetting(SETTINGS_FILE_BASE_URL) !== null) return 'db'
|
||||
if (getFileBaseUrlFromEnv(event)) return 'env'
|
||||
return 'none'
|
||||
}
|
||||
|
||||
export function getFileBaseUrlConfigured(event: H3Event): string {
|
||||
const dbRaw = getSetting(SETTINGS_FILE_BASE_URL)
|
||||
if (dbRaw !== null) return normalizeFileBaseUrl(dbRaw)
|
||||
return getFileBaseUrlFromEnv(event)
|
||||
}
|
||||
|
||||
export function getSiteBaseUrl(event: H3Event): string {
|
||||
const dbRaw = getSetting(SETTINGS_SITE_BASE_URL)
|
||||
if (dbRaw !== null) {
|
||||
@@ -155,6 +201,15 @@ export function getSiteBaseUrl(event: H3Event): string {
|
||||
}
|
||||
|
||||
export function getImageBaseUrl(event: H3Event): string {
|
||||
if (isDomainSeparationActive(event) && !isImageDomainSeparated(event)) {
|
||||
return getSiteBaseUrl(event)
|
||||
}
|
||||
if (
|
||||
getSetting(SETTINGS_DOMAIN_SEPARATION) === 'false'
|
||||
&& getSetting(SETTINGS_IMAGE_DOMAIN_SEPARATED) === 'false'
|
||||
) {
|
||||
return getSiteBaseUrl(event)
|
||||
}
|
||||
const dbRaw = getSetting(SETTINGS_IMAGE_BASE_URL)
|
||||
if (dbRaw !== null) {
|
||||
const configured = normalizeImageBaseUrl(dbRaw)
|
||||
@@ -172,6 +227,64 @@ export function getImageBaseUrl(event: H3Event): string {
|
||||
return requestUrl.origin
|
||||
}
|
||||
|
||||
export function getVideoBaseUrl(event: H3Event): string {
|
||||
if (isDomainSeparationActive(event) && !isVideoDomainSeparated(event)) {
|
||||
return getSiteBaseUrl(event)
|
||||
}
|
||||
if (
|
||||
getSetting(SETTINGS_DOMAIN_SEPARATION) === 'false'
|
||||
&& getSetting(SETTINGS_VIDEO_DOMAIN_SEPARATED) === 'false'
|
||||
) {
|
||||
return getSiteBaseUrl(event)
|
||||
}
|
||||
return getVideoBaseUrlConfigured(event) || getImageBaseUrl(event)
|
||||
}
|
||||
|
||||
export function getFileBaseUrl(event: H3Event): string {
|
||||
if (isDomainSeparationActive(event) && !isFileDomainSeparated(event)) {
|
||||
return getSiteBaseUrl(event)
|
||||
}
|
||||
if (
|
||||
getSetting(SETTINGS_DOMAIN_SEPARATION) === 'false'
|
||||
&& getSetting(SETTINGS_FILE_DOMAIN_SEPARATED) === 'false'
|
||||
) {
|
||||
return getSiteBaseUrl(event)
|
||||
}
|
||||
return getFileBaseUrlConfigured(event) || getImageBaseUrl(event)
|
||||
}
|
||||
|
||||
export function getMediaBaseUrl(event: H3Event, key: string): string {
|
||||
if (key.startsWith('videos/')) return getVideoBaseUrl(event)
|
||||
if (key.startsWith('files/')) return getFileBaseUrl(event)
|
||||
return getImageBaseUrl(event)
|
||||
}
|
||||
|
||||
function parseStoredBoolean(raw: string | null): boolean | null {
|
||||
if (raw === null) return null
|
||||
return raw === 'true'
|
||||
}
|
||||
|
||||
export function isImageDomainSeparated(event: H3Event): boolean {
|
||||
if (!isDomainSeparationActive(event)) return false
|
||||
const explicit = parseStoredBoolean(getSetting(SETTINGS_IMAGE_DOMAIN_SEPARATED))
|
||||
if (explicit !== null) return explicit
|
||||
return Boolean(getImageBaseUrlConfigured(event))
|
||||
}
|
||||
|
||||
export function isVideoDomainSeparated(event: H3Event): boolean {
|
||||
if (!isDomainSeparationActive(event)) return false
|
||||
const explicit = parseStoredBoolean(getSetting(SETTINGS_VIDEO_DOMAIN_SEPARATED))
|
||||
if (explicit !== null) return explicit
|
||||
return Boolean(getVideoBaseUrlConfigured(event))
|
||||
}
|
||||
|
||||
export function isFileDomainSeparated(event: H3Event): boolean {
|
||||
if (!isDomainSeparationActive(event)) return false
|
||||
const explicit = parseStoredBoolean(getSetting(SETTINGS_FILE_DOMAIN_SEPARATED))
|
||||
if (explicit !== null) return explicit
|
||||
return Boolean(getFileBaseUrlConfigured(event))
|
||||
}
|
||||
|
||||
export function isHideFolderInUrlFromEnv(): boolean {
|
||||
try {
|
||||
return process.env.HIDE_FOLDER_IN_URL?.trim().toLowerCase() === 'true'
|
||||
@@ -555,26 +668,32 @@ export function isValidSiteBaseUrl(value: string): boolean {
|
||||
|
||||
export function validateDomainSeparationPair(
|
||||
siteBaseUrl: string,
|
||||
imageBaseUrl: string
|
||||
imageBaseUrl: string,
|
||||
videoBaseUrl = '',
|
||||
fileBaseUrl = ''
|
||||
): string | null {
|
||||
if (!siteBaseUrl || !imageBaseUrl) {
|
||||
return '启用域名分离时需同时填写网站域名与图片域名'
|
||||
return '启用域名分离时需同时填写后台域名与图片域名'
|
||||
}
|
||||
if (!isValidSiteBaseUrl(siteBaseUrl) || !isValidImageBaseUrl(imageBaseUrl)) {
|
||||
if (
|
||||
!isValidSiteBaseUrl(siteBaseUrl)
|
||||
|| !isValidImageBaseUrl(imageBaseUrl)
|
||||
|| (videoBaseUrl && !isValidImageBaseUrl(videoBaseUrl))
|
||||
|| (fileBaseUrl && !isValidImageBaseUrl(fileBaseUrl))
|
||||
) {
|
||||
return '域名需为 http(s) 地址,且末尾不加 /'
|
||||
}
|
||||
const siteHost = hostnameFromBaseUrl(siteBaseUrl)
|
||||
const imageHost = hostnameFromBaseUrl(imageBaseUrl)
|
||||
if (!siteHost || !imageHost) {
|
||||
const videoHost = hostnameFromBaseUrl(videoBaseUrl)
|
||||
const fileHost = hostnameFromBaseUrl(fileBaseUrl)
|
||||
if (!siteHost || !imageHost || (videoBaseUrl && !videoHost) || (fileBaseUrl && !fileHost)) {
|
||||
return '域名格式无效'
|
||||
}
|
||||
if (siteHost === imageHost) {
|
||||
return '网站域名与图片域名不能使用相同主机名'
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export type RequestHostRole = 'site' | 'image' | 'unknown' | 'single'
|
||||
export type RequestHostRole = 'site' | 'image' | 'video' | 'file' | 'unknown' | 'single'
|
||||
|
||||
export function getIsolationRequestHost(event: H3Event): string {
|
||||
const requestUrl = getRequestURL(event, {
|
||||
@@ -587,8 +706,12 @@ export function getIsolationRequestHost(event: H3Event): string {
|
||||
export function validateSettingsDomainPatch(input: {
|
||||
existingSite: string
|
||||
existingImage: string
|
||||
existingVideo?: string
|
||||
existingFile?: string
|
||||
nextSite: string
|
||||
nextImage: string
|
||||
nextVideo?: string
|
||||
nextFile?: string
|
||||
wantSeparation: boolean | null
|
||||
siteBaseUrlProvided: boolean
|
||||
}): string | null {
|
||||
@@ -597,6 +720,8 @@ export function validateSettingsDomainPatch(input: {
|
||||
existingImage,
|
||||
nextSite,
|
||||
nextImage,
|
||||
nextVideo = '',
|
||||
nextFile = '',
|
||||
wantSeparation,
|
||||
siteBaseUrlProvided
|
||||
} = input
|
||||
@@ -609,9 +734,9 @@ export function validateSettingsDomainPatch(input: {
|
||||
|
||||
if (wantSeparation === true) {
|
||||
if (!nextSite || !nextImage) {
|
||||
return '启用域名分离时需同时填写网站域名与图片域名'
|
||||
return '启用域名分离时需同时填写后台域名与图片域名'
|
||||
}
|
||||
return validateDomainSeparationPair(nextSite, nextImage)
|
||||
return validateDomainSeparationPair(nextSite, nextImage, nextVideo, nextFile)
|
||||
}
|
||||
|
||||
if (wantSeparation === false) {
|
||||
@@ -623,7 +748,7 @@ export function validateSettingsDomainPatch(input: {
|
||||
}
|
||||
|
||||
if (nextSite && nextImage) {
|
||||
return validateDomainSeparationPair(nextSite, nextImage)
|
||||
return validateDomainSeparationPair(nextSite, nextImage, nextVideo, nextFile)
|
||||
}
|
||||
|
||||
return null
|
||||
@@ -647,12 +772,18 @@ export function getRequestRuntime(event: H3Event) {
|
||||
|
||||
const siteHost = hostnameFromBaseUrl(getSiteBaseUrlConfigured(event))
|
||||
const imageHost = hostnameFromBaseUrl(getImageBaseUrlConfigured(event))
|
||||
const videoHost = hostnameFromBaseUrl(getVideoBaseUrl(event))
|
||||
const fileHost = hostnameFromBaseUrl(getFileBaseUrl(event))
|
||||
|
||||
let hostRole: RequestHostRole = 'unknown'
|
||||
if (currentHost === siteHost) {
|
||||
hostRole = 'site'
|
||||
} else if (currentHost === imageHost) {
|
||||
hostRole = 'image'
|
||||
} else if (currentHost === videoHost) {
|
||||
hostRole = 'video'
|
||||
} else if (currentHost === fileHost) {
|
||||
hostRole = 'file'
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -668,8 +799,12 @@ export function getSettingsPayload(event: H3Event) {
|
||||
const allowedRefererHosts = getAllowedRefererHostsRaw(event)
|
||||
const siteBaseUrlConfigured = getSiteBaseUrlConfigured(event)
|
||||
const imageBaseUrlConfigured = getImageBaseUrlConfigured(event)
|
||||
const videoBaseUrlConfigured = getVideoBaseUrlConfigured(event)
|
||||
const fileBaseUrlConfigured = getFileBaseUrlConfigured(event)
|
||||
const effectiveSiteBaseUrl = getSiteBaseUrl(event)
|
||||
const effectiveImageBaseUrl = getImageBaseUrl(event)
|
||||
const effectiveVideoBaseUrl = getVideoBaseUrl(event)
|
||||
const effectiveFileBaseUrl = getFileBaseUrl(event)
|
||||
const autoDeleteDays = getAutoDeleteDays(event)
|
||||
const appVersion = config.appVersion as string
|
||||
const domainSeparation = isDomainSeparationActive(event)
|
||||
@@ -693,8 +828,17 @@ export function getSettingsPayload(event: H3Event) {
|
||||
imageBaseUrl: imageBaseUrlConfigured,
|
||||
imageBaseUrlConfigured,
|
||||
imageBaseUrlSource: getImageBaseUrlSource(event),
|
||||
imageDomainSeparated: isImageDomainSeparated(event),
|
||||
videoBaseUrl: videoBaseUrlConfigured,
|
||||
videoBaseUrlSource: getVideoBaseUrlSource(event),
|
||||
videoDomainSeparated: isVideoDomainSeparated(event),
|
||||
fileBaseUrl: fileBaseUrlConfigured,
|
||||
fileBaseUrlSource: getFileBaseUrlSource(event),
|
||||
fileDomainSeparated: isFileDomainSeparated(event),
|
||||
effectiveSiteBaseUrl,
|
||||
effectiveImageBaseUrl,
|
||||
effectiveVideoBaseUrl,
|
||||
effectiveFileBaseUrl,
|
||||
domainSeparation,
|
||||
runtime: getRequestRuntime(event),
|
||||
hideFolderInUrl,
|
||||
@@ -725,6 +869,8 @@ export function getSettingsPayload(event: H3Event) {
|
||||
}
|
||||
|
||||
export function isDomainSeparationActive(event: H3Event): boolean {
|
||||
const explicit = getSetting(SETTINGS_DOMAIN_SEPARATION)
|
||||
if (explicit !== null) return explicit === 'true'
|
||||
const siteHost = hostnameFromBaseUrl(getSiteBaseUrlConfigured(event))
|
||||
const imageHost = hostnameFromBaseUrl(getImageBaseUrlConfigured(event))
|
||||
return Boolean(siteHost && imageHost && siteHost !== imageHost)
|
||||
|
||||
Reference in new issue
Block a user