feat(*): Add filename validity checks to SftpRepository

This commit is contained in:
Josh Creek
2021-08-30 18:56:54 +01:00
parent d80cc8237d
commit 4600ebf82b
3 changed files with 65 additions and 1 deletions
@@ -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;
}
}
}
@@ -1,4 +1,5 @@
using Creek.FileRepository.Models; using Creek.FileRepository.Helpers;
using Creek.FileRepository.Models;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Renci.SshNet; using Renci.SshNet;
using Renci.SshNet.Sftp; using Renci.SshNet.Sftp;
@@ -40,6 +41,11 @@ namespace Creek.FileRepository.Repositories
/// <returns>Returns the filename.</returns> /// <returns>Returns the filename.</returns>
public async Task<string> CreateFileAsync(RepoFile file) public async Task<string> 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; bool canOverride = false;
this.UploadFile(file, canOverride); this.UploadFile(file, canOverride);
@@ -57,6 +63,10 @@ namespace Creek.FileRepository.Repositories
{ {
throw new ArgumentException($"'{nameof(filename)}' cannot be null or empty.", nameof(filename)); 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)) 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)); 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 repoFile = new RepoFile();
repoFile.Content = new System.IO.MemoryStream(); repoFile.Content = new System.IO.MemoryStream();
@@ -128,6 +142,11 @@ namespace Creek.FileRepository.Repositories
/// <returns>Returns true if update was successful.</returns> /// <returns>Returns true if update was successful.</returns>
public async Task<bool> UpdateFileAsync(RepoFile file) public async Task<bool> 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; bool canOverride = true;
this.UploadFile(file, canOverride); this.UploadFile(file, canOverride);
+6
View File
@@ -20,6 +20,12 @@ namespace UnitTests
{ {
} }
[Test]
public async Task ShouldNotCreateAFileWithAnInvalidFilename()
{
Assert.That(() => CreateTestFile("create><invalid?/test.txt"), Throws.TypeOf<ArgumentException>());
}
[Test] [Test]
public async Task ShouldCreateAFileWithoutThrowing() public async Task ShouldCreateAFileWithoutThrowing()
{ {