The next generation of the Teknik Services. Written in ASP.NET.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

UploadController.cs 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. using nClam;
  2. using Piwik.Tracker;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Data.Entity;
  6. using System.Drawing;
  7. using System.Drawing.Imaging;
  8. using System.IO;
  9. using System.Linq;
  10. using System.Web;
  11. using System.Web.Mvc;
  12. using Teknik.Areas.Error.ViewModels;
  13. using Teknik.Areas.Upload.Models;
  14. using Teknik.Areas.Upload.ViewModels;
  15. using Teknik.Areas.Users.Utility;
  16. using Teknik.Controllers;
  17. using Teknik.Filters;
  18. using Teknik.Utilities;
  19. using Teknik.Models;
  20. using Teknik.Attributes;
  21. using System.Text;
  22. using Org.BouncyCastle.Crypto;
  23. namespace Teknik.Areas.Upload.Controllers
  24. {
  25. [TeknikAuthorize]
  26. public class UploadController : DefaultController
  27. {
  28. private TeknikEntities db = new TeknikEntities();
  29. // GET: Upload/Upload
  30. [HttpGet]
  31. [TrackPageView]
  32. [AllowAnonymous]
  33. public ActionResult Index()
  34. {
  35. ViewBag.Title = "Teknik Upload - End to End Encryption";
  36. UploadViewModel model = new UploadViewModel();
  37. model.CurrentSub = Subdomain;
  38. Users.Models.User user = UserHelper.GetUser(db, User.Identity.Name);
  39. if (user != null)
  40. {
  41. model.Encrypt = user.UploadSettings.Encrypt;
  42. model.Vaults = user.Vaults.ToList();
  43. }
  44. else
  45. {
  46. model.Encrypt = false;
  47. }
  48. return View(model);
  49. }
  50. [HttpPost]
  51. [AllowAnonymous]
  52. public ActionResult Upload(string fileType, string fileExt, string iv, int keySize, int blockSize, bool encrypt, HttpPostedFileWrapper data)
  53. {
  54. try
  55. {
  56. if (Config.UploadConfig.UploadEnabled)
  57. {
  58. if (data.ContentLength <= Config.UploadConfig.MaxUploadSize)
  59. {
  60. // convert file to bytes
  61. int contentLength = data.ContentLength;
  62. // Scan the file to detect a virus
  63. if (Config.UploadConfig.VirusScanEnable)
  64. {
  65. ClamClient clam = new ClamClient(Config.UploadConfig.ClamServer, Config.UploadConfig.ClamPort);
  66. clam.MaxStreamSize = Config.UploadConfig.MaxUploadSize;
  67. ClamScanResult scanResult = clam.SendAndScanFile(data.InputStream);
  68. switch (scanResult.Result)
  69. {
  70. case ClamScanResults.Clean:
  71. break;
  72. case ClamScanResults.VirusDetected:
  73. return Json(new { error = new { message = string.Format("Virus Detected: {0}. As per our <a href=\"{1}\">Terms of Service</a>, Viruses are not permited.", scanResult.InfectedFiles.First().VirusName, Url.SubRouteUrl("tos", "TOS.Index")) } });
  74. case ClamScanResults.Error:
  75. return Json(new { error = new { message = string.Format("Error scanning the file upload for viruses. {0}", scanResult.RawResult) } });
  76. case ClamScanResults.Unknown:
  77. return Json(new { error = new { message = string.Format("Unknown result while scanning the file upload for viruses. {0}", scanResult.RawResult) } });
  78. }
  79. }
  80. Models.Upload upload = Uploader.SaveFile(db, Config, data.InputStream, fileType, contentLength, encrypt, fileExt, iv, null, keySize, blockSize);
  81. if (upload != null)
  82. {
  83. if (User.Identity.IsAuthenticated)
  84. {
  85. Users.Models.User user = UserHelper.GetUser(db, User.Identity.Name);
  86. if (user != null)
  87. {
  88. upload.UserId = user.UserId;
  89. db.Entry(upload).State = EntityState.Modified;
  90. db.SaveChanges();
  91. }
  92. }
  93. return Json(new { result = new { name = upload.Url, url = Url.SubRouteUrl("u", "Upload.Download", new { file = upload.Url }), contentType = upload.ContentType, contentLength = StringHelper.GetBytesReadable(upload.ContentLength), deleteUrl = Url.SubRouteUrl("u", "Upload.Delete", new { file = upload.Url, key = upload.DeleteKey }) } }, "text/plain");
  94. }
  95. return Json(new { error = new { message = "Unable to upload file" } });
  96. }
  97. else
  98. {
  99. return Json(new { error = new { message = "File Too Large" } });
  100. }
  101. }
  102. return Json(new { error = new { message = "Uploads are disabled" } });
  103. }
  104. catch (Exception ex)
  105. {
  106. return Json(new { error = new { message = "Exception while uploading file: " + ex.GetFullMessage(true) } });
  107. }
  108. }
  109. // User did not supply key
  110. [HttpGet]
  111. [TrackDownload]
  112. [AllowAnonymous]
  113. public ActionResult Download(string file)
  114. {
  115. if (Config.UploadConfig.DownloadEnabled)
  116. {
  117. ViewBag.Title = "Teknik Download - " + file;
  118. Models.Upload upload = db.Uploads.Where(up => up.Url == file).FirstOrDefault();
  119. if (upload != null)
  120. {
  121. upload.Downloads += 1;
  122. db.Entry(upload).State = EntityState.Modified;
  123. db.SaveChanges();
  124. // We don't have the key, so we need to decrypt it client side
  125. if (string.IsNullOrEmpty(upload.Key) && !string.IsNullOrEmpty(upload.IV))
  126. {
  127. DownloadViewModel model = new DownloadViewModel();
  128. model.FileName = file;
  129. model.ContentType = upload.ContentType;
  130. model.ContentLength = upload.ContentLength;
  131. model.IV = upload.IV;
  132. return View(model);
  133. }
  134. else // We have the key, so that means server side decryption
  135. {
  136. // Are they downloading it by range?
  137. bool byRange = !string.IsNullOrEmpty(Request.ServerVariables["HTTP_RANGE"]); // We do not support ranges
  138. // Check to see if they have a cache
  139. bool isCached = !string.IsNullOrEmpty(Request.Headers["If-Modified-Since"]);
  140. if (isCached)
  141. {
  142. // The file is cached, let's just 304 this
  143. Response.StatusCode = 304;
  144. Response.StatusDescription = "Not Modified";
  145. Response.AddHeader("Content-Length", "0");
  146. return Content(string.Empty);
  147. }
  148. else
  149. {
  150. string subDir = upload.FileName[0].ToString();
  151. string filePath = Path.Combine(Config.UploadConfig.UploadDirectory, subDir, upload.FileName);
  152. if (System.IO.File.Exists(filePath))
  153. {
  154. // Add cache parameters
  155. Response.Cache.SetCacheability(HttpCacheability.Public);
  156. Response.Cache.SetMaxAge(new TimeSpan(365, 0, 0, 0));
  157. Response.Cache.SetLastModified(upload.DateUploaded);
  158. // Notify the client the content length we'll be outputting
  159. Response.AddHeader("Content-Length", upload.ContentLength.ToString());
  160. // Create content disposition
  161. var cd = new System.Net.Mime.ContentDisposition
  162. {
  163. FileName = upload.Url,
  164. Inline = true
  165. };
  166. Response.AddHeader("Content-Disposition", cd.ToString());
  167. string contentType = upload.ContentType;
  168. // We need to prevent html (make cleaner later)
  169. if (contentType == "text/html")
  170. {
  171. contentType = "text/plain";
  172. }
  173. // Read in the file
  174. FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
  175. // If the IV is set, and Key is set, then decrypt it while sending
  176. if (!string.IsNullOrEmpty(upload.Key) && !string.IsNullOrEmpty(upload.IV))
  177. {
  178. byte[] keyBytes = Encoding.UTF8.GetBytes(upload.Key);
  179. byte[] ivBytes = Encoding.UTF8.GetBytes(upload.IV);
  180. return new FileGenerateResult(upload.Url,
  181. contentType,
  182. (response) => ResponseHelper.StreamToOutput(response, true, new AESCryptoStream(fs, false, keyBytes, ivBytes, "CTR", "NoPadding"), (int)upload.ContentLength, Config.UploadConfig.ChunkSize),
  183. false);
  184. }
  185. else // Otherwise just send it
  186. {
  187. // Don't buffer the response
  188. Response.Buffer = false;
  189. // Send the file
  190. return new FileGenerateResult(upload.Url,
  191. contentType,
  192. (response) => ResponseHelper.StreamToOutput(response, true, fs, (int)upload.ContentLength, Config.UploadConfig.ChunkSize),
  193. false);
  194. }
  195. }
  196. }
  197. }
  198. }
  199. return Redirect(Url.SubRouteUrl("error", "Error.Http404"));
  200. }
  201. return Redirect(Url.SubRouteUrl("error", "Error.Http403"));
  202. }
  203. [HttpPost]
  204. [AllowAnonymous]
  205. public FileResult DownloadData(string file)
  206. {
  207. if (Config.UploadConfig.DownloadEnabled)
  208. {
  209. Models.Upload upload = db.Uploads.Where(up => up.Url == file).FirstOrDefault();
  210. if (upload != null)
  211. {
  212. string subDir = upload.FileName[0].ToString();
  213. string filePath = Path.Combine(Config.UploadConfig.UploadDirectory, subDir, upload.FileName);
  214. if (System.IO.File.Exists(filePath))
  215. {
  216. FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
  217. return File(fileStream, System.Net.Mime.MediaTypeNames.Application.Octet, file);
  218. }
  219. }
  220. Redirect(Url.SubRouteUrl("error", "Error.Http404"));
  221. return null;
  222. }
  223. Redirect(Url.SubRouteUrl("error", "Error.Http403"));
  224. return null;
  225. }
  226. [HttpGet]
  227. [AllowAnonymous]
  228. public ActionResult Delete(string file, string key)
  229. {
  230. ViewBag.Title = "File Delete - " + file + " - " + Config.Title;
  231. Models.Upload upload = db.Uploads.Where(up => up.Url == file).FirstOrDefault();
  232. if (upload != null)
  233. {
  234. DeleteViewModel model = new DeleteViewModel();
  235. model.File = file;
  236. if (!string.IsNullOrEmpty(upload.DeleteKey) && upload.DeleteKey == key)
  237. {
  238. string filePath = upload.FileName;
  239. // Delete from the DB
  240. db.Uploads.Remove(upload);
  241. db.SaveChanges();
  242. // Delete the File
  243. if (System.IO.File.Exists(filePath))
  244. {
  245. System.IO.File.Delete(filePath);
  246. }
  247. model.Deleted = true;
  248. }
  249. else
  250. {
  251. model.Deleted = false;
  252. }
  253. return View(model);
  254. }
  255. return RedirectToRoute("Error.Http404");
  256. }
  257. [HttpPost]
  258. public ActionResult GenerateDeleteKey(string file)
  259. {
  260. Models.Upload upload = db.Uploads.Where(up => up.Url == file).FirstOrDefault();
  261. if (upload != null)
  262. {
  263. if (upload.User.Username == User.Identity.Name)
  264. {
  265. string delKey = StringHelper.RandomString(Config.UploadConfig.DeleteKeyLength);
  266. upload.DeleteKey = delKey;
  267. db.Entry(upload).State = EntityState.Modified;
  268. db.SaveChanges();
  269. return Json(new { result = new { url = Url.SubRouteUrl("u", "Upload.Delete", new { file = file, key = delKey }) } });
  270. }
  271. return Json(new { error = new { message = "You do not own this upload" } });
  272. }
  273. return Json(new { error = new { message = "Invalid URL" } });
  274. }
  275. }
  276. }