// (C) Copyright 2019 C-xC-c // This file is part of BantFlags. // BantFlags is licensed under the GNU AGPL Version 3.0 or later. // see the LICENSE file or 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 Flags { get; set; } public string Password { get; } public HashSet Names { get; set; } public Staging(string password) { Flags = new List(); Password = password; } public void Clear() { Flags = new List(); } } 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 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 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); } /// /// Filters file names created by users. /// /// The file name to validate. /// The list of current file names. private static (bool, string) ValidateFileName(string name, HashSet 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); } } }