feat: trust proxies option (#879)

This commit is contained in:
diced
2025-10-03 20:55:35 -07:00
parent a7a23f3fd9
commit c9d492f9d2
9 changed files with 32 additions and 7 deletions

View File

@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "public"."Zipline" ADD COLUMN "coreTrustProxy" BOOLEAN NOT NULL DEFAULT false;

View File

@@ -20,6 +20,7 @@ model Zipline {
coreReturnHttpsUrls Boolean @default(false)
coreDefaultDomain String?
coreTempDirectory String // default join(tmpdir(), 'zipline')
coreTrustProxy Boolean @default(false)
chunksEnabled Boolean @default(true)
chunksMax String @default("95mb")

View File

@@ -17,11 +17,13 @@ export default function Core({
coreReturnHttpsUrls: boolean;
coreDefaultDomain: string | null | undefined;
coreTempDirectory: string;
coreTrustProxy: boolean;
}>({
initialValues: {
coreReturnHttpsUrls: false,
coreDefaultDomain: '',
coreTempDirectory: '/tmp/zipline',
coreTrustProxy: false,
},
enhanceGetInputProps: (payload) => ({
disabled: data?.tampered?.includes(payload.field) || false,
@@ -45,6 +47,7 @@ export default function Core({
coreReturnHttpsUrls: data.settings.coreReturnHttpsUrls ?? false,
coreDefaultDomain: data.settings.coreDefaultDomain ?? '',
coreTempDirectory: data.settings.coreTempDirectory ?? '/tmp/zipline',
coreTrustProxy: data.settings.coreTrustProxy ?? false,
});
}, [data]);
@@ -55,14 +58,20 @@ export default function Core({
<Title order={2}>Core</Title>
<form onSubmit={form.onSubmit(onSubmit)}>
<Switch
mt='md'
label='Return HTTPS URLs'
description='Return URLs with HTTPS protocol.'
{...form.getInputProps('coreReturnHttpsUrls', { type: 'checkbox' })}
/>
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
<Switch
mt='md'
label='Return HTTPS URLs'
description='Return URLs with HTTPS protocol.'
{...form.getInputProps('coreReturnHttpsUrls', { type: 'checkbox' })}
/>
<Switch
label='Trust Proxies'
description='Trust the X-Forwarded-* headers set by proxies. Only enable this if you are behind a trusted proxy (nginx, caddy, etc.). Requires a server restart.'
{...form.getInputProps('coreTrustProxy', { type: 'checkbox' })}
/>
<TextInput
label='Default Domain'
description='The domain to use when generating URLs. This value should not include the protocol.'

View File

@@ -6,6 +6,7 @@ export const DATABASE_TO_PROP = {
coreReturnHttpsUrls: 'core.returnHttpsUrls',
coreDefaultDomain: 'core.defaultDomain',
coreTempDirectory: 'core.tempDirectory',
coreTrustProxy: 'core.trustProxy',
chunksMax: 'chunks.max',
chunksSize: 'chunks.size',

View File

@@ -32,6 +32,7 @@ export const ENVS = [
env('ssl.cert', 'SSL_CERT', 'string'),
// database stuff
env('core.trustProxy', 'CORE_TRUST_PROXY', 'boolean', true),
env('core.returnHttpsUrls', 'CORE_RETURN_HTTPS_URLS', 'boolean', true),
env('core.defaultDomain', 'CORE_DEFAULT_DOMAIN', 'string', true),
env('core.tempDirectory', 'CORE_TEMP_DIRECTORY', 'string', true),

View File

@@ -13,6 +13,7 @@ export const rawConfig: any = {
databaseUrl: undefined,
returnHttpsUrls: undefined,
tempDirectory: undefined,
trustProxy: undefined,
},
chunks: {
max: undefined,

View File

@@ -74,6 +74,7 @@ export const schema = z.object({
.string()
.transform((s) => resolve(s))
.default(join(tmpdir(), 'zipline')),
trustProxy: z.boolean().default(false),
}),
chunks: z.object({
max: z.string().default('95mb'),

View File

@@ -65,6 +65,13 @@ async function main() {
await mkdir(config.core.tempDirectory, { recursive: true });
logger.debug('creating server', {
port: config.core.port,
hostname: config.core.hostname,
ssl: notNull(config.ssl.key, config.ssl.cert),
trustProxy: config.core.trustProxy,
});
const server = fastify({
https: notNull(config.ssl.key, config.ssl.cert)
? {
@@ -72,6 +79,7 @@ async function main() {
cert: await readFile(config.ssl.cert!, 'utf8'),
}
: null,
trustProxy: config.core.trustProxy,
});
await server.register(fastifyCookie, {

View File

@@ -118,6 +118,7 @@ export default fastifyPlugin(
.nullable()
.refine((value) => !value || /^[a-z0-9-.]+$/.test(value), 'Invalid domain format'),
coreReturnHttpsUrls: z.boolean(),
coreTrustProxy: z.boolean(),
chunksEnabled: z.boolean(),
chunksMax: zBytes,