You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bantflags/BantFlags/Data/Staging.cs

150 lines
4.4 KiB

// (C) Copyright 2019 C-xC-c <boku@plum.moe>
// This file is part of BantFlags.
// BantFlags is licensed under the GNU AGPL Version 3.0 or later.
// see the LICENSE file or <https://www.gnu.org/licenses/>
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
{
public class Staging
{
public List<Flag> Flags { get; set; }
public string Password { get; }
public HashSet<string> Names { get; set; }
public Staging(string password)
{
Flags = new List<Flag>();
Password = password;
}
public void Clear()
{
Flags = new List<Flag>();
}
}
public enum Method
{
Add = 0,
Delete = 1,
Rename = 2
}
public class Flag
{
public string Name { get; set; }
public string OldName { get; set; }
public bool IsChecked { get; set; }
public Method FlagMethod { get; set; }
// This is bad but we need it so Flags can be generated by the input tag helper
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 Flag CreateFromDelete(string name) => new Flag(name, Method.Delete); // We don't need any validation for deleted flags.
public static (Flag, string) CreateFromRename(string oldName, string newName, HashSet<string> names)
{
(bool valid, string error) = ValidateFileName(newName, names);
if (!valid)
{
return (default, error);
}
return (new Flag(newName, oldName, Method.Rename), default);
}
public static async Task<(Flag, string)> CreateFromFile(IFormFile upload, HashSet<string> names)
{
byte[] PNGHeader = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
if (upload.ContentType.ToLower() != "image/png")
return (default, "Image must be a png.");
if (upload.Length > 15 * 1024)
return (default, "File too big. Max size is 15kb.");
var name = Path.GetFileNameWithoutExtension(upload.FileName);
(bool valid, string error) = ValidateFileName(name, names);
if (!valid)
return (default, error);
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 (default, "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 (default, "Invalid png header.");
}
}
return (new Flag(name, Method.Add), default);
}
/// <summary>
/// Filters file names created by users.
/// </summary>
/// <param name="name">The file name to validate.</param>
/// <param name="names">The list of current file names.</param>
private static (bool, string) ValidateFileName(string name, HashSet<string> names)
{
if (string.IsNullOrWhiteSpace(name))
return (false, "Flag name can't be empty.");
if (name.Length > 100)
return (false, "Flag name too long.");
if (name == "empty, or there were errors. Re - set your flags.")
return (false, "Invalid flag name.");
if (name.Contains("||") || name.Contains(","))
return (false, "Flag name contains invalid characters. You can't use \"||\" or \",\".");
if (names.Contains(name))
return (false, "A flag with that name already exists.");
return (true, name);
}
}
}