Rewrite the upload page.

dotnetflags
C-xC-c 4 years ago
parent 4f1fceadcd
commit dc88b5ccf1

@ -15,6 +15,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.0" />
<PackageReference Include="MySql.Data" Version="8.0.18" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />

@ -32,27 +32,6 @@ namespace BantFlags.Data.Database
KnownFlags = flags.ToHashSet();
}
public async Task DeleteFlagsAsync(List<FormFlag> flags)
{
using var rentedConnection = await ConnectionPool.RentConnectionAsync();
using var query = rentedConnection.Object.UseStoredProcedure("delete_flag");
flags.ForEach(async f =>
await query.SetParam("@flag", f.Name)
.ExecuteNonQueryAsync(reuse: true));
}
public async Task RenameFlagsAsync(List<RenameFlag> flags)
{
using var rentedConnection = await ConnectionPool.RentConnectionAsync();
using var query = rentedConnection.Object.UseStoredProcedure("rename_flag");
flags.ForEach(async flag =>
await query.SetParam("@old", flag.Name)
.SetParam("@new", flag.NewName)
.ExecuteNonQueryAsync(reuse: true));
}
public async Task InsertPost(PostModel post)
{
using (var rentedConnection = await ConnectionPool.RentConnectionAsync())
@ -88,14 +67,29 @@ namespace BantFlags.Data.Database
.ToList();
}
public async Task InsertFlagsAsync(List<FormFlag> flags)
public async Task InsertFlagAsync(Flag flag)
{
using var rentedConnection = await ConnectionPool.RentConnectionAsync();
await rentedConnection.Object.UseStoredProcedure("insert_flag")
.SetParam("@flag", flag.Name)
.ExecuteNonQueryAsync();
}
public async Task RenameFlagAsync(Flag flag)
{
using var rentedConnection = await ConnectionPool.RentConnectionAsync();
using var query = rentedConnection.Object.UseStoredProcedure("insert_flag");
await rentedConnection.Object.UseStoredProcedure("rename_flag")
.SetParam("@old", flag.OldName)
.SetParam("@new", flag.Name)
.ExecuteNonQueryAsync();
}
flags.ForEach(async f =>
await query.SetParam("@flag", f.Name)
.ExecuteNonQueryAsync(reuse: true));
public async Task DeleteFlagAsync(Flag flag)
{
using var rentedConnection = await ConnectionPool.RentConnectionAsync();
await rentedConnection.Object.UseStoredProcedure("delete_flag")
.SetParam("@flag", flag.Name)
.ExecuteNonQueryAsync();
}
}

@ -1,63 +1,139 @@
using System.Collections.Generic;
using ImageMagick;
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace BantFlags.Data
{
/// <summary>
/// Singleton class comprised of objects used in/Upload.
/// It's a fucking mess and I hate it so much.
/// </summary>
public class Staging
{
public List<RenameFlag> RenamedFlags { get; set; }
public List<FormFlag> DeletedFlags { get; set; }
public List<FormFlag> AddedFlags { get; set; }
/// <summary>
/// The current list of resolved flags including changes currently in Staging.
/// Exists here since it's a singleton.
/// </summary>
public List<string> Flags { get; set; }
/// <summary>
/// Used for commiting and unstaging staged flags.
/// </summary>
public List<Flag> Flags { get; set; }
public string Password { get; }
public HashSet<string> Names { get; set; }
public Staging(string password)
{
RenamedFlags = new List<RenameFlag>();
DeletedFlags = new List<FormFlag>();
AddedFlags = new List<FormFlag>();
Flags = new List<Flag>();
Password = password;
}
public void Clear()
{
RenamedFlags = new List<RenameFlag>();
DeletedFlags = new List<FormFlag>();
AddedFlags = new List<FormFlag>();
Flags = new List<Flag>();
}
}
public class FormFlag
public enum Method
{
public string Name { get; set; }
public bool IsChecked { get; set; }
Delete,
public Method FormMethod { get; set; }
}
Rename,
public class RenameFlag : FormFlag
{
public string NewName { get; set; }
Add
}
public enum Method
public class Flag
{
Delete,
public string Name { get; set; }
Rename,
public string OldName { get; set; }
Add
public bool IsChecked { get; set; }
public Method FlagMethod { get; set; }
public Flag()
{
}
private Flag(string name, Method method)
{
Name = name;
FlagMethod = method;
}
private Flag(string name, string oldName, Method method)
{
Name = name;
OldName = oldName;
FlagMethod = method;
}
public static Result<Flag> CreateFromDelete(string name)
=> Result<Flag>.Pass(new Flag(name, Method.Delete)); // We don't need any validation for deleted flags.
public static Result<Flag> CreateFromRename(string oldName, string newName, HashSet<string> names)
{
Result<string> fileName = ValidateFileName(newName, names);
if (fileName.Failed)
return Result<Flag>.Fail(fileName.ErrorMessage);
return Result<Flag>.Pass(new Flag(newName, oldName, Method.Rename));
}
public static async Task<Result<Flag>> CreateFromFile(IFormFile upload, HashSet<string> names)
{
byte[] PNGHeader = new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
if (upload.ContentType.ToLower() != "image/png")
return Result<Flag>.Fail("Image must be a png.");
if (upload.Length > 15 * 1024)
return Result<Flag>.Fail("File too big. Max size is 15kb.");
var name = Path.GetFileNameWithoutExtension(upload.FileName);
Result<string> fileName = ValidateFileName(name, names);
if (fileName.Failed)
return Result<Flag>.Fail(fileName.ErrorMessage);
using (var memoryStream = new MemoryStream())
{
await upload.CopyToAsync(memoryStream);
memoryStream.Position = 0;
using (var image = new MagickImage(memoryStream))
{
if (image.Width != 16 || image.Height != 11)
return Result<Flag>.Fail("Invalid image dimensions. Flags should be 16px by 11px.");
}
using (var reader = new BinaryReader(memoryStream))
{
reader.BaseStream.Position = 0;
if (!reader.ReadBytes(PNGHeader.Length).SequenceEqual(PNGHeader))
return Result<Flag>.Fail("Invalid png header.");
}
}
return Result<Flag>.Pass(new Flag(name, Method.Add));
}
private static Result<string> ValidateFileName(string name, HashSet<string> names)
{
if (string.IsNullOrWhiteSpace(name))
return Result<string>.Fail("Flag name can't be empty.");
if (name.Length > 100)
return Result<string>.Fail("Flag name too long.");
if (name == "empty, or there were errors. Re - set your flags.")
return Result<string>.Fail("Invalid flag name.");
if (name.Contains("||") || name.Contains(","))
return Result<string>.Fail("Flag name contains invalid characters. You can't use \"||\" or \",\".");
if (names.Contains(name))
return Result<string>.Fail("A flag with that name already exists.");
return Result<string>.Pass(name);
}
}
}

@ -10,8 +10,8 @@
<a href="~/bantflags.user.js">Install Bantflags</a>
<br />
<br />
<a href="https://nineball.party/srsbsn/3521">Official Thread</a>
<br />
<a href="https://nineball.party/srsbsn/3521#bottom">Official Thread</a>
<br />
<br />
<a asp-page="Upload">Upload Flags</a>

@ -1,5 +1,5 @@
@page
@using BantFlags.Data
@using BantFlags.Data
@model BantFlags.UploadModel
@{
ViewData["Title"] = "Upload";
@ -8,27 +8,24 @@
<h1>Upload</h1>
<img src="~/montage.png" />
@Model.Message
<h2 id="message">@Model.Message</h2>
<h2>Add a Flag</h2>
<form method="post" asp-page-handler="Add" enctype="multipart/form-data">
<input type="file" asp-for="Upload" />
@Html.CheckBoxFor(model => model.ShouldGloss)<span>Apply Gloss?</span>
<input type="file" name="upload" />
<input type="checkbox" name="gloss" value="true" /><span>Apply Gloss?</span>
<br />
<br />
<input type="submit" value="Upload Flag" />
</form>
<h2>Manage Existing Flags</h2>
<form method="post" enctype="multipart/form-data">
<label>Flag:</label>
<form method="post">
<select name="flag">
@foreach (string s in Model.staging.Flags)
@foreach (string s in Model.StagedFlags.Names)
{
<option>@s</option>
}
</select>
<label>New Name:</label>
<input type="text" name="newName" />
<br />
<br />
@ -45,77 +42,65 @@
<input type="submit" value="Commit Changes" />
</form>
<h2>Pending Changes</h2>
<form method="post" asp-page-handler="Unstage">
<label>Password:</label>
<input type="text" name="password" />
<br />
<br />
<button type="submit" onclick="window.confirm('Really unstage the selected flags?')">unstage</button>
@if (Model.staging.AddedFlags.Any())
{
<h3>New Flags</h3>
<div class="flag-container">
@foreach (FormFlag flag in Model.staging.AddedFlags)
@if (Model.StagedFlags.Flags.Any())
{
<h2>Pending Changes</h2>
<form method="post" asp-page-handler="Unstage">
<input type="text" name="password" />
<br />
<br />
<button type="submit">Remove from staging</button>
<h3>Deleted Flags</h3>
@* TODO: There has to be a better way to handle this*@
@for (int i = 0; i < Model.StagedFlags.Flags.Count(); i++)
{
if (Model.StagedFlags.Flags[i].FlagMethod == Method.Delete)
{
<div class="flag">
<img src="~/flags/staging/@(flag.Name).png" />
<br />
<span>@flag.Name</span>
<input type="hidden" name="addedAndDeletedFlags.Index" value="@flag.Name" />
<input type="hidden" name="addedAndDeletedFlags[@flag.Name].Name" value="@flag.Name" />
<input type="hidden" name="addedAndDeletedFlags[@flag.Name].Method" value="@Method.Add" />
<br />
<input type="checkbox" name="addedAndDeletedFlags[@flag.Name].IsChecked" value="true" />
<label>@(Model.StagedFlags.Flags[i].Name)</label>
<img src="~/flags/@(Model.StagedFlags.Flags[i].Name).png" />
<input type="hidden" name="flags[@i].Name" value="@Model.StagedFlags.Flags[i].Name" />
<input type="hidden" name="flags[@i].FormMethod" value="@Model.StagedFlags.Flags[i].FlagMethod" />
<input type="checkbox" name="flags[@i].IsChecked" value="true" />
</div>
}
</div>
}
@if (Model.staging.DeletedFlags.Any())
{
<h3>Deleted Flags</h3>
<div class="flag-container">
@foreach (FormFlag flag in Model.staging.DeletedFlags)
}
<h3>Renamed Flags</h3>
@for (int i = 0; i < Model.StagedFlags.Flags.Count(); i++)
{
if (Model.StagedFlags.Flags[i].FlagMethod == Method.Rename)
{
<div class="flag">
<img src="~/flags/@(flag.Name).png" />
<br />
<span>@flag.Name</span>
<input type="hidden" name="addedAndDeletedFlags.Index" value="@flag.Name" />
<input type="hidden" name="addedAndDeletedFlags[@flag.Name].Name" value="@flag.Name" />
<input type="hidden" name="addedAndDeletedFlags[@flag.Name].Method" value="@Method.Delete" />
<br />
<input type="checkbox" name="addedAndDeletedFlags[@flag.Name].IsChecked" value="true" />
<label>@(Model.StagedFlags.Flags[i].Name)</label>
<img src="~/flags/@(Model.StagedFlags.Flags[i].OldName).png" />
<input type="hidden" name="flags[@i].Name" value="@Model.StagedFlags.Flags[i].Name" />
<input type="hidden" name="flags[@i].FormMethod" value="@Model.StagedFlags.Flags[i].FlagMethod" />
<input type="checkbox" name="flags[@i].IsChecked" value="true" />
</div>
}
</div>
}
}
@if (Model.staging.RenamedFlags.Any())
{
<h3>Renamed Flags</h3>
<div class="flag-container">
@foreach (RenameFlag flag in Model.staging.RenamedFlags)
<h3>Added Flags</h3>
@for (int i = 0; i < Model.StagedFlags.Flags.Count(); i++)
{
if (Model.StagedFlags.Flags[i].FlagMethod == Method.Add)
{
<div class="flag">
<img src="~/flags/@(flag.Name).png" />
<br />
<span>@flag.NewName</span>
<input type="hidden" name="renamedFlags.Index" value="@flag.Name" />
<input type="hidden" name="renamedFlags[@flag.Name].Name" value="@flag.Name" />
<input type="hidden" name="renamedFlags[@flag.Name].Method" value="@Method.Rename" />
<input type="hidden" name="renamedFlags[@flag.Name].NewName" value="@flag.NewName" />
<br />
<input type="checkbox" name="renamedFlags[@flag.Name].IsChecked" value="true" />
<label>@(Model.StagedFlags.Flags[i].Name)</label>
<img src="~/flags/staging/@(Model.StagedFlags.Flags[i].Name).png" />
<input type="hidden" name="flags[@i].Name" value="@Model.StagedFlags.Flags[i].Name" />
<input type="hidden" name="flags[@i].FormMethod" value="@Model.StagedFlags.Flags[i].FlagMethod" />
<input type="checkbox" name="flags[@i].IsChecked" value="true" />
</div>
}
</div>
}
</form>
}
</form>
}
@section Head {
<link rel="stylesheet" href="~/upload.css" />
@ -128,7 +113,7 @@
let x = document.getElementsByTagName('select')[0].children
Array.prototype.slice.call(x).forEach(function (y) {
var name = y.innerHTML;
y.innerHTML = "<img src=\"https://flags.plum.moe/flags/" + name + ".png\">" + name
y.innerHTML = "<img src=\"flags/" + name + ".png\">" + name
});
}, { once: true });
</script>

@ -7,274 +7,181 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace BantFlags
{
// I don't know if I need these anymore.
[RequestFormLimits(ValueCountLimit = 5000)]
[IgnoreAntiforgeryToken(Order = 2000)]
public class UploadModel : PageModel
{
private IWebHostEnvironment Env { get; }
private DatabaseService Database { get; set; }
public Staging StagedFlags { get; set; }
public string Message { get; private set; }
private readonly byte[] PNGHeader = new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
private string FlagsPath { get; set; }
private string WebRoot { get; }
public Staging staging { get; set; }
public HashSet<string> AllNames => StagedFlags.Names.Concat(StagedFlags.Flags.Select(x => x.Name)).ToHashSet();
public UploadModel(IWebHostEnvironment env, DatabaseService db, Staging s)
public UploadModel(DatabaseService dbs, Staging ns, IWebHostEnvironment env)
{
Env = env;
Database = db;
Database = dbs;
staging = s;
StagedFlags = ns;
FlagsPath = Env.WebRootPath + "/flags/";
WebRoot = env.WebRootPath;
}
public string Message { get; private set; }
// TODO: These bound properties should be inlined.
[BindProperty]
public IFormFile Upload { get; set; }
[BindProperty]
public bool ShouldGloss { get; set; }
public async void OnGet()
public void OnGet()
{
if (staging.Flags == null)
{
staging.Flags = await Database.GetFlags(); // Because we can't populate Flags in the constructor.
}
StagedFlags.Names = StagedFlags.Names ?? Database.KnownFlags;
}
public IActionResult OnPostUnstage(List<FormFlag> addedAndDeletedFlags, List<RenameFlag> renamedFlags, string password)
public IActionResult OnPostDelete(string flag)
{
if (password != staging.Password) // TODO: Maybe we should hash this?
{
Message = "Wrong Password";
return Page();
}
try // Haha I can't program
{
var addedAndDeleted = addedAndDeletedFlags.Where(x => x.IsChecked);
var renamed = renamedFlags.Where(x => x.IsChecked);
var stagingFlag = Flag.CreateFromDelete(flag).Value;
addedAndDeleted.ForEach(x =>
_ = x.FormMethod switch
{
// Using an enum seems kinda redundant here.
Method.Delete => staging.DeletedFlags.Remove(staging.DeletedFlags.First(y => y.Name == x.Name)),
Method.Add => staging.AddedFlags.Remove(staging.AddedFlags.First(y => y.Name == x.Name)),
_ => throw new Exception()
});
StagedFlags.Flags.Add(stagingFlag);
StagedFlags.Names.Remove(stagingFlag.Name);
renamed.ForEach(x => staging.RenamedFlags.Remove(staging.RenamedFlags.First(y => y.Name == x.Name))); // These can be reworked to use asp-for and then we can work off the original objects.
addedAndDeleted.ForEach(x => staging.Flags.Add(x.Name));
renamed.ForEach(x => staging.Flags.Add(x.Name));
Message = $"{stagingFlag.Name} deleted.";
return Page();
}
staging.Flags = staging.Flags.Distinct().OrderBy(x => x).ToList();
public IActionResult OnPostRename(string flag, string newName)
{
var stagingFlag = Flag.CreateFromRename(flag, newName, AllNames);
Message = $"Successfully unstaged flags";
}
catch
if (stagingFlag.Failed)
{
Message = "Something went very wrong";
Message = stagingFlag.ErrorMessage;
return Page();
}
StagedFlags.Flags.Add(stagingFlag.Value);
StagedFlags.Names.Remove(stagingFlag.Value.OldName);
Message = $"{stagingFlag.Value.OldName} renamed to {stagingFlag.Value.Name}.";
return Page();
}
public async Task<IActionResult> OnPostCommitAsync(string password)
public async Task<IActionResult> OnPostAddAsync(IFormFile upload, bool gloss)
{
if (password != staging.Password)
var stagingFlag = await Flag.CreateFromFile(upload, AllNames);
if (stagingFlag.Failed)
{
Message = "Wrong Password";
Message = stagingFlag.ErrorMessage;
return Page();
}
try
{
// TODO: This needs to be rewritten / burnt / both
if (staging.DeletedFlags.Any())
{
await Database.DeleteFlagsAsync(staging.DeletedFlags);
staging.DeletedFlags
.ForEach(flag => System.IO.File.Copy(Path.Combine(FlagsPath, flag.Name + ".png"), Path.Combine(FlagsPath, "dead/", flag.Name + ".png")));
}
if (staging.AddedFlags.Any())
{
await Database.InsertFlagsAsync(staging.AddedFlags);
using var memoryStream = new MemoryStream();
await upload.CopyToAsync(memoryStream);
staging.AddedFlags
.ForEach(flag => System.IO.File.Copy(Path.Combine(FlagsPath, "staging/", flag.Name + ".png"), Path.Combine(FlagsPath, flag.Name + ".png")));
}
memoryStream.Position = 0;
if (staging.RenamedFlags.Any())
{
await Database.RenameFlagsAsync(staging.RenamedFlags);
staging.RenamedFlags
.ForEach(flag => System.IO.File.Copy(Path.Combine(FlagsPath, flag.Name + ".png"), Path.Combine(FlagsPath, flag.NewName + ".png")));
}
// Magic.NET is a huge dependency to be used like this
// Maybe we should switch to a Process and expect to have
// ImageMagick installed on the target machine.
using var image = new MagickImage(memoryStream);
await Database.UpdateKnownFlags();
staging.Flags = await Database.GetFlags();
staging.Clear();
Message = "Changes Commited successfully";
}
catch (Exception e)
if (gloss)
{
Message = "Something went bang\n" + e.Message;
}
using var glossImage = new MagickImage(WebRoot + "/gloss.png");
return Page();
}
glossImage.Composite(image, new PointD(0, 0), CompositeOperator.Over);
}
public IActionResult OnPostDelete(string flag)
{
staging.DeletedFlags.Add(new FormFlag
{
Name = flag
});
image.Write(WebRoot + "/flags/staging/" + upload.FileName);
staging.Flags.Remove(flag);
StagedFlags.Flags.Add(stagingFlag.Value);
Message = $"{stagingFlag.Value.Name} uploaded";
return Page();
}
public IActionResult OnPostRename(string flag, string newName)
public IActionResult OnPostUnstage(Flag[] flags, string password)
{
if (!(FileNameIsValid(newName)))
if (password != StagedFlags.Password)
{
Message = "Invalid Filename.";
Message = "Incorrect Password";
return Page();
}
staging.RenamedFlags.Add(new RenameFlag
{
Name = flag,
NewName = newName
});
staging.Flags.Remove(flag);
return Page();
}
public async Task<IActionResult> OnPostAddAsync()
{
try
for (int i = flags.Length - 1; i >= 0; i--)
{
if (!(await ValidateImageAsync()))
if (flags[i].IsChecked != true)
{
Message = "Invalid Image.";
return Page();
continue;
}
// TODO: maybe there's something no releasing memory here. - can't Directory.Move().
StagedFlags.Flags.RemoveAt(i);
using var memoryStream = new MemoryStream();
await Upload.CopyToAsync(memoryStream);
memoryStream.Position = 0;
// Magic.NET is a huge dependency to be used like this
// Maybe we should switch to a Process and expect to have
// ImageMagick installed on the target machine.
using var image = new MagickImage(memoryStream);
if (ShouldGloss)
var flag = flags[i];
switch (flag.FlagMethod)
{
using var gloss = new MagickImage(Env.WebRootPath + "/gloss.png");
case Method.Add:
System.IO.File.Delete(WebRoot + "/flags/staging/" + flag.Name);
StagedFlags.Names.Remove(flag.Name);
break;
gloss.Composite(image, new PointD(0, 0), CompositeOperator.Over);
}
case Method.Delete:
StagedFlags.Names.Add(flag.Name);
break;
image.Write(FlagsPath + "staging/" + Upload.FileName);
case Method.Rename:
StagedFlags.Names.Add(flag.OldName);
break;
staging.AddedFlags.Add(new FormFlag
{
Name = Path.GetFileNameWithoutExtension(Upload.FileName)
});
Message = "Flag uploaded successfully!";
return Page();
default:
throw new Exception();
}
}
catch (Exception e)
{
Message = $"Something went bang.\n\n\n{e.Message}";
return Page();
}
Message = "Removed flags from staging";
return Page();
}
// TODO: hash images and check against for duplicates.
// or is that going too far?
/// <summary>
/// Rigorously validates an image to ensure it's a flag.
/// </summary>
public async Task<bool> ValidateImageAsync()
public async Task<IActionResult> OnPostCommit(string password)
{
var fileName = Path.GetFileNameWithoutExtension(Upload.FileName);
if (!(FileNameIsValid(fileName))
|| Upload.Length > 15 * 1024 // 15KB
|| Upload.ContentType.ToLower() != "image/png")
if (password != StagedFlags.Password)
{
return false;
Message = "Incorrect Password";
return Page();
}
using (var memoryStream = new MemoryStream())
foreach (var flag in StagedFlags.Flags)
{
await Upload.CopyToAsync(memoryStream);
string flagname = flag.Name + ".png";
memoryStream.Position = 0;
using (var image = new MagickImage(memoryStream))
switch (flag.FlagMethod)
{
if (image.Width != 16 || image.Height != 11)
{
return false;
}
case Method.Add:
await Database.InsertFlagAsync(flag);
Directory.Move(WebRoot + "/flags/staging/" + flagname, WebRoot + "/flags/" + flagname);
break;
case Method.Delete:
await Database.DeleteFlagAsync(flag);
Directory.Move(WebRoot + "/flags/" + flagname, WebRoot + "/flags/dead/" + flagname);
break;
case Method.Rename:
await Database.RenameFlagAsync(flag);
Directory.Move(WebRoot + "/flags/" + flag.OldName + ".png", WebRoot + "/flags/" + flagname);
break;
default:
throw new Exception();
}
}
using (var reader = new BinaryReader(memoryStream))
{
reader.BaseStream.Position = 0;
await Database.UpdateKnownFlags();
StagedFlags.Names = Database.KnownFlags;
StagedFlags.Clear();
return reader.ReadBytes(PNGHeader.Length).SequenceEqual(PNGHeader);
}
}
Message = "Changes committed successfully";
return Page();
}
/// <summary>
/// Matches bad things we don't want in filenames.
/// Inverts the result - returns false on a match.
/// </summary>
/// <param name="fileName">The name of the file to validate.</param>
/// <returns></returns>
private bool FileNameIsValid(string fileName) =>
!(fileName == null
|| fileName.Contains("||")
|| fileName.Contains(",")
|| Database.KnownFlags.Contains(fileName)
|| staging.AddedFlags.Select(x => x.Name).Contains(fileName)
|| staging.DeletedFlags.Select(x => x.Name).Contains(fileName)
|| staging.RenamedFlags.Select(x => x.Name).Contains(fileName)
|| staging.RenamedFlags.Select(x => x.NewName).Contains(fileName)
|| fileName.Length > 100);
}
}

@ -4,7 +4,6 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;

@ -21,4 +21,8 @@ h3 {
width: 12%;
display: inline-block;
padding-bottom: 10px;
}
#message {
color: #ee0;
}
Loading…
Cancel
Save