[DONT MERGE] give a spec to input files

main
Paul Schneider 8 years ago
parent 26a1caf088
commit 8d09f50f22
12 changed files with 67 additions and 44 deletions

@ -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();
}
}

@ -1,7 +1,7 @@
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Yavsc.Helpers; using Yavsc.Abstract.FileSystem;
namespace Yavsc.ViewModels.UserFiles namespace Yavsc.ViewModels.UserFiles
{ {
@ -9,14 +9,14 @@ namespace Yavsc.ViewModels.UserFiles
{ {
public string UserName { get; private set; } public string UserName { get; private set; }
public string SubPath { get; private set; } public string SubPath { get; private set; }
public DefaultFileInfo [] Files { public RemoteFileInfo [] Files {
get; private set; get; private set;
} }
public string [] SubDirectories {  public string [] SubDirectories { 
get; private set; get; private set;
} }
private DirectoryInfo dInfo; private DirectoryInfo dInfo;
public UserDirectoryInfo(string username, string path) public UserDirectoryInfo(string userReposPath, string username, string path)
{ {
if (string.IsNullOrWhiteSpace(username)) if (string.IsNullOrWhiteSpace(username))
throw new NotSupportedException("No user name, no user dir."); throw new NotSupportedException("No user name, no user dir.");
@ -24,15 +24,15 @@ namespace Yavsc.ViewModels.UserFiles
var finalPath = username; var finalPath = username;
if (!string.IsNullOrWhiteSpace(path)) if (!string.IsNullOrWhiteSpace(path))
finalPath += Path.DirectorySeparatorChar + path; finalPath += Path.DirectorySeparatorChar + path;
if (!finalPath.IsValidPath()) if (!finalPath.IsValidYavscPath())
throw new InvalidOperationException( throw new InvalidOperationException(
$"File name contains invalid chars, using path {finalPath}"); $"File name contains invalid chars, using path {finalPath}");
dInfo = new DirectoryInfo( dInfo = new DirectoryInfo(
Startup.UserFilesDirName+Path.DirectorySeparatorChar+finalPath); userReposPath+FileSystemConstants.RemoteDirectorySeparator+finalPath);
if (!dInfo.Exists) dInfo.Create(); if (!dInfo.Exists) dInfo.Create();
Files = dInfo.GetFiles().Select 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(); CreationTime = entry.CreationTime, LastModified = entry.LastWriteTime }).ToArray();
SubDirectories = dInfo.GetDirectories().Select SubDirectories = dInfo.GetDirectories().Select
( d=> d.Name ).ToArray(); ( d=> d.Name ).ToArray();

@ -2,7 +2,7 @@ using System;
namespace Yavsc.ViewModels namespace Yavsc.ViewModels
{ {
public class DefaultFileInfo public class RemoteFileInfo
{ {
public string Name { get; set; } public string Name { get; set; }

@ -10,6 +10,7 @@ using Yavsc.Models;
namespace Yavsc.ApiControllers namespace Yavsc.ApiControllers
{ {
using System.Threading.Tasks; using System.Threading.Tasks;
using Yavsc.Abstract.FileSystem;
using Yavsc.Exceptions; using Yavsc.Exceptions;
public class FSQuotaException : Exception { public class FSQuotaException : Exception {
@ -38,16 +39,17 @@ namespace Yavsc.ApiControllers
public IActionResult GetDir(string subdir="") public IActionResult GetDir(string subdir="")
{ {
if (subdir !=null) if (subdir !=null)
if (!FileSystemHelpers.IsValidPath(subdir)) if (!subdir.IsValidYavscPath())
return new BadRequestResult(); return new BadRequestResult();
var files = User.GetUserFiles(subdir); var files = User.GetUserFiles(subdir);
return Ok(files); return Ok(files);
} }
[HttpPost] [HttpPost]
public IEnumerable<IActionResult> Post(string subdir="") public IEnumerable<IActionResult> Post(string subdir="", string names = null)
{ {
string root = null; string root = null;
string [] destinationFileNames = names?.Split('/');
InvalidPathException pathex = null; InvalidPathException pathex = null;
try { try {
@ -61,10 +63,12 @@ namespace Yavsc.ApiControllers
var user = dbContext.Users.Single( var user = dbContext.Users.Single(
u => u.Id == User.GetUserId() u => u.Id == User.GetUserId()
); );
int i=0;
foreach (var f in Request.Form.Files) 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()); dbContext.SaveChanges(User.GetUserId());
yield return Ok(item); yield return Ok(item);
}; };

@ -30,7 +30,7 @@ namespace Yavsc
AvatarsPath = "/avatars", AvatarsPath = "/avatars",
DefaultAvatar = "/images/Users/icon_user.png", DefaultAvatar = "/images/Users/icon_user.png",
AnonAvatar = "/images/Users/icon_anon_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 long DefaultFSQ = 1024*1024*500;
public static readonly Scope[] SiteScopes = {  public static readonly Scope[] SiteScopes = { 

@ -11,7 +11,6 @@ using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.OptionsModel; using Microsoft.Extensions.OptionsModel;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Yavsc.Helpers;
using Yavsc.Models; using Yavsc.Models;
using Yavsc.Services; using Yavsc.Services;
using Yavsc.ViewModels.Account; using Yavsc.ViewModels.Account;

@ -1,5 +1,4 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -13,10 +12,8 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.OptionsModel; using Microsoft.Extensions.OptionsModel;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using OAuth.AspNet.AuthServer; using OAuth.AspNet.AuthServer;
using Yavsc.Helpers;
using Yavsc.Models; using Yavsc.Models;
using Yavsc.Models.Auth; using Yavsc.Models.Auth;
using Yavsc.ViewModels.Account;
namespace Yavsc.Controllers namespace Yavsc.Controllers
{ {

@ -7,8 +7,10 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net.Mime; using System.Net.Mime;
using System.Security.Claims; using System.Security.Claims;
using System.Text;
using System.Web; using System.Web;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Yavsc.Abstract.FileSystem;
using Yavsc.Exceptions; using Yavsc.Exceptions;
using Yavsc.Models; using Yavsc.Models;
using Yavsc.Models.FileSystem; using Yavsc.Models.FileSystem;
@ -20,33 +22,30 @@ namespace Yavsc.Helpers
public static class FileSystemHelpers public static class FileSystemHelpers
{ {
public static UserDirectoryInfo GetUserFiles(this ClaimsPrincipal user, string subdir) 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; return di;
} }
public static bool IsValidDirectoryName(this string name)
{
return !name.Any(c => !Constants.ValidChars.Contains(c));
}
// Ensure this path is canonical, // Ensure this path is canonical,
// No "dirto/./this", neither "dirt/to/that/" // No "dirto/./this", neither "dirt/to/that/"
// no .. and each char must be listed as valid in constants // 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; if (fileName==null) return null;
foreach (var name in path.Split(Path.DirectorySeparatorChar)) StringBuilder sb = new StringBuilder();
foreach (var c in fileName)
{ {
if (!IsValidDirectoryName(name) || name.Equals("..") || name.Equals(".")) if (FileSystemConstants.ValidFileNameChars.Contains(c))
return false; sb.Append(c);
else sb.Append('_');
} }
if (path.EndsWith($"{Path.DirectorySeparatorChar}")) return false; return sb.ToString();
return true;
} }
public static string InitPostToFileSystem( public static string InitPostToFileSystem(
this ClaimsPrincipal user, this ClaimsPrincipal user,
@ -56,7 +55,7 @@ namespace Yavsc.Helpers
var diRoot = new DirectoryInfo(root); var diRoot = new DirectoryInfo(root);
if (!diRoot.Exists) diRoot.Create(); if (!diRoot.Exists) diRoot.Create();
if (!string.IsNullOrWhiteSpace(subpath)) { if (!string.IsNullOrWhiteSpace(subpath)) {
if (!subpath.IsValidPath()) if (!subpath.IsValidYavscPath())
{ {
throw new InvalidPathException(); throw new InvalidPathException();
} }
@ -66,6 +65,7 @@ namespace Yavsc.Helpers
if (!di.Exists) di.Create(); if (!di.Exists) di.Create();
return root; return root;
} }
public static void DeleteUserFile(this ApplicationUser user, string fileName) public static void DeleteUserFile(this ApplicationUser user, string fileName)
{ {
var root = Path.Combine(Startup.UserFilesDirName, user.UserName); var root = Path.Combine(Startup.UserFilesDirName, user.UserName);
@ -74,14 +74,14 @@ namespace Yavsc.Helpers
fi.Delete(); fi.Delete();
user.DiskUsage -= fi.Length; 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; long usage = user.DiskUsage;
var item = new FileRecievedInfo(); var item = new FileRecievedInfo();
// form-data; name="file"; filename="capt0008.jpg" // form-data; name="file"; filename="capt0008.jpg"
ContentDisposition contentDisposition = new ContentDisposition(f.ContentDisposition); ContentDisposition contentDisposition = new ContentDisposition(f.ContentDisposition);
item.FileName = contentDisposition.FileName; item.FileName = FilterFileName (destFileName ?? contentDisposition.FileName);
item.MimeType = contentDisposition.DispositionType; item.MimeType = contentDisposition.DispositionType;
var fi = new FileInfo(Path.Combine(root, item.FileName)); var fi = new FileInfo(Path.Combine(root, item.FileName));
if (fi.Exists) item.Overriden = true; if (fi.Exists) item.Overriden = true;
@ -111,7 +111,7 @@ namespace Yavsc.Helpers
user.DiskUsage = usage; user.DiskUsage = usage;
return item; 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 + "/" + return new HtmlString( Startup.UserFilesOptions.RequestPath+"/"+ username + "/" + subpath + "/" +
HttpUtility.UrlEncode(info.Name) ); HttpUtility.UrlEncode(info.Name) );

@ -1,7 +1,6 @@
using System; using System;
using Microsoft.Data.Entity; using Microsoft.Data.Entity;
using Microsoft.Data.Entity.Infrastructure; using Microsoft.Data.Entity.Infrastructure;
using Microsoft.Data.Entity.Metadata;
using Microsoft.Data.Entity.Migrations; using Microsoft.Data.Entity.Migrations;
using Yavsc.Models; using Yavsc.Models;

@ -1,5 +1,3 @@
using System;
using System.Collections.Generic;
using Microsoft.Data.Entity.Migrations; using Microsoft.Data.Entity.Migrations;
namespace Yavsc.Migrations namespace Yavsc.Migrations

@ -12,7 +12,7 @@ namespace Yavsc.ViewComponents
IViewComponentResult result = null; IViewComponentResult result = null;
await Task.Run(() => await Task.Run(() =>
{ {
result = View(new UserDirectoryInfo(User.Identity.Name, dirname)); result = View(new UserDirectoryInfo(Startup.UserFilesDirName, User.Identity.Name, dirname));
}); });
return result; return result;
} }

@ -1,7 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Yavsc.Models.Auth namespace Yavsc.Models.Auth
{ {
public class Me : IApplicationUser { public class Me : IApplicationUser {

Loading…