Skip to content

Commit

Permalink
Fix: Support cloudflare proxy IP (#702)
Browse files Browse the repository at this point in the history
* temp: print debug headers

* stringify

* read cf header

* Resolve Cloudflare IP

* print trustproxy state

* pr comments
  • Loading branch information
arcoraven authored Oct 3, 2024
1 parent 8992694 commit 2770527
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 18 deletions.
2 changes: 1 addition & 1 deletion src/scripts/apply-migrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const main = async () => {

logger({
level: "info",
message: "Completed migrations without errors.",
message: "Completed migrations successfully.",
service: "server",
});
} catch (e) {
Expand Down
17 changes: 13 additions & 4 deletions src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,23 @@ export const initServer = async () => {
};
}

// env.TRUST_PROXY is used to determine if the X-Forwarded-For header should be trusted.
// This option is force enabled for cloud-hosted Engines.
// See: https://fastify.dev/docs/latest/Reference/Server/#trustproxy
const trustProxy = env.TRUST_PROXY || !!env.ENGINE_TIER;
if (trustProxy) {
logger({
service: "server",
level: "info",
message: "Server is enabled with trustProxy.",
});
}

// Start the server with middleware.
const server: FastifyInstance = fastify({
connectionTimeout: SERVER_CONNECTION_TIMEOUT,
disableRequestLogging: true,
// env.TRUST_PROXY is used to determine if the X-Forwarded-For header should be trusted.
// This option is force enabled for cloud-hosted Engines.
// See: https://fastify.dev/docs/latest/Reference/Server/#trustproxy
trustProxy: env.TRUST_PROXY || !!env.ENGINE_TIER,
trustProxy,
...(env.ENABLE_HTTPS ? httpsObject : {}),
}).withTypeProvider<TypeBoxTypeProvider>();

Expand Down
36 changes: 23 additions & 13 deletions src/server/middleware/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,12 +265,12 @@ const handleWebsocketAuth = async (
req.headers.authorization = `Bearer ${jwt}`;
const user = await getUser(req);

const isIpInAllowlist = await checkIpInAllowlist(req);
if (!isIpInAllowlist) {
const { isAllowed, ip } = await checkIpInAllowlist(req);
if (!isAllowed) {
logger({
service: "server",
level: "error",
message: `Unauthorized IP address: ${req.ip}`,
message: `Unauthorized IP address: ${ip}`,
});
return {
isAuthed: false,
Expand Down Expand Up @@ -339,12 +339,12 @@ const handleKeypairAuth = async (args: {
throw error;
}

const isIpInAllowlist = await checkIpInAllowlist(req);
if (!isIpInAllowlist) {
const { isAllowed, ip } = await checkIpInAllowlist(req);
if (!isAllowed) {
logger({
service: "server",
level: "error",
message: `Unauthorized IP address: ${req.ip}`,
message: `Unauthorized IP address: ${ip}`,
});
throw new Error(
"Unauthorized IP address. See: https://portal.thirdweb.com/engine/features/security",
Expand Down Expand Up @@ -400,12 +400,12 @@ const handleAccessToken = async (
return { isAuthed: false };
}

const isIpInAllowlist = await checkIpInAllowlist(req);
if (!isIpInAllowlist) {
const { isAllowed, ip } = await checkIpInAllowlist(req);
if (!isAllowed) {
logger({
service: "server",
level: "error",
message: `Unauthorized IP address: ${req.ip}`,
message: `Unauthorized IP address: ${ip}`,
});
return {
isAuthed: false,
Expand Down Expand Up @@ -523,12 +523,22 @@ const hashRequestBody = (req: FastifyRequest): string => {
* @returns boolean
* @async
*/
const checkIpInAllowlist = async (req: FastifyRequest) => {
const config = await getConfig();
const checkIpInAllowlist = async (
req: FastifyRequest,
): Promise<{ isAllowed: boolean; ip: string }> => {
let ip = req.ip;
const trustProxy = env.TRUST_PROXY || !!env.ENGINE_TIER;
if (trustProxy && req.headers["cf-connecting-ip"]) {
ip = req.headers["cf-connecting-ip"] as string;
}

const config = await getConfig();
if (config.ipAllowlist.length === 0) {
return true;
return { isAllowed: true, ip };
}

return config.ipAllowlist.includes(req.ip);
return {
isAllowed: config.ipAllowlist.includes(ip),
ip,
};
};

0 comments on commit 2770527

Please sign in to comment.