Add X-Real-IP, X-Forwarded-Proto, X-Forwarded-Host, and X-Forwarded-Port headers to all proxy hosts for proper client IP detection, HTTPS enforcement, and logging. - New feature flag: enable_standard_headers (default: true for new hosts, false for existing) - UI: Checkbox in proxy host form and bulk apply modal for easy migration - Security: Always configure trusted_proxies when headers enabled - Backward compatible: Existing hosts preserve legacy behavior until explicitly enabled BREAKING CHANGE: New proxy hosts will have standard headers enabled by default. Existing hosts maintain legacy behavior. Users can opt-in via UI. Backend: 98.7% coverage, 8 new tests Frontend: 87.7% coverage, full TypeScript support Docs: Comprehensive migration guide and troubleshooting Closes #<issue-number> (FileFlows WebSocket fix)
110 lines
3.1 KiB
TypeScript
110 lines
3.1 KiB
TypeScript
import type { ProxyHost } from '../api/proxyHosts'
|
|
|
|
export function formatSettingLabel(key: string) {
|
|
switch (key) {
|
|
case 'ssl_forced':
|
|
return 'Force SSL'
|
|
case 'http2_support':
|
|
return 'HTTP/2 Support'
|
|
case 'hsts_enabled':
|
|
return 'HSTS Enabled'
|
|
case 'hsts_subdomains':
|
|
return 'HSTS Subdomains'
|
|
case 'block_exploits':
|
|
return 'Block Exploits'
|
|
case 'websocket_support':
|
|
return 'Websockets Support'
|
|
case 'enable_standard_headers':
|
|
return 'Standard Proxy Headers'
|
|
default:
|
|
return key
|
|
}
|
|
}
|
|
|
|
export function settingHelpText(key: string) {
|
|
switch (key) {
|
|
case 'ssl_forced':
|
|
return 'Redirect all HTTP traffic to HTTPS.'
|
|
case 'http2_support':
|
|
return 'Enable HTTP/2 for improved performance.'
|
|
case 'hsts_enabled':
|
|
return 'Send HSTS header to enforce HTTPS.'
|
|
case 'hsts_subdomains':
|
|
return 'Include subdomains in HSTS policy.'
|
|
case 'block_exploits':
|
|
return 'Add common exploit-mitigation headers and rules.'
|
|
case 'websocket_support':
|
|
return 'Enable websocket proxying support.'
|
|
case 'enable_standard_headers':
|
|
return 'Add X-Real-IP and X-Forwarded-* headers for client IP detection.'
|
|
default:
|
|
return ''
|
|
}
|
|
}
|
|
|
|
export function settingKeyToField(key: string) {
|
|
switch (key) {
|
|
case 'ssl_forced':
|
|
return 'ssl_forced'
|
|
case 'http2_support':
|
|
return 'http2_support'
|
|
case 'hsts_enabled':
|
|
return 'hsts_enabled'
|
|
case 'hsts_subdomains':
|
|
return 'hsts_subdomains'
|
|
case 'block_exploits':
|
|
return 'block_exploits'
|
|
case 'websocket_support':
|
|
return 'websocket_support'
|
|
case 'enable_standard_headers':
|
|
return 'enable_standard_headers'
|
|
default:
|
|
return key
|
|
}
|
|
}
|
|
|
|
export async function applyBulkSettingsToHosts(options: {
|
|
hosts: ProxyHost[]
|
|
hostUUIDs: string[]
|
|
keysToApply: string[]
|
|
bulkApplySettings: Record<string, { apply: boolean; value: boolean }>
|
|
updateHost: (uuid: string, data: Partial<ProxyHost>) => Promise<ProxyHost>
|
|
setApplyProgress?: (p: { current: number; total: number } | null) => void
|
|
}) {
|
|
const { hosts, hostUUIDs, keysToApply, bulkApplySettings, updateHost, setApplyProgress } = options
|
|
let completed = 0
|
|
let errors = 0
|
|
setApplyProgress?.({ current: 0, total: hostUUIDs.length })
|
|
|
|
for (const uuid of hostUUIDs) {
|
|
const patch: Partial<ProxyHost> = {}
|
|
for (const key of keysToApply) {
|
|
const field = settingKeyToField(key) as keyof ProxyHost
|
|
;(patch as unknown as Record<string, unknown>)[field as string] = bulkApplySettings[key].value
|
|
}
|
|
|
|
const host = hosts.find(h => h.uuid === uuid)
|
|
if (!host) {
|
|
errors++
|
|
completed++
|
|
setApplyProgress?.({ current: completed, total: hostUUIDs.length })
|
|
continue
|
|
}
|
|
|
|
const merged: Partial<ProxyHost> = { ...host, ...patch }
|
|
try {
|
|
await updateHost(uuid, merged)
|
|
} catch {
|
|
errors++
|
|
}
|
|
|
|
completed++
|
|
setApplyProgress?.({ current: completed, total: hostUUIDs.length })
|
|
}
|
|
|
|
setApplyProgress?.(null)
|
|
return { errors, completed }
|
|
}
|
|
|
|
export default {}
|