From 465cb1ff6cfe898202cea7e8cb22b9ae9f9fb840 Mon Sep 17 00:00:00 2001 From: daniel-c-harvey Date: Sun, 7 Jun 2026 16:53:49 -0400 Subject: [PATCH 1/2] feat: allow /FramePlayer to be embedded in external iframes via CORS + CSP frame-ancestors --- DeepDrftPublic/Program.cs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/DeepDrftPublic/Program.cs b/DeepDrftPublic/Program.cs index dff19a3..695d6ed 100644 --- a/DeepDrftPublic/Program.cs +++ b/DeepDrftPublic/Program.cs @@ -24,6 +24,11 @@ Startup.ConfigureDomainServices(builder); // Add services to the container. builder.Services.AddControllers(); +builder.Services.AddCors(options => +{ + options.AddPolicy("FramePlayerEmbedPolicy", policy => + policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()); +}); builder.Services.AddRazorComponents() .AddInteractiveServerComponents() .AddInteractiveWebAssemblyComponents(); @@ -72,6 +77,26 @@ else } } +app.UseCors("FramePlayerEmbedPolicy"); + +// For requests to /FramePlayer, remove any X-Frame-Options header and set a permissive +// frame-ancestors CSP so the page can be embedded in iframes on any external domain. +// OnStarting fires just before headers are flushed, ensuring this overrides headers set +// by other middleware (e.g. HSTS, reverse proxy). +app.Use(async (context, next) => +{ + if (context.Request.Path.StartsWithSegments("/FramePlayer", StringComparison.OrdinalIgnoreCase)) + { + context.Response.OnStarting(() => + { + context.Response.Headers.Remove("X-Frame-Options"); + context.Response.Headers["Content-Security-Policy"] = "frame-ancestors *"; + return Task.CompletedTask; + }); + } + await next(); +}); + // Antiforgery is required by Blazor form handling. Authentication / authorization // middleware is intentionally absent — this host is fully anonymous. app.UseAntiforgery(); From ceb0984262ee3ea8c95572f26b7376c5bd35095a Mon Sep 17 00:00:00 2001 From: daniel-c-harvey Date: Sun, 7 Jun 2026 17:16:49 -0400 Subject: [PATCH 2/2] fix: force FramePlayer to WASM-only render mode; document CORS policy intent --- DeepDrftPublic.Client/Pages/FramePlayer.razor | 1 + DeepDrftPublic/Program.cs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/DeepDrftPublic.Client/Pages/FramePlayer.razor b/DeepDrftPublic.Client/Pages/FramePlayer.razor index 177c406..24b1ab6 100644 --- a/DeepDrftPublic.Client/Pages/FramePlayer.razor +++ b/DeepDrftPublic.Client/Pages/FramePlayer.razor @@ -5,6 +5,7 @@ @page "/FramePlayer" @layout EmbedLayout +@rendermode InteractiveWebAssembly diff --git a/DeepDrftPublic/Program.cs b/DeepDrftPublic/Program.cs index 695d6ed..8add77d 100644 --- a/DeepDrftPublic/Program.cs +++ b/DeepDrftPublic/Program.cs @@ -77,6 +77,9 @@ else } } +// CORS policy registered for hygiene and potential direct cross-origin API consumers. +// The FramePlayer embed use case does not require this: WASM inside a cross-site iframe +// fetches to the same deepdrft.com origin, so all API calls are same-origin. app.UseCors("FramePlayerEmbedPolicy"); // For requests to /FramePlayer, remove any X-Frame-Options header and set a permissive