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";
}
}
}