diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs index 098f770ebc75..cf44114c19e9 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs @@ -317,8 +317,9 @@ private void AddCoreServices() Services.AddSingleton(); Services.AddSingleton(); - // Register a noop IHtmlSanitizer to be replaced + // Register a noop IHtmlSanitizer & IMarkdownSanitizer to be replaced Services.AddUnique(); + Services.AddUnique(); Services.AddUnique(); Services.AddUnique(); diff --git a/src/Umbraco.Core/PropertyEditors/MarkDownPropertyValueEditor.cs b/src/Umbraco.Core/PropertyEditors/MarkDownPropertyValueEditor.cs new file mode 100644 index 000000000000..637a971d6836 --- /dev/null +++ b/src/Umbraco.Core/PropertyEditors/MarkDownPropertyValueEditor.cs @@ -0,0 +1,39 @@ +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.Models.Editors; +using Umbraco.Cms.Core.Security; +using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Strings; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Core.PropertyEditors; + +/// +/// A custom value editor to ensure that macro syntax is parsed when being persisted and formatted correctly for +/// display in the editor +/// +internal class MarkDownPropertyValueEditor : DataValueEditor +{ + private readonly IMarkdownSanitizer _markdownSanitizer; + + public MarkDownPropertyValueEditor( + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer, + IIOHelper ioHelper, + DataEditorAttribute attribute, + IMarkdownSanitizer markdownSanitizer) + : base(localizedTextService, shortStringHelper, jsonSerializer, ioHelper, attribute) => _markdownSanitizer = markdownSanitizer; + + public override object? FromEditor(ContentPropertyData editorValue, object? currentValue) + { + if (string.IsNullOrWhiteSpace(editorValue.Value?.ToString())) + { + return null; + } + + var sanitized = _markdownSanitizer.Sanitize(editorValue.Value.ToString()!); + + return sanitized.NullOrWhiteSpaceAsNull(); + } +} diff --git a/src/Umbraco.Core/PropertyEditors/MarkdownPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/MarkdownPropertyEditor.cs index 8b1b181c8cad..531262f0b2f3 100644 --- a/src/Umbraco.Core/PropertyEditors/MarkdownPropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/MarkdownPropertyEditor.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Services; namespace Umbraco.Cms.Core.PropertyEditors; @@ -50,4 +51,11 @@ public MarkdownPropertyEditor( /// protected override IConfigurationEditor CreateConfigurationEditor() => new MarkdownConfigurationEditor(_ioHelper, _editorConfigurationParser); + + /// + /// Create a custom value editor + /// + /// + protected override IDataValueEditor CreateValueEditor() => + DataValueEditorFactory.Create(Attribute!); } diff --git a/src/Umbraco.Core/Security/IMarkdownSanitizer.cs b/src/Umbraco.Core/Security/IMarkdownSanitizer.cs new file mode 100644 index 000000000000..ed1fed2a2cc9 --- /dev/null +++ b/src/Umbraco.Core/Security/IMarkdownSanitizer.cs @@ -0,0 +1,14 @@ +namespace Umbraco.Cms.Core.Security; + +/// +/// Sanitizer service for the markdown editor. +/// +public interface IMarkdownSanitizer +{ + /// + /// Sanitizes Markdown + /// + /// Markdown to be sanitized + /// Sanitized Markdown + string Sanitize(string markdown); +} diff --git a/src/Umbraco.Core/Security/NoopMarkdownSanitizer.cs b/src/Umbraco.Core/Security/NoopMarkdownSanitizer.cs new file mode 100644 index 000000000000..3da03b0e6374 --- /dev/null +++ b/src/Umbraco.Core/Security/NoopMarkdownSanitizer.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Cms.Core.Security; + +/// +public class NoopMarkdownSanitizer : IMarkdownSanitizer +{ + /// + public string Sanitize(string markdown) => markdown; +}