Skip to content

Commit d4a004f

Browse files
authored
[dev-v5] Add MarkupStringSanitized to enhances security and clarifies usage. (#4424)
* Make Title in FluentMessageBar plain text only The Title property now accepts only plain strings and no HTML markup. For custom or formatted titles, use the ChildContent property. Updated code and docs to clarify usage and provide examples. * Sanitize inline CSS to prevent XSS in custom styles Introduce MarkupSanitizedOptions and MarkupStringSanitized to sanitize inline CSS styles * Update MarkupStringSanitized * Update MarkupStringSanitized * Refactoring MarkupStringSanitized * Refactoring * Refactor * Add Unit Tests * Update components to use MarkupStringSanitized * Update Dialog and Add unit tests * Refactor * Fix errors * Update doc * Refactor sanitizers to use [GeneratedRegex] partial methods * Add Unit Tests * Update doc
1 parent 66dd9fb commit d4a004f

20 files changed

+516
-45
lines changed

src/Core/Components/Base/FluentComponentBase.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public abstract class FluentComponentBase : ComponentBase, IAsyncDisposable, IFl
2424
protected FluentComponentBase(LibraryConfiguration configuration)
2525
{
2626
configuration?.DefaultValues.ApplyDefaults(this);
27+
LibraryConfiguration = configuration;
2728
}
2829

2930
[Inject]
@@ -37,6 +38,11 @@ protected FluentComponentBase(LibraryConfiguration configuration)
3738
[Inject]
3839
protected IFluentLocalizer Localizer { get; set; } = FluentLocalizerInternal.Default;
3940

41+
/// <summary>
42+
/// Gets the configuration settings for the library instance.
43+
/// </summary>
44+
protected internal LibraryConfiguration? LibraryConfiguration { get; }
45+
4046
/// <summary>
4147
/// Gets the JavaScript module imported with the <see cref="FluentJSModule.ImportJavaScriptModuleAsync"/> method.
4248
/// You need to call this method (in the `OnAfterRenderAsync` method) before using the module.

src/Core/Components/DateTime/FluentCalendar.razor.cs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ public partial class FluentCalendar<TValue> : FluentCalendarBase<TValue>
2222
{
2323
private ElementReference _calendarReference = default!;
2424
private const string JAVASCRIPT_FILE = FluentJSModule.JAVASCRIPT_ROOT + "DateTime/FluentCalendar.razor.js";
25-
26-
internal static string ArrowUp = "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M4.2 10.73a.75.75 0 001.1 1.04l5.95-6.25v14.73a.75.75 0 001.5 0V5.52l5.95 6.25a.75.75 0 001.1-1.04l-7.08-7.42a1 1 0 00-1.44 0L4.2 10.73z\"/></svg>";
27-
internal static string ArrowDown = "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M19.8 13.27a.75.75 0 00-1.1-1.04l-5.95 6.25V3.75a.75.75 0 10-1.5 0v14.73L5.3 12.23a.75.75 0 10-1.1 1.04l7.08 7.42a1 1 0 001.44 0l7.07-7.42z\"/></svg>";
25+
26+
internal static MarkupStringSanitized ArrowUp = new("<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M4.2 10.73a.75.75 0 001.1 1.04l5.95-6.25v14.73a.75.75 0 001.5 0V5.52l5.95 6.25a.75.75 0 001.1-1.04l-7.08-7.42a1 1 0 00-1.44 0L4.2 10.73z\"/></svg>", MarkupStringSanitized.Formats.AlreadySanitized);
27+
internal static MarkupStringSanitized ArrowDown = new("<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M19.8 13.27a.75.75 0 00-1.1-1.04l-5.95 6.25V3.75a.75.75 0 10-1.5 0v14.73L5.3 12.23a.75.75 0 10-1.1 1.04l7.08 7.42a1 1 0 001.44 0l7.07-7.42z\"/></svg>", MarkupStringSanitized.Formats.AlreadySanitized);
2828

2929
private CalendarViews _pickerView = CalendarViews.Days;
3030
private bool _refreshAccessibilityPending;
@@ -167,12 +167,14 @@ public virtual TValue? PickerMonth
167167
internal bool IsReadOnlyOrDisabled => ReadOnly || Disabled == true;
168168

169169
/// <summary />
170-
internal string GetAnimationClass(string existingClass) => CanBeAnimated ? _animationRunning switch
171-
{
172-
AnimationRunning.Up => $"{existingClass} animation-running-up",
173-
AnimationRunning.Down => $"{existingClass} animation-running-down",
174-
_ => $"{existingClass} animation-none"
175-
} : existingClass;
170+
internal string GetAnimationClass(string existingClass) => CanBeAnimated
171+
? _animationRunning switch
172+
{
173+
AnimationRunning.Up => $"{existingClass} animation-running-up",
174+
AnimationRunning.Down => $"{existingClass} animation-running-down",
175+
_ => $"{existingClass} animation-none",
176+
}
177+
: existingClass;
176178

177179
/// <summary>
178180
/// All days of this current month.

src/Core/Components/Dialog/FluentDialog.razor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,14 +268,14 @@ async Task<bool> ShortCutPressedAsync(DialogOptionsFooterAction button, string s
268268
private bool IsDialog() => !IsDrawer();
269269

270270
/// <summary />
271-
private MarkupString? GetDialogStyle()
271+
private MarkupStringSanitized? GetDialogStyle()
272272
{
273273
if (string.IsNullOrEmpty(StyleValue))
274274
{
275275
return null;
276276
}
277277

278-
return (MarkupString)$"<style>#{Id}::part(dialog) {{ {StyleValue} }}</style>";
278+
return new MarkupStringSanitized($"<style>#{Id}::part(dialog) {{ {StyleValue} }}</style>", LibraryConfiguration);
279279
}
280280

281281
/// <summary>

src/Core/Components/Dialog/FluentDialogBody.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
}
1717
else if (!string.IsNullOrEmpty(Instance?.Options.Header.Title))
1818
{
19-
<div slot="@FluentSlot.DialogTitle">@((MarkupString)(Instance.Options.Header.Title))</div>
19+
<div slot="@FluentSlot.DialogTitle">@(new MarkupStringSanitized(Instance.Options.Header.Title, MarkupStringSanitized.Formats.Html, LibraryConfiguration))</div>
2020
}
2121

2222
@* Header Action *@

src/Core/Components/Dialog/MessageBox/DialogService.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
// This file is licensed to you under the MIT License.
33
// ------------------------------------------------------------------------
44

5-
using Microsoft.AspNetCore.Components;
5+
using Microsoft.Extensions.DependencyInjection;
66
using Microsoft.FluentUI.AspNetCore.Components.Dialog.MessageBox;
77
using Microsoft.FluentUI.AspNetCore.Components.Localization;
8+
using Microsoft.FluentUI.AspNetCore.Components.Utilities;
89

910
namespace Microsoft.FluentUI.AspNetCore.Components;
1011

@@ -94,7 +95,7 @@ public Task<DialogResult> ShowMessageBoxAsync(MessageBoxOptions options)
9495
config.Footer.PrimaryAction.ShortCut = options.PrimaryShortCut;
9596
config.Footer.SecondaryAction.Label = options.SecondaryButton;
9697
config.Footer.SecondaryAction.ShortCut = options.SecondaryShortCut;
97-
config.Parameters.Add(nameof(FluentMessageBox.Message), new MarkupString(options.Message ?? ""));
98+
config.Parameters.Add(nameof(FluentMessageBox.Message), new MarkupStringSanitized(options.Message ?? "", MarkupStringSanitized.Formats.Html, _serviceProvider.GetService<LibraryConfiguration>()));
9899
config.Parameters.Add(nameof(FluentMessageBox.Icon), options.Icon);
99100
config.Parameters.Add(nameof(FluentMessageBox.IconColor), options.IconColor);
100101
});

src/Core/Components/Dialog/MessageBox/FluentMessageBox.razor.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// ------------------------------------------------------------------------
44

55
using Microsoft.AspNetCore.Components;
6+
using Microsoft.FluentUI.AspNetCore.Components.Utilities;
67

78
namespace Microsoft.FluentUI.AspNetCore.Components.Dialog.MessageBox;
89

@@ -13,9 +14,10 @@ public partial class FluentMessageBox
1314
{
1415
/// <summary>
1516
/// Gets or sets the content of the message box.
17+
/// For security reasons, the content is sanitized using the configured <see cref="LibraryConfiguration.MarkupSanitized"/> before rendering.
1618
/// </summary>
1719
[Parameter]
18-
public MarkupString? Message { get; set; }
20+
public MarkupStringSanitized? Message { get; set; }
1921

2022
/// <summary>
2123
/// Gets or sets the icon of the message box.

src/Core/Components/Dialog/MessageBox/MessageBoxOptions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ public class MessageBoxOptions
1111
{
1212
/// <summary>
1313
/// Gets or sets the message to display in the dialog.
14+
/// The message can contain simple HTML markup for formatting.
15+
/// See <see cref="LibraryConfiguration.MarkupSanitized"/> for more information.
1416
/// </summary>
1517
public string? Message { get; set; }
1618

src/Core/Components/Dialog/Services/DialogOptionsHeader.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ public class DialogOptionsHeader
1212
/// <summary />
1313
public DialogOptionsHeader()
1414
{
15-
1615
}
1716

1817
/// <summary>
1918
/// Gets or sets the title of the dialog.
19+
/// For security reasons, the content is sanitized using the configured <see cref="LibraryConfiguration.MarkupSanitized"/> before rendering.
2020
/// </summary>
2121
public string? Title { get; set; }
2222
}

src/Core/Components/MessageBar/FluentMessageBar.razor

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919

2020
@if (!string.IsNullOrEmpty(Title))
2121
{
22-
<span class="title">@Title</span>
22+
<span class="title">
23+
@(new MarkupStringSanitized(Title, MarkupStringSanitized.Formats.Html, LibraryConfiguration))
24+
</span>
2325
}
2426
</AddTag>
2527

src/Core/Components/MessageBar/FluentMessageBar.razor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public FluentMessageBar(LibraryConfiguration configuration) : base(configuration
7070

7171
/// <summary>
7272
/// Gets or sets the most important info to be shown in the message bar.
73-
/// You cannot format this string using HTML tags (bold, italic, etc.).
73+
/// For security reasons, the content is sanitized using the configured <see cref="LibraryConfiguration.MarkupSanitized"/> before rendering.
7474
/// If you need to format the content, use the <see cref="ChildContent"/> parameter.
7575
/// </summary>
7676
[Parameter]

0 commit comments

Comments
 (0)