Skip to content

Commit

Permalink
Add a nonce option and Render testing (#465)
Browse files Browse the repository at this point in the history
Fix for #393, allows passing a nonce through the new `RenderOptions` API added in #451.

Also a minor optimization for async...we don't need that attribute value for any browser that'll support us today.
  • Loading branch information
NickCraver authored Apr 4, 2020
1 parent 75acbc4 commit b5313cc
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 3 deletions.
2 changes: 1 addition & 1 deletion docs/AspDotNetCore.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerF
```html
<mini-profiler />
```
<sub>Note: `<mini-profiler>` has many options like `max-traces`, `position`, etc. [You can find them in code here](https://github.com/MiniProfiler/dotnet/blob/master/src/MiniProfiler.AspNetCore.Mvc/MiniProfilerScriptTagHelper.cs).</sub>
<sub>Note: `<mini-profiler>` has many options like `max-traces`, `position`, `color-scheme`, `nonce`, etc. [You can find them in code here](https://github.com/MiniProfiler/dotnet/blob/master/src/MiniProfiler.AspNetCore.Mvc/MiniProfilerScriptTagHelper.cs).</sub>
<sub>Note #2: The above tag helper registration may go away in future versions of ASP.NET Core, they're working on smoother alternatives here.</sub>


Expand Down
12 changes: 12 additions & 0 deletions docs/Releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ layout: "default"
### Release Notes
This page tracks major changes included in any update starting with version 4.0.0.3

#### Version 4.2.0 (In preview)
- Added `<script nonce="..." />` to rendering for CSP support ([#465](https://github.com/MiniProfiler/dotnet/pull/465))
- Added dark and "auto" (system preference decides) color themes, total is "Light", "Dark", and "Auto" ([#451](https://github.com/MiniProfiler/dotnet/pull/451))
- Generally moves to CSS 3 variables, for easier custom themes as well.
- Added `SqlServerFormatter.IncludeParameterValues` for excluding actual values in output if desired ([#463](https://github.com/MiniProfiler/dotnet/pull/463))
- Fix for ['i.Started.toUTCString is not a function'](https://github.com/MiniProfiler/dotnet/pull/462) when global serializer options are changed.
- Removed jQuery (built-in) dependency ([#442](https://github.com/MiniProfiler/dotnet/pull/442))
- Drops IE 11 support
- Fix for missing `IMemoryCache` depending on config ([#440](https://github.com/MiniProfiler/dotnet/pull/440))
- Updates `MySqlConnector` to 0.60.1 for misc fixes ([#432](https://github.com/MiniProfiler/dotnet/pull/432)) (thanks [@bgrainger](https://github.com/bgrainger)!)


#### Version 4.1.0
- ASP.NET Core 3.0 support ([MiniProfiler.AspNetCore](https://www.nuget.org/packages/MiniProfiler.AspNetCore/) and [MiniProfiler.AspNetCore.Mvc](https://www.nuget.org/packages/MiniProfiler.AspNetCore.Mvc/) packages, now with a `netcoreapp3.0` build)
- Error support via `CustomTiming.Errored = true`, this will turn the UI red to raise error awareness ([#418](https://github.com/MiniProfiler/dotnet/pull/418) & [#420](https://github.com/MiniProfiler/dotnet/pull/420))
Expand Down
2 changes: 1 addition & 1 deletion samples/Samples.AspNetCore3/Views/Shared/_Layout.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
@RenderSection("scripts", required: false)

@* Simple options are exposed...or make a full options class for customizing. *@
<mini-profiler position="@RenderPosition.Right" max-traces="5" color-scheme="ColorScheme.Auto" />
<mini-profiler position="@RenderPosition.Right" max-traces="5" color-scheme="ColorScheme.Auto" nonce="45" />
@*<mini-profiler options="new RenderOptions { Position = RenderPosition.Right, MaxTracesToShow = 5, ColorScheme = ColorScheme.Auto }" />*@
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ public class MiniProfilerScriptTagHelper : TagHelper
[HtmlAttributeName("color-scheme")]
public ColorScheme? ColorScheme { get; set; }

/// <summary>
/// The JavaScript nonce (if any) to use on this script tag render.
/// </summary>
[HtmlAttributeName("nonce")]
public string Nonce { get; set; }

/// <summary>
/// The options to use when rendering this MiniProfiler.
/// Note: overrides all other options.
Expand All @@ -77,6 +83,7 @@ private RenderOptions GetOptions()
if (ShowControls.HasValue) options.ShowControls = ShowControls;
if (StartHidden.HasValue) options.StartHidden = StartHidden;
if (ColorScheme.HasValue) options.ColorScheme = ColorScheme;
if (Nonce.HasValue()) options.Nonce = Nonce;

return options;
}
Expand Down
6 changes: 5 additions & 1 deletion src/MiniProfiler.Shared/Internal/Render.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public static string Includes(
var sb = StringBuilderCache.Get();
var options = profiler.Options;

sb.Append("<script async=\"async\" id=\"mini-profiler\" src=\"");
sb.Append("<script async id=\"mini-profiler\" src=\"");
sb.Append(path);
sb.Append("includes.min.js?v=");
sb.Append(options.VersionHash);
Expand Down Expand Up @@ -82,6 +82,10 @@ public static string Includes(
{
sb.Append(" data-start-hidden=\"true\"");
}
if (renderOptions?.Nonce.HasValue() ?? false)
{
sb.Append(" nonce=\"").Append(System.Web.HttpUtility.HtmlAttributeEncode(renderOptions.Nonce)).Append("\"");
}

sb.Append(" data-max-traces=\"");
sb.Append((renderOptions?.MaxTracesToShow ?? options.PopupMaxTracesToShow).ToString(CultureInfo.InvariantCulture));
Expand Down
1 change: 1 addition & 0 deletions src/MiniProfiler.Shared/MiniProfiler.Shared.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net461'">
<Reference Include="System.Transactions" />
<Reference Include="System.Web" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="ui\includes.min.css" DependentUpon="includes.css" />
Expand Down
6 changes: 6 additions & 0 deletions src/MiniProfiler.Shared/RenderOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,11 @@ public class RenderOptions
/// Defaults to <see cref="MiniProfilerBaseOptions.ColorScheme"/>.
/// </summary>
public ColorScheme? ColorScheme { get; set; }

/// <summary>
/// A one-time-use nonce to render in the script tag.
/// </summary>
/// <remarks>https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script</remarks>
public string Nonce { get; set; }
}
}
123 changes: 123 additions & 0 deletions tests/MiniProfiler.Tests/RenderTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using StackExchange.Profiling.Internal;
using Xunit;
using Xunit.Abstractions;

namespace StackExchange.Profiling.Tests
{
public class RenderTests : BaseTest
{
public RenderTests(ITestOutputHelper output) : base(output) { }

[Fact]
public void DefaultRender()
{
var profiler = GetBasicProfiler();
var renderOptions = new RenderOptions();
var result = Render.Includes(profiler, "/", true, renderOptions, new List<Guid>() { profiler.Id });
Output.WriteLine("Result: " + result);

Assert.NotNull(result);
Assert.Contains("id=\"mini-profiler\"", result);

var expected = $@"<script async id=""mini-profiler"" src=""/includes.min.js?v={Options.VersionHash}"" data-version=""{Options.VersionHash}"" data-path=""/"" data-current-id=""{profiler.Id}"" data-ids=""{profiler.Id}"" data-position=""Left"""" data-scheme=""Light"" data-authorized=""true"" data-max-traces=""15"" data-toggle-shortcut=""Alt+P"" data-trivial-milliseconds=""2.0"" data-ignored-duplicate-execute-types=""Open,OpenAsync,Close,CloseAsync""></script>";
Assert.Equal(expected, result);
}

[Fact]
public void OptionsSet()
{
var profiler = GetBasicProfiler();
var renderOptions = new RenderOptions()
{
ColorScheme = ColorScheme.Auto,
MaxTracesToShow = 12,
Nonce = "myNonce",
PopupToggleKeyboardShortcut = "Alt+Q",
Position = RenderPosition.Right,
ShowControls = true,
ShowTimeWithChildren = true,
ShowTrivial = true,
StartHidden = true,
TrivialDurationThresholdMilliseconds = 23
};
var result = Render.Includes(profiler, "/", true, renderOptions, new List<Guid>() { profiler.Id });
Output.WriteLine("Result: " + result);

Assert.NotNull(result);
Assert.Contains("id=\"mini-profiler\"", result);

var expected = $@"<script async id=""mini-profiler"" src=""/includes.min.js?v={Options.VersionHash}"" data-version=""{Options.VersionHash}"" data-path=""/"" data-current-id=""{profiler.Id}"" data-ids=""{profiler.Id}"" data-position=""Right"""" data-scheme=""Auto"" data-authorized=""true"" data-trivial=""true"" data-children=""true"" data-controls=""true"" data-start-hidden=""true"" nonce=""myNonce"" data-max-traces=""12"" data-toggle-shortcut=""Alt+Q"" data-trivial-milliseconds=""23"" data-ignored-duplicate-execute-types=""Open,OpenAsync,Close,CloseAsync""></script>";
Assert.Equal(expected, result);
}

[Theory]
[InlineData(null, @"data-scheme=""Light""")]
[InlineData(ColorScheme.Auto, @"data-scheme=""Auto""")]
[InlineData(ColorScheme.Dark, @"data-scheme=""Dark""")]
[InlineData(ColorScheme.Light, @"data-scheme=""Light""")]
public void ColorSchemes(ColorScheme? scheme, string expected)
{
var profiler = GetBasicProfiler();
var renderOptions = new RenderOptions() { ColorScheme = scheme };

var result = Render.Includes(profiler, " / ", true, renderOptions);
Output.WriteLine("Result: " + result);

Assert.NotNull(result);
Assert.Contains(expected, result);
}

[Theory]
[InlineData(null, @"data-position=""Left""")]
[InlineData(RenderPosition.BottomLeft, @"data-position=""BottomLeft""")]
[InlineData(RenderPosition.BottomRight, @"data-position=""BottomRight""")]
[InlineData(RenderPosition.Left, @"data-position=""Left""")]
[InlineData(RenderPosition.Right, @"data-position=""Right""")]
public void Positions(RenderPosition? position, string expected)
{
var profiler = GetBasicProfiler();
var renderOptions = new RenderOptions() { Position = position };

var result = Render.Includes(profiler, " / ", true, renderOptions);
Output.WriteLine("Result: " + result);

Assert.NotNull(result);
Assert.Contains(expected, result);
}

[Fact]
public void Nonce()
{
var profiler = GetBasicProfiler();
var renderOptions = new RenderOptions();

// Default
var result = Render.Includes(profiler, "/", true, renderOptions);
Output.WriteLine("Result: " + result);
Assert.DoesNotContain("nonce", result);

// With nonce
var nonce = Guid.NewGuid().ToString();
renderOptions.Nonce = nonce;
result = Render.Includes(profiler, "/", true, renderOptions);
Assert.Contains($@"nonce=""{nonce}""", result);
}
[Theory]
[InlineData("foo", @"nonce=""foo""")]
[InlineData("foo!@#$%", @"nonce=""foo!@#$%""")]
[InlineData("e31df82b-5102-4134-af97-f29bf724bedd", @"nonce=""e31df82b-5102-4134-af97-f29bf724bedd""")]
[InlineData("f\"oo", @"nonce=""f&quot;oo""")]
[InlineData("󆲢L軾󯮃򮬛ŝ󅫤򄷌򆰃񟕺􆷀;鮡ƾ󤕵ԁf\'\"&23", @"nonce=""󆲢L軾󯮃򮬛ŝ󅫤򄷌򆰃񟕺􆷀;鮡ƾ󤕵ԁf&#39;&quot;&amp;23""")]
public void NonceEncoding(string nonce, string expected)
{
var profiler = GetBasicProfiler();
var renderOptions = new RenderOptions() { Nonce = nonce };

var result = Render.Includes(profiler, "/", true, renderOptions);
Assert.Contains(expected, result);
}
}
}

0 comments on commit b5313cc

Please sign in to comment.