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 9f780a395..d4711801d 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 @@ -28,7 +28,7 @@ - + diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/ImageAssetMetadataSource.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/ImageAssetMetadataSource.cs index ec66d886d..c9d45c97e 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/ImageAssetMetadataSource.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/ImageAssetMetadataSource.cs @@ -36,9 +36,11 @@ public sealed class ImageAssetMetadataSource : IAssetMetadataSource if (imageInfo != null) { - var isSwapped = imageInfo.Orientation > ImageOrientation.TopLeft; + var needsFix = + imageInfo.HasSensitiveMetadata || + imageInfo.Orientation > ImageOrientation.TopLeft; - if (command.File != null && isSwapped) + if (command.File != null && needsFix) { var tempFile = TempAssetFile.Create(command.File); @@ -46,7 +48,7 @@ public sealed class ImageAssetMetadataSource : IAssetMetadataSource { await using (var tempStream = tempFile.OpenWrite()) { - await assetThumbnailGenerator.FixOrientationAsync(uploadStream, mimeType, tempStream, ct); + await assetThumbnailGenerator.FixAsync(uploadStream, mimeType, tempStream, ct); } } @@ -60,7 +62,7 @@ public sealed class ImageAssetMetadataSource : IAssetMetadataSource command.File = tempFile; } - if (command.Type == AssetType.Unknown || isSwapped) + if (command.Type == AssetType.Unknown || needsFix) { command.Type = AssetType.Image; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Builder.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Builder.cs index af4e62466..739c735de 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Builder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Builder.cs @@ -48,8 +48,6 @@ internal sealed class Builder public IInterfaceGraphType ComponentInterface { get; } = new ComponentInterfaceGraphType(); - public List Schemas { get; private set; } - public Builder(IAppEntity app, GraphQLOptions options) { partitionResolver = app.PartitionResolver(); @@ -66,9 +64,9 @@ internal sealed class Builder allSchemas.AddRange(SchemaInfo.Build(schemas, typeNames).Where(x => x.Fields.Count > 0)); // Only published normal schemas (not components are used for entities). - Schemas = allSchemas.Where(x => x.Schema.SchemaDef.IsPublished && x.Schema.SchemaDef.Type != SchemaType.Component).ToList(); + var normalSchemas = allSchemas.Where(x => x.Schema.SchemaDef.IsPublished && x.Schema.SchemaDef.Type != SchemaType.Component).ToList(); - foreach (var schemaInfo in Schemas) + foreach (var schemaInfo in normalSchemas) { var contentType = new ContentGraphType(schemaInfo); @@ -76,7 +74,7 @@ internal sealed class Builder contentResultTypes[schemaInfo] = new ContentResultGraphType(contentType, schemaInfo); } - foreach (var schemaInfo in Schemas) + foreach (var schemaInfo in normalSchemas) { var componentType = new ComponentGraphType(schemaInfo); @@ -85,7 +83,7 @@ internal sealed class Builder var newSchema = new GraphQLSchema { - Query = new ApplicationQueries(this, Schemas) + Query = new ApplicationQueries(this, normalSchemas) }; newSchema.RegisterType(ComponentInterface); @@ -94,9 +92,9 @@ internal sealed class Builder newSchema.Directives.Register(SharedTypes.CacheDirective); newSchema.Directives.Register(SharedTypes.OptimizeFieldQueriesDirective); - if (Schemas.Any()) + if (normalSchemas.Any()) { - var mutations = new ApplicationMutations(this, Schemas); + var mutations = new ApplicationMutations(this, normalSchemas); if (mutations.Fields.Count > 0) { @@ -111,7 +109,7 @@ internal sealed class Builder foreach (var (schemaInfo, contentType) in contentTypes) { - contentType.Initialize(this, schemaInfo, Schemas); + contentType.Initialize(this, schemaInfo, normalSchemas); } foreach (var (schemaInfo, componentType) in componentTypes) diff --git a/backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj b/backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj index db21de289..9bd81aeb4 100644 --- a/backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj +++ b/backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj @@ -24,12 +24,12 @@ - - - - - - + + + + + + diff --git a/backend/src/Squidex/Config/Web/WebExtensions.cs b/backend/src/Squidex/Config/Web/WebExtensions.cs index 4cd4c8f6a..5a788f8c2 100644 --- a/backend/src/Squidex/Config/Web/WebExtensions.cs +++ b/backend/src/Squidex/Config/Web/WebExtensions.cs @@ -32,7 +32,7 @@ public static class WebExtensions public static IApplicationBuilder UseSquidexLocalization(this IApplicationBuilder app) { - var supportedCultures = new[] { "en", "nl", "it", "zh", "pt","fr" }; + var supportedCultures = new[] { "en", "nl", "it", "zh", "pt", "fr" }; var localizationOptions = new RequestLocalizationOptions() .SetDefaultCulture(supportedCultures[0]) @@ -93,7 +93,7 @@ public static class WebExtensions httpContext.Response.Headers[HeaderNames.ContentType] = "application/json"; - return httpContext.Response.WriteAsync(json); + return httpContext.Response.WriteAsync(json, httpContext.RequestAborted); }); app.UseHealthChecks("/readiness", new HealthCheckOptions diff --git a/backend/src/Squidex/Squidex.csproj b/backend/src/Squidex/Squidex.csproj index 034305341..befd10c0a 100644 --- a/backend/src/Squidex/Squidex.csproj +++ b/backend/src/Squidex/Squidex.csproj @@ -62,18 +62,18 @@ - - - - - - - - + + + + + + + + - - - + + + diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppCommandMiddlewareTests.cs index 6481d8d74..66c736381 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppCommandMiddlewareTests.cs @@ -51,7 +51,7 @@ public class AppCommandMiddlewareTests : HandlerTestBase var file = new NoopAssetFile(); A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(A._, file.MimeType, CancellationToken)) - .Returns(new ImageInfo(100, 100, ImageOrientation.None, ImageFormat.PNG)); + .Returns(new ImageInfo(ImageFormat.PNG, 100, 100, ImageOrientation.None, false)); await HandleAsync(new UploadAppImage { File = file }, None.Value); 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 2e8e1ea20..c85cc15b7 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/ImageAssetMetadataSourceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/ImageAssetMetadataSourceTests.cs @@ -43,6 +43,9 @@ public class ImageAssetMetadataSourceTests : GivenContext { var command = new CreateAsset { File = file }; + A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(stream, file.MimeType, CancellationToken)) + .Returns(Task.FromResult(null)); + await sut.EnhanceAsync(command, CancellationToken); Assert.Empty(command.Tags); @@ -54,7 +57,7 @@ public class ImageAssetMetadataSourceTests : GivenContext var command = new CreateAsset { File = file }; A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(stream, file.MimeType, CancellationToken)) - .Returns(new ImageInfo(800, 600, ImageOrientation.None, ImageFormat.PNG)); + .Returns(new ImageInfo(ImageFormat.PNG, 800, 600, ImageOrientation.None, false)); await sut.EnhanceAsync(command, CancellationToken); @@ -62,7 +65,7 @@ public class ImageAssetMetadataSourceTests : GivenContext Assert.Equal(600, command.Metadata.GetPixelHeight()); Assert.Equal(AssetType.Image, command.Type); - A.CallTo(() => assetThumbnailGenerator.FixOrientationAsync(stream, file.MimeType, A._, A._)) + A.CallTo(() => assetThumbnailGenerator.FixAsync(stream, file.MimeType, A._, A._)) .MustNotHaveHappened(); } @@ -72,10 +75,31 @@ public class ImageAssetMetadataSourceTests : GivenContext var command = new CreateAsset { File = file }; A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(A._, file.MimeType, CancellationToken)) - .Returns(new ImageInfo(800, 600, ImageOrientation.None, ImageFormat.PNG)); + .Returns(new ImageInfo(ImageFormat.PNG, 800, 600, ImageOrientation.None, false)); + + A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(stream, file.MimeType, CancellationToken)) + .Returns(new ImageInfo(ImageFormat.PNG, 800, 600, ImageOrientation.BottomRight, false)).Once(); + + await sut.EnhanceAsync(command, CancellationToken); + + Assert.Equal(800, command.Metadata.GetPixelWidth()); + Assert.Equal(600, command.Metadata.GetPixelHeight()); + Assert.Equal(AssetType.Image, command.Type); + + A.CallTo(() => assetThumbnailGenerator.FixAsync(stream, file.MimeType, A._, CancellationToken)) + .MustHaveHappened(); + } + + [Fact] + public async Task Should_fix_image_if_it_contains_sensitive_metadata() + { + var command = new CreateAsset { File = file }; + + A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(A._, file.MimeType, CancellationToken)) + .Returns(new ImageInfo(ImageFormat.PNG, 800, 600, ImageOrientation.None, false)); A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(stream, file.MimeType, CancellationToken)) - .Returns(new ImageInfo(600, 800, ImageOrientation.BottomRight, ImageFormat.PNG)).Once(); + .Returns(new ImageInfo(ImageFormat.PNG, 800, 600, ImageOrientation.None, true)).Once(); await sut.EnhanceAsync(command, CancellationToken); @@ -83,7 +107,7 @@ public class ImageAssetMetadataSourceTests : GivenContext Assert.Equal(600, command.Metadata.GetPixelHeight()); Assert.Equal(AssetType.Image, command.Type); - A.CallTo(() => assetThumbnailGenerator.FixOrientationAsync(stream, file.MimeType, A._, CancellationToken)) + A.CallTo(() => assetThumbnailGenerator.FixAsync(stream, file.MimeType, A._, CancellationToken)) .MustHaveHappened(); } diff --git a/frontend/src/app/features/rules/pages/events/rule-event.component.html b/frontend/src/app/features/rules/pages/events/rule-event.component.html index 05c48cb3b..134fefa01 100644 --- a/frontend/src/app/features/rules/pages/events/rule-event.component.html +++ b/frontend/src/app/features/rules/pages/events/rule-event.component.html @@ -49,7 +49,7 @@
- +
diff --git a/frontend/src/app/features/rules/shared/actions/formattable-input.component.html b/frontend/src/app/features/rules/shared/actions/formattable-input.component.html index bd75523bf..734103da1 100644 --- a/frontend/src/app/features/rules/shared/actions/formattable-input.component.html +++ b/frontend/src/app/features/rules/shared/actions/formattable-input.component.html @@ -1,6 +1,6 @@
- +