From c2adab07160e724dbe3d22aac2de293096bad4c5 Mon Sep 17 00:00:00 2001 From: Jaime Bernardo Date: Mon, 8 Nov 2021 16:43:50 +0000 Subject: [PATCH] [ImageResizer]Sanitize target file name (#14040) * [ImageResizer] Sanitize target file name * Add a test * Avoid not recommended file names --- .../tests/Models/ResizeOperationTests.cs | 35 +++++++++++++++++++ .../imageresizer/ui/Models/ResizeOperation.cs | 33 ++++++++++++++++- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/modules/imageresizer/tests/Models/ResizeOperationTests.cs b/src/modules/imageresizer/tests/Models/ResizeOperationTests.cs index fa5f3882cb..ea22ccd05c 100644 --- a/src/modules/imageresizer/tests/Models/ResizeOperationTests.cs +++ b/src/modules/imageresizer/tests/Models/ResizeOperationTests.cs @@ -486,6 +486,41 @@ namespace ImageResizer.Models image => Assert.IsNull(((BitmapMetadata)image.Frames[0].Metadata).GetQuerySafe("System.Photo.Orientation"))); } + [TestMethod] + public void VerifyFileNameIsSanitized() + { + var operation = new ResizeOperation( + "Test.png", + _directory, + Settings( + s => + { + s.FileName = @"Directory\%1:*?""<>|(%2)"; + s.SelectedSize.Name = "Test\\/"; + })); + + operation.Execute(); + + Assert.IsTrue(File.Exists(_directory + @"\Directory\Test_______(Test__).png")); + } + + [TestMethod] + public void VerifyNotRecommendedNameIsChanged() + { + var operation = new ResizeOperation( + "Test.png", + _directory, + Settings( + s => + { + s.FileName = @"nul"; + })); + + operation.Execute(); + + Assert.IsTrue(File.Exists(_directory + @"\nul_.png")); + } + private static Settings Settings(Action action = null) { var settings = new Settings() diff --git a/src/modules/imageresizer/ui/Models/ResizeOperation.cs b/src/modules/imageresizer/ui/Models/ResizeOperation.cs index 268457e491..954c5c09c5 100644 --- a/src/modules/imageresizer/ui/Models/ResizeOperation.cs +++ b/src/modules/imageresizer/ui/Models/ResizeOperation.cs @@ -26,6 +26,14 @@ namespace ImageResizer.Models private readonly string _destinationDirectory; private readonly Settings _settings; + // Filenames to avoid according to https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#file-and-directory-names + private static readonly string[] _avoidFilenames = + { + "CON", "PRN", "AUX", "NUL", + "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", + "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", + }; + public ResizeOperation(string file, string destinationDirectory, Settings settings) { _file = file; @@ -205,16 +213,39 @@ namespace ImageResizer.Models extension = supportedExtensions.FirstOrDefault(); } + // Remove directory characters from the size's name. + string sizeNameSanitized = _settings.SelectedSize.Name; + sizeNameSanitized = sizeNameSanitized + .Replace('\\', '_') + .Replace('/', '_'); + // Using CurrentCulture since this is user facing var fileName = string.Format( CultureInfo.CurrentCulture, _settings.FileNameFormat, originalFileName, - _settings.SelectedSize.Name, + sizeNameSanitized, _settings.SelectedSize.Width, _settings.SelectedSize.Height, encoder.Frames[0].PixelWidth, encoder.Frames[0].PixelHeight); + + // Remove invalid characters from the final file name. + fileName = fileName + .Replace(':', '_') + .Replace('*', '_') + .Replace('?', '_') + .Replace('"', '_') + .Replace('<', '_') + .Replace('>', '_') + .Replace('|', '_'); + + // Avoid creating not recommended filenames + if (_avoidFilenames.Contains(fileName.ToUpperInvariant())) + { + fileName = fileName + "_"; + } + var path = _fileSystem.Path.Combine(directory, fileName + extension); var uniquifier = 1; while (_fileSystem.File.Exists(path))