diff --git a/Yavsc.Abstract/FileSystem/FileSystemHelpers.cs b/Yavsc.Abstract/FileSystem/FileSystemHelpers.cs new file mode 100644 index 00000000..df09b244 --- /dev/null +++ b/Yavsc.Abstract/FileSystem/FileSystemHelpers.cs @@ -0,0 +1,30 @@ +using System.Linq; + +namespace Yavsc.Abstract.FileSystem +{ + public static class FileSystemHelpers + { + public static bool IsValidYavscPath(this string path) + { + if (path == null) return true; + foreach (var name in path.Split('/')) + { + if (!IsValidDirectoryName(name) || name.Equals("..") || name.Equals(".")) + return false; + } + if (path[path.Length]==FileSystemConstants.RemoteDirectorySeparator) return false; + return true; + } + public static bool IsValidDirectoryName(this string name) + { + return !name.Any(c => !FileSystemConstants.ValidFileNameChars.Contains(c)); + } + + } + + public static class FileSystemConstants + { + public const char RemoteDirectorySeparator = '/'; + public static char[] ValidFileNameChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-=_~. ".ToCharArray(); + } +} \ No newline at end of file diff --git a/Yavsc/ViewModels/UserFiles/UserDirectoryInfo.cs b/Yavsc.Abstract/FileSystem/UserDirectoryInfo.cs similarity index 76% rename from Yavsc/ViewModels/UserFiles/UserDirectoryInfo.cs rename to Yavsc.Abstract/FileSystem/UserDirectoryInfo.cs index e4bc5703..c4b1c71a 100644 --- a/Yavsc/ViewModels/UserFiles/UserDirectoryInfo.cs +++ b/Yavsc.Abstract/FileSystem/UserDirectoryInfo.cs @@ -1,7 +1,7 @@ using System; using System.IO; using System.Linq; -using Yavsc.Helpers; +using Yavsc.Abstract.FileSystem; namespace Yavsc.ViewModels.UserFiles { @@ -9,14 +9,14 @@ namespace Yavsc.ViewModels.UserFiles { public string UserName { get; private set; } public string SubPath { get; private set; } - public DefaultFileInfo [] Files { + public RemoteFileInfo [] Files { get; private set; } public string [] SubDirectories {  get; private set; } private DirectoryInfo dInfo; - public UserDirectoryInfo(string username, string path) + public UserDirectoryInfo(string userReposPath, string username, string path) { if (string.IsNullOrWhiteSpace(username)) throw new NotSupportedException("No user name, no user dir."); @@ -24,15 +24,15 @@ namespace Yavsc.ViewModels.UserFiles var finalPath = username; if (!string.IsNullOrWhiteSpace(path)) finalPath += Path.DirectorySeparatorChar + path; - if (!finalPath.IsValidPath()) + if (!finalPath.IsValidYavscPath()) throw new InvalidOperationException( $"File name contains invalid chars, using path {finalPath}"); dInfo = new DirectoryInfo( - Startup.UserFilesDirName+Path.DirectorySeparatorChar+finalPath); + userReposPath+FileSystemConstants.RemoteDirectorySeparator+finalPath); if (!dInfo.Exists) dInfo.Create(); Files = dInfo.GetFiles().Select - ( entry => new DefaultFileInfo { Name = entry.Name, Size = entry.Length, + ( entry => new RemoteFileInfo { Name = entry.Name, Size = entry.Length, CreationTime = entry.CreationTime, LastModified = entry.LastWriteTime }).ToArray(); SubDirectories = dInfo.GetDirectories().Select ( d=> d.Name ).ToArray(); diff --git a/Yavsc/ViewModels/UserFiles/UserFileInfo.cs b/Yavsc.Abstract/FileSystem/UserFileInfo.cs similarity index 87% rename from Yavsc/ViewModels/UserFiles/UserFileInfo.cs rename to Yavsc.Abstract/FileSystem/UserFileInfo.cs index bf7cfc6b..027161a2 100644 --- a/Yavsc/ViewModels/UserFiles/UserFileInfo.cs +++ b/Yavsc.Abstract/FileSystem/UserFileInfo.cs @@ -2,7 +2,7 @@ using System; namespace Yavsc.ViewModels { - public class DefaultFileInfo + public class RemoteFileInfo { public string Name { get; set; } diff --git a/Yavsc/ApiControllers/FileSystemApiController.cs b/Yavsc/ApiControllers/FileSystemApiController.cs index 0007931f..66bbbfe0 100644 --- a/Yavsc/ApiControllers/FileSystemApiController.cs +++ b/Yavsc/ApiControllers/FileSystemApiController.cs @@ -10,6 +10,7 @@ using Yavsc.Models; namespace Yavsc.ApiControllers { using System.Threading.Tasks; + using Yavsc.Abstract.FileSystem; using Yavsc.Exceptions; public class FSQuotaException : Exception { @@ -38,16 +39,17 @@ namespace Yavsc.ApiControllers public IActionResult GetDir(string subdir="") { if (subdir !=null) - if (!FileSystemHelpers.IsValidPath(subdir)) + if (!subdir.IsValidYavscPath()) return new BadRequestResult(); var files = User.GetUserFiles(subdir); return Ok(files); } [HttpPost] - public IEnumerable Post(string subdir="") + public IEnumerable Post(string subdir="", string names = null) { string root = null; + string [] destinationFileNames = names?.Split('/'); InvalidPathException pathex = null; try { @@ -61,10 +63,12 @@ namespace Yavsc.ApiControllers var user = dbContext.Users.Single( u => u.Id == User.GetUserId() ); - + int i=0; foreach (var f in Request.Form.Files) { - var item = user.ReceiveUserFile(root, f); + var destFileName = destinationFileNames?.Length >i ? destinationFileNames[i] : null; + + var item = user.ReceiveUserFile(root, f, destFileName); dbContext.SaveChanges(User.GetUserId()); yield return Ok(item); }; diff --git a/Yavsc/Constants.cs b/Yavsc/Constants.cs index 7bbe243a..3945fd16 100644 --- a/Yavsc/Constants.cs +++ b/Yavsc/Constants.cs @@ -30,7 +30,7 @@ namespace Yavsc AvatarsPath = "/avatars", DefaultAvatar = "/images/Users/icon_user.png", AnonAvatar = "/images/Users/icon_anon_user.png"; - public static char[] ValidChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-=_~. ".ToCharArray(); + public static readonly long DefaultFSQ = 1024*1024*500; public static readonly Scope[] SiteScopes = {  diff --git a/Yavsc/Controllers/AccountController.cs b/Yavsc/Controllers/AccountController.cs index 490df43b..064c56a0 100644 --- a/Yavsc/Controllers/AccountController.cs +++ b/Yavsc/Controllers/AccountController.cs @@ -11,7 +11,6 @@ using Microsoft.AspNet.Mvc.Rendering; using Microsoft.Extensions.Logging; using Microsoft.Extensions.OptionsModel; using Microsoft.AspNet.Http; -using Yavsc.Helpers; using Yavsc.Models; using Yavsc.Services; using Yavsc.ViewModels.Account; diff --git a/Yavsc/Controllers/OAuthController.cs b/Yavsc/Controllers/OAuthController.cs index 2dc92d16..2ef7d150 100644 --- a/Yavsc/Controllers/OAuthController.cs +++ b/Yavsc/Controllers/OAuthController.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; @@ -13,10 +12,8 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.OptionsModel; using Microsoft.Extensions.Primitives; using OAuth.AspNet.AuthServer; -using Yavsc.Helpers; using Yavsc.Models; using Yavsc.Models.Auth; -using Yavsc.ViewModels.Account; namespace Yavsc.Controllers { diff --git a/Yavsc/Helpers/FileSystemHelpers.cs b/Yavsc/Helpers/FileSystemHelpers.cs index 64ad15c6..56a38294 100644 --- a/Yavsc/Helpers/FileSystemHelpers.cs +++ b/Yavsc/Helpers/FileSystemHelpers.cs @@ -7,8 +7,10 @@ using System.IO; using System.Linq; using System.Net.Mime; using System.Security.Claims; +using System.Text; using System.Web; using Microsoft.AspNet.Http; +using Yavsc.Abstract.FileSystem; using Yavsc.Exceptions; using Yavsc.Models; using Yavsc.Models.FileSystem; @@ -20,33 +22,30 @@ namespace Yavsc.Helpers public static class FileSystemHelpers { + public static UserDirectoryInfo GetUserFiles(this ClaimsPrincipal user, string subdir) { - UserDirectoryInfo di = new UserDirectoryInfo(user.Identity.Name, subdir); + UserDirectoryInfo di = new UserDirectoryInfo(Startup.UserFilesDirName, user.Identity.Name, subdir); return di; } - - public static bool IsValidDirectoryName(this string name) - { - return !name.Any(c => !Constants.ValidChars.Contains(c)); - } - // Ensure this path is canonical, // No "dirto/./this", neither "dirt/to/that/" // no .. and each char must be listed as valid in constants - public static bool IsValidPath(this string path) + + public static string FilterFileName(string fileName) { - if (path == null) return true; - foreach (var name in path.Split(Path.DirectorySeparatorChar)) + if (fileName==null) return null; + StringBuilder sb = new StringBuilder(); + foreach (var c in fileName) { - if (!IsValidDirectoryName(name) || name.Equals("..") || name.Equals(".")) - return false; + if (FileSystemConstants.ValidFileNameChars.Contains(c)) + sb.Append(c); + else sb.Append('_'); } - if (path.EndsWith($"{Path.DirectorySeparatorChar}")) return false; - return true; + return sb.ToString(); } public static string InitPostToFileSystem( this ClaimsPrincipal user, @@ -56,7 +55,7 @@ namespace Yavsc.Helpers var diRoot = new DirectoryInfo(root); if (!diRoot.Exists) diRoot.Create(); if (!string.IsNullOrWhiteSpace(subpath)) { - if (!subpath.IsValidPath()) + if (!subpath.IsValidYavscPath()) { throw new InvalidPathException(); } @@ -66,6 +65,7 @@ namespace Yavsc.Helpers if (!di.Exists) di.Create(); return root; } + public static void DeleteUserFile(this ApplicationUser user, string fileName) { var root = Path.Combine(Startup.UserFilesDirName, user.UserName); @@ -74,14 +74,14 @@ namespace Yavsc.Helpers fi.Delete(); user.DiskUsage -= fi.Length; } - public static FileRecievedInfo ReceiveUserFile(this ApplicationUser user, string root, IFormFile f) + public static FileRecievedInfo ReceiveUserFile(this ApplicationUser user, string root, IFormFile f, string destFileName = null) { long usage = user.DiskUsage; var item = new FileRecievedInfo(); // form-data; name="file"; filename="capt0008.jpg" ContentDisposition contentDisposition = new ContentDisposition(f.ContentDisposition); - item.FileName = contentDisposition.FileName; + item.FileName = FilterFileName (destFileName ?? contentDisposition.FileName); item.MimeType = contentDisposition.DispositionType; var fi = new FileInfo(Path.Combine(root, item.FileName)); if (fi.Exists) item.Overriden = true; @@ -111,7 +111,7 @@ namespace Yavsc.Helpers user.DiskUsage = usage; return item; } - public static HtmlString FileLink(this DefaultFileInfo info, string username, string subpath) + public static HtmlString FileLink(this RemoteFileInfo info, string username, string subpath) { return new HtmlString( Startup.UserFilesOptions.RequestPath+"/"+ username + "/" + subpath + "/" + HttpUtility.UrlEncode(info.Name) ); diff --git a/Yavsc/Migrations/20180102153009_chatRooms.Designer.cs b/Yavsc/Migrations/20180102153009_chatRooms.Designer.cs index 0d3d4fdd..a6163caa 100644 --- a/Yavsc/Migrations/20180102153009_chatRooms.Designer.cs +++ b/Yavsc/Migrations/20180102153009_chatRooms.Designer.cs @@ -1,7 +1,6 @@ using System; using Microsoft.Data.Entity; using Microsoft.Data.Entity.Infrastructure; -using Microsoft.Data.Entity.Metadata; using Microsoft.Data.Entity.Migrations; using Yavsc.Models; diff --git a/Yavsc/Migrations/20180102153009_chatRooms.cs b/Yavsc/Migrations/20180102153009_chatRooms.cs index 334da8e2..c23fac19 100644 --- a/Yavsc/Migrations/20180102153009_chatRooms.cs +++ b/Yavsc/Migrations/20180102153009_chatRooms.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections.Generic; using Microsoft.Data.Entity.Migrations; namespace Yavsc.Migrations diff --git a/Yavsc/ViewComponents/DirectoryViewComponent.cs b/Yavsc/ViewComponents/DirectoryViewComponent.cs index faf327f3..8b97167f 100644 --- a/Yavsc/ViewComponents/DirectoryViewComponent.cs +++ b/Yavsc/ViewComponents/DirectoryViewComponent.cs @@ -12,7 +12,7 @@ namespace Yavsc.ViewComponents IViewComponentResult result = null; await Task.Run(() => { - result = View(new UserDirectoryInfo(User.Identity.Name, dirname)); + result = View(new UserDirectoryInfo(Startup.UserFilesDirName, User.Identity.Name, dirname)); }); return result; } diff --git a/Yavsc/ViewModels/Account/Me.cs b/Yavsc/ViewModels/Account/Me.cs index 20e23481..1cd7d954 100644 --- a/Yavsc/ViewModels/Account/Me.cs +++ b/Yavsc/ViewModels/Account/Me.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Yavsc.Models.Auth +namespace Yavsc.Models.Auth { public class Me : IApplicationUser { public Me(ApplicationUser user)