From b60d255f9d8bf0ab99ddbf10529b24fea7e21e6f Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Wed, 30 Jun 2021 12:23:17 +0200 Subject: [PATCH] Feature/svg check (#732) * SVG check. * Fix github login. * Revert domain check. * Fix. --- backend/i18n/frontend_en.json | 1 + backend/i18n/frontend_it.json | 1 + backend/i18n/frontend_nl.json | 1 + backend/i18n/frontend_zh.json | 1 + backend/i18n/source/frontend_en.json | 1 + .../Extensions/StringJintExtension.cs | 4 +- ...Squidex.Domain.Apps.Core.Operations.csproj | 4 +- .../Extensions/StringFluidExtension.cs | 4 +- .../TextHelpers.cs | 97 --------- .../DefaultFieldValueValidatorsFactory.cs | 5 +- .../Assets/ImageAssetMetadataSource.cs | 5 - .../Assets/SvgAssetMetadataSource.cs | 66 ++++++ .../Squidex.Infrastructure.csproj | 2 +- .../Controllers/Error/ErrorController.cs | 10 +- .../Squidex/Config/Domain/AssetServices.cs | 3 + .../Assets/ImageAssetMetadataSourceTests.cs | 12 -- .../Assets/SvgAssetMetadataSourceTests.cs | 83 +++++++ .../Properties/Resources.Designer.cs | 95 ++++++++ .../Properties/Resources.resx | 204 ++++++++++++++++++ .../Squidex.Domain.Apps.Entities.Tests.csproj | 13 ++ 20 files changed, 487 insertions(+), 125 deletions(-) delete mode 100644 backend/src/Squidex.Domain.Apps.Core.Operations/TextHelpers.cs create mode 100644 backend/src/Squidex.Domain.Apps.Entities/Assets/SvgAssetMetadataSource.cs create mode 100644 backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/SvgAssetMetadataSourceTests.cs create mode 100644 backend/tests/Squidex.Domain.Apps.Entities.Tests/Properties/Resources.Designer.cs create mode 100644 backend/tests/Squidex.Domain.Apps.Entities.Tests/Properties/Resources.resx diff --git a/backend/i18n/frontend_en.json b/backend/i18n/frontend_en.json index d3afa743e..8a78b7cc6 100644 --- a/backend/i18n/frontend_en.json +++ b/backend/i18n/frontend_en.json @@ -942,6 +942,7 @@ "validation.min": "{field|upper} must be greater or equal to '{min}'.", "validation.minlength": "{field|upper} must have at least {requiredlength} item(s).", "validation.minlengthstring": "{field|upper} must have at least {requiredlength} character(s).", + "validation.notAnValidSvg": "The SVG is malicious and contains script tags.", "validation.pattern": "{field|upper} does not match to the pattern.", "validation.patternmessage": "{message}", "validation.required": "{field|upper} is required.", diff --git a/backend/i18n/frontend_it.json b/backend/i18n/frontend_it.json index b831f70ea..cc11634e1 100644 --- a/backend/i18n/frontend_it.json +++ b/backend/i18n/frontend_it.json @@ -942,6 +942,7 @@ "validation.min": "{field|upper} deve essere maggiore o uguale a '{min}'.", "validation.minlength": "{field|upper} deve avere almeno {requiredlength} elemento(i).", "validation.minlengthstring": "{field|upper} deve avere almeno {requiredlength} carattere(i).", + "validation.notAnValidSvg": "The SVG is malicious and contains script tags.", "validation.pattern": "{field|upper} non corrisponde al pattern.", "validation.patternmessage": "{message}", "validation.required": "{field|upper} è obbligatorio.", diff --git a/backend/i18n/frontend_nl.json b/backend/i18n/frontend_nl.json index 0ec83baca..e5ea8382b 100644 --- a/backend/i18n/frontend_nl.json +++ b/backend/i18n/frontend_nl.json @@ -942,6 +942,7 @@ "validation.min": "{field|upper} moet groter zijn dan of gelijk zijn aan '{min}'.", "validation.minlength": "{field|upper} moet minimaal {requiredlength} item (s) bevatten.", "validation.minlengthstring": "{field|upper} moet minimaal {requiredlength} teken (s) bevatten.", + "validation.notAnValidSvg": "The SVG is malicious and contains script tags.", "validation.pattern": "{field|upper} komt niet overeen met het patroon.", "validation.patternmessage": "{message}", "validation.required": "{field|upper} is vereist.", diff --git a/backend/i18n/frontend_zh.json b/backend/i18n/frontend_zh.json index b5afad968..1c366bd82 100644 --- a/backend/i18n/frontend_zh.json +++ b/backend/i18n/frontend_zh.json @@ -942,6 +942,7 @@ "validation.min": "{field|upper} 必须大于或等于 '{min}'。", "validation.minlength": "{field|upper} 必须至少有 {requiredlength} 项。", "validation.minlengthstring": "{field|upper} 必须至少有 {requiredlength} 个字符。", + "validation.notAnValidSvg": "The SVG is malicious and contains script tags.", "validation.pattern": "{field|upper} 与模式不匹配。", "validation.patternmessage": "{message}", "validation.required": "{field|upper} 是必需的。", diff --git a/backend/i18n/source/frontend_en.json b/backend/i18n/source/frontend_en.json index d3afa743e..8a78b7cc6 100644 --- a/backend/i18n/source/frontend_en.json +++ b/backend/i18n/source/frontend_en.json @@ -942,6 +942,7 @@ "validation.min": "{field|upper} must be greater or equal to '{min}'.", "validation.minlength": "{field|upper} must have at least {requiredlength} item(s).", "validation.minlengthstring": "{field|upper} must have at least {requiredlength} character(s).", + "validation.notAnValidSvg": "The SVG is malicious and contains script tags.", "validation.pattern": "{field|upper} does not match to the pattern.", "validation.patternmessage": "{message}", "validation.required": "{field|upper} is required.", diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/StringJintExtension.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/StringJintExtension.cs index d0c78c238..c2ec4a72a 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/StringJintExtension.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/StringJintExtension.cs @@ -81,7 +81,7 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions { try { - return TextHelpers.Html2Text(text); + return text.Html2Text(); } catch { @@ -93,7 +93,7 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions { try { - return TextHelpers.Markdown2Text(text); + return text.Markdown2Text(); } catch { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj b/backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj index 34764e618..4f3e2bd98 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj @@ -17,9 +17,7 @@ - - - + diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Templates/Extensions/StringFluidExtension.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Templates/Extensions/StringFluidExtension.cs index 89e7bffb1..47b32b446 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Templates/Extensions/StringFluidExtension.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Templates/Extensions/StringFluidExtension.cs @@ -39,12 +39,12 @@ namespace Squidex.Domain.Apps.Core.Templates.Extensions private static readonly FilterDelegate Markdown2Text = (input, arguments, context) => { - return FluidValue.Create(TextHelpers.Markdown2Text(input.ToStringValue())); + return FluidValue.Create(input.ToStringValue().Markdown2Text()); }; private static readonly FilterDelegate Html2Text = (input, arguments, context) => { - return FluidValue.Create(TextHelpers.Html2Text(input.ToStringValue())); + return FluidValue.Create(input.ToStringValue().Html2Text()); }; private static readonly FilterDelegate Trim = (input, arguments, context) => diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/TextHelpers.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/TextHelpers.cs deleted file mode 100644 index 033f53d53..000000000 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/TextHelpers.cs +++ /dev/null @@ -1,97 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System.Text; -using HtmlAgilityPack; -using Markdig; - -namespace Squidex.Domain.Apps.Core -{ - public static class TextHelpers - { - public static string Markdown2Text(string markdown) - { - return Markdown.ToPlainText(markdown).Trim(' ', '\n', '\r'); - } - - public static string Html2Text(string html) - { - var document = LoadHtml(html); - - var sb = new StringBuilder(); - - WriteTextTo(document.DocumentNode, sb); - - return sb.ToString().Trim(' ', '\n', '\r'); - } - - private static HtmlDocument LoadHtml(string text) - { - var document = new HtmlDocument(); - - document.LoadHtml(text); - - return document; - } - - private static void WriteTextTo(HtmlNode node, StringBuilder sb) - { - switch (node.NodeType) - { - case HtmlNodeType.Comment: - break; - case HtmlNodeType.Document: - WriteChildrenTextTo(node, sb); - break; - case HtmlNodeType.Text: - var html = ((HtmlTextNode)node).Text; - - if (HtmlNode.IsOverlappedClosingElement(html)) - { - break; - } - - if (!string.IsNullOrWhiteSpace(html)) - { - sb.Append(HtmlEntity.DeEntitize(html)); - } - - break; - - case HtmlNodeType.Element: - switch (node.Name) - { - case "p": - sb.AppendLine(); - break; - case "br": - sb.AppendLine(); - break; - case "style": - return; - case "script": - return; - } - - if (node.HasChildNodes) - { - WriteChildrenTextTo(node, sb); - } - - break; - } - } - - private static void WriteChildrenTextTo(HtmlNode node, StringBuilder sb) - { - foreach (var child in node.ChildNodes) - { - WriteTextTo(child, sb); - } - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs index a8495a821..727e9a2d0 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs @@ -11,6 +11,7 @@ using NodaTime; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.ValidateContent.Validators; using Squidex.Infrastructure.Json.Objects; +using Squidex.Text; namespace Squidex.Domain.Apps.Core.ValidateContent { @@ -203,10 +204,10 @@ namespace Squidex.Domain.Apps.Core.ValidateContent switch (properties.ContentType) { case StringContentType.Markdown: - transform = TextHelpers.Markdown2Text; + transform = MarkdownExtensions.Markdown2Text; break; case StringContentType.Html: - transform = TextHelpers.Html2Text; + transform = HtmlExtensions.Html2Text; break; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/ImageAssetMetadataSource.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/ImageAssetMetadataSource.cs index 09268285b..5a4103615 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/ImageAssetMetadataSource.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/ImageAssetMetadataSource.cs @@ -117,11 +117,6 @@ namespace Squidex.Domain.Apps.Entities.Assets command.Tags.Add("image/small"); } } - - if (command.File.MimeType == "image/svg+xml") - { - command.Tags.Add("image"); - } } public IEnumerable Format(IAssetEntity asset) diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/SvgAssetMetadataSource.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/SvgAssetMetadataSource.cs new file mode 100644 index 000000000..6fad2ff36 --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/SvgAssetMetadataSource.cs @@ -0,0 +1,66 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Squidex.Domain.Apps.Entities.Assets.Commands; +using Squidex.Infrastructure.Translations; +using Squidex.Infrastructure.Validation; +using Squidex.Text; + +namespace Squidex.Domain.Apps.Entities.Assets +{ + public sealed class SvgAssetMetadataSource : IAssetMetadataSource + { + private const int FileSizeLimit = 2 * 1024 * 1024; // 2MB + + public Task EnhanceAsync(UploadAssetCommand command) + { + var isSvg = + command.File.MimeType == "image/svg+xml" || + command.File.FileName.EndsWith(".svg", StringComparison.OrdinalIgnoreCase); + + if (isSvg) + { + command.Tags.Add("image"); + + if (command.File.FileSize < FileSizeLimit) + { + try + { + using (var reader = new StreamReader(command.File.OpenRead())) + { + var text = reader.ReadToEnd(); + + if (!text.IsValidSvg()) + { + throw new ValidationException(T.Get("validation.notAnValidSvg")); + } + } + } + catch (ValidationException) + { + throw; + } + catch + { + return Task.CompletedTask; + } + } + } + + return Task.CompletedTask; + } + + public IEnumerable Format(IAssetEntity asset) + { + yield break; + } + } +} diff --git a/backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj b/backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj index 26b02c4bd..9ea21eb73 100644 --- a/backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj +++ b/backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj @@ -29,7 +29,7 @@ - + diff --git a/backend/src/Squidex/Areas/IdentityServer/Controllers/Error/ErrorController.cs b/backend/src/Squidex/Areas/IdentityServer/Controllers/Error/ErrorController.cs index 0a5e85fb7..fa83bd8a6 100644 --- a/backend/src/Squidex/Areas/IdentityServer/Controllers/Error/ErrorController.cs +++ b/backend/src/Squidex/Areas/IdentityServer/Controllers/Error/ErrorController.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore; using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc; +using Squidex.Infrastructure; namespace Squidex.Areas.IdentityServer.Controllers.Error { @@ -30,7 +31,14 @@ namespace Squidex.Areas.IdentityServer.Controllers.Error { var exception = HttpContext.Features.Get()?.Error; - vm.ErrorMessage = exception?.Message; + if (exception is DomainException domainException1) + { + vm.ErrorMessage = domainException1.Message; + } + else if (exception?.InnerException is DomainException domainException2) + { + vm.ErrorMessage = domainException2.Message; + } } return View("Error", vm); diff --git a/backend/src/Squidex/Config/Domain/AssetServices.cs b/backend/src/Squidex/Config/Domain/AssetServices.cs index 2ce86e2d5..b1faccf76 100644 --- a/backend/src/Squidex/Config/Domain/AssetServices.cs +++ b/backend/src/Squidex/Config/Domain/AssetServices.cs @@ -85,6 +85,9 @@ namespace Squidex.Config.Domain services.AddSingletonAs() .As(); + + services.AddSingletonAs() + .As(); } public static void AddSquidexAssetInfrastructure(this IServiceCollection services, IConfiguration config) diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/ImageAssetMetadataSourceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/ImageAssetMetadataSourceTests.cs index 16de32bd4..56e9e55bf 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/ImageAssetMetadataSourceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/ImageAssetMetadataSourceTests.cs @@ -132,18 +132,6 @@ namespace Squidex.Domain.Apps.Entities.Assets Assert.Contains("image/large", command.Tags); } - [Fact] - public async Task Should_add_image_tag_if_svg() - { - var svg = new DelegateAssetFile("MyImage.png", "image/svg+xml", 1024, () => stream); - - var command = new CreateAsset { File = svg }; - - await sut.EnhanceAsync(command); - - Assert.Contains("image", command.Tags); - } - [Fact] public void Should_format_image() { diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/SvgAssetMetadataSourceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/SvgAssetMetadataSourceTests.cs new file mode 100644 index 000000000..a9fc6c669 --- /dev/null +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/SvgAssetMetadataSourceTests.cs @@ -0,0 +1,83 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Squidex.Assets; +using Squidex.Domain.Apps.Entities.Assets.Commands; +using Squidex.Domain.Apps.Entities.Properties; +using Squidex.Infrastructure.Validation; +using Xunit; + +namespace Squidex.Domain.Apps.Entities.Assets +{ + public class SvgAssetMetadataSourceTests + { + private readonly MemoryStream stream = new MemoryStream(); + private readonly SvgAssetMetadataSource sut = new SvgAssetMetadataSource(); + + public SvgAssetMetadataSourceTests() + { + sut = new SvgAssetMetadataSource(); + } + + [Fact] + public async Task Should_add_image_tag_if_svg_mime() + { + var svg = new DelegateAssetFile("MyImage.png", "image/svg+xml", 1024, () => stream); + + var command = new CreateAsset { File = svg }; + + await sut.EnhanceAsync(command); + + Assert.Contains("image", command.Tags); + } + + [Fact] + public async Task Should_add_image_tag_if_svg_extension() + { + var svg = new DelegateAssetFile("MyImage.svg", "other", 1024, () => stream); + + var command = new CreateAsset { File = svg }; + + await sut.EnhanceAsync(command); + + Assert.Contains("image", command.Tags); + } + + [Fact] + public async Task Should_throw_exception_if_svg_is_malicious() + { + var bytes = Encoding.UTF8.GetBytes(Resources.SvgInvalid); + + stream.Write(bytes); + stream.Seek(0, SeekOrigin.Begin); + + var svg = new DelegateAssetFile("MyImage.svg", "other", 1024, () => stream); + + var command = new CreateAsset { File = svg }; + + await Assert.ThrowsAsync(() => sut.EnhanceAsync(command)); + } + + [Fact] + public async Task Should_not_throw_exception_if_svg_is_not_malicious() + { + var bytes = Encoding.UTF8.GetBytes(Resources.SvgValid); + + stream.Write(bytes); + stream.Seek(0, SeekOrigin.Begin); + + var svg = new DelegateAssetFile("MyImage.svg", "other", 1024, () => stream); + + var command = new CreateAsset { File = svg }; + + await sut.EnhanceAsync(command); + } + } +} diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Properties/Resources.Designer.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Properties/Resources.Designer.cs new file mode 100644 index 000000000..458ced345 --- /dev/null +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Properties/Resources.Designer.cs @@ -0,0 +1,95 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Squidex.Domain.Apps.Entities.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Squidex.Domain.Apps.Entities.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" onload="alert(localStorage.getItem('oidc.user:https://cloud.squidex.io/identity-server/:squidex-frontend'))"> + /// <path d="M30,1h40l29,29v40l-29,29h-40l-29-29v-40z" stroke="#000" fill="none"/> + /// <path d="M31,3h38l28,28v38l-28,28h-38l-28-28v-38z" fill="#a23"/> + /// <text x="50" y="68" font-size="48" fill="#FFF" text-anchor="middle"><![CDATA[410]]></text> + ///</svg>. + /// + internal static string SvgInvalid { + get { + return ResourceManager.GetString("SvgInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + /// + ///<svg + /// xmlns:dc="http://purl.org/dc/elements/1.1/" + /// xmlns:cc="http://creativecommons.org/ns#" + /// xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + /// xmlns:svg="http://www.w3.org/2000/svg" + /// xmlns="http://www.w3.org/2000/svg" + /// xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + /// xmlns:inkscape="http://www.inkscape.org/n [rest of string was truncated]";. + /// + internal static string SvgValid { + get { + return ResourceManager.GetString("SvgValid", resourceCulture); + } + } + } +} diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Properties/Resources.resx b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Properties/Resources.resx new file mode 100644 index 000000000..2a348720d --- /dev/null +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Properties/Resources.resx @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" onload="alert(localStorage.getItem('oidc.user:https://cloud.squidex.io/identity-server/:squidex-frontend'))"> + <path d="M30,1h40l29,29v40l-29,29h-40l-29-29v-40z" stroke="#000" fill="none"/> + <path d="M31,3h38l28,28v38l-28,28h-38l-28-28v-38z" fill="#a23"/> + <text x="50" y="68" font-size="48" fill="#FFF" text-anchor="middle"><![CDATA[410]]></text> +</svg> + + + <?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + id="Layer_1" + x="0px" + y="0px" + width="110" + height="110" + viewBox="0 0 110 110" + enable-background="new 0 0 494 111" + xml:space="preserve" + inkscape:version="0.91 r13725" + sodipodi:docname="logo-squared.svg" + inkscape:export-filename="C:\Users\mail2\Downloads\logo-squared.png" + inkscape:export-xdpi="490.91" + inkscape:export-ydpi="490.91"><metadata + id="metadata45"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs + id="defs43" /><sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1017" + id="namedview41" + showgrid="false" + inkscape:zoom="2.3319838" + inkscape:cx="-70.482725" + inkscape:cy="106.27906" + inkscape:window-x="1912" + inkscape:window-y="-8" + inkscape:window-maximized="1" + inkscape:current-layer="Layer_1" /><g + id="g19" + transform="matrix(1.0069983,0,0,1.0058932,11.091568,0.44387448)"><g + id="g21"><path + d="m 21.267,80.827 c -0.473,0 -0.971,-0.031 -1.494,-0.096 -3.67,-0.459 -6.484,-2.862 -7.531,-6.428 -1.109,-3.789 0.053,-8.048 2.826,-10.359 1.144,-0.955 2.844,-0.799 3.797,0.345 0.953,1.145 0.798,2.844 -0.346,3.797 -1.138,0.948 -1.611,2.968 -1.104,4.7 0.309,1.051 1.083,2.353 3.025,2.596 1.399,0.175 2.459,-0.063 3.246,-0.724 1.435,-1.209 1.869,-3.684 1.922,-4.596 l 0,-16.985 c 0,-1.489 1.207,-2.695 2.695,-2.695 1.488,0 2.697,1.206 2.697,2.695 l 0,17.051 c 0,0.033 0,0.065 -0.001,0.098 -0.02,0.558 -0.297,5.538 -3.803,8.525 -1.165,0.991 -3.089,2.076 -5.929,2.076 z" + id="path23" + inkscape:connector-curvature="0" + style="fill:#3389ff" /></g><g + id="g25"><path + d="m 31.435,99.967 c -0.473,0 -0.971,-0.031 -1.494,-0.096 -3.67,-0.46 -6.486,-2.862 -7.531,-6.428 -1.109,-3.789 0.051,-8.048 2.826,-10.358 1.144,-0.955 2.845,-0.8 3.797,0.342 0.953,1.146 0.798,2.845 -0.346,3.799 -1.138,0.947 -1.612,2.968 -1.104,4.701 0.308,1.049 1.082,2.351 3.025,2.594 1.404,0.177 2.473,-0.065 3.259,-0.735 1.638,-1.394 1.887,-4.275 1.909,-4.586 l 0,-36.962 c 0,-1.489 1.207,-2.696 2.695,-2.696 1.488,0 2.695,1.207 2.695,2.696 l 0,37.031 c 0,0.032 0,0.062 -0.002,0.097 -0.019,0.558 -0.296,5.538 -3.803,8.525 -1.162,0.991 -3.086,2.076 -5.926,2.076 z" + id="path27" + inkscape:connector-curvature="0" + style="fill:#3389ff" /></g><g + id="g29"><path + d="m 65.941,80.827 c -2.84,0 -4.764,-1.085 -5.928,-2.076 -3.507,-2.987 -3.784,-7.968 -3.803,-8.525 -0.002,-0.032 -0.002,-0.064 -0.002,-0.098 l 0,-17.051 c 0,-1.489 1.206,-2.695 2.695,-2.695 1.488,0 2.695,1.207 2.695,2.695 l 0,16.991 c 0.05,0.889 0.482,3.377 1.923,4.591 0.786,0.66 1.849,0.899 3.245,0.723 1.942,-0.242 2.718,-1.544 3.025,-2.595 0.509,-1.732 0.034,-3.752 -1.104,-4.7 -1.144,-0.953 -1.299,-2.652 -0.345,-3.797 0.951,-1.144 2.65,-1.299 3.796,-0.345 2.774,2.312 3.936,6.57 2.826,10.359 -1.045,3.565 -3.861,5.969 -7.53,6.428 -0.522,0.064 -1.02,0.095 -1.493,0.095 z" + id="path31" + inkscape:connector-curvature="0" + style="fill:#3389ff" /></g><g + id="g33"><path + d="m 55.773,99.967 c -2.84,0 -4.764,-1.085 -5.928,-2.076 C 46.338,94.904 46.062,89.923 46.042,89.366 46.04,89.332 46.04,89.302 46.04,89.269 l 0,-37.031 c 0,-1.489 1.207,-2.696 2.696,-2.696 1.488,0 2.694,1.207 2.694,2.696 l 0,36.967 c 0.051,0.891 0.482,3.379 1.923,4.592 0.786,0.661 1.847,0.9 3.245,0.724 1.942,-0.243 2.718,-1.545 3.025,-2.594 0.509,-1.733 0.034,-3.754 -1.104,-4.701 -1.144,-0.954 -1.298,-2.652 -0.345,-3.799 0.952,-1.141 2.651,-1.297 3.797,-0.342 2.774,2.311 3.935,6.569 2.825,10.358 -1.045,3.565 -3.861,5.968 -7.53,6.428 -0.522,0.065 -1.019,0.096 -1.493,0.096 z" + id="path35" + inkscape:connector-curvature="0" + style="fill:#3389ff" /></g><g + id="g37"><path + d="M 64.793,38.868 C 64.615,36.921 68.58,37.699 68.104,35.928 63.147,17.484 43.646,8.512 43.632,8.506 43.617,8.512 24.116,17.484 19.16,35.928 c -0.478,1.771 3.487,0.993 3.31,2.94 -0.217,2.364 -4.765,3.333 -4.172,10.121 0.641,7.341 7.182,14.765 7.418,18.873 l 5.295,0 0,-0.153 c 0,-1.319 1.069,-2.388 2.389,-2.388 1.32,0 2.388,1.068 2.388,2.388 l 0,0.153 5.39,-2.695 0,-0.107 c 0,-1.345 1.09,-2.435 2.436,-2.435 1.344,0 2.434,1.09 2.434,2.435 l 0,0.107 5.375,2.695 0,-0.153 c 0,-1.319 1.069,-2.388 2.389,-2.388 1.32,0 2.389,1.068 2.389,2.388 l 0,0.153 5.391,0 c 0.542,-5.791 6.735,-11.532 7.376,-18.873 0.59,-6.788 -3.959,-7.757 -4.175,-10.121 z" + id="path39" + inkscape:connector-curvature="0" + style="fill:#3389ff" /></g></g></svg> + + \ No newline at end of file diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj index 5479a3985..9d2e184da 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj @@ -40,6 +40,19 @@ + + + True + True + Resources.resx + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + PreserveNewest