From 8314145b44b2125f51dba127c5683dfa2428e065 Mon Sep 17 00:00:00 2001 From: David Lebee Date: Thu, 20 Aug 2020 17:28:42 -0400 Subject: [PATCH] sanitize and validate name of file s3. --- .../Blob/AzureBlobStorageProvider.cs | 10 ++++++ PoweredSoft.Storage.Core/IStorageProvider.cs | 3 ++ .../PhysicalStorageProvider.cs | 10 ++++++ PoweredSoft.Storage.S3/S3StorageProvider.cs | 23 ++++++++++++ .../PoweredSoft.Storage.Test.csproj | 20 +++++++++++ PoweredSoft.Storage.Test/S3Tests.cs | 35 +++++++++++++++++++ PoweredSoft.Storage.sln | 10 ++++-- 7 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 PoweredSoft.Storage.Test/PoweredSoft.Storage.Test.csproj create mode 100644 PoweredSoft.Storage.Test/S3Tests.cs diff --git a/PoweredSoft.Storage.Azure/Blob/AzureBlobStorageProvider.cs b/PoweredSoft.Storage.Azure/Blob/AzureBlobStorageProvider.cs index c3ef2d3..487f97d 100644 --- a/PoweredSoft.Storage.Azure/Blob/AzureBlobStorageProvider.cs +++ b/PoweredSoft.Storage.Azure/Blob/AzureBlobStorageProvider.cs @@ -212,5 +212,15 @@ namespace PoweredSoft.Storage.Azure.Blob var container = GetContainer(); return encoding.GetString(await this.GetFileBytesAsync(path)); } + + public bool IsFileNameAllowed(string fileName) + { + return true; + } + + public string SanitizeFileName(string key, string replacement) + { + return key; + } } } diff --git a/PoweredSoft.Storage.Core/IStorageProvider.cs b/PoweredSoft.Storage.Core/IStorageProvider.cs index 1ad1193..68e7281 100644 --- a/PoweredSoft.Storage.Core/IStorageProvider.cs +++ b/PoweredSoft.Storage.Core/IStorageProvider.cs @@ -20,5 +20,8 @@ namespace PoweredSoft.Storage.Core Task DeleteFileAsync(string path); Task DeleteDirectoryAsync(string path, bool force = false); Task CreateDirectoryAsync(string path); + + bool IsFileNameAllowed(string fileName); + string SanitizeFileName(string key, string replacement); } } diff --git a/PoweredSoft.Storage.Physical/PhysicalStorageProvider.cs b/PoweredSoft.Storage.Physical/PhysicalStorageProvider.cs index 05eccf6..514992c 100644 --- a/PoweredSoft.Storage.Physical/PhysicalStorageProvider.cs +++ b/PoweredSoft.Storage.Physical/PhysicalStorageProvider.cs @@ -145,5 +145,15 @@ namespace PoweredSoft.Storage.Physical if (!Directory.Exists(directoryPath)) Directory.CreateDirectory(directoryPath); } + + public bool IsFileNameAllowed(string fileName) + { + return true; + } + + public string SanitizeFileName(string key, string replacement) + { + return key; + } } } diff --git a/PoweredSoft.Storage.S3/S3StorageProvider.cs b/PoweredSoft.Storage.S3/S3StorageProvider.cs index e7dd278..ef00cae 100644 --- a/PoweredSoft.Storage.S3/S3StorageProvider.cs +++ b/PoweredSoft.Storage.S3/S3StorageProvider.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace PoweredSoft.Storage.S3 @@ -223,5 +224,27 @@ namespace PoweredSoft.Storage.S3 var ret = new S3FileInfo(s3o); return ret; } + + public string SanitizeFileName(string key, string replacement) + { + string pattern = @"[^a-zA-Z0-9.!/-_*'()]"; + string substitution = replacement; + string input = key; + RegexOptions options = RegexOptions.Multiline; + + Regex regex = new Regex(pattern, options); + + string result = regex.Replace(input, substitution); + return result; + } + + public bool IsFileNameAllowed(string fileName) + { + string pattern = @"[^a-zA-Z0-9.!/-_*'()]"; + RegexOptions options = RegexOptions.Multiline; + Regex regex = new Regex(pattern, options); + var hasMatches = regex.IsMatch(fileName); + return false == hasMatches; + } } } diff --git a/PoweredSoft.Storage.Test/PoweredSoft.Storage.Test.csproj b/PoweredSoft.Storage.Test/PoweredSoft.Storage.Test.csproj new file mode 100644 index 0000000..9cc1395 --- /dev/null +++ b/PoweredSoft.Storage.Test/PoweredSoft.Storage.Test.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp3.1 + + false + + + + + + + + + + + + + + diff --git a/PoweredSoft.Storage.Test/S3Tests.cs b/PoweredSoft.Storage.Test/S3Tests.cs new file mode 100644 index 0000000..b981746 --- /dev/null +++ b/PoweredSoft.Storage.Test/S3Tests.cs @@ -0,0 +1,35 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using PoweredSoft.Storage.S3; + +namespace PoweredSoft.Storage.Test +{ + [TestClass] + public class S3Tests + { + [TestMethod] + public void NameValidation() + { + var space = GetMockS3Space(); + + Assert.IsFalse(space.IsFileNameAllowed("Operations .pdf"), "Should not be valid"); + Assert.IsFalse(space.IsFileNameAllowed("Operations$$.pdf"), "Should not be valid"); + } + + [TestMethod] + public void NameSanitation() + { + var space = GetMockS3Space(); + + Assert.AreEqual("Operations_.pdf", space.SanitizeFileName("Operations .pdf", "_"), "does not match sanitation expectations"); + Assert.AreEqual("Operations__.pdf", space.SanitizeFileName("Operations$$.pdf", "_"), "does not match sanitation expectations"); + } + + private static S3StorageProvider GetMockS3Space() + { + var space = new S3StorageProvider("http://localhost:9000", "mybucket", "myminio", "myexample"); + space.SetForcePathStyle(true); + space.SetS3UsEast1RegionalEndpointValue(Amazon.Runtime.S3UsEast1RegionalEndpointValue.Legacy); + return space; + } + } +} diff --git a/PoweredSoft.Storage.sln b/PoweredSoft.Storage.sln index 68255e9..346c592 100644 --- a/PoweredSoft.Storage.sln +++ b/PoweredSoft.Storage.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.852 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30406.217 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PoweredSoft.Storage.Azure", "PoweredSoft.Storage.Azure\PoweredSoft.Storage.Azure.csproj", "{B937F389-07BE-4235-B2A8-7D1229B3D0FC}" EndProject @@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PoweredSoft.Storage.Physica EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PoweredSoft.Storage.S3", "PoweredSoft.Storage.S3\PoweredSoft.Storage.S3.csproj", "{457912EA-48E3-4B2E-941F-2116D18C6D88}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PoweredSoft.Storage.Test", "PoweredSoft.Storage.Test\PoweredSoft.Storage.Test.csproj", "{305416EE-51A4-4293-9262-87865D2784F4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,6 +35,10 @@ Global {457912EA-48E3-4B2E-941F-2116D18C6D88}.Debug|Any CPU.Build.0 = Debug|Any CPU {457912EA-48E3-4B2E-941F-2116D18C6D88}.Release|Any CPU.ActiveCfg = Release|Any CPU {457912EA-48E3-4B2E-941F-2116D18C6D88}.Release|Any CPU.Build.0 = Release|Any CPU + {305416EE-51A4-4293-9262-87865D2784F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {305416EE-51A4-4293-9262-87865D2784F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {305416EE-51A4-4293-9262-87865D2784F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {305416EE-51A4-4293-9262-87865D2784F4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE