diff --git a/Creek.FileRepository/Helpers/StringHelper.cs b/Creek.FileRepository/Helpers/StringHelper.cs
new file mode 100644
index 0000000..82e235b
--- /dev/null
+++ b/Creek.FileRepository/Helpers/StringHelper.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Creek.FileRepository.Helpers
+{
+ internal class StringHelper
+ {
+ public static bool IsInvalidFileName(string filename)
+ {
+ char[] invalidCharacters = new char[] { '<', '>', ':', '\'', '/', '\\', '|', '?', '*' };
+
+ return Array.Exists(invalidCharacters, character => filename.Contains(character.ToString()));
+ }
+
+ internal static string MakeValidFileName(string originalFileName)
+ {
+ char[] invalids = System.IO.Path.GetInvalidFileNameChars();
+ string validFileName = String.Join("_", originalFileName.Split(invalids, StringSplitOptions.RemoveEmptyEntries)).TrimEnd('.');
+
+ // Additionally remove Windows characters explicitly, in case we're running on Linux (e.g. in Docker) but need to access the files in Windows
+ string[] charsToRemove = new string[] { "<", ">", ":", "\"", "/", "\\", "|", "?", "*" };
+
+ validFileName = RemoveCharsFromString(charsToRemove, validFileName);
+
+ return validFileName;
+ }
+
+ internal static string RemoveCharsFromString(string[] charsToRemove, string str)
+ {
+ foreach (string c in charsToRemove)
+ {
+ str = str.Replace(c, string.Empty);
+ }
+
+ return str;
+ }
+ }
+}
diff --git a/Creek.FileRepository/Repositories/SftpRepository.cs b/Creek.FileRepository/Repositories/SftpRepository.cs
index 76dc630..0f4aeba 100644
--- a/Creek.FileRepository/Repositories/SftpRepository.cs
+++ b/Creek.FileRepository/Repositories/SftpRepository.cs
@@ -1,4 +1,5 @@
-using Creek.FileRepository.Models;
+using Creek.FileRepository.Helpers;
+using Creek.FileRepository.Models;
using Microsoft.Extensions.Configuration;
using Renci.SshNet;
using Renci.SshNet.Sftp;
@@ -40,6 +41,11 @@ namespace Creek.FileRepository.Repositories
/// Returns the filename.
public async Task CreateFileAsync(RepoFile file)
{
+ if (StringHelper.IsInvalidFileName(file.Filename))
+ {
+ throw new ArgumentException($"The filename for'{nameof(file)}' contains invalid characters for a filename.", nameof(file));
+ }
+
bool canOverride = false;
this.UploadFile(file, canOverride);
@@ -57,6 +63,10 @@ namespace Creek.FileRepository.Repositories
{
throw new ArgumentException($"'{nameof(filename)}' cannot be null or empty.", nameof(filename));
}
+ else if (StringHelper.IsInvalidFileName(filename))
+ {
+ throw new ArgumentException($"'{nameof(filename)}' contains invalid characters for a filename.", nameof(filename));
+ }
using (var client = new SftpClient(this.host, this.port == 0 ? 22 : this.port, this.username, this.password))
{
@@ -91,6 +101,10 @@ namespace Creek.FileRepository.Repositories
{
throw new ArgumentException($"'{nameof(filename)}' cannot be null or empty.", nameof(filename));
}
+ else if (StringHelper.IsInvalidFileName(filename))
+ {
+ throw new ArgumentException($"'{nameof(filename)}' contains invalid characters for a filename.", nameof(filename));
+ }
RepoFile repoFile = new RepoFile();
repoFile.Content = new System.IO.MemoryStream();
@@ -128,6 +142,11 @@ namespace Creek.FileRepository.Repositories
/// Returns true if update was successful.
public async Task UpdateFileAsync(RepoFile file)
{
+ if (StringHelper.IsInvalidFileName(file.Filename))
+ {
+ throw new ArgumentException($"The filename for'{nameof(file)}' contains invalid characters for a filename.", nameof(file));
+ }
+
bool canOverride = true;
this.UploadFile(file, canOverride);
diff --git a/UnitTests/SftpRepositoryShould.cs b/UnitTests/SftpRepositoryShould.cs
index 6b1f8a9..cf0b52f 100644
--- a/UnitTests/SftpRepositoryShould.cs
+++ b/UnitTests/SftpRepositoryShould.cs
@@ -20,6 +20,12 @@ namespace UnitTests
{
}
+ [Test]
+ public async Task ShouldNotCreateAFileWithAnInvalidFilename()
+ {
+ Assert.That(() => CreateTestFile("create>());
+ }
+
[Test]
public async Task ShouldCreateAFileWithoutThrowing()
{