From dd05c558758a49e13474c956d0386c2c213f65a4 Mon Sep 17 00:00:00 2001 From: Tate M Walker Date: Wed, 29 Oct 2025 00:14:49 -0500 Subject: [PATCH] global: add support for specifying known proxies (#63) * Add KNOWN_PROXIES * Add known proxy setup in Startup.cs Refactor forwarded headers configuration to use a variable for options. * Document KNOWN_PROXIES in .env file Added documentation for KNOWN_PROXIES environment variable * Clean up Restored license comments and formatting in Constants.cs. * Apply suggestion from @thecodrr * Added KnownProxies functionality at Streetwriters.Common level --------- Co-authored-by: Abdullah Atta --- .env | 5 ++++ Notesnook.API/Startup.cs | 8 +----- Streetwriters.Common/Constants.cs | 4 ++- .../Extensions/AppBuilderExtensions.cs | 28 +++++++++++++++++++ Streetwriters.Identity/Startup.cs | 9 +----- Streetwriters.Messenger/Startup.cs | 8 +----- 6 files changed, 39 insertions(+), 23 deletions(-) diff --git a/.env b/.env index 385a470..d41d1cc 100644 --- a/.env +++ b/.env @@ -46,6 +46,11 @@ TWILIO_SERVICE_SID= # Example: https://app.notesnook.com,http://localhost:3000 NOTESNOOK_CORS_ORIGINS= +# Description: Add known proxies for incoming HTTP requests +# Required: no +# Example: 192.168.1.2,192.168.1.3 +KNOWN_PROXIES= + # Description: This is the public URL for the web app, and is used by the backend for creating redirect URLs (e.g. after email confirmation etc). # Note: the URL has no slashes at the end # Required: yes diff --git a/Notesnook.API/Startup.cs b/Notesnook.API/Startup.cs index 599c7bc..872c088 100644 --- a/Notesnook.API/Startup.cs +++ b/Notesnook.API/Startup.cs @@ -251,13 +251,7 @@ namespace Notesnook.API // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { - if (!env.IsDevelopment()) - { - app.UseForwardedHeaders(new ForwardedHeadersOptions - { - ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto - }); - } + app.UseForwardedHeadersWithKnownProxies(env); app.UseOpenTelemetryPrometheusScrapingEndpoint((context) => context.Request.Path == "/metrics" && context.Connection.LocalPort == 5067); app.UseResponseCompression(); diff --git a/Streetwriters.Common/Constants.cs b/Streetwriters.Common/Constants.cs index 09c8400..0c970ae 100644 --- a/Streetwriters.Common/Constants.cs +++ b/Streetwriters.Common/Constants.cs @@ -57,6 +57,7 @@ namespace Streetwriters.Common public static string? NOTESNOOK_SERVER_HOST => Environment.GetEnvironmentVariable("NOTESNOOK_SERVER_HOST"); public static string? NOTESNOOK_CERT_PATH => Environment.GetEnvironmentVariable("NOTESNOOK_CERT_PATH"); public static string? NOTESNOOK_CERT_KEY_PATH => Environment.GetEnvironmentVariable("NOTESNOOK_CERT_KEY_PATH"); + public static string[] KNOWN_PROXIES => (Environment.GetEnvironmentVariable("KNOWN_PROXIES") ?? "").Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); public static int IDENTITY_SERVER_PORT => int.Parse(Environment.GetEnvironmentVariable("IDENTITY_SERVER_PORT") ?? "80"); public static string? IDENTITY_SERVER_HOST => Environment.GetEnvironmentVariable("IDENTITY_SERVER_HOST"); @@ -79,4 +80,5 @@ namespace Streetwriters.Common public static string? SUBSCRIPTIONS_CERT_KEY_PATH => Environment.GetEnvironmentVariable("SUBSCRIPTIONS_CERT_KEY_PATH"); public static string[] NOTESNOOK_CORS_ORIGINS => Environment.GetEnvironmentVariable("NOTESNOOK_CORS")?.Split(",") ?? new string[] { }; } -} \ No newline at end of file +} + diff --git a/Streetwriters.Common/Extensions/AppBuilderExtensions.cs b/Streetwriters.Common/Extensions/AppBuilderExtensions.cs index 19e10a4..5c4610d 100644 --- a/Streetwriters.Common/Extensions/AppBuilderExtensions.cs +++ b/Streetwriters.Common/Extensions/AppBuilderExtensions.cs @@ -19,9 +19,12 @@ along with this program. If not, see . using System; using System.Collections.Generic; +using System.Net; using System.Text.Json; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.HttpOverrides; using Microsoft.Extensions.DependencyInjection; using WampSharp.AspNetCore.WebSockets.Server; using WampSharp.Binding; @@ -82,5 +85,30 @@ namespace Streetwriters.Common.Extensions return scope.ServiceProvider.GetRequiredService(); } } + + public static IApplicationBuilder UseForwardedHeadersWithKnownProxies(this IApplicationBuilder app, IWebHostEnvironment env, string forwardedForHeaderName = null) + { + if (!env.IsDevelopment()) + { + var forwardedHeadersOptions = new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto + }; + + if (!string.IsNullOrEmpty(forwardedForHeaderName)) + { + forwardedHeadersOptions.ForwardedForHeaderName = forwardedForHeaderName; + } + + foreach (var proxy in Constants.KNOWN_PROXIES) + { + forwardedHeadersOptions.KnownProxies.Add(IPAddress.Parse(proxy)); + } + + app.UseForwardedHeaders(forwardedHeadersOptions); + } + + return app; + } } } \ No newline at end of file diff --git a/Streetwriters.Identity/Startup.cs b/Streetwriters.Identity/Startup.cs index c134c12..2166084 100644 --- a/Streetwriters.Identity/Startup.cs +++ b/Streetwriters.Identity/Startup.cs @@ -212,14 +212,7 @@ namespace Streetwriters.Identity // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { - if (!env.IsDevelopment()) - { - app.UseForwardedHeaders(new ForwardedHeadersOptions - { - ForwardedForHeaderName = "CF-Connecting-IP", - ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto - }); - } + app.UseForwardedHeadersWithKnownProxies(env, "CF-Connecting-IP"); app.UseCors("notesnook"); app.UseVersion(Servers.IdentityServer); diff --git a/Streetwriters.Messenger/Startup.cs b/Streetwriters.Messenger/Startup.cs index 8a510d2..4e01ab2 100644 --- a/Streetwriters.Messenger/Startup.cs +++ b/Streetwriters.Messenger/Startup.cs @@ -94,13 +94,7 @@ namespace Streetwriters.Messenger // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { - if (!env.IsDevelopment()) - { - app.UseForwardedHeaders(new ForwardedHeadersOptions - { - ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto - }); - } + app.UseForwardedHeadersWithKnownProxies(env); app.UseCors("notesnook"); app.UseVersion(Servers.MessengerServer);