feat: add a trust proxy env to control whether to trust incoming x-forwarded-for headers (#662)
This commit is contained in:
parent
8fdf858dcb
commit
9632c77177
4 changed files with 21 additions and 1 deletions
|
|
@ -5,4 +5,5 @@ ZEROBYTE_REPOSITORIES_DIR=./data/repositories
|
|||
ZEROBYTE_VOLUMES_DIR=./data/volumes
|
||||
APP_SECRET=<openssl rand -hex 32>
|
||||
BASE_URL=http://localhost:300
|
||||
TRUST_PROXY=false
|
||||
PORT=3000
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ Zerobyte can be customized using environment variables. Below are the available
|
|||
| `PORT` | The port the web interface and API will listen on. | `4096` |
|
||||
| `RESTIC_HOSTNAME` | The hostname used by Restic when creating snapshots. Automatically detected if a custom hostname is set in Docker. | `zerobyte` |
|
||||
| `TZ` | Timezone for the container (e.g., `Europe/Zurich`). **Crucial for accurate backup scheduling.** | `UTC` |
|
||||
| `TRUST_PROXY` | When `true`, trust an existing `X-Forwarded-For` header from your reverse proxy. Leave `false` for direct deployments. | `false` |
|
||||
| `TRUSTED_ORIGINS` | Comma-separated list of extra trusted origins for CORS (e.g., `http://localhost:3000,http://example.com`). | (none) |
|
||||
| `LOG_LEVEL` | Logging verbosity. Options: `debug`, `info`, `warn`, `error`. | `info` |
|
||||
| `SERVER_IDLE_TIMEOUT` | Idle timeout for the server in seconds. | `60` |
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { config } from "~/server/core/config";
|
|||
const app = createApp();
|
||||
|
||||
type NodeRuntimeRequest = Request & {
|
||||
ip?: string;
|
||||
runtime?: {
|
||||
node?: {
|
||||
res?: { setTimeout: (timeoutMs: number) => void };
|
||||
|
|
@ -16,7 +17,22 @@ export const prepareApiRequest = (request: Request, timeoutMs: number) => {
|
|||
const nodeRequest = request as NodeRuntimeRequest;
|
||||
nodeRequest.runtime?.node?.res?.setTimeout(timeoutMs);
|
||||
|
||||
return request.clone();
|
||||
if (config.trustProxy && request.headers.has("x-forwarded-for")) {
|
||||
return request.clone();
|
||||
}
|
||||
|
||||
const remoteAddress = nodeRequest.ip;
|
||||
if (remoteAddress) {
|
||||
const headers = new Headers(request.headers);
|
||||
headers.set("x-forwarded-for", remoteAddress);
|
||||
|
||||
return new Request(request, { headers });
|
||||
}
|
||||
|
||||
const headers = new Headers(request.headers);
|
||||
headers.delete("x-forwarded-for");
|
||||
|
||||
return new Request(request, { headers });
|
||||
};
|
||||
|
||||
const handle = ({ request }: { request: Request }) =>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ const envSchema = z
|
|||
MIGRATIONS_PATH: z.string().optional(),
|
||||
APP_VERSION: z.string().default("dev"),
|
||||
TRUSTED_ORIGINS: z.string().optional(),
|
||||
TRUST_PROXY: z.string().default("false"),
|
||||
DISABLE_RATE_LIMITING: z.string().default("false"),
|
||||
APP_SECRET: z.string().min(32).max(256),
|
||||
BASE_URL: z.string(),
|
||||
|
|
@ -53,6 +54,7 @@ const envSchema = z
|
|||
.map((origin) => origin.trim())
|
||||
.filter(Boolean)
|
||||
.concat(s.BASE_URL) ?? [s.BASE_URL],
|
||||
trustProxy: s.TRUST_PROXY === "true",
|
||||
disableRateLimiting: s.DISABLE_RATE_LIMITING === "true",
|
||||
appSecret: s.APP_SECRET,
|
||||
baseUrl: s.BASE_URL,
|
||||
|
|
|
|||
Loading…
Reference in a new issue