From a5ed11dc6d51c5e05186e420f355306c93174078 Mon Sep 17 00:00:00 2001 From: Raif Atef Date: Sat, 28 Jan 2023 02:20:44 +0200 Subject: [PATCH 01/11] Eliminate the use of inline styles, making it compatible with strict CSP for style. --- src/MiniProfiler.Shared/ui/includes.css | 3 +++ src/MiniProfiler.Shared/ui/includes.less | 4 ++++ src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts | 16 +++++++++++++--- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/MiniProfiler.Shared/ui/includes.css b/src/MiniProfiler.Shared/ui/includes.css index 90936eac..f6c48f69 100644 --- a/src/MiniProfiler.Shared/ui/includes.css +++ b/src/MiniProfiler.Shared/ui/includes.css @@ -179,6 +179,9 @@ .mp-result table.mp-client-timings { margin-top: 10px; } +.mp-result table.mp-client-timings th:first-child { + text-align: left; +} .mp-result table.mp-client-timings td:nth-child(2) { width: 100%; padding: 0; diff --git a/src/MiniProfiler.Shared/ui/includes.less b/src/MiniProfiler.Shared/ui/includes.less index 150dfebc..1546728d 100644 --- a/src/MiniProfiler.Shared/ui/includes.less +++ b/src/MiniProfiler.Shared/ui/includes.less @@ -153,6 +153,10 @@ table.mp-client-timings { margin-top: 10px; + + th:first-child { + text-align: left; + } td:nth-child(2) { width: 100%; diff --git a/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts b/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts index f4ee8521..a51012f9 100644 --- a/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts +++ b/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts @@ -728,7 +728,7 @@ namespace StackExchange.Profiling { let str = ` ${renderDebugInfo(timing)} - 0 ? ` style="padding-left:${timing.Depth * 11}px;"` : ''}> + 0 ? ` data-padding-left="${timing.Depth * 11}px"` : ''}> ${encode(timing.Name)} @@ -830,7 +830,7 @@ namespace StackExchange.Profiling { - + @@ -840,7 +840,7 @@ namespace StackExchange.Profiling { ${list.map((t) => ` - + @@ -970,6 +970,16 @@ namespace StackExchange.Profiling { for (let i = 0; i < toRemove; i++) { results[i].parentNode.removeChild(results[i]); } + // dynamic padding, margin and width + this.container.querySelectorAll("[data-padding-left]").forEach(function (element) { + element.style.paddingLeft = element.dataset.paddingLeft; + }); + this.container.querySelectorAll("[data-margin-left]").forEach(function (element) { + element.style.marginLeft = element.dataset.marginLeft; + }); + this.container.querySelectorAll("[data-width]").forEach(function (element) { + element.style.width = element.dataset.width; + }); } private scrollToQuery = (link: HTMLElement, queries: HTMLElement) => { From ca4d9dc20e39dff2b2ffb2ab6985c39f96fe3c79 Mon Sep 17 00:00:00 2001 From: Raif Atef Date: Sat, 28 Jan 2023 03:39:31 +0200 Subject: [PATCH 02/11] Attempt to eliminate redraws. --- .../ui/lib/MiniProfiler.ts | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts b/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts index a51012f9..9aaeb45d 100644 --- a/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts +++ b/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts @@ -957,11 +957,24 @@ namespace StackExchange.Profiling { } const profilerHtml = this.renderProfiler(json, true); + const nonVisibleElement = document.createElement("div"); + nonVisibleElement.innerHTML = profilerHtml; + + // dynamic padding, margin and width + nonVisibleElement.querySelectorAll("[data-padding-left]").forEach(function (element) { + element.style.paddingLeft = element.dataset.paddingLeft; + }); + nonVisibleElement.querySelectorAll("[data-margin-left]").forEach(function (element) { + element.style.marginLeft = element.dataset.marginLeft; + }); + nonVisibleElement.querySelectorAll("[data-width]").forEach(function (element) { + element.style.width = element.dataset.width; + }); if (this.controls) { - this.controls.insertAdjacentHTML('beforebegin', profilerHtml); + this.controls.insertAdjacentElement('beforebegin', nonVisibleElement.firstElementChild); } else { - this.container.insertAdjacentHTML('beforeend', profilerHtml); + this.container.insertAdjacentElement('beforeend', nonVisibleElement.firstElementChild); } // limit count to maxTracesToShow, remove those before it @@ -970,16 +983,6 @@ namespace StackExchange.Profiling { for (let i = 0; i < toRemove; i++) { results[i].parentNode.removeChild(results[i]); } - // dynamic padding, margin and width - this.container.querySelectorAll("[data-padding-left]").forEach(function (element) { - element.style.paddingLeft = element.dataset.paddingLeft; - }); - this.container.querySelectorAll("[data-margin-left]").forEach(function (element) { - element.style.marginLeft = element.dataset.marginLeft; - }); - this.container.querySelectorAll("[data-width]").forEach(function (element) { - element.style.width = element.dataset.width; - }); } private scrollToQuery = (link: HTMLElement, queries: HTMLElement) => { From 82fe3cb6ef41a9c7ded6671dcc17ed68dbfe5463 Mon Sep 17 00:00:00 2001 From: Raif Atef Date: Fri, 16 Jun 2023 00:08:46 +0300 Subject: [PATCH 03/11] Introduce NonceGetter option. Use it to render the nonce if available in all tags and scripts. --- .../MiniProfilerExtensions.cs | 1 + .../MiniProfilerMiddleware.cs | 2 +- .../Internal/MiniProfilerBaseOptions.cs | 6 +++ src/MiniProfiler.Shared/Internal/Render.cs | 49 ++++++++++++++++--- src/MiniProfiler/MiniProfilerHandler.cs | 2 +- tests/MiniProfiler.Tests/RenderTests.cs | 4 +- 6 files changed, 52 insertions(+), 12 deletions(-) diff --git a/src/MiniProfiler.AspNetCore/MiniProfilerExtensions.cs b/src/MiniProfiler.AspNetCore/MiniProfilerExtensions.cs index d62ef997..18ceb8eb 100644 --- a/src/MiniProfiler.AspNetCore/MiniProfilerExtensions.cs +++ b/src/MiniProfiler.AspNetCore/MiniProfilerExtensions.cs @@ -35,6 +35,7 @@ public static HtmlString RenderIncludes( path: context.Request.PathBase + path, isAuthorized: state?.IsAuthorized ?? false, renderOptions, + context.RequestServices, requestIDs: state?.RequestIDs); return new HtmlString(result); diff --git a/src/MiniProfiler.AspNetCore/MiniProfilerMiddleware.cs b/src/MiniProfiler.AspNetCore/MiniProfilerMiddleware.cs index c2ba22a9..94dd3199 100644 --- a/src/MiniProfiler.AspNetCore/MiniProfilerMiddleware.cs +++ b/src/MiniProfiler.AspNetCore/MiniProfilerMiddleware.cs @@ -406,7 +406,7 @@ private async Task ResultsListAsync(HttpContext context) else { context.Response.ContentType = "text/html; charset=utf-8"; - return Render.SingleResultHtml(profiler, context.Request.PathBase + Options.RouteBasePath.Value.EnsureTrailingSlash()); + return Render.SingleResultHtml(profiler, context.RequestServices, context.Request.PathBase + Options.RouteBasePath.Value.EnsureTrailingSlash()); } } } diff --git a/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs b/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs index c798a546..716ebe2a 100644 --- a/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs +++ b/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Reflection; +using System.Web; using StackExchange.Profiling.Data; using StackExchange.Profiling.Helpers; using StackExchange.Profiling.SqlFormatters; @@ -227,6 +228,11 @@ public class MiniProfilerBaseOptions /// public Func? TimingInstrumentationProvider { get; set; } + /// + /// Called whenever a nonce is required for a script or style tag for each request. + /// + public Func NonceGetter { get; set; } = _ => null; + /// /// Called when passed to . /// diff --git a/src/MiniProfiler.Shared/Internal/Render.cs b/src/MiniProfiler.Shared/Internal/Render.cs index 737fbf94..9ba118bd 100644 --- a/src/MiniProfiler.Shared/Internal/Render.cs +++ b/src/MiniProfiler.Shared/Internal/Render.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Web; namespace StackExchange.Profiling.Internal { @@ -16,13 +17,15 @@ public static class Render /// The profiler to render a tag for. /// The root path that MiniProfiler is being served from. /// Whether the current user is authorized for MiniProfiler. + /// The current http request service provider /// The option overrides (if any) to use rendering this MiniProfiler. /// The request IDs to fetch for this render. public static string Includes( MiniProfiler profiler, string path, bool isAuthorized, - RenderOptions renderOptions, + RenderOptions? renderOptions, + IServiceProvider? serviceProvider = null, List? requestIDs = null) { var sb = StringBuilderCache.Get(); @@ -84,9 +87,12 @@ public static string Includes( { sb.Append(" data-start-hidden=\"true\""); } - if (renderOptions?.Nonce.HasValue() ?? false) + + var nonce = renderOptions?.Nonce ?? + (serviceProvider != null ? profiler.Options.NonceGetter(serviceProvider) : null); + if (nonce?.HasValue() ?? false) { - sb.Append(" nonce=\"").Append(System.Web.HttpUtility.HtmlAttributeEncode(renderOptions.Nonce)).Append("\""); + sb.Append(" nonce=\"").Append(HttpUtility.HtmlAttributeEncode(nonce)).Append("\""); } sb.Append(" data-max-traces=\""); @@ -131,6 +137,7 @@ public static string Includes( /// The maximum number of profilers to show (before the oldest is removed - defaults to ). /// Whether to show the controls (defaults to ). /// Whether to start hidden (defaults to ). + /// Content script policy nonce value to use for script and style tags generated. public static string Includes( MiniProfiler profiler, string path, @@ -141,12 +148,22 @@ public static string Includes( bool? showTimeWithChildren = null, int? maxTracesToShow = null, bool? showControls = null, - bool? startHidden = null) + bool? startHidden = null, + string? nonce = null) { var sb = StringBuilderCache.Get(); var options = profiler.Options; - sb.Append(""); - sb.Append(Includes(profiler, path: path, isAuthorized: true)); + sb.Append(Includes(profiler, path: path, isAuthorized: true, nonce: nonce)); sb.Append(@"
"); return sb.ToString(); } diff --git a/src/MiniProfiler/MiniProfilerHandler.cs b/src/MiniProfiler/MiniProfilerHandler.cs index 63926687..fca4f711 100644 --- a/src/MiniProfiler/MiniProfilerHandler.cs +++ b/src/MiniProfiler/MiniProfilerHandler.cs @@ -279,7 +279,7 @@ private static string ResultsJson(HttpContext context, MiniProfiler profiler) private string ResultsFullPage(HttpContext context, MiniProfiler profiler) { context.Response.ContentType = "text/html; charset=utf-8"; - return Render.SingleResultHtml(profiler, VirtualPathUtility.ToAbsolute(Options.RouteBasePath).EnsureTrailingSlash()); + return Render.SingleResultHtml(profiler, context, VirtualPathUtility.ToAbsolute(Options.RouteBasePath).EnsureTrailingSlash()); } private bool TryGetResource(string filename, out string resource) diff --git a/tests/MiniProfiler.Tests/RenderTests.cs b/tests/MiniProfiler.Tests/RenderTests.cs index 7aa8bcd7..a88eba0c 100644 --- a/tests/MiniProfiler.Tests/RenderTests.cs +++ b/tests/MiniProfiler.Tests/RenderTests.cs @@ -15,7 +15,7 @@ public void DefaultRender() { var profiler = GetBasicProfiler(); var renderOptions = new RenderOptions(); - var result = Render.Includes(profiler, "/", true, renderOptions, new List() { profiler.Id }); + var result = Render.Includes(profiler, "/", true, renderOptions, null, new List() { profiler.Id }); Output.WriteLine("Result: " + result); Assert.NotNull(result); @@ -43,7 +43,7 @@ public void OptionsSet() TrivialDurationThresholdMilliseconds = 23, DecimalPlaces = 1, }; - var result = Render.Includes(profiler, "/", true, renderOptions, new List() { profiler.Id }); + var result = Render.Includes(profiler, "/", true, renderOptions, null, new List() { profiler.Id }); Output.WriteLine("Result: " + result); Assert.NotNull(result); From b4ef01c7ea3289fea8908735dea976f615e6580b Mon Sep 17 00:00:00 2001 From: Raif Atef Date: Fri, 16 Jun 2023 01:18:10 +0300 Subject: [PATCH 04/11] Fix style rendering in full results page. --- .../ui/lib/MiniProfiler.ts | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts b/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts index 9aaeb45d..25a69e26 100644 --- a/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts +++ b/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts @@ -355,7 +355,7 @@ namespace StackExchange.Profiling { // profiler will be defined in the full page's head window.profiler.Started = new Date('' + window.profiler.Started); // Ugh, JavaScript const profilerHtml = mp.renderProfiler(window.profiler, false); - mp.container.insertAdjacentHTML('beforeend', profilerHtml); + mp.setStylesAndDisplay(profilerHtml); // highight mp.container.querySelectorAll('pre code').forEach(block => mp.highlight(block as HTMLElement)); @@ -957,25 +957,7 @@ namespace StackExchange.Profiling { } const profilerHtml = this.renderProfiler(json, true); - const nonVisibleElement = document.createElement("div"); - nonVisibleElement.innerHTML = profilerHtml; - - // dynamic padding, margin and width - nonVisibleElement.querySelectorAll("[data-padding-left]").forEach(function (element) { - element.style.paddingLeft = element.dataset.paddingLeft; - }); - nonVisibleElement.querySelectorAll("[data-margin-left]").forEach(function (element) { - element.style.marginLeft = element.dataset.marginLeft; - }); - nonVisibleElement.querySelectorAll("[data-width]").forEach(function (element) { - element.style.width = element.dataset.width; - }); - - if (this.controls) { - this.controls.insertAdjacentElement('beforebegin', nonVisibleElement.firstElementChild); - } else { - this.container.insertAdjacentElement('beforeend', nonVisibleElement.firstElementChild); - } + this.setStylesAndDisplay(profilerHtml); // limit count to maxTracesToShow, remove those before it const results = this.container.querySelectorAll('.mp-result'); @@ -984,6 +966,28 @@ namespace StackExchange.Profiling { results[i].parentNode.removeChild(results[i]); } } + + private setStylesAndDisplay(profilerHtml: string) { + const nonVisibleElement = document.createElement("div"); + nonVisibleElement.innerHTML = profilerHtml; + + // dynamic padding, margin and width + nonVisibleElement.querySelectorAll("[data-padding-left]").forEach(function (element) { + element.style.paddingLeft = element.dataset.paddingLeft; + }); + nonVisibleElement.querySelectorAll("[data-margin-left]").forEach(function (element) { + element.style.marginLeft = element.dataset.marginLeft; + }); + nonVisibleElement.querySelectorAll("[data-width]").forEach(function (element) { + element.style.width = element.dataset.width; + }); + + if (this.controls) { + this.controls.insertAdjacentElement('beforebegin', nonVisibleElement.firstElementChild); + } else { + this.container.insertAdjacentElement('beforeend', nonVisibleElement.firstElementChild); + } + } private scrollToQuery = (link: HTMLElement, queries: HTMLElement) => { const id = link.closest('tr').dataset['timingId']; From 06533e4dcffdca456a133801f527ecd965395b55 Mon Sep 17 00:00:00 2001 From: Raif Atef Date: Fri, 16 Jun 2023 01:34:43 +0300 Subject: [PATCH 05/11] Remove unused import. --- src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs b/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs index 716ebe2a..fe392c70 100644 --- a/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs +++ b/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Reflection; -using System.Web; using StackExchange.Profiling.Data; using StackExchange.Profiling.Helpers; using StackExchange.Profiling.SqlFormatters; From a943d5b2c2c51f6dd3ac07f0dfcf6d8601fb5307 Mon Sep 17 00:00:00 2001 From: Raif Atef Date: Fri, 16 Jun 2023 01:36:37 +0300 Subject: [PATCH 06/11] Nit. --- src/MiniProfiler.Shared/Internal/Render.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/MiniProfiler.Shared/Internal/Render.cs b/src/MiniProfiler.Shared/Internal/Render.cs index 9ba118bd..28927b29 100644 --- a/src/MiniProfiler.Shared/Internal/Render.cs +++ b/src/MiniProfiler.Shared/Internal/Render.cs @@ -268,11 +268,7 @@ public static string SingleResultHtml(MiniProfiler profiler, IServiceProvider se { sb.Append(" nonce=\""); sb.Append(HttpUtility.HtmlAttributeEncode(nonce)); - sb.Append("\" "); - } - else - { - sb.Append(' '); + sb.Append("\""); } sb.Append(">var profiler = "); From 3180a07c1066a8f5d6cbc623e6c7d5b2d67b7e88 Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Wed, 2 Aug 2023 18:28:20 -0400 Subject: [PATCH 07/11] Fix formatting Spaces > tabs :) --- src/MiniProfiler.Shared/ui/includes.less | 11 +++++------ src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts | 10 +++++----- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/MiniProfiler.Shared/ui/includes.less b/src/MiniProfiler.Shared/ui/includes.less index 1546728d..c5820e43 100644 --- a/src/MiniProfiler.Shared/ui/includes.less +++ b/src/MiniProfiler.Shared/ui/includes.less @@ -51,7 +51,7 @@ } .mp-scheme-light { - color-scheme: light; + color-scheme: light; } .mp-scheme-dark { @@ -72,7 +72,6 @@ --mp-highlight-keyword-color: #36a1ef; /* Borders */ --mp-result-border: solid 0.5px #575757; - color-scheme: dark; body { @@ -153,10 +152,10 @@ table.mp-client-timings { margin-top: 10px; - - th:first-child { - text-align: left; - } + + th:first-child { + text-align: left; + } td:nth-child(2) { width: 100%; diff --git a/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts b/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts index 25a69e26..0e06984f 100644 --- a/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts +++ b/src/MiniProfiler.Shared/ui/lib/MiniProfiler.ts @@ -319,11 +319,11 @@ namespace StackExchange.Profiling { // fetch and render results mp.fetchResults(mp.options.ids); - + let lsDisplayValue; try { lsDisplayValue = window.localStorage.getItem('MiniProfiler-Display'); - } catch(e) { } + } catch (e) { } if (lsDisplayValue) { mp.container.style.display = lsDisplayValue; @@ -957,7 +957,7 @@ namespace StackExchange.Profiling { } const profilerHtml = this.renderProfiler(json, true); - this.setStylesAndDisplay(profilerHtml); + this.setStylesAndDisplay(profilerHtml); // limit count to maxTracesToShow, remove those before it const results = this.container.querySelectorAll('.mp-result'); @@ -966,7 +966,7 @@ namespace StackExchange.Profiling { results[i].parentNode.removeChild(results[i]); } } - + private setStylesAndDisplay(profilerHtml: string) { const nonVisibleElement = document.createElement("div"); nonVisibleElement.innerHTML = profilerHtml; @@ -1238,7 +1238,7 @@ namespace StackExchange.Profiling { results.style.display = newValue; try { window.localStorage.setItem('MiniProfiler-Display', newValue); - } catch(e) { } + } catch (e) { } } }, false); } From 9520afe6864bae2c4c13f61a1009d3f10c78acb4 Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Wed, 2 Aug 2023 18:29:56 -0400 Subject: [PATCH 08/11] Add release notes --- docs/Releases.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/Releases.md b/docs/Releases.md index cd85345e..f8185323 100644 --- a/docs/Releases.md +++ b/docs/Releases.md @@ -6,6 +6,8 @@ layout: "default" This page tracks major changes included in any update starting with version 4.0.0.3 #### Unreleased +- **New**: + - Support for strict CSP (dynamic inline styles removed) ([#634](https://github.com/MiniProfiler/dotnet/pull/634) - thanks [rwasef1830](https://github.com/rwasef1830)) - **Fixes/Changes**: - Upgraded MongoDB driver, allowing automatic index creation and profiler expiration ([#613](https://github.com/MiniProfiler/dotnet/pull/613) - thanks [IanKemp](https://github.com/IanKemp)) From 1b2d58912fceb7bbc03c6ee4918ab177fd270b3f Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Wed, 2 Aug 2023 21:10:51 -0400 Subject: [PATCH 09/11] Update Bundler to stop erroring so much --- src/MiniProfiler.Shared/MiniProfiler.Shared.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MiniProfiler.Shared/MiniProfiler.Shared.csproj b/src/MiniProfiler.Shared/MiniProfiler.Shared.csproj index 760e8d15..7a762319 100644 --- a/src/MiniProfiler.Shared/MiniProfiler.Shared.csproj +++ b/src/MiniProfiler.Shared/MiniProfiler.Shared.csproj @@ -14,7 +14,7 @@ - + From 03d5f6379a537eca2ec73cfc32fd2b9dfd891cb5 Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Wed, 2 Aug 2023 21:15:19 -0400 Subject: [PATCH 10/11] Simplify naming, support list page as well --- .../MiniProfilerMiddleware.cs | 2 +- .../Internal/MiniProfilerBaseOptions.cs | 2 +- src/MiniProfiler.Shared/Internal/Render.cs | 31 +++++++++---------- src/MiniProfiler/MiniProfilerHandler.cs | 2 +- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/MiniProfiler.AspNetCore/MiniProfilerMiddleware.cs b/src/MiniProfiler.AspNetCore/MiniProfilerMiddleware.cs index 94dd3199..e3ee34f5 100644 --- a/src/MiniProfiler.AspNetCore/MiniProfilerMiddleware.cs +++ b/src/MiniProfiler.AspNetCore/MiniProfilerMiddleware.cs @@ -291,7 +291,7 @@ private async Task ResultsIndexAsync(HttpContext context) context.Response.ContentType = "text/html; charset=utf-8"; var path = context.Request.PathBase + Options.RouteBasePath.Value.EnsureTrailingSlash(); - return Render.ResultListHtml(Options, path); + return Render.ResultListHtml(Options, context.RequestServices, path); } /// diff --git a/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs b/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs index 242bd8c4..6f2b65f6 100644 --- a/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs +++ b/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs @@ -230,7 +230,7 @@ public class MiniProfilerBaseOptions /// /// Called whenever a nonce is required for a script or style tag for each request. /// - public Func NonceGetter { get; set; } = _ => null; + public Func NonceProvider { get; set; } = _ => null; /// /// Called when passed to . diff --git a/src/MiniProfiler.Shared/Internal/Render.cs b/src/MiniProfiler.Shared/Internal/Render.cs index 28927b29..032466c7 100644 --- a/src/MiniProfiler.Shared/Internal/Render.cs +++ b/src/MiniProfiler.Shared/Internal/Render.cs @@ -17,8 +17,8 @@ public static class Render /// The profiler to render a tag for. /// The root path that MiniProfiler is being served from. /// Whether the current user is authorized for MiniProfiler. - /// The current http request service provider /// The option overrides (if any) to use rendering this MiniProfiler. + /// The current request service provider. /// The request IDs to fetch for this render. public static string Includes( MiniProfiler profiler, @@ -89,7 +89,7 @@ public static string Includes( } var nonce = renderOptions?.Nonce ?? - (serviceProvider != null ? profiler.Options.NonceGetter(serviceProvider) : null); + (serviceProvider != null ? profiler.Options.NonceProvider?.Invoke(serviceProvider) : null); if (nonce?.HasValue() ?? false) { sb.Append(" nonce=\"").Append(HttpUtility.HtmlAttributeEncode(nonce)).Append("\""); @@ -154,19 +154,16 @@ public static string Includes( var sb = StringBuilderCache.Get(); var options = profiler.Options; - sb.Append("A full HTML page for this MiniProfiler. public static string SingleResultHtml(MiniProfiler profiler, IServiceProvider serviceProvider, string path) { - var nonce = profiler.Options.NonceGetter(serviceProvider) ?? string.Empty; - var sb = StringBuilderCache.Get(); sb.Append(""); sb.Append(profiler.Name); @@ -264,6 +259,7 @@ public static string SingleResultHtml(MiniProfiler profiler, IServiceProvider se sb.Append(profiler.DurationMilliseconds.ToString(CultureInfo.InvariantCulture)); sb.Append(" ms) - Profiling Results /// The options to render for. + /// The current request service provider. /// The root path that MiniProfiler is being served from. /// A full HTML page for this MiniProfiler. - public static string ResultListHtml(MiniProfilerBaseOptions options, string path) + public static string ResultListHtml(MiniProfilerBaseOptions options, IServiceProvider serviceProvider, string path) { var version = options.VersionHash; + var nonce = options.NonceProvider?.Invoke(serviceProvider) ?? string.Empty; + var nonceAttribute = !string.IsNullOrWhiteSpace(nonce) ? " nonce=\"" + HttpUtility.HtmlAttributeEncode(nonce) + "\"" : null; return $@" List of profiling sessions - + - + MiniProfiler.listInit({{path: '{path}', version: '{version}', colorScheme: '{options.ColorScheme}'}});
client eventclient event duration (ms) from start (ms)
${encode(t.name)}
${(t.duration >= 0 ? `${duration(t.duration, 0)}` : '')}
diff --git a/src/MiniProfiler/MiniProfilerHandler.cs b/src/MiniProfiler/MiniProfilerHandler.cs index fca4f711..ed6ef36c 100644 --- a/src/MiniProfiler/MiniProfilerHandler.cs +++ b/src/MiniProfiler/MiniProfilerHandler.cs @@ -143,7 +143,7 @@ public void ProcessRequest(HttpContext context) context.Response.ContentType = "text/html; charset=utf-8"; var path = VirtualPathUtility.ToAbsolute(Options.RouteBasePath).EnsureTrailingSlash(); - return Render.ResultListHtml(Options, path); + return Render.ResultListHtml(Options, context, path); } /// From 787535516cacbfa0e5c9ca31b24595afaa5c0acc Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Wed, 2 Aug 2023 21:15:31 -0400 Subject: [PATCH 11/11] Add nonce to sample project for demo --- .../Samples.AspNet/Helpers/NonceService.cs | 20 +++++++++++++++++++ .../Pages/RazorPagesSample.cshtml | 2 +- samples/Samples.AspNet/Startup.cs | 12 +++++++++++ .../Samples.AspNet/Views/Shared/Index.cshtml | 2 +- .../Views/Shared/_Layout.cshtml | 2 +- 5 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 samples/Samples.AspNet/Helpers/NonceService.cs diff --git a/samples/Samples.AspNet/Helpers/NonceService.cs b/samples/Samples.AspNet/Helpers/NonceService.cs new file mode 100644 index 00000000..3c7ac3ba --- /dev/null +++ b/samples/Samples.AspNet/Helpers/NonceService.cs @@ -0,0 +1,20 @@ +using System; +using System.Security.Cryptography; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; + +namespace Samples.AspNetCore +{ + /// + /// Nonce service (custom implementation) for sharing a random nonce for the lifetime of a request. + /// + public class NonceService + { + public string RequestNonce { get; } = Convert.ToBase64String(RandomNumberGenerator.GetBytes(64)); + } + + public static class NonceExtensions + { + public static string? GetNonce(this HttpContext context) => context.RequestServices.GetService()?.RequestNonce; + } +} diff --git a/samples/Samples.AspNet/Pages/RazorPagesSample.cshtml b/samples/Samples.AspNet/Pages/RazorPagesSample.cshtml index 1cd9cf6d..9c315856 100644 --- a/samples/Samples.AspNet/Pages/RazorPagesSample.cshtml +++ b/samples/Samples.AspNet/Pages/RazorPagesSample.cshtml @@ -13,7 +13,7 @@ @section scripts { -