2019-01-13_19-25-29.txt

// /buckets/floatr/2019-01-13_19-25-29.txt
2019-01-13_19-25-29.txt view original go back
2019-01-13_19-25-29.txt
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.AspNetCore.Http;
using System.IO;
using IO = System.IO;

namespace filehost.Controllers
{
    /*
        Project Scope:
            To create a simple, basic, and primitive file host, similar to floatr.
            We will use only native functions, and basics.
            No database, tracking, or configuration is involved.
            This is not meant to be deployed in a production environment.
            This is for educational purposes only.

        To-Do:
            * Create an action to recieve files.
                * Prevent executables and malicious files from being uplaoded. 
                * Save the file. 
                * Return file information.
            * Create an action for returning files.
                * Find the file by name.
                * Return the file in the HTTP request.
            * Create an action to respond with static files (html/css/js/etc..)
                * Create a basic HTML page
                * Create a UI that allows people to upload
                * Return the files based on file name.
                
        Notes:
            * The "await Task.Run(...)" lines do not matter and should be ignored.
    */
    
    public class MainController : Controller
    {
        public static string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        public static string FilesPath = "files/";
        public static string StaticPath = "static/";
        public static string[] bad_extensions = { "html", "htm", "aspx", "asp", "exe", "dmg" };
        public static bool Debug = true;
        
        [Route("/")]
        [AcceptVerbs("GET")]
        public async Task<IActionResult> GetIndex()
        {
            await Task.Run(() => { if(Debug){ Console.WriteLine("[DEBUG] Returning static file 'index.html.'"); }});
            
            return File(IO.File.OpenRead(StaticPath + "index.html"), "text/html");
        }
        
        [Route("/u/{file_id}.{ext?}")]
        [AcceptVerbs("GET")]
        public async Task<IActionResult> GetFile([FromRoute] string file_id = null, [FromRoute] string ext = null)
        {
            if(bad_extensions.Contains(ext))
            {
                Response.ContentType = "text/html";
                Response.StatusCode = 400;
                string error_template = IO.File.ReadAllText(StaticPath + "upload_error.html");
                string error = "uh oh! pixl-sama wants to protect you from bad files; gomen. :)";
                await Task.Run(() => { if(Debug){ Console.WriteLine("[DEBUG] Returning static file 'upload_error.html.'"); }});
                
                return Content(error_template.Replace("-ERROR-", error));
            }
            
            string file_path = Directory.GetFiles(FilesPath).FirstOrDefault(x => Path.GetFileNameWithoutExtension(x.Split('.')[0]) == file_id);
            
            //Advanced LINQ lambada coded by bin.
            
            if(!IO.File.Exists(file_path))
            {
                Response.ContentType = "text/html";
                Response.StatusCode = 404;
                string error_template = IO.File.ReadAllText(StaticPath + "upload_error.html");
                string error = "uh oh! pixl-sama couldn't find the file. ;-;";
                await Task.Run(() => { if(Debug){ Console.WriteLine("[DEBUG] Returning static file 'upload_error.html.'"); }});
                
                return Content(error_template.Replace("-ERROR-", error));  
            }
            else
            {
                return File(IO.File.OpenRead(file_path), GetContentType(file_path));
            }
        }
        
        [Route("/upload_file")]
        [AcceptVerbs("GET")]
        public async Task<IActionResult> GetFileUpload()
        {
            await Task.Run(() => { if(Debug){ Console.WriteLine("[DEBUG] Returning static file 'upload_file.html.'"); }});
            
            return File(IO.File.OpenRead(StaticPath + "upload_file.html"), "text/html");
        }
        
        [Route("/upload_file")]
        [AcceptVerbs("POST")]
        public async Task<IActionResult> UploadFile([FromForm] IFormFile file = null)
        {
            string error = null;
            string file_id = GenerateRandomString(5); // Generates a 5 character long random string.
            
            if(file == null || file.Length < 1)
            {
                Response.StatusCode = 400;
                error = "please upload a file.";
            }
            else if(file.Length > 10 * 1024 * 1024)
            {
                Response.StatusCode = 400;
                error = "file size is too large. the maximum is 10 megabytes.";
            }
            
            if(error == null)
            {
                string extension = IO.Path.GetExtension(file.FileName);

                if(bad_extensions.Contains(extension))
                {
                    Response.StatusCode = 400;
                    error = "uh oh! pixl-sama doesn't like bad files :(";
                }
                else
                {
                    using(var Stream = new FileStream(FilesPath + file_id + extension, FileMode.Create))
                    {
                        await file.CopyToAsync(Stream);
                    }
                }
            }
            
            await Task.Run(() => { if(Debug){ Console.WriteLine("[DEBUG] Returning static file 'file_uploaded.html.'"); }});
            
            Response.ContentType = "text/html";
            
            if(error != null)
            {
                string error_template = IO.File.ReadAllText(StaticPath + "upload_error.html");
                return Content(error_template.Replace("-ERROR-", error));
            }
            
            string template = IO.File.ReadAllText(StaticPath + "file_uploaded.html");
            template = template.Replace("-FILE_ID-", file_id);
            
            return Content(template);
        }
        
        [NonAction]
        public string GenerateRandomString(int len)
        {
            return new string(Enumerable.Repeat(chars, len)
              .Select(s => s[new Random().Next(s.Length)]).ToArray());
        }
        
        [NonAction]
        public string GetContentType(string filename)
        {
            string contentType;
            new FileExtensionContentTypeProvider().TryGetContentType(filename, out contentType);
            return contentType ?? "application/octet-stream";
        }
    }
}